#include "log.hpp" #include #include #include "util.hpp" #ifdef __ANDROID__ #include #endif namespace Looper::Log { std::set LogStream::global_outputs; int LogStream::log_level = #ifdef DEBUG_MODE -2; #else 0; #endif std::set LogStream::get_used_outputs() { std::set 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 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) { const char *buf = vcformat(fmt, args); va_end(args); if (buf == NULL) { throw std::exception(); } LogStream::writes(buf); free((void*)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 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 names, std::initializer_list streams, int log_level) : LogStream(names, log_level, true, nullptr) { this->streams = std::set(streams); } #ifdef __ANDROID__ LogStream::LogStream(std::initializer_list names, std::initializer_list> outputs, int log_level) #else LogStream::LogStream(std::initializer_list names, std::initializer_list outputs, int log_level) #endif : LogStream(names, log_level, false, nullptr) { #ifdef __ANDROID__ std::set file_outputs; std::set android_outputs; for (auto output : outputs) { android_LogPriority *logPriority = std::get_if(&output); FILE **file = std::get_if(&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; } } } void write_log(int level, const char *log) { LOG(level).writes(log); } void write_logln(int level, const char *log) { LOG(level).writeln(log); }