2021-03-11 19:28:50 +01:00
|
|
|
#define SATDUMP_DLL_EXPORT 1
|
2021-02-14 12:05:44 +01:00
|
|
|
#include "logger.h"
|
|
|
|
|
#include <iostream>
|
2023-02-26 00:54:58 +00:00
|
|
|
#include <ctime>
|
|
|
|
|
#include <algorithm>
|
2021-05-09 23:50:14 +02:00
|
|
|
#ifdef __ANDROID__
|
2023-02-26 00:54:58 +00:00
|
|
|
#include <android/log.h>
|
|
|
|
|
static char ag_LogTag[] = "SatDump";
|
2021-05-09 23:50:14 +02:00
|
|
|
#endif
|
2023-03-01 16:04:51 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <wincon.h>
|
|
|
|
|
#endif
|
2021-02-14 12:05:44 +01:00
|
|
|
|
|
|
|
|
// Logger and sinks. We got a console sink and file sink
|
2021-05-09 23:50:14 +02:00
|
|
|
#ifdef __ANDROID__
|
2023-02-26 00:54:58 +00:00
|
|
|
std::shared_ptr<slog::AndroidSink> console_sink;
|
2023-03-01 16:04:51 +00:00
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
std::shared_ptr<slog::WinOutSink> console_sink;
|
2021-05-09 23:50:14 +02:00
|
|
|
#else
|
2023-02-26 00:54:58 +00:00
|
|
|
std::shared_ptr<slog::StdOutSink> console_sink;
|
2021-05-09 23:50:14 +02:00
|
|
|
#endif
|
2023-02-26 00:54:58 +00:00
|
|
|
std::shared_ptr<slog::FileSink> file_sink;
|
|
|
|
|
SATDUMP_DLL std::shared_ptr<slog::Logger> logger;
|
|
|
|
|
|
|
|
|
|
namespace slog
|
|
|
|
|
{
|
|
|
|
|
const std::string log_schar[] = {"T", "D", "I", "W", "E", "C"};
|
2023-03-01 16:04:51 +00:00
|
|
|
const std::string colors[] = {"\033[37m",
|
|
|
|
|
"\033[36m",
|
|
|
|
|
"\033[32m",
|
|
|
|
|
"\033[33m\033[1m",
|
|
|
|
|
"\033[31m\033[1m",
|
|
|
|
|
"\033[1m\033[41m"};
|
|
|
|
|
|
2023-05-08 23:08:34 +02:00
|
|
|
template <typename... T>
|
|
|
|
|
std::string vformat(const char *fmt, T &&...args)
|
|
|
|
|
{
|
|
|
|
|
// Allocate a buffer on the stack that's big enough for us almost
|
|
|
|
|
// all the time.
|
|
|
|
|
size_t size = 1024;
|
2023-05-09 08:04:50 +02:00
|
|
|
std::vector<char> buf;
|
|
|
|
|
buf.resize(size);
|
2023-05-08 23:08:34 +02:00
|
|
|
|
|
|
|
|
// Try to vsnprintf into our buffer.
|
|
|
|
|
size_t needed = snprintf((char *)&buf[0], size, fmt, args...);
|
|
|
|
|
// NB. On Windows, vsnprintf returns -1 if the string didn't fit the
|
|
|
|
|
// buffer. On Linux & OSX, it returns the length it would have needed.
|
|
|
|
|
|
2023-05-09 08:04:50 +02:00
|
|
|
if (needed <= size)
|
2023-05-08 23:08:34 +02:00
|
|
|
{
|
|
|
|
|
// It fit fine the first time, we're done.
|
|
|
|
|
return std::string(&buf[0]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// vsnprintf reported that it wanted to write more characters
|
|
|
|
|
// than we allotted. So do a malloc of the right size and try again.
|
|
|
|
|
// This doesn't happen very often if we chose our initial size
|
|
|
|
|
// well.
|
|
|
|
|
size = needed;
|
|
|
|
|
buf.resize(size);
|
|
|
|
|
needed = snprintf((char *)&buf[0], size, fmt, args...);
|
|
|
|
|
return std::string(&buf[0]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 16:04:51 +00:00
|
|
|
std::string LoggerSink::format_log(LogMsg m, bool color, int *cpos)
|
2023-02-26 00:54:58 +00:00
|
|
|
{
|
|
|
|
|
time_t ct = time(0);
|
|
|
|
|
std::tm *tmr = gmtime(&ct);
|
|
|
|
|
|
2023-02-26 02:44:09 +00:00
|
|
|
std::string timestamp =
|
2023-05-07 23:44:57 +02:00
|
|
|
(tmr->tm_hour < 10 ? "0" : "") + std::to_string(tmr->tm_hour) + ":" + // Hour
|
|
|
|
|
(tmr->tm_min < 10 ? "0" : "") + std::to_string(tmr->tm_min) + ":" + // Min
|
|
|
|
|
(tmr->tm_sec < 10 ? "0" : "") + std::to_string(tmr->tm_sec) + " - " + // Sec
|
|
|
|
|
(tmr->tm_mday < 10 ? "0" : "") + std::to_string(tmr->tm_mday) + "/" + // Day
|
|
|
|
|
(tmr->tm_mon + 1 < 10 ? "0" : "") + std::to_string(tmr->tm_mon + 1) + "/" + // Mon
|
|
|
|
|
(tmr->tm_year < 10 ? "0" : "") + std::to_string(tmr->tm_year + 1900); // Year
|
2023-02-26 02:44:09 +00:00
|
|
|
|
2023-03-01 16:04:51 +00:00
|
|
|
if (cpos != nullptr)
|
|
|
|
|
*cpos = timestamp.size() + 3;
|
|
|
|
|
|
2023-02-26 00:54:58 +00:00
|
|
|
if (color)
|
2023-05-08 23:08:34 +02:00
|
|
|
return vformat("[%s] %s(%s) %s\033[m\n",
|
|
|
|
|
timestamp.c_str(),
|
|
|
|
|
colors[m.lvl].c_str(), log_schar[m.lvl].c_str(), m.str.c_str());
|
2023-02-26 00:54:58 +00:00
|
|
|
else
|
2023-05-08 23:08:34 +02:00
|
|
|
return vformat("[%s] (%s) %s\n",
|
|
|
|
|
timestamp.c_str(),
|
|
|
|
|
log_schar[m.lvl].c_str(), m.str.c_str());
|
2023-02-26 00:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StdOutSink::receive(LogMsg log)
|
|
|
|
|
{
|
|
|
|
|
if (log.lvl >= sink_lvl)
|
|
|
|
|
{
|
|
|
|
|
std::string s = format_log(log, true);
|
|
|
|
|
fwrite(s.c_str(), sizeof(char), s.size(), stderr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 16:04:51 +00:00
|
|
|
#if defined(_WIN32)
|
2023-03-01 09:25:02 -08:00
|
|
|
const int colors_win[] = {FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
|
2023-03-24 18:03:33 +01:00
|
|
|
FOREGROUND_GREEN | FOREGROUND_BLUE,
|
|
|
|
|
FOREGROUND_GREEN,
|
|
|
|
|
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
|
|
|
|
|
FOREGROUND_RED | FOREGROUND_INTENSITY,
|
|
|
|
|
BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY};
|
2023-03-01 16:04:51 +00:00
|
|
|
|
2023-03-24 18:03:33 +01:00
|
|
|
int win_set_foreground_color(HANDLE &out_handle_, int attribs)
|
2023-03-01 09:25:02 -08:00
|
|
|
{
|
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;
|
|
|
|
|
if (!::GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info))
|
|
|
|
|
{
|
|
|
|
|
// just return white if failed getting console info
|
|
|
|
|
return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// change only the foreground bits (lowest 4 bits)
|
|
|
|
|
auto new_attribs = static_cast<int>(attribs) | (orig_buffer_info.wAttributes & 0xfff0);
|
|
|
|
|
auto ignored = ::SetConsoleTextAttribute(out_handle_, static_cast<WORD>(new_attribs));
|
|
|
|
|
(void)(ignored);
|
|
|
|
|
return orig_buffer_info.wAttributes; // return orig attribs
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-01 16:04:51 +00:00
|
|
|
void WinOutSink::receive(LogMsg log)
|
|
|
|
|
{
|
|
|
|
|
if (log.lvl >= sink_lvl)
|
|
|
|
|
{
|
|
|
|
|
int color_pos = 0;
|
|
|
|
|
std::string s = format_log(log, false, &color_pos);
|
|
|
|
|
std::string s1 = s.substr(0, color_pos);
|
2023-03-01 09:25:02 -08:00
|
|
|
std::string s2 = s.substr(color_pos, s.size() - color_pos - 1);
|
|
|
|
|
std::string s3 = s.substr(s.size() - 1, 1);
|
|
|
|
|
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
|
fwrite(s1.c_str(), sizeof(char), s1.size(), stderr);
|
|
|
|
|
int rst = win_set_foreground_color(hConsole, colors_win[log.lvl]);
|
|
|
|
|
fwrite(s2.c_str(), sizeof(char), s2.size(), stderr);
|
|
|
|
|
SetConsoleTextAttribute(hConsole, rst);
|
|
|
|
|
fwrite(s3.c_str(), sizeof(char), s3.size(), stderr);
|
2023-03-01 16:04:51 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2023-02-26 00:54:58 +00:00
|
|
|
FileSink::FileSink(std::string path)
|
|
|
|
|
{
|
|
|
|
|
outf = std::ofstream(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FileSink::~FileSink()
|
|
|
|
|
{
|
|
|
|
|
outf.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FileSink::receive(LogMsg log)
|
|
|
|
|
{
|
|
|
|
|
if (log.lvl >= sink_lvl)
|
|
|
|
|
{
|
|
|
|
|
std::string s = format_log(log, false);
|
|
|
|
|
outf.write(s.c_str(), s.size());
|
|
|
|
|
outf.flush(); // Too annoying when there's a segault not letting it flush
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Logger::log(LogLevel lvl, std::string v)
|
|
|
|
|
{
|
2023-03-24 18:03:33 +01:00
|
|
|
sink_mtx.lock();
|
2023-02-26 00:54:58 +00:00
|
|
|
LogMsg m;
|
|
|
|
|
m.str = v;
|
|
|
|
|
m.lvl = lvl;
|
|
|
|
|
if (m.lvl >= logger_lvl)
|
|
|
|
|
for (auto &l : sinks)
|
|
|
|
|
l->receive(m);
|
2023-03-24 18:03:33 +01:00
|
|
|
sink_mtx.unlock();
|
2023-02-26 00:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
2023-05-08 23:08:34 +02:00
|
|
|
void Logger::logf(LogLevel lvl, std::string fmt, va_list args)
|
|
|
|
|
{
|
|
|
|
|
std::string output;
|
|
|
|
|
output.resize(1024);
|
|
|
|
|
|
|
|
|
|
va_list argscopy;
|
|
|
|
|
va_copy(argscopy, args);
|
|
|
|
|
|
|
|
|
|
size_t size = vsnprintf((char *)output.c_str(), output.size(), fmt.c_str(), args);
|
|
|
|
|
|
|
|
|
|
if (output.size() <= size)
|
|
|
|
|
{
|
|
|
|
|
log(lvl, output);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
output.resize(size + 1);
|
|
|
|
|
size = vsnprintf((char *)output.c_str(), output.size(), fmt.c_str(), argscopy);
|
|
|
|
|
log(lvl, output);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-26 00:54:58 +00:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
|
const android_LogPriority log_lvls_a[] = {
|
|
|
|
|
ANDROID_LOG_VERBOSE,
|
|
|
|
|
ANDROID_LOG_DEBUG,
|
|
|
|
|
ANDROID_LOG_INFO,
|
|
|
|
|
ANDROID_LOG_WARN,
|
|
|
|
|
ANDROID_LOG_ERROR,
|
|
|
|
|
ANDROID_LOG_FATAL,
|
|
|
|
|
};
|
2023-03-01 16:04:51 +00:00
|
|
|
|
2023-02-26 00:54:58 +00:00
|
|
|
void AndroidSink::receive(LogMsg log)
|
|
|
|
|
{
|
|
|
|
|
if (log.lvl >= sink_lvl)
|
|
|
|
|
{
|
|
|
|
|
std::string s = format_log(log, false);
|
|
|
|
|
__android_log_print(log_lvls_a[log.lvl], ag_LogTag, "%s", log.str.c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
void Logger::set_level(LogLevel lvl)
|
|
|
|
|
{
|
|
|
|
|
logger_lvl = lvl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Logger::add_sink(std::shared_ptr<LoggerSink> sink)
|
|
|
|
|
{
|
2023-03-24 18:03:33 +01:00
|
|
|
sink_mtx.lock();
|
2023-02-26 00:54:58 +00:00
|
|
|
sinks.push_back(sink);
|
2023-03-24 18:03:33 +01:00
|
|
|
sink_mtx.unlock();
|
2023-02-26 00:54:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Logger::del_sink(std::shared_ptr<LoggerSink> sink)
|
|
|
|
|
{
|
2023-03-24 18:03:33 +01:00
|
|
|
sink_mtx.lock();
|
2023-08-16 14:13:14 -04:00
|
|
|
auto it = std::find_if(sinks.begin(), sinks.end(), [&sink](std::shared_ptr<LoggerSink>& c)
|
|
|
|
|
{ return sink.get() == c.get(); });
|
2023-02-26 00:54:58 +00:00
|
|
|
if (it != sinks.end())
|
|
|
|
|
sinks.erase(it);
|
2023-03-24 18:03:33 +01:00
|
|
|
sink_mtx.unlock();
|
2023-02-26 00:54:58 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-02-14 12:05:44 +01:00
|
|
|
|
|
|
|
|
void initLogger()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2021-05-09 23:50:14 +02:00
|
|
|
// Initialize everything
|
|
|
|
|
#ifdef __ANDROID__
|
2023-02-26 00:54:58 +00:00
|
|
|
console_sink = std::make_shared<slog::AndroidSink>();
|
2023-03-01 16:04:51 +00:00
|
|
|
#elif defined(_WIN32)
|
|
|
|
|
console_sink = std::make_shared<slog::WinOutSink>();
|
2021-05-09 23:50:14 +02:00
|
|
|
#else
|
2023-02-26 00:54:58 +00:00
|
|
|
console_sink = std::make_shared<slog::StdOutSink>();
|
2021-05-09 23:50:14 +02:00
|
|
|
#endif
|
2022-05-13 21:35:51 +02:00
|
|
|
|
2023-02-26 00:54:58 +00:00
|
|
|
// logger = std::shared_ptr<spdlog::logger>(new spdlog::logger("SatDump", {console_sink}));
|
|
|
|
|
logger = std::make_shared<slog::Logger>();
|
|
|
|
|
logger->add_sink(console_sink);
|
2021-02-14 12:05:44 +01:00
|
|
|
|
|
|
|
|
// Use a custom, nicer log pattern. No color in the file
|
2023-02-26 00:54:58 +00:00
|
|
|
// console_sink->set_pattern("[%D - %T] %^(%L) %v%$");
|
2021-02-14 12:05:44 +01:00
|
|
|
|
2022-11-26 17:50:44 +01:00
|
|
|
// Default log level
|
2023-02-26 00:54:58 +00:00
|
|
|
console_sink->set_level(slog::LOG_TRACE);
|
|
|
|
|
logger->set_level(slog::LOG_TRACE);
|
2021-02-14 12:05:44 +01:00
|
|
|
}
|
|
|
|
|
catch (std::exception &e)
|
|
|
|
|
{
|
|
|
|
|
std::cout << e.what() << std::endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-26 17:50:44 +01:00
|
|
|
void initFileSink()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2023-02-26 00:54:58 +00:00
|
|
|
file_sink = std::make_shared<slog::FileSink>("satdump.logs");
|
|
|
|
|
logger->add_sink(file_sink);
|
|
|
|
|
// file_sink->set_pattern("[%D - %T] (%L) %v");
|
|
|
|
|
file_sink->set_level(slog::LOG_TRACE);
|
2022-11-26 17:50:44 +01:00
|
|
|
}
|
|
|
|
|
catch (std::exception &e)
|
|
|
|
|
{
|
|
|
|
|
std::cout << e.what() << std::endl;
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-26 00:54:58 +00:00
|
|
|
void setConsoleLevel(slog::LogLevel level)
|
2021-02-14 12:05:44 +01:00
|
|
|
{
|
|
|
|
|
// Just change our log level
|
|
|
|
|
console_sink->set_level(level);
|
|
|
|
|
}
|