1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
/* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
#include <cstdio>
#include <cstdarg>
#include <cstring>
#include <set>
#include "Backend.h"
#include "DefaultFilter.h"
#include "LogUtil.h"
#include "System/MainDefines.h"
namespace {
std::set<log_sink_ptr>& log_formatter_getSinks() {
static std::set<log_sink_ptr> sinks;
return sinks;
}
std::set<log_cleanup_ptr>& log_formatter_getCleanupFuncs() {
static std::set<log_cleanup_ptr> cleanupFuncs;
return cleanupFuncs;
}
}
#ifdef __cplusplus
extern "C" {
#endif
// note: no real point to TLS, sinks themselves are not thread-safe
static _threadlocal log_record_t cur_record = {{0}, "", "", 0, 0};
static _threadlocal log_record_t prv_record = {{0}, "", "", 0, 0};
extern void log_formatter_format(log_record_t* log, va_list arguments);
void log_backend_registerSink(log_sink_ptr sink) { log_formatter_getSinks().insert(sink); }
void log_backend_unregisterSink(log_sink_ptr sink) { log_formatter_getSinks().erase(sink); }
void log_backend_registerCleanup(log_cleanup_ptr cleanupFunc) { log_formatter_getCleanupFuncs().insert(cleanupFunc); }
void log_backend_unregisterCleanup(log_cleanup_ptr cleanupFunc) { log_formatter_getCleanupFuncs().erase(cleanupFunc); }
/**
* @name logging_backend
* ILog.h backend implementation.
*/
///@{
// formats and routes the record to all sinks
void log_backend_record(int level, const char* section, const char* fmt, va_list arguments)
{
const auto& sinks = log_formatter_getSinks();
if (sinks.empty())
return;
cur_record.sec = section;
cur_record.fmt = fmt;
cur_record.lvl = level;
// format the record
log_formatter_format(&cur_record, arguments);
// check for duplicates after formatting; can not be
// done in log_frontend_record or log_filter_record
const int cmp = (prv_record.msg[0] != 0 && STRCASECMP(cur_record.msg, prv_record.msg) == 0);
cur_record.cnt += cmp;
cur_record.cnt *= cmp;
if (cur_record.cnt >= log_filter_getRepeatLimit())
return;
// sink the record into each registered sink
for (log_sink_ptr fptr: sinks) {
fptr(level, section, cur_record.msg);
}
if (cur_record.cnt > 0)
return;
memcpy(prv_record.msg, cur_record.msg, sizeof(cur_record.msg));
}
/// Passes on a cleanup request to all sinks
void log_backend_cleanup() {
for (log_cleanup_ptr fptr: log_formatter_getCleanupFuncs()) {
fptr();
}
}
///@}
#ifdef __cplusplus
} // extern "C"
#endif
|