UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
debug.h
Go to the documentation of this file.
1/*
2 * FILE: debug.h
3 * PROGRAM: RAT
4 * AUTHOR: Isidor Kouvelas + Colin Perkins + Mark Handley + Orion Hodson
5 *
6 * Copyright (c) 1995-2000 University College London
7 * Copyright (c) 2005-2023 CESNET, z. s. p. o.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, is permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the Computer Science
21 * Department at University College London
22 * 4. Neither the name of the University nor of the Department may be used
23 * to endorse or promote products derived from this software without
24 * specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND
26 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37
38#ifndef _RAT_DEBUG_H
39#define _RAT_DEBUG_H
40
41#ifdef __cplusplus
42#include <cstdint>
43#include <cstdio> // FILE
44#else
45#include <stdbool.h>
46#include <stdint.h>
47#include <stdio.h> // FILE
48#endif // defined __cplusplus
49
50#ifdef HAVE_CONFIG_H
51#include "config.h" // DEBUG
52#endif // defined HAVE_CONFIG_H
53#include "tv.h"
54
55#define UNUSED(x) (x=x)
56
57#define LOG_LEVEL_QUIET 0
58#define LOG_LEVEL_FATAL 1
59#define LOG_LEVEL_ERROR 2
60#define LOG_LEVEL_WARNING 3
61#define LOG_LEVEL_NOTICE 4
62#define LOG_LEVEL_INFO 5
63#define LOG_LEVEL_VERBOSE 6
65#define LOG_LEVEL_DEBUG 7
67#define LOG_LEVEL_DEBUG2 8
69#define LOG_LEVEL_MAX LOG_LEVEL_DEBUG2
70extern volatile int log_level;
71
77
78#ifdef __cplusplus
79extern "C" {
80#endif
81
82void debug_dump(const void*lp, int len);
83#ifdef DEBUG
84void debug_file_dump(const char *key, void (*serialize)(const void *data, FILE *), void *data);
85#else
86#define debug_file_dump(key, serialize, data) (void) (key), (void) (serialize), (void) (data)
87#endif
88
89#define error_msg(...) log_msg(LOG_LEVEL_ERROR, __VA_ARGS__)
90#define verbose_msg(...) log_msg(LOG_LEVEL_VERBOSE, __VA_ARGS__)
92#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, __VA_ARGS__)
93void log_msg(int log_level, const char *format, ...) __attribute__((format (printf, 2, 3)));
94void log_msg_once(int log_level, uint32_t id, const char *msg, ...) __attribute__((format (printf, 3, 4)));
95void log_perror(int log_level, const char *msg);
96#define MSG(l, fmt, ...) \
97 log_msg(LOG_LEVEL_##l, "%s" fmt, MOD_NAME, ##__VA_ARGS__)
98
99bool parse_log_cfg(const char *conf_str,
100 int *log_lvl,
101 bool *logger_skip_repeats,
102 enum log_timestamp_mode *show_timestamps);
103
104void bug_msg(int level, const char *format, ...) __attribute__((format (printf, 2, 3)));
105
106#ifdef __cplusplus
107}
108#endif
109
110#define CUMULATIVE_REPORTS_INTERVAL 30
111
112#ifdef __cplusplus
113#include <atomic>
114#include <iomanip>
115#include <iostream>
116#include <stdio.h>
117#include <set>
118#include <sstream>
119#include <string>
120#include <string_view>
121#include <mutex>
122#include "tv.h"
123#include "utils/color_out.h"
124
126 class Buffer{
127 public:
129
130 void append(std::string_view sv){
131 get() += sv;
132 }
133 void append(int count, char c) { get().append(count, c); }
134
135 void reserve(size_t size){ if(get().capacity() < size) get().reserve(size); }
136 std::string& get() { return lo.get_internal_buffer(); }
137 char *data() { return get().data(); }
138
139 void submit() { lo.submit(); }
141
142 Buffer(const Buffer&) = delete;
143 Buffer(Buffer&&) = delete;
144 Buffer& operator=(const Buffer&) = delete;
145 Buffer& operator=(Buffer&&) = delete;
146
147 private:
149 };
150public:
151 Log_output();
152
153 Buffer get_buffer() { return Buffer(*this); }
154
155 void set_skip_repeats(bool val) { skip_repeated.store(val, std::memory_order_relaxed); }
156 bool get_skip_repeats() const { return skip_repeated.load(std::memory_order_relaxed); }
157
159
160 const std::string& get_level_style(int lvl);
161 bool is_interactive() const { return interactive; }
162
163 Log_output(const Log_output&) = delete;
165
166 Log_output& operator=(const Log_output&) = delete;
168
169private:
170 void submit();
171 void submit_raw(); //just pass to output as is, no styles, timestamps, etc.
172
173 constexpr static int initial_buf_size = 256;
174 std::string& get_internal_buffer(){
175 thread_local static std::string buffer(initial_buf_size, '\0');
176 return buffer;
177 }
178
179 std::atomic<bool> skip_repeated = true;
181
182 bool interactive = false;
183
184 /* Since writing to stdout uses locks internally anyway (C11 standard
185 * 7.21.2 sections 7&8), using a mutex here does not cause any significant
186 * overhead, we just wait for the lock a bit earlier. */
187 std::mutex mut;
188 std::string last_msg;
190
191 friend class Buffer;
192};
193
194inline const std::string& Log_output::get_level_style(int lvl){
195 static std::string empty = "";
196
197 if (!is_interactive()) {
198 return empty;
199 }
200
201 switch(lvl){
202 case LOG_LEVEL_FATAL: {
203 static std::string style = TERM_BOLD TERM_FG_RED;
204 return style;
205 }
206 case LOG_LEVEL_ERROR: {
207 static std::string style = TERM_FG_RED;
208 return style;
209 }
210 case LOG_LEVEL_WARNING: {
211 static std::string style = TERM_FG_YELLOW;
212 return style;
213 }
214 case LOG_LEVEL_NOTICE: {
215 static std::string style = TERM_FG_GREEN;
216 return style;
217 }
218 default:
219 return empty;
220 }
221}
222
223inline void Log_output::submit(){
224 static constexpr int ts_bufsize = 32; //log10(2^64) is 19.3, so should be enough
225 char ts_str[ts_bufsize];
226 ts_str[0] = '\0';
227
230 {
231 const time_ns_t time_ns = get_time_in_ns();
232 snprintf(ts_str, ts_bufsize, "[%.3f] ",
233 (double) time_ns / NS_IN_SEC_DBL);
234 }
235
236 const char *start_newline = "";
237 std::lock_guard<std::mutex> lock(mut);
238 if (skip_repeated && interactive) {
239 if (get_internal_buffer() == last_msg) {
241 printf(" Last message repeated %d times\r", last_msg_repeats);
242 fflush(stdout);
243 return;
244 }
245
246 if (last_msg_repeats > 0) {
247 start_newline = "\n";
248 }
250 }
251
252 printf("%s%s%s", start_newline, ts_str, get_internal_buffer().c_str());
253
254 std::swap(last_msg, get_internal_buffer());
255}
256
258 std::lock_guard<std::mutex> lock(mut);
259 if(last_msg_repeats > 0)
260 fputc('\n', stdout);
261 fputs(get_internal_buffer().c_str(), stdout);
262 std::swap(last_msg, get_internal_buffer());
264}
265
267 static Log_output out;
268 return out;
269}
270
271// Log, version 0.1: a simple logging class
273{
274public:
275 inline Logger(int l) : level(l) {
277 }
278
279 inline ~Logger() {
280 std::string msg = oss.str();
281
282 if (get_log_output().is_interactive()) {
283 // add TERM_RESET (before NL if present at the end)
284 const bool eol_nl =
285 msg.size() > 0 && msg.at(msg.size() - 1) == '\n';
286 if (eol_nl) {
287 msg.resize(msg.size() - 1);
288 }
289 msg += TERM_RESET;
290 if (eol_nl) {
291 msg += "\n";
292 }
293 } else {
295 }
296
297 auto buf = get_log_output().get_buffer();
298 buf.append(msg);
299 buf.submit();
300 }
301
302 inline std::ostream& Get() {
303 return oss;
304 }
305
306private:
307 int level;
308 std::ostringstream oss;
309
310 friend void log_msg_once(int level, uint32_t id, const char *msg, ...);
311};
312
313#define LOG(level) \
314if ((level) <= log_level) Logger(level).Get()
315
316
317#endif
318
319#ifdef DEBUG
320#define DEBUG_TIMER_EVENT(name) time_ns_t name = get_time_in_ns()
321#define DEBUG_TIMER_START(name) DEBUG_TIMER_EVENT(name##_start);
322#define DEBUG_TIMER_STOP(name) DEBUG_TIMER_EVENT(name##_stop); log_msg(LOG_LEVEL_DEBUG2, "%s duration: %lf s\n", #name, (name##_stop - name##_start) / NS_IN_SEC_DBL) // NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg)
323#else
324#define DEBUG_TIMER_START(name)
325#define DEBUG_TIMER_STOP(name)
326#endif
327
328#endif
int void * val
int void size_t * len
Buffer & operator=(Buffer &&)=delete
Buffer(Log_output &lo)
Definition debug.h:128
Buffer(Buffer &&)=delete
std::string & get()
Definition debug.h:136
void append(std::string_view sv)
Definition debug.h:130
void append(int count, char c)
Definition debug.h:133
char * data()
Definition debug.h:137
void submit_raw()
Definition debug.h:140
Buffer(const Buffer &)=delete
void reserve(size_t size)
Definition debug.h:135
Buffer & operator=(const Buffer &)=delete
Log_output & lo
Definition debug.h:148
const std::string & get_level_style(int lvl)
Definition debug.h:194
Log_output(Log_output &&)=delete
int last_msg_repeats
Definition debug.h:189
log_timestamp_mode show_timestamps
Definition debug.h:180
void set_skip_repeats(bool val)
Definition debug.h:155
friend class Buffer
Definition debug.h:191
std::atomic< bool > skip_repeated
Definition debug.h:179
void submit_raw()
Definition debug.h:257
Log_output(const Log_output &)=delete
bool get_skip_repeats() const
Definition debug.h:156
static constexpr int initial_buf_size
Definition debug.h:173
bool is_interactive() const
Definition debug.h:161
std::string & get_internal_buffer()
Definition debug.h:174
void submit()
Definition debug.h:223
Log_output & operator=(Log_output &&)=delete
Log_output & operator=(const Log_output &)=delete
std::string last_msg
Definition debug.h:188
bool interactive
Definition debug.h:182
Buffer get_buffer()
Definition debug.h:153
std::mutex mut
Definition debug.h:187
void set_timestamp_mode(log_timestamp_mode val)
Definition debug.h:158
Logger(int l)
Definition debug.h:275
friend void log_msg_once(int level, uint32_t id, const char *msg,...)
Definition debug.cpp:137
std::ostream & Get()
Definition debug.h:302
std::ostringstream oss
Definition debug.h:308
int level
Definition debug.h:307
~Logger()
Definition debug.h:279
string prune_ansi_sequences_str(const char *in)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_YELLOW
Definition color_out.h:52
#define TERM_FG_GREEN
Definition color_out.h:51
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_RESET
Definition color_out.h:47
void debug_dump(const void *lp, int len)
Definition debug.cpp:179
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
void bug_msg(int level, const char *format,...) __attribute__((format(printf
bool parse_log_cfg(const char *conf_str, int *log_lvl, bool *logger_skip_repeats, enum log_timestamp_mode *show_timestamps)
Definition debug.cpp:227
#define debug_file_dump(key, serialize, data)
Definition debug.h:86
volatile int log_level
Definition debug.cpp:65
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
void log_msg(int log_level, const char *format,...) __attribute__((format(printf
Definition debug.cpp:130
void void log_msg_once(int log_level, uint32_t id, const char *msg,...) __attribute__((format(printf
Definition debug.cpp:137
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
Log_output & get_log_output()
Definition debug.h:266
log_timestamp_mode
Definition debug.h:72
@ LOG_TIMESTAMP_AUTO
Definition debug.h:75
@ LOG_TIMESTAMP_ENABLED
Definition debug.h:74
@ LOG_TIMESTAMP_DISABLED
Definition debug.h:73
void void void log_perror(int log_level, const char *msg)
Definition debug.cpp:165
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
int count
Definition hd-rum.c:44
long long time_ns_t
Definition tv.h:81
#define NS_IN_SEC_DBL
Definition tv.h:93
static time_ns_t get_time_in_ns()
Definition tv.h:101
const char * key
Definition cineform.cpp:125