topic "U++ Logging";
[i448;a25;kKO9;2 $$1,0#37138531426314131252341829483380:class]
[l288;2 $$2,2#27521748481378242620020725143825:desc]
[0 $$3,0#96390100711032703541132217272105:end]
[H6;0 $$4,0#05600065144404261032431302351956:begin]
[i448;a25;kKO9;2 $$5,0#37138531426314131252341829483370:item]
[l288;a4;*@5;1 $$6,6#70004532496200323422659154056402:requirement]
[l288;i1121;b17;O9;~~~.1408;2 $$7,0#10431211400427159095818037425705:param]
[i448;b42;O9;2 $$8,8#61672508125594000341940100500538:tparam]
[b42;2 $$9,9#13035079074754324216151401829390:normal]
[2 $$0,0#00000000000000000000000000000000:Default]
[{_}%EN-US 
[ {{10000@(113.42.0) [s0; [*@7;4 U`+`+ Logging]]}}&]
[s0;i448;a25;kKO9;@(0.0.255)%- &]
[s0; U`+`+ logging infrastructure is based on output stream, which 
is capable of outputting log lines into decided output facilities 
(files, console output, syslog).&]
[s0; &]
[s0; Logging itself is then based on set o macros that output values 
to this stream, usually using AsString or operator<<(Stream`&, 
...) to convert values.&]
[s0; &]
[s0; This stream is accessible through UppLog() function and its 
default version is provided by U`+`+, however it can be replaced 
(using SetUppLog).&]
[s0; &]
[s0; Multithreading note: Standard log stream handles serialization 
of output in its implementation  (and any possible replacement 
should do that too), so it is possible to use single output stream 
in all threads.&]
[s0; &]
[ {{10000F(128)G(128)@1 [s0; [* Entity List]]}}&]
[s0;%- &]
[s5;:StdLogSetup`(dword`,const char`*`,int`):%- [@(0.0.255) void]_[* StdLogSetup]([_^dword^ d
word]_[*@3 options], [@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 filepath]_`=_NULL, 
[@(0.0.255) int]_[*@3 filesize`_limit]_`=_[@3 10]_`*_[@3 1024]_`*_[@3 1024])&]
[s2; This function setups standard U`+`+ logging. [%-*@3 filepath] 
is the path of .log file (if logging to file is active), [%-*@3 filesize`_limit] 
is maximum size of log (if LOG`_FILE options is active), if achieved, 
a new log file is created. [%-*@3 options] is a combination of 
bit flags:&]
[s2; &]
[ {{2939:7061<288;^ [s0; LOG`_FILE ]
:: [s0; Output log to file (this is default). The default path of file 
is ConfigFile(`"[/ program`_name].log`").]
:: [s0; LOG`_COUT ]
:: [s0; Output log to standard output, using plain putchar.]
:: [s0; LOG`_CERR ]
:: [s0; Output log to error output, using plain putc.]
:: [s0; LOG`_DBG ]
:: [s0; Output log to debugger (Win32 specific).]
:: [s0; LOG`_SYS ]
:: [s0; Output log to syslog (POSIX specific).]
:: [s0; LOG`_ELAPSED]
:: [s0; Prepend a number of miliseconds to each log line since the previous 
log line.]
:: [s0; LOG`_TIMESTAMP ]
:: [s0; Prepend local time timestamp to each log line (not with LOG`_SYS, 
as syslog already does this).]
:: [s0; LOG`_TIMESTAMP`_UTC]
:: [s0; Prepend universal time timestamp to each log line (not with 
LOG`_SYS).]
:: [s0; LOG`_APPEND ]
:: [s0; When starting a program, append log to existing file instead 
of replacing it.]
:: [s0; LOG`_ROTATE([*@3 x])]
:: [s0; When starting a new log file, up to [*@3 x] older logs is preserved 
(renamed with extension `'.1`', `'.2`' etc...).]
:: [s0; LOG`_ROTATE`_GZIP]
:: [s0; Older preserved log files are compressed using gzip (except 
the most recent log `'.1`'.]
:: [s0; LOG`_COUTW]
:: [s0; Output log to standard output, using Cout. This provides eventual 
conversion of UTF8 characters, at the price of using heap (so 
cannot be used to e.g. LOG inside heap routines).]
:: [s0; LOG`_CERRW]
:: [s0; Output log to standard output, using Cerr. This provides eventual 
conversion of UTF8 characters, at the price of using heap (so 
cannot be used to e.g. LOG inside heap routines).]}}&]
[s3; &]
[s4;%- &]
[s5;:StdLog`(`):%- [_^Stream^ Stream][@(0.0.255) `&]_[* StdLog]()&]
[s2; Returns a reference to standard log stream.&]
[s3;%- &]
[s4;%- &]
[s5;:Upp`:`:GetStdLogPath`(`):%- [_^Upp`:`:String^ String]_[* GetStdLogPath]()&]
[s2; Returns the path of current log, if any.&]
[s3;%- &]
[s4;%- &]
[s5;:LOG`_BEGIN:%- [@(0.0.255) const]_[@(0.0.255) char]_[* LOG`_BEGIN `= 
`'`\x1e`';]&]
[s2; Putting this character into standard log stream adds one tabulator 
of indentation to all subsequent lines (moves text `"right`").&]
[s3;%- &]
[s4;%- &]
[s5;:LOG`_END:%- [@(0.0.255) const]_[@(0.0.255) char]_[* LOG`_END `= `'`\x1f`';]&]
[s2; Putting this character into standard log stream removes one 
tabulator of indentation to all subsequent lines (moves text 
`"left`").&]
[s3;%- &]
[s4;%- &]
[s5;:UppLog`(`):%- [_^Stream^ Stream][@(0.0.255) `&]_[* UppLog]()&]
[s2; Returns a reference to [/ current] log stream.&]
[s3; &]
[s4;%- &]
[s5;:SetUppLog`(Stream`&`):%- [@(0.0.255) void]_[* SetUppLog]([_^Stream^ Stream][@(0.0.255) `&
]_[*@3 log])&]
[s2; Sets the current log stream to [%-*@3 log] (must be an object 
with global lifetime).&]
[s3; &]
[s4;%- &]
[s5;:Upp`:`:SetUppLog`(Upp`:`:LogLineFn`):%- [_^Upp`:`:LogLineFn^ LogLineFn]_[* SetUppLog
]([_^Upp`:`:LogLineFn^ LogLineFn]_[*@3 log`_line])&]
[s0;l288; Similar to SetUppLog with Stream parameter, but instead 
of replacing the whole stream, it just replaces the final routine 
to write the single line, while returning its previous definition 
(as function pointer). LogLineFn is defined as&]
[s0;l288; &]
[s0;l288; [C typedef void (`*LogLineFn)(const char `*buffer, int len, 
int depth);]&]
[s2; &]
[s2; where dept is incremented by LOG`_BEGIN character and decremented 
by LOG`_END `- standard logging stream inserts equivalent number 
of tabs at the beginning of line.&]
[s3; &]
[s0; &]
[s0; &]
[ {{10000F(128)G(128)@1 [s0; [* Logging macros]]}}&]
[s0; &]
[s0; Standard logging macros come in 3 basic flavors. `"Normal`" 
macros (LOG, DUMP, ...) only emit code in debug mode, `"Debugging`" 
macros (DLOG, DDUMP, ..., first letter is `'D`') only [*/ compile] 
in debug mode and their presence causes release mode compilation 
to fail (this is to prevent any forgotten debugging macros in 
code) and finally `"Release`" macros (RLOG, RDUMP, ..., first 
letter is `'R`') produce output even in release mode.&]
[s0; &]
[ {{5000:5000^ [s0; LOG(x), DLOG(x), RLOG(x)]
:: [s0; Outputs a single line to log.]
:: [s0; DUMP(x), DDUMP(x), RDUMP(x)]
:: [s0; Outputs a variable `- adds a variable name before value `-  
defined as LOG(#x << `"`=`" << x)]
:: [s0; DUMPC(x), DDUMPC(x), RDUMPC(x)]
:: [s0; Outputs a Vector or Array or Index of values.]
:: [s0; DUMPM(x), DDUMPM(x), RDUMPM(x)]
:: [s0; Outputs a VectorMap or ArrayMap.]
:: [s0; TIMING(x), DTIMING(x), RTIMING(x)]
:: [s0; Establishes profiling timing inspector which profiles since 
definition till the end of block, profiling values are printed 
to log at the program exit.]
:: [s0; LOGHEX(x), DLOGHEX(x), RLOGHEX(x)]
:: [s0; Outputs value as hexadecimal dump, currently works with String.]
:: [s0; DUMPHEX(x), DDUMPHEX(x), RDUMPHEX(x)]
:: [s0; Outputs variable as hexadecimal dump, like LOGHEX but puts variable 
name into log.]}}&]
[s0; &]
[s0; In addition to this it is common practice to use `'local`' macros 
that can be switched on/off for given modules files; standard 
approach is to add&]
[s0; &]
[s0; #define LLOG(x)    // DLOG(x)&]
[s0; &]
[s0; at the start of files with local logging, then activate logging 
by uncommenting the DLOG.&]
[s0; &]
[s0; U`+`+ has also concept of `"modular`" logging, where specific 
logging macros can be created that are bound to some global boolean 
entity (usually INI`_BOOL). Creation of these modular logs is 
simplified by macro:&]
[s0; &]
[s0; #define [* LOG`_](flag, x)     do `{ if(flag) RLOG(x); `} while(false)&]
[s0; &]
[s0; One such predefined type exists, USRLOG, that is indended to 
log user actions (like opening windows, pressing keyboard keys) 
and can be activated by IniBool Ini`::user`_log (and also by setting 
user`_log`=true in .ini file):&]
[s0; &]
[s0; #define [* USRLOG](x)         LOG`_(Ini`::user`_log, x)&]
[s0; ]]