forked from KjellKod/g3log
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathg3log.hpp
220 lines (179 loc) · 9.47 KB
/
g3log.hpp
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================
*
* Filename:g3log.hpp Framework for Logging and Design By Contract
* Created: 2011 by Kjell Hedström
*
* PUBLIC DOMAIN and Not copywrited since it was built on public-domain software and influenced
* at least in "spirit" from the following sources
* 1. kjellkod.cc ;)
* 2. Dr.Dobbs, Petru Marginean: http://drdobbs.com/article/printableArticle.jhtml?articleId=201804215&dept_url=/caddpp/
* 3. Dr.Dobbs, Michael Schulze: http://drdobbs.com/article/printableArticle.jhtml?articleId=225700666&dept_url=/cpp/
* 4. Google 'glog': http://google-glog.googlecode.com/svn/trunk/doc/glog.html
* 5. Various Q&A at StackOverflow
* ********************************************* */
#pragma once
#include "g3log/loglevels.hpp"
#include "g3log/logcapture.hpp"
#include "g3log/logmessage.hpp"
#include <string>
#include <functional>
#if !(defined(__PRETTY_FUNCTION__))
#define __PRETTY_FUNCTION__ __FUNCTION__
#endif
// thread_local doesn't exist before VS2013
// it exists on VS2015
#if !(defined(thread_local)) && defined(_MSC_VER) && _MSC_VER < 1900
#define thread_local __declspec(thread)
#endif
/** namespace for LOG() and CHECK() frameworks
* History lesson: Why the names 'g3' and 'g3log'?:
* The framework was made in my own free time as PUBLIC DOMAIN but the
* first commercial project to use it used 'g3' as an internal denominator for
* the current project. g3 as in 'generation 2'. I decided to keep the g3 and g3log names
* to give credit to the people in that project (you know who you are :) and I guess also
* for 'sentimental' reasons. That a big influence was google's glog is just a happy
* concidence or subconscious choice. Either way g3log became the name for this logger.
*
* --- Thanks for a great 2011 and good luck with 'g3' --- KjellKod
*/
namespace g3 {
class LogWorker;
struct LogMessage;
struct FatalMessage;
/** Should be called at very first startup of the software with \ref g3LogWorker
* pointer. Ownership of the \ref g3LogWorker is the responsibilkity of the caller */
void initializeLogging(LogWorker *logger);
/** setFatalPreLoggingHook() provides an optional extra step before the fatalExitHandler is called
*
* Set a function-hook before a fatal message will be sent to the logger
* i.e. this is a great place to put a break point, either in your debugger
* or programatically to catch LOG(FATAL), CHECK(...) or an OS fatal event (exception or signal)
* This will be reset to default (does nothing) at initializeLogging(...);
*
* Example usage:
* Windows: g3::setFatalPreLoggingHook([]{__debugbreak();}); // remember #include <intrin.h>
* WARNING: '__debugbreak()' when not running in Debug in your Visual Studio IDE will likely
* trigger a recursive crash if used here. It should only be used when debugging
* in your Visual Studio IDE. Recursive crashes are handled but are unnecessary.
*
* Linux: g3::setFatalPreLoggingHook([]{ raise(SIGTRAP); });
*/
void setFatalPreLoggingHook(std::function<void(void)> pre_fatal_hook);
/** If the @ref setFatalPreLoggingHook is not enough and full fatal exit handling is needed then
* use "setFatalExithandler". Please see g3log.cpp and crashhandler_windows.cpp or crashhandler_unix for
* example of restoring signal and exception handlers, flushing the log and shutting down.
*/
void setFatalExitHandler(std::function<void(FatalMessagePtr)> fatal_call);
// internal namespace is for completely internal or semi-hidden from the g3 namespace due to that it is unlikely
// that you will use these
namespace internal {
/// @returns true if logger is initialized
bool isLoggingInitialized();
// Save the created LogMessage to any existing sinks
void saveMessage(const char *message, const char *file, int line, const char *function, const LEVELS &level,
const char *boolean_expression, int fatal_signal, const char *stack_trace);
// forwards the message to all sinks
void pushMessageToLogger(LogMessagePtr log_entry);
// forwards a FATAL message to all sinks,. after which the g3logworker
// will trigger crashhandler / g3::internal::exitWithDefaultSignalHandler
//
// By default the "fatalCall" will forward a Fatalessageptr to this function
// this behaviour can be changed if you set a different fatal handler through
// "setFatalExitHandler"
void pushFatalMessageToLogger(FatalMessagePtr message);
// Save the created FatalMessage to any existing sinks and exit with
// the originating fatal signal,. or SIGABRT if it originated from a broken contract
// By default forwards to: pushFatalMessageToLogger, see "setFatalExitHandler" to override
//
// If you override it then you probably want to call "pushFatalMessageToLogger" after your
// custom fatal handler is done. This will make sure that the fatal message the pushed
// to sinks as well as shutting down the process
void fatalCall(FatalMessagePtr message);
// Shuts down logging. No object cleanup but further LOG(...) calls will be ignored.
void shutDownLogging();
// Shutdown logging, but ONLY if the active logger corresponds to the one currently initialized
bool shutDownLoggingForActiveOnly(LogWorker *active);
} // internal
} // g3
#define INTERNAL_LOG_MESSAGE(level) LogCapture(__FILE__, __LINE__, __PRETTY_FUNCTION__, level)
#define INTERNAL_CONTRACT_MESSAGE(boolean_expression) \
LogCapture(__FILE__, __LINE__, __PRETTY_FUNCTION__, g3::internal::CONTRACT, boolean_expression)
// LOG(level) is the API for the stream log
#define LOG(level) if(g3::logLevel(level)) INTERNAL_LOG_MESSAGE(level).stream()
// 'Conditional' stream log
#define LOG_IF(level, boolean_expression) \
if(true == boolean_expression) \
if(g3::logLevel(level)) INTERNAL_LOG_MESSAGE(level).stream()
// 'Design By Contract' stream API. For Broken Contracts:
// unit testing: it will throw std::runtime_error when a contract breaks
// I.R.L : it will exit the application by using fatal signal SIGABRT
#define CHECK(boolean_expression) \
if (false == (boolean_expression)) INTERNAL_CONTRACT_MESSAGE(#boolean_expression).stream()
/** For details please see this
* REFERENCE: http://www.cppreference.com/wiki/io/c/printf_format
* \verbatim
*
There are different %-codes for different variable types, as well as options to
limit the length of the variables and whatnot.
Code Format
%[flags][width][.precision][length]specifier
SPECIFIERS
----------
%c character
%d signed integers
%i signed integers
%e scientific notation, with a lowercase “e”
%E scientific notation, with a uppercase “E”
%f floating point
%g use %e or %f, whichever is shorter
%G use %E or %f, whichever is shorter
%o octal
%s a string of characters
%u unsigned integer
%x unsigned hexadecimal, with lowercase letters
%X unsigned hexadecimal, with uppercase letters
%p a pointer
%n the argument shall be a pointer to an integer into which is placed the number of characters written so far
For flags, width, precision etc please see the above references.
EXAMPLES:
{
LOGF(INFO, "Characters: %c %c \n", 'a', 65);
LOGF(INFO, "Decimals: %d %ld\n", 1977, 650000L); // printing long
LOGF(INFO, "Preceding with blanks: %10d \n", 1977);
LOGF(INFO, "Preceding with zeros: %010d \n", 1977);
LOGF(INFO, "Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
LOGF(INFO, "floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
LOGF(INFO, "Width trick: %*d \n", 5, 10);
LOGF(INFO, "%s \n", "A string");
return 0;
}
And here is possible output
: Characters: a A
: Decimals: 1977 650000
: Preceding with blanks: 1977
: Preceding with zeros: 0000001977
: Some different radixes: 100 64 144 0x64 0144
: floats: 3.14 +3e+000 3.141600E+000
: Width trick: 10
: A string \endverbatim */
#define LOGF(level, printf_like_message, ...) \
if(g3::logLevel(level)) INTERNAL_LOG_MESSAGE(level).capturef(printf_like_message, ##__VA_ARGS__)
// Conditional log printf syntax
#define LOGF_IF(level,boolean_expression, printf_like_message, ...) \
if(true == boolean_expression) \
if(g3::logLevel(level)) INTERNAL_LOG_MESSAGE(level).capturef(printf_like_message, ##__VA_ARGS__)
// Design By Contract, printf-like API syntax with variadic input parameters.
// Throws std::runtime_eror if contract breaks
#define CHECKF(boolean_expression, printf_like_message, ...) \
if (false == (boolean_expression)) INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)
// Backwards compatible. The same as CHECKF.
// Design By Contract, printf-like API syntax with variadic input parameters.
// Throws std::runtime_eror if contract breaks
#define CHECK_F(boolean_expression, printf_like_message, ...) \
if (false == (boolean_expression)) INTERNAL_CONTRACT_MESSAGE(#boolean_expression).capturef(printf_like_message, ##__VA_ARGS__)