CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
log.h
Go to the documentation of this file.
1#pragma once
4
86
87#include <cx/cx.h>
88#include <cx/string/strbase.h>
89#include <cx/stype/stvar.h>
90#include <cx/thread/atomic.h>
91
92CX_C_BEGIN
93
108
109 LOG_Count // Not a real level, used for array sizing
110};
111
113extern strref LogLevelNames[];
114
116extern strref LogLevelAbbrev[];
117
123#define LOG_Broadcast 0x00000001
124
131#define LOG_Restricted 0x00000002
132
138#define LOG_Declared 0x00000004
139
148typedef struct LogChannel {
149 string path;
151 uint32 idx;
152 uint32 gatedepth;
153 flags_t flags;
154
160 atomic(int32) maxlevel;
161
167 atomic(int32) destlevel;
168
172 atomic(ptr) ring;
173
174 bool ownring;
175
180 atomic(uint32) groupmask;
181
182 atomic(uint32) sample;
183 atomic(uint32) samplecnt;
185
187typedef struct LogDest LogDest;
188
208typedef struct LogSite {
209 atomic(uint32) count;
210 atomic(uint32) last;
212
222
224extern LogChannel* LogDefault;
225
227typedef struct LogCtx LogCtx;
228
246_Ret_opt_valid_ LogChannel* logChan(_In_ strref path);
247
265_Ret_opt_valid_ LogChannel* logDeclareChan(_In_ strref path, flags_t flags);
266
267// Drain-owned cache of a record's flat rendering, shared between the destinations of one
268// dispatch. Not part of the destination interface; use logRecordRender().
269typedef struct LogRenderCache {
270 string str;
271 bool valid;
272} LogRenderCache;
273
294typedef struct LogRecord {
295 int level;
297 int64 timestamp;
298 uint64 seq;
299 const LogSite* site;
300 strref msgtmpl;
301 const stvar* args;
302 int nargs;
303
311
317 bool istmpl;
318
319 const LogCtx* ctx;
320 uint32 batchid;
321
327 uint32 sample;
328
334 strref origin;
335
337 uint8 hops;
338
345
346 LogRenderCache* _cache; // internal: shared rendering, use logRecordRender()
348
366void logRecordRender(_Inout_ string* out, _In_ const LogRecord* rec);
367
376typedef void (*LogDestMsg)(_In_ const LogRecord* rec, _In_opt_ void* userdata);
377
385typedef void (*LogDestBatchDone)(uint32 batchid, _In_opt_ void* userdata);
386
393typedef void (*LogDestClose)(_In_opt_ void* userdata);
394
436_Ret_opt_valid_ LogDest*
437logRegisterDest(int maxlevel, _In_opt_ strref chanfilter, _In_ LogDestMsg msgfunc,
438 _In_opt_ LogDestBatchDone batchfunc, _In_opt_ LogDestClose closefunc,
439 _In_opt_ void* userdata);
440
455bool logDestAddFilter(_In_ LogDest* dhandle, _In_ strref pattern, bool exclude);
456
469bool logDestSetFilter(_In_ LogDest* dhandle, _In_opt_ strref pattern);
470
479bool logDestSetLevel(_In_ LogDest* dhandle, int maxlevel);
480
486typedef bool (*LogChanEnumCB)(_In_ LogChannel* chan, _In_opt_ void* ctx);
487
498void logEnumChans(_In_ LogChanEnumCB cb, _In_opt_ void* ctx);
499
507bool logUnregisterDest(_Pre_valid_ _Post_invalid_ LogDest* dhandle);
508
513void logFlush(void);
514
520void logShutdown(void);
521
526void logRestart(void);
527
540void logBatchBegin(void);
541
546void logBatchEnd(void);
547
560_meta_inline bool logWouldLog(int level, _In_opt_ LogChannel* chan)
561{
562 if (!chan)
563 chan = LogDefault;
564 return level <= atomicLoad(int32, &chan->maxlevel, Relaxed);
565}
566
568
602
612#define logStr(level, str) _logStr_##level(LOG_##level, LOG_CHANNEL, LOG_SiteAlways, 0, str)
613
624#define logStrC(level, chan, str) _logStr_##level(LOG_##level, chan, LOG_SiteAlways, 0, str)
625
643#define logFmt(level, fmt, ...) _logFmtArgs(level, LOG_CHANNEL, LOG_SiteAlways, 0, fmt, __VA_ARGS__)
644
656#define logFmtC(level, chan, fmt, ...) _logFmtArgs(level, chan, LOG_SiteAlways, 0, fmt, __VA_ARGS__)
657
659
675
684#define logStrOnce(level, str) _logStr_##level(LOG_##level, LOG_CHANNEL, LOG_SiteOnce, 0, str)
685
695#define logStrEveryN(level, n, str) \
696 _logStr_##level(LOG_##level, LOG_CHANNEL, LOG_SiteEveryN, (n), str)
697
707#define logStrEveryT(level, interval, str) \
708 _logStr_##level(LOG_##level, LOG_CHANNEL, LOG_SiteEveryT, (interval), str)
709
719#define logFmtOnce(level, fmt, ...) \
720 _logFmtArgs(level, LOG_CHANNEL, LOG_SiteOnce, 0, fmt, __VA_ARGS__)
721
732#define logFmtEveryN(level, n, fmt, ...) \
733 _logFmtArgs(level, LOG_CHANNEL, LOG_SiteEveryN, (n), fmt, __VA_ARGS__)
734
745#define logFmtEveryT(level, interval, fmt, ...) \
746 _logFmtArgs(level, LOG_CHANNEL, LOG_SiteEveryT, (interval), fmt, __VA_ARGS__)
747
749
750// The channel logStr()/logFmt() use. A source file overrides it with #undef followed by its own
751// #define; see the log_macros documentation above.
752#define LOG_CHANNEL LogDefault
753
754// Internal implementation functions used by macros - do not call directly
755void _logStr(int level, int64 timestamp, _In_ LogChannel* chan, _In_opt_ const LogSite* site,
756 _In_ strref str);
757void _logFmt(int level, int64 timestamp, _In_ LogChannel* chan, _In_opt_ const LogSite* site,
758 _In_ strref fmtstr, int n, _In_ stvar* args);
759
760// Advances a call site's counters and decides whether it emits this time. Only called for gates
761// other than LOG_SiteAlways.
762bool _logSiteGate(_Inout_ LogSite* site, int gate, int64 garg);
763
764_meta_inline bool _logSitePasses(_Inout_ LogSite* site, int level, _In_ LogChannel* chan, int gate,
765 int64 garg)
766{
767 // gate is a constant at every call site, so an ungated call folds this away entirely and
768 // costs exactly what it did before sites existed
769 if (gate == LOG_SiteAlways)
770 return true;
771
772 // The level check comes first deliberately: a gate consumed while nothing is listening would
773 // spend logStrOnce()'s single emission on a message that goes nowhere.
774 return logWouldLog(level, chan) && _logSiteGate(site, gate, garg);
775}
776
777// Opens the block that holds the call site's LogSite. The static is declared here, inside each
778// level's own macro, rather than by the outer macro, so that a level compiled out by DEBUG_LEVEL
779// costs no storage either. The channel is bound to a local because the gated forms would
780// otherwise evaluate the expression twice.
781#define _logStrSite(level, chan, gate, garg, str) \
782 do { \
783 static LogSite _log_site; \
784 LogChannel* _log_site_chan = (chan); \
785 if (_logSitePasses(&_log_site, level, _log_site_chan, gate, garg)) \
786 _logStr(level, -1, _log_site_chan, &_log_site, str); \
787 } while (0)
788
789#define _logFmtSite(level, chan, gate, garg, fmt, nargs, args) \
790 do { \
791 static LogSite _log_site; \
792 LogChannel* _log_site_chan = (chan); \
793 if (_logSitePasses(&_log_site, level, _log_site_chan, gate, garg)) \
794 _logFmt(level, -1, _log_site_chan, &_log_site, fmt, nargs, args); \
795 } while (0)
796
797// Collapses a variadic argument list before handing off to the per-level table, so that the
798// table itself stays non-variadic and every user-facing logFmt variant is one line.
799//
800// count_macro_args() reports 1 for an empty list and there is no portable way to do better, so
801// every logFmt() needs at least one argument; a template that substitutes only context fields
802// passes stvNone. Expanding __VA_ARGS__ a second time to count it exactly is not an option --
803// format.h records what that costs on MSVC.
804#define _logFmtArgs(level, chan, gate, garg, fmt, ...) \
805 _logFmt_##level(LOG_##level, \
806 chan, \
807 gate, \
808 garg, \
809 fmt, \
810 count_macro_args(__VA_ARGS__), \
811 ((stvar[]) { __VA_ARGS__ }))
812
813// Implementation macros for conditional compilation based on DEBUG_LEVEL. The disabled forms are
814// variadic so that they cannot fall out of step with the enabled ones' arity; a level compiled
815// out never expands its arguments at all, which is what keeps a Trace call site and everything
816// it computes out of a release binary.
817#if DEBUG_LEVEL >= 2
818#define _logStr_Trace _logStrSite
819#define _logFmt_Trace _logFmtSite
820#else
821#define _logStr_Trace(...) ((void)0)
822#define _logFmt_Trace(...) ((void)0)
823#endif
824
825#if DEBUG_LEVEL >= 1
826#define _logStr_Debug _logStrSite
827#define _logFmt_Debug _logFmtSite
828#define _logStr_DevDiag(level, chan, gate, garg, str) _logStrSite(LOG_Diag, chan, gate, garg, str)
829#define _logFmt_DevDiag(level, chan, gate, garg, fmt, nargs, args) \
830 _logFmtSite(LOG_Diag, chan, gate, garg, fmt, nargs, args)
831#define _logStr_DevVerbose(level, chan, gate, garg, str) \
832 _logStrSite(LOG_Verbose, chan, gate, garg, str)
833#define _logFmt_DevVerbose(level, chan, gate, garg, fmt, nargs, args) \
834 _logFmtSite(LOG_Verbose, chan, gate, garg, fmt, nargs, args)
835#define _logStr_DevInfo(level, chan, gate, garg, str) _logStrSite(LOG_Info, chan, gate, garg, str)
836#define _logFmt_DevInfo(level, chan, gate, garg, fmt, nargs, args) \
837 _logFmtSite(LOG_Info, chan, gate, garg, fmt, nargs, args)
838#define _logStr_DevNotice(level, chan, gate, garg, str) \
839 _logStrSite(LOG_Notice, chan, gate, garg, str)
840#define _logFmt_DevNotice(level, chan, gate, garg, fmt, nargs, args) \
841 _logFmtSite(LOG_Notice, chan, gate, garg, fmt, nargs, args)
842#define _logStr_DevWarn(level, chan, gate, garg, str) _logStrSite(LOG_Warn, chan, gate, garg, str)
843#define _logFmt_DevWarn(level, chan, gate, garg, fmt, nargs, args) \
844 _logFmtSite(LOG_Warn, chan, gate, garg, fmt, nargs, args)
845#define _logStr_DevError(level, chan, gate, garg, str) _logStrSite(LOG_Error, chan, gate, garg, str)
846#define _logFmt_DevError(level, chan, gate, garg, fmt, nargs, args) \
847 _logFmtSite(LOG_Error, chan, gate, garg, fmt, nargs, args)
848#else
849#define _logStr_Debug(...) ((void)0)
850#define _logFmt_Debug(...) ((void)0)
851#define _logStr_DevDiag(...) ((void)0)
852#define _logFmt_DevDiag(...) ((void)0)
853#define _logStr_DevVerbose(...) ((void)0)
854#define _logFmt_DevVerbose(...) ((void)0)
855#define _logStr_DevInfo(...) ((void)0)
856#define _logFmt_DevInfo(...) ((void)0)
857#define _logStr_DevNotice(...) ((void)0)
858#define _logFmt_DevNotice(...) ((void)0)
859#define _logStr_DevWarn(...) ((void)0)
860#define _logFmt_DevWarn(...) ((void)0)
861#define _logStr_DevError(...) ((void)0)
862#define _logFmt_DevError(...) ((void)0)
863#endif
864
865#define _logStr_Diag _logStrSite
866#define _logFmt_Diag _logFmtSite
867#define _logStr_Verbose _logStrSite
868#define _logFmt_Verbose _logFmtSite
869#define _logStr_Info _logStrSite
870#define _logFmt_Info _logFmtSite
871#define _logStr_Notice _logStrSite
872#define _logFmt_Notice _logFmtSite
873#define _logStr_Warn _logStrSite
874#define _logFmt_Warn _logFmtSite
875#define _logStr_Error _logStrSite
876#define _logFmt_Error _logFmtSite
877#define _logStr_Fatal _logStrSite
878#define _logFmt_Fatal _logFmtSite
879
880CX_C_END
Atomic operations.
LogDest * logRegisterDest(int maxlevel, strref chanfilter, LogDestMsg msgfunc, LogDestBatchDone batchfunc, LogDestClose closefunc, void *userdata)
LogChannel * LogDefault
Default log channel used when no channel is specified.
bool logDestSetFilter(LogDest *dhandle, strref pattern)
LogChannel * logDeclareChan(strref path, flags_t flags)
bool logUnregisterDest(LogDest *dhandle)
void logBatchBegin(void)
void logEnumChans(LogChanEnumCB cb, void *ctx)
LogChannel * logChan(strref path)
strref LogLevelNames[]
Array of log level names as strings (e.g., "Fatal", "Error", etc.)
void logRecordRender(string *out, const LogRecord *rec)
void logRestart(void)
LOG_SITE_GATE
Definition log.h:216
struct LogDest LogDest
Opaque handle to a registered log destination.
Definition log.h:187
void logShutdown(void)
LOG_LEVEL_ENUM
Definition log.h:98
strref LogLevelAbbrev[]
Array of single-character log level abbreviations (e.g., "F", "E", etc.)
bool logWouldLog(int level, LogChannel *chan)
Definition log.h:560
void(* LogDestBatchDone)(uint32 batchid, void *userdata)
Definition log.h:385
void logFlush(void)
struct LogCtx LogCtx
Opaque handle to a log context; see logctx.h.
Definition log.h:227
void(* LogDestMsg)(const LogRecord *rec, void *userdata)
Definition log.h:376
bool logDestAddFilter(LogDest *dhandle, strref pattern, bool exclude)
void logBatchEnd(void)
bool logDestSetLevel(LogDest *dhandle, int maxlevel)
void(* LogDestClose)(void *userdata)
Definition log.h:393
bool(* LogChanEnumCB)(LogChannel *chan, void *ctx)
Definition log.h:486
@ LOG_SiteAlways
no rate limiting
Definition log.h:217
@ LOG_SiteEveryN
emit every Nth time this call site is reached
Definition log.h:219
@ LOG_SiteEveryT
emit at most once per interval
Definition log.h:220
@ LOG_SiteOnce
emit only the first time this call site is reached
Definition log.h:218
@ LOG_Notice
Normal but significant conditions.
Definition log.h:102
@ LOG_Debug
Debug messages (compiled out of non-development builds)
Definition log.h:106
@ LOG_Trace
Detailed trace messages (only available in debug builds)
Definition log.h:107
@ LOG_Fatal
Fatal errors, application cannot continue.
Definition log.h:99
@ LOG_Verbose
Detailed informational messages.
Definition log.h:104
@ LOG_Info
Informational messages.
Definition log.h:103
@ LOG_Error
Non-fatal errors requiring attention.
Definition log.h:100
@ LOG_Warn
Warning conditions that may indicate problems.
Definition log.h:101
@ LOG_Diag
Release build diagnostics not normally needed.
Definition log.h:105
#define stvar(typen, val)
Definition stvar.h:162
Core string types and fundamental operations.
uint32 idx
Stable index into the routing table.
Definition log.h:151
uint32 gatedepth
Depth of the deepest restricted ancestor-or-self.
Definition log.h:152
struct LogChannel * parent
Parent channel, NULL for the root channel.
Definition log.h:150
bool ownring
This channel's ring is its own, not inherited.
Definition log.h:174
atomic(int32) maxlevel
string path
Full channel path.
Definition log.h:149
atomic(ptr) ring
atomic(int32) destlevel
atomic(uint32) sample
Keep one record in N; 0 or 1 is every record.
atomic(uint32) groupmask
atomic(uint32) samplecnt
Arrivals so far, for the sampling decision.
flags_t flags
Visibility and policy flags.
Definition log.h:153
uint32 batchid
Opaque batch identifier for grouping related records.
Definition log.h:320
strref origin
Definition log.h:334
uint32 sample
Definition log.h:327
int level
Log severity level (LOG_Fatal, LOG_Error, etc.)
Definition log.h:295
const LogSite * site
Call site identity, or NULL if logged dynamically.
Definition log.h:299
bool localonly
Definition log.h:344
LogChannel * chan
Channel this record was logged to, never NULL.
Definition log.h:296
uint8 hops
How many instances this record has been forwarded through, 0 for a local one.
Definition log.h:337
const stvar * args
Arguments the record was logged with, NULL if none.
Definition log.h:301
int trigger
Definition log.h:310
strref msgtmpl
Message template, or the literal message when istmpl is false.
Definition log.h:300
int nargs
Number of arguments.
Definition log.h:302
int64 timestamp
Wall clock timestamp when the record was created.
Definition log.h:297
uint64 seq
Increasing sequence number, ordering records across threads.
Definition log.h:298
bool istmpl
Definition log.h:317
const LogCtx * ctx
Context in scope when the record was logged, or NULL.
Definition log.h:319
Definition log.h:208
atomic(uint32) last
coarse timestamp of the last emission, in milliseconds
atomic(uint32) count
times a gated call site has been reached
Variant type containers and type-safe variadic argument support.