155 lines
4.6 KiB
C++
155 lines
4.6 KiB
C++
|
#include "log.hpp"
|
||
|
#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
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;
|
||
|
}
|
||
|
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 {
|
||
|
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)
|
||
|
: 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)
|
||
|
{
|
||
|
this->streams = std::set(streams);
|
||
|
}
|
||
|
LogStream::LogStream(std::initializer_list<std::string> names, std::initializer_list<FILE*> outputs, int log_level)
|
||
|
: LogStream(names, log_level, false)
|
||
|
{
|
||
|
this->outputs = std::set(outputs);
|
||
|
}
|
||
|
static LogStream *debug_stream;
|
||
|
static LogStream *info_stream;
|
||
|
static LogStream *warning_stream;
|
||
|
static LogStream *error_stream;
|
||
|
void init_logging() {
|
||
|
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);
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|