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 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 { 74 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 85 inline StreamString operator <<( 86 SAL_UNUSED_PARAMETER StreamStart const &, char const * s) 87 { 88 return StreamString(s); 89 } 90 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 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 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 120 inline char const * unwrapStream(StreamString const & s) { return s.string; } 121 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 (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 along with a backtrace of the 390 calling location. 391 392 This macro is meant to be used only while working on code and should never 393 exist in production code. 394 395 @param stream input stream 396 397 @param backtraceDepth a sal_uInt32 value indicating the maximum backtrace 398 depth; zero means no backtrace 399 400 See @ref sal_log "basic logging functionality" for details. 401 */ 402 #define SAL_DEBUG_BACKTRACE(stream, backtraceDepth) \ 403 do { \ 404 if (sizeof ::sal::detail::getResult( \ 405 ::sal::detail::StreamStart() << stream) == 1) \ 406 { \ 407 ::sal_detail_log( \ 408 ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, \ 409 ::sal::detail::unwrapStream( \ 410 ::sal::detail::StreamStart() << stream), \ 411 backtraceDepth); \ 412 } else { \ 413 ::std::ostringstream sal_detail_stream; \ 414 sal_detail_stream << stream; \ 415 ::sal::detail::log( \ 416 ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, sal_detail_stream, \ 417 backtraceDepth); \ 418 } \ 419 } while (false) 420 421 422 423 #endif 424 425 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 426
