196 lines
No EOL
6.1 KiB
C++
196 lines
No EOL
6.1 KiB
C++
#include "log.hpp"
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#ifdef __ANDROID__
|
|
#include <android/log.h>
|
|
#endif
|
|
namespace Looper::Log {
|
|
std::set<FILE*> LogStream::global_outputs;
|
|
int LogStream::log_level = 0;
|
|
std::set<FILE*> LogStream::get_used_outputs() {
|
|
std::set<FILE*> used_outputs;
|
|
for (auto my_output : outputs) {
|
|
used_outputs.insert(my_output);
|
|
}
|
|
for (auto global_output : global_outputs) {
|
|
used_outputs.insert(global_output);
|
|
}
|
|
return used_outputs;
|
|
}
|
|
std::string line;
|
|
void LogStream::writec(const char chr) {
|
|
bool is_newline = (chr == '\n' || chr == '\r');
|
|
if (my_log_level < log_level) {
|
|
return;
|
|
}
|
|
writeprefix();
|
|
if (nested) {
|
|
for (auto &stream : streams) {
|
|
stream->writec(chr);
|
|
}
|
|
} else {
|
|
#ifdef __ANDROID__
|
|
if (!is_newline) {
|
|
line += chr;
|
|
} else {
|
|
for (auto logPriority : android_outputs) {
|
|
__android_log_print(logPriority, "Looper", "%s", line.c_str());
|
|
}
|
|
}
|
|
#endif
|
|
std::set<FILE*> used_outputs = get_used_outputs();
|
|
for (auto &file : used_outputs) {
|
|
fwrite(&chr, 1, 1, file);
|
|
}
|
|
}
|
|
if (is_newline) {
|
|
need_prefix = true;
|
|
}
|
|
}
|
|
void LogStream::writeprefix() {
|
|
if (need_prefix) {
|
|
need_prefix = false;
|
|
for (auto name : names) {
|
|
writec('[');
|
|
writes(name);
|
|
writes("] ");
|
|
}
|
|
}
|
|
}
|
|
void LogStream::writes(const char *msg) {
|
|
while (*msg != '\0') {
|
|
writec(*(msg++));
|
|
}
|
|
}
|
|
void LogStream::writesn(const char *msg, size_t n) {
|
|
for (size_t i = 0; i < n && msg[i] != '\0'; i++) {
|
|
writec(msg[i]);
|
|
}
|
|
}
|
|
void LogStream::writes(std::string msg) {
|
|
LogStream::writesn(msg.c_str(), msg.size());
|
|
}
|
|
void LogStream::writeln(const char *msg) {
|
|
LogStream::writes(msg);
|
|
LogStream::writec('\n');
|
|
}
|
|
void LogStream::writeln_n(const char *msg, size_t n) {
|
|
LogStream::writesn(msg, n);
|
|
LogStream::writec('\n');
|
|
}
|
|
void LogStream::writeln(std::string msg) {
|
|
LogStream::writes(msg);
|
|
LogStream::writec('\n');
|
|
}
|
|
void LogStream::writef(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vwritef(fmt, args);
|
|
va_end(args);
|
|
}
|
|
void LogStream::vwritef(const char *fmt, va_list args) {
|
|
va_list args_backup;
|
|
va_copy(args_backup, args);
|
|
size_t n = vsnprintf(NULL, 0, fmt, args);
|
|
va_end(args);
|
|
va_copy(args, args_backup);
|
|
size_t bufsize = n + 1;
|
|
char *buf = (char*)malloc(bufsize);
|
|
memset(buf, 0, bufsize);
|
|
if (buf == NULL) {
|
|
va_end(args);
|
|
va_end(args_backup);
|
|
throw std::exception();
|
|
}
|
|
n = vsnprintf(buf, bufsize, fmt, args);
|
|
va_end(args_backup);
|
|
LogStream::writes(buf);
|
|
free(buf);
|
|
}
|
|
void LogStream::vwritefln(const char *fmt, va_list args) {
|
|
vwritef(fmt, args);
|
|
writec('\n');
|
|
}
|
|
void LogStream::writefln(const char *fmt, ...) {
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vwritefln(fmt, args);
|
|
va_end(args);
|
|
}
|
|
LogStream::LogStream(std::initializer_list<std::string> names, int log_level, bool nested, void *discriminator)
|
|
: names(names),
|
|
need_prefix(true),
|
|
my_log_level(log_level),
|
|
nested(nested)
|
|
{
|
|
|
|
}
|
|
LogStream::LogStream(std::initializer_list<std::string> names, std::initializer_list<LogStream*> streams, int log_level)
|
|
: LogStream(names, log_level, true, nullptr)
|
|
{
|
|
this->streams = std::set(streams);
|
|
}
|
|
#ifdef __ANDROID__
|
|
LogStream::LogStream(std::initializer_list<std::string> names, std::initializer_list<std::variant<FILE*, android_LogPriority>> outputs, int log_level)
|
|
#else
|
|
LogStream::LogStream(std::initializer_list<std::string> names, std::initializer_list<FILE*> outputs, int log_level)
|
|
#endif
|
|
: LogStream(names, log_level, false, nullptr)
|
|
{
|
|
#ifdef __ANDROID__
|
|
std::set<FILE*> file_outputs;
|
|
std::set<android_LogPriority> android_outputs;
|
|
for (auto output : outputs) {
|
|
android_LogPriority *logPriority = std::get_if<android_LogPriority>(&output);
|
|
FILE **file = std::get_if<FILE*>(&output);
|
|
if (logPriority != nullptr) {
|
|
android_outputs.insert(*logPriority);
|
|
} else if (file != nullptr){
|
|
file_outputs.insert(*file);
|
|
}
|
|
}
|
|
this->android_outputs = android_outputs;
|
|
this->outputs = file_outputs;
|
|
#else
|
|
|
|
this->outputs = std::set(outputs);
|
|
#endif
|
|
}
|
|
static LogStream *debug_stream;
|
|
static LogStream *info_stream;
|
|
static LogStream *warning_stream;
|
|
static LogStream *error_stream;
|
|
void init_logging() {
|
|
#ifdef __ANDROID__
|
|
debug_stream = new LogStream({"DEBUG"}, {ANDROID_LOG_DEBUG}, -1);
|
|
info_stream = new LogStream({"INFO"}, {ANDROID_LOG_INFO}, 0);
|
|
warning_stream = new LogStream({"WARNING"}, {ANDROID_LOG_WARN}, 1);
|
|
error_stream = new LogStream({"ERROR"}, {ANDROID_LOG_ERROR}, 2);
|
|
#else
|
|
debug_stream = new LogStream({"DEBUG"}, {stderr}, -1);
|
|
info_stream = new LogStream({"INFO"}, {stdout}, 0);
|
|
warning_stream = new LogStream({"WARNING"}, {stderr}, 1);
|
|
error_stream = new LogStream({"ERROR"}, {stderr}, 2);
|
|
#endif
|
|
}
|
|
LogStream &get_log_stream_by_level(int level) {
|
|
switch (level) {
|
|
case -1: {
|
|
return *debug_stream;
|
|
} break;
|
|
case 0: {
|
|
return *info_stream;
|
|
} break;
|
|
case 1: {
|
|
return *warning_stream;
|
|
} break;
|
|
case 2: {
|
|
return *error_stream;
|
|
} break;
|
|
default: {
|
|
return *info_stream;
|
|
} break;
|
|
}
|
|
}
|
|
|
|
} |