53#include <unordered_map>
63using std::unordered_map;
78 _vsnprintf(
msg, 65535, format, ap);
80 OutputDebugString(
msg);
85 vfprintf(stderr, format, ap);
101 int size =
vsnprintf(NULL, 0, format, aq);
109 buf.append(size + 1,
'\0');
112 vsnprintf(buf.data() + style.length(), size + 1, format, ap);
114 auto & str = buf.get();
115 str.resize(str.size() - 1);
119 }
else if (style.size() > 0) {
120 if (str.at(str.size() - 1) ==
'\n') {
121 str.erase(str.size() - 1);
130void log_msg(
int level,
const char *format, ...) {
132 va_start(ap, format);
141 static volatile uint32_t oneshot_messages[10];
142 static atomic<size_t> oneshot_messages_cnt;
143 for (
size_t i = 0; i < oneshot_messages_cnt; ++i) {
144 if (oneshot_messages[i] ==
id) {
154 size_t last_cnt = oneshot_messages_cnt.fetch_add(1);
155 if (last_cnt <
sizeof oneshot_messages /
sizeof oneshot_messages[0]) {
156 oneshot_messages[last_cnt] = id;
193 p = (
const char *)lp +
start;
194 snprintf(Buff,
sizeof Buff,
"%p: ", p);
197 for (i =
start, j = 0; j < 16; p++, i++, j++) {
199 snprintf(tmpBuf,
sizeof tmpBuf,
"%02X", ((
int)(*p) & 0xFF));
200 strcat(Buff, tmpBuf);
212 for (i =
start, j = 0, p = (
const char *)lp +
start;
213 (i <
len && j < 16); p++, i++, j++) {
214 if (((*p) >=
' ') && ((*p) <=
'~'))
215 snprintf(tmpBuf,
sizeof tmpBuf,
"%c", *p);
217 snprintf(tmpBuf,
sizeof tmpBuf,
"%c",
'.');
218 strcat(Buff, tmpBuf);
229 bool *logger_skip_repeats,
232 assert(conf_str !=
nullptr);
233 assert(log_lvl !=
nullptr);
234 assert(logger_skip_repeats !=
nullptr);
235 assert(show_timestamps !=
nullptr);
239 static const struct {
const char *
name;
int level; }
mapping[] = {
251 std::string_view cfg = conf_str;
256 col() <<
"|" << m.name;
258 col() <<
"][+repeat][+/-timestamps]\n";
259 col() <<
TBOLD(
"\trepeat") <<
" - print repeating log messages\n";
260 col() <<
TBOLD(
"\ttimestamps") <<
" - enable/disable timestamps\n";
261 col() <<
"environment variable " <<
SBOLD(
"ULTRAGRID_VERBOSE") <<
" - use verbose output (same as `-V` on command-line)\n";
266 *logger_skip_repeats =
false;
269 if(
auto ts_pos = cfg.find(
"timestamps"); ts_pos != cfg.npos && ts_pos > 0){
270 if(cfg[ts_pos - 1] ==
'+')
276 if (cfg.empty() || cfg[0] ==
'+' || cfg[0] ==
'-') {
280 if (isdigit(cfg[0])) {
284 clog <<
"Log: wrong value: " << cfg <<
" (allowed range [0.." <<
LOG_LEVEL_MAX <<
"])\n";
291 auto log_lvl_sv = cfg;
292 auto sign_pos = log_lvl_sv.find_first_of(
"+-");
293 if(sign_pos != log_lvl_sv.npos)
294 log_lvl_sv.remove_suffix(log_lvl_sv.size() - sign_pos);
297 if (log_lvl_sv == m.name) {
308#define DUMP_FILE_USAGE \
309 "* debug-dump=<module>[=<n>][,<module2>[=<n>]\n" \
310 " Dumps specified buffer to a file for debugging, n-th buffer may " \
311 "be selected, name is <module>.dump.\n" \
312 " Avaiable modules: lavc-avframe, lavd-avframe\n"
314void debug_file_dump(
const char *
key,
void (*serialize)(
const void *data, FILE *),
void *data) {
316 static thread_local unordered_map<string, int> skip_map;
317 if (dump_file_val ==
nullptr) {
321 if (strcmp(dump_file_val,
"help") == 0) {
323 printf(
"%s\n", DUMP_FILE_USAGE);
329 string not_first = string(
",") +
key;
331 if (strstr(dump_file_val,
key) == dump_file_val) {
332 const char *
val = dump_file_val + strlen(
key);
334 skip_n = atoi(
val + 1);
336 }
else if (strstr(dump_file_val, not_first.c_str()) != NULL) {
337 const char *
val = strstr(dump_file_val, not_first.c_str()) + strlen(
key);
339 skip_n = atoi(
val + 1);
345 if (skip_map.find(
key) == skip_map.end()) {
346 skip_map[
key] = skip_n;
349 if (skip_map[
key] == -1) {
353 if (skip_map[
key] > 0) {
359 string name = string(
key) +
".dump";
360 FILE *out = fopen(
name.c_str(),
"wb");
361 if (out ==
nullptr) {
362 perror(
"debug_file_dump fopen");
365 serialize(data, out);
383 "%sPlease report a bug"
384#ifdef PACKAGE_BUGREPORT
385 " to " PACKAGE_BUGREPORT
387 " if you reach here.\n",
391 va_start(ap, format);
static const struct codec_param mapping[AC_COUNT]
const std::string & get_level_style(int lvl)
static constexpr int initial_buf_size
void prune_ansi_sequences_inplace(std::string &str)
bool color_output_init()
sets internal variable color_stdout and retunrs its contents
int color_printf(const char *format,...)
void debug_dump(const void *lp, int len)
static void log_vprintf(int level, const char *format, va_list ap)
static void _dprintf(const char *format,...)
void log_msg(int level, const char *format,...)
void log_msg_once(int level, uint32_t id, const char *msg,...)
void log_perror(int level, const char *msg)
void bug_msg(int level, const char *format,...)
prints the error with the advice to report the bug
bool parse_log_cfg(const char *conf_str, int *log_lvl, bool *logger_skip_repeats, log_timestamp_mode *show_timestamps)
#define LOG_LEVEL_NOTICE
information that may be interesting
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_QUIET
suppress all logging
#define debug_file_dump(key, serialize, data)
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_VERBOSE
#define LOG_LEVEL_FATAL
errors that prevent UG run
Log_output & get_log_output()
#define LOG_LEVEL_WARNING
less severe errors
const char * get_commandline_param(const char *key)
#define ADD_TO_PARAM(param, doc)
#define snprintf_ch(str,...)
shortcut for snprintf(var, sizeof var...), var must be a char array
@ STR_LEN
"standard" string length placeholder
const char * ug_strerror(int errnum)
bool sv_contains(std::string_view haystack, std::string_view needle)
bool parse_num(std::string_view sv, T &res, int base=10)
int vsnprintf(char *s, size_t buf_size, const char *format, va_list ap)