xref: /core/include/sal/log.hxx (revision 1fd6298b)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  */
9 
10 /*
11  * This file is part of LibreOffice published API.
12  */
13 
14 #ifndef INCLUDED_SAL_LOG_HXX
15 #define INCLUDED_SAL_LOG_HXX
16 
17 #include "sal/config.h"
18 
19 #include <cstdlib>
20 #include <sstream>
21 #include <string>
22 
23 #include "sal/detail/log.h"
24 #include "sal/saldllapi.h"
25 #include "sal/types.h"
26 
27 // Avoid the use of other sal code in this header as much as possible, so that
28 // this code can be called from other sal code without causing endless
29 // recursion.
30 
31 /// @cond INTERNAL
32 
33 enum sal_detail_LogAction
34 {
35     SAL_DETAIL_LOG_ACTION_IGNORE,
36     SAL_DETAIL_LOG_ACTION_LOG,
37     SAL_DETAIL_LOG_ACTION_FATAL
38 };
39 
40 extern "C" SAL_DLLPUBLIC void SAL_CALL sal_detail_log(
41     sal_detail_LogLevel level, char const * area, char const * where,
42     char const * message, sal_uInt32 backtraceDepth);
43 
44 extern "C" SAL_DLLPUBLIC void SAL_CALL sal_detail_set_log_selector(char const *logSelector);
45 
46 // the return value is actually "enum sal_detail_LogAction", but due to ABI
47 // compatibility, it's left as the original "sal_Bool" / "unsigned char".
48 extern "C" SAL_DLLPUBLIC unsigned char SAL_CALL sal_detail_log_report(
49     sal_detail_LogLevel level, char const * area);
50 
51 namespace sal { namespace detail {
52 
log(sal_detail_LogLevel level,char const * area,char const * where,std::ostringstream const & stream,sal_uInt32 backtraceDepth)53 inline void log(
54     sal_detail_LogLevel level, char const * area, char const * where,
55     std::ostringstream const & stream, sal_uInt32 backtraceDepth)
56 {
57     // An alternative would be to have sal_detail_log take a std::ostringstream
58     // pointer (via a C void pointer); the advantage would be smaller client
59     // code (the ".str().c_str()" part would move into the implementation of
60     // sal_detail_log) and potential for proper support of embedded null
61     // characters within the message, but the disadvantage would be dependence
62     // on the C++ ABI; as a compromise, the ".str().c_str()" part has been moved
63     // to this inline function so that it is potentially only emitted once per
64     // dynamic library:
65     sal_detail_log(level, area, where, stream.str().c_str(), backtraceDepth);
66 }
67 
68 // Special handling of the common case where the message consists of just a
69 // string literal, to produce smaller call-site code:
70 
71 struct StreamStart {};
72 
73 struct StreamString {
StreamStringsal::detail::StreamString74     StreamString(char const * s): string(s) {}
75 
76     char const * string;
77 
78     typedef char Result;
79 };
80 
81 struct StreamIgnore {
82     typedef struct { char a[2]; } Result;
83 };
84 
operator <<(SAL_UNUSED_PARAMETER StreamStart const &,char const * s)85 inline StreamString operator <<(
86     SAL_UNUSED_PARAMETER StreamStart const &, char const * s)
87 {
88     return StreamString(s);
89 }
90 
operator <<(SAL_UNUSED_PARAMETER StreamStart const &,SAL_UNUSED_PARAMETER T const &)91 template< typename T > inline StreamIgnore operator <<(
92     SAL_UNUSED_PARAMETER StreamStart const &, SAL_UNUSED_PARAMETER T const &)
93 {
94     std::abort();
95 #if defined _MSC_VER && _MSC_VER < 1700
96     return StreamIgnore();
97 #endif
98 }
99 
operator <<(SAL_UNUSED_PARAMETER StreamString const &,SAL_UNUSED_PARAMETER T const &)100 template< typename T > inline StreamIgnore operator <<(
101     SAL_UNUSED_PARAMETER StreamString const &, SAL_UNUSED_PARAMETER T const &)
102 {
103     std::abort();
104 #if defined _MSC_VER && _MSC_VER < 1700
105     return StreamIgnore();
106 #endif
107 }
108 
operator <<(SAL_UNUSED_PARAMETER StreamIgnore const &,SAL_UNUSED_PARAMETER T const &)109 template< typename T > inline StreamIgnore operator <<(
110     SAL_UNUSED_PARAMETER StreamIgnore const &, SAL_UNUSED_PARAMETER T const &)
111 {
112     std::abort();
113 #if defined _MSC_VER && _MSC_VER < 1700
114     return StreamIgnore();
115 #endif
116 }
117 
118 template< typename T > typename T::Result getResult(T const &);
119 
unwrapStream(StreamString const & s)120 inline char const * unwrapStream(StreamString const & s) { return s.string; }
121 
unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &)122 inline char const * unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &) {
123     std::abort();
124 #if defined _MSC_VER && _MSC_VER < 1700
125     return 0;
126 #endif
127 }
128 
129 } }
130 
131 // to prevent using a local variable, which can eventually shadow,
132 // resulting in compiler warnings (or even errors with -Werror)
133 #define SAL_DETAIL_LOG_STREAM_PRIVATE_(level, area, where, stream) \
134     if (sizeof ::sal::detail::getResult( \
135             ::sal::detail::StreamStart() << stream) == 1) \
136     { \
137         ::sal_detail_log( \
138             (level), (area), (where), \
139             ::sal::detail::unwrapStream( \
140                 ::sal::detail::StreamStart() << stream), \
141             0); \
142     } else { \
143         ::std::ostringstream sal_detail_stream; \
144         sal_detail_stream << stream; \
145         ::sal::detail::log( \
146             (level), (area), (where), sal_detail_stream, 0); \
147     }
148 
149 #define SAL_DETAIL_LOG_STREAM(condition, level, area, where, stream) \
150     do { \
151         if (SAL_UNLIKELY(condition)) \
152         { \
153             switch (sal_detail_log_report(level, area)) \
154             { \
155             case SAL_DETAIL_LOG_ACTION_IGNORE: break; \
156             case SAL_DETAIL_LOG_ACTION_LOG: \
157                 SAL_DETAIL_LOG_STREAM_PRIVATE_(level, area, where, stream); \
158                 break; \
159             case SAL_DETAIL_LOG_ACTION_FATAL: \
160                 SAL_DETAIL_LOG_STREAM_PRIVATE_(level, area, where, stream); \
161                 std::abort(); \
162                 break; \
163             } \
164         } \
165     } while (false)
166 
167 /// @endcond
168 
169 /** A simple macro to create a "file and line number" string.
170 
171     Potentially not only useful within the log framework (where it is used
172     automatically), but also when creating exception messages.
173 
174     @attention For now, this functionality should only be used internally within
175     LibreOffice. It may change again in a future version.
176 
177     @since LibreOffice 3.5
178 */
179 #define SAL_WHERE SAL_DETAIL_WHERE
180 
181 /** A facility for generating temporary string messages by piping items into a
182     C++ std::ostringstream.
183 
184     This can be useful for example in a call to SAL_INFO when depending on some
185     boolean condition data of incompatible types shall be streamed into the
186     message, as in:
187 
188       SAL_INFO("foo", "object: " << (hasName ? obj->name : SAL_STREAM(obj)));
189 
190     @attention For now, this functionality should only be used internally within
191     LibreOffice. It may change again in a future version.
192 
193     @since LibreOffice 3.5
194 */
195 #if defined _LIBCPP_VERSION \
196     || (defined _GLIBCXX_RELEASE \
197         && (_GLIBCXX_RELEASE >= 12 || (_GLIBCXX_RELEASE == 11 && __GLIBCXX__ > 20210428))) \
198     || (defined _MSC_VER && _MSC_VER >= 1915)
199 #define SAL_STREAM(stream) \
200     (::std::ostringstream() << stream).str()
201 #else
202 #define SAL_STREAM(stream) \
203     (dynamic_cast< ::std::ostringstream & >(::std::ostringstream() << stream).str())
204 #endif
205 
206 /**
207     @page sal_log Basic logging functionality.
208 
209     @short Macros for logging.
210 
211     SAL_INFO(char const * area, expr),
212     SAL_INFO_IF(bool condition, char const * area, expr),
213     SAL_WARN(char const * area, expr),
214     SAL_WARN_IF(bool condition, char const * area, expr), and SAL_DEBUG(expr)
215     produce an info, warning, or debug log entry with a message produced by
216     piping items into a C++ std::ostringstream.  The given expr must be so that
217     the full expression "stream << expr" is valid, where stream is a variable of
218     type std::ostringstream.
219 
220       SAL_INFO("foo", "string " << s << " of length " << n)
221 
222     would be an example of such a call.
223 
224     The composed message should be in UTF-8 and it should contain no vertical
225     formatting characters and no null characters
226 
227     For the _IF variants, log output is only generated if the given condition is
228     true (in addition to the other conditions that have to be met).
229 
230     The SAL_DEBUG macro is for temporary debug statements that are used while
231     working on code.  It is never meant to remain in the code.  It will always
232     simply output the given expression in debug builds.
233 
234     For all the other macros, the given area argument must be non-null and must
235     match the regular expression
236 
237     @verbatim
238       <area> ::= <segment>("."<segment>)*
239     @endverbatim
240 
241     with
242 
243     @verbatim
244       <segment> ::= [0-9a-z]+
245     @endverbatim
246 
247     For a list of areas used see @ref sal_log_areas "SAL debug areas". Whenever
248     you use a new log area, add it to the file include/sal/log-areas.dox .
249 
250     Whether these macros generate any log output is controlled in a two-stage
251     process.
252 
253     First, at compile time the macros SAL_LOG_INFO and SAL_LOG_WARN,
254     respectively, control whether the INFO and WARN macros, respectively,
255     expand to actual code (in case the macro is defined, to any value) or to
256     no-ops (in case the macro is not defined).
257 
258     Second, at runtime the environment variable SAL_LOG further limits which
259     macro calls actually generate log output.  The environment variable SAL_LOG
260     must either be unset or must match the regular expression
261 
262     @verbatim
263       <env> ::= <switch>*
264     @endverbatim
265 
266     with
267 
268     @verbatim
269       <switch> ::= <sense><item>
270       <sense> ::= "+"|"-"
271       <item> ::= <flag>|<level>("."<area>)?
272       <flag> ::= "TIMESTAMP"|"RELATIVETIMER"|"FATAL"
273       <level> ::= "INFO"|"WARN"
274     @endverbatim
275 
276     If the environment variable is unset, the setting "+WARN" is
277     assumed instead (which results in all warnings being output but no
278     infos).  If the given value does not match the regular expression,
279     "+INFO+WARN" is used instead (which in turn results in everything
280     being output).
281 
282     The "+TIMESTAMP" flag causes each output line (as selected by the level
283     switch(es)) to be prefixed by a timestamp like 2016-08-18:14:04:43.
284 
285     The "+RELATIVETIMER" flag causes each output line (as selected by
286     the level switch(es)) to be prefixed by a relative timestamp in
287     seconds since the first output line like 1.312.
288 
289     The "+FATAL" flag will cause later matching rules to log and call
290     std::abort. This can be disabled at some later point by using the
291     "-FATAL" flag before specifying additional rules. The flag will just
292     abort on positive rules, as it doesn't seem to make sense to abort
293     on ignored output.
294 
295     If both +TIMESTAMP and +RELATIVETIMER are specified, they are
296     output in that order.
297 
298     Specifying a flag with a negative sense has no effect. Specifying
299     the same flag multiple times has no extra effect.
300 
301     A given macro call's level (INFO or WARN) and area is matched against the
302     given switches as follows:  Only those switches for which the level matches
303     the given level and for which the area is a prefix (including both empty and
304     full prefixes) of the given area are considered.  Log output is generated if
305     and only if among the longest such switches (if any), there is at least one
306     that has a sense of "+".  (That is, if both +INFO.foo and -INFO.foo are
307     present, +INFO.foo wins.)
308 
309     If no WARN selection is specified, but an INFO selection is, the
310     INFO selection is used for WARN messages, too.
311 
312     For example, if SAL_LOG is "+INFO-INFO.foo+INFO.foo.bar", then calls like
313     SAL_INFO("foo.bar", ...), SAL_INFO("foo.bar.baz", ...), or
314     SAL_INFO("other", ...) generate output, while calls like
315     SAL_INFO("foo", ...) or SAL_INFO("foo.barzzz", ...) do not.
316 
317     The generated log output consists of the optional timestamp, the given level
318     ("info" or "warn"), the given area, the process ID, the thread ID, the
319     source file, and the source line number, each followed by a colon, followed
320     by a space, the given message, and a newline.  The precise format of the log
321     output is subject to change.  The log output is printed to stderr without
322     further text encoding conversion.
323 
324     On some systems, log output can be redirected to other log sinks,
325     notably a file provided as a system path and filename via
326     environment variable SAL_LOG_FILE; or to a syslog facility if
327     LibreOffice is suitably built, by setting environment variable
328     SAL_LOG_SYSLOG.
329 
330     @see @ref sal_log_areas
331 
332     @attention For now, this functionality should only be used internally within
333     LibreOffice. It may change again in a future version.
334 
335     @since LibreOffice 3.5
336 */
337 
338 /**
339   Produce log entry from stream in the given log area.
340 
341   See @ref sal_log "basic logging functionality" for details.
342 */
343 #define SAL_INFO(area, stream) \
344     SAL_DETAIL_LOG_STREAM( \
345         SAL_DETAIL_ENABLE_LOG_INFO, ::SAL_DETAIL_LOG_LEVEL_INFO, area, \
346         SAL_WHERE, stream)
347 
348 /**
349   Produce log entry from stream in the given log area if condition is true.
350 
351   See @ref sal_log "basic logging functionality" for details.
352 */
353 #define SAL_INFO_IF(condition, area, stream)  \
354     SAL_DETAIL_LOG_STREAM( \
355         SAL_DETAIL_ENABLE_LOG_INFO && (condition), \
356         ::SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, stream)
357 
358 /**
359   Produce warning entry from stream in the given log area.
360 
361   See @ref sal_log "basic logging functionality" for details.
362 */
363 #define SAL_WARN(area, stream) \
364     SAL_DETAIL_LOG_STREAM( \
365         SAL_DETAIL_ENABLE_LOG_WARN, ::SAL_DETAIL_LOG_LEVEL_WARN, area, \
366         SAL_WHERE, stream)
367 
368 /**
369   Produce warning entry from stream in the given log area if condition is true.
370 
371   See @ref sal_log "basic logging functionality" for details.
372 */
373 #define SAL_WARN_IF(condition, area, stream)   \
374     SAL_DETAIL_LOG_STREAM( \
375         SAL_DETAIL_ENABLE_LOG_WARN && (condition), \
376         ::SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, stream)
377 
378 /**
379   Produce temporary debugging output from stream.  This macro is meant to be
380   used only while working on code and should never exist in production code.
381 
382   See @ref sal_log "basic logging functionality" for details.
383 */
384 #define SAL_DEBUG(stream) \
385     SAL_DETAIL_LOG_STREAM( \
386         SAL_LOG_TRUE, ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, stream)
387 
388 /**
389   Produce temporary debugging output from stream, if condition is true.  This
390   macro is meant to be used only while working on code and should never exist
391   in production code.
392 
393   See @ref sal_log "basic logging functionality" for details.
394 */
395 #define SAL_DEBUG_IF(condition, stream)   \
396     SAL_DETAIL_LOG_STREAM( \
397         (condition), ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, stream)
398 
399 /**
400   Produce temporary debugging output from stream along with a backtrace of the
401   calling location.
402 
403   This macro is meant to be used only while working on code and should never
404   exist in production code.
405 
406   @param stream input stream
407 
408   @param backtraceDepth a sal_uInt32 value indicating the maximum backtrace
409   depth; zero means no backtrace
410 
411   See @ref sal_log "basic logging functionality" for details.
412 */
413 #define SAL_DEBUG_BACKTRACE(stream, backtraceDepth) \
414     do { \
415         if (sizeof ::sal::detail::getResult( \
416                 ::sal::detail::StreamStart() << stream) == 1) \
417         { \
418             ::sal_detail_log( \
419                 ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, \
420                 ::sal::detail::unwrapStream( \
421                     ::sal::detail::StreamStart() << stream), \
422                 backtraceDepth); \
423         } else { \
424             ::std::ostringstream sal_detail_stream; \
425             sal_detail_stream << stream; \
426             ::sal::detail::log( \
427                 ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, sal_detail_stream, \
428                 backtraceDepth); \
429         } \
430     } while (false)
431 
432 
433 
434 #endif
435 
436 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
437