/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project .
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file , You can obtain one at http : //mozilla.org/MPL/2.0/.
*/
/*
* This file is part of LibreOffice published API .
*/
#ifndef INCLUDED_SAL_LOG_HXX
#define INCLUDED_SAL_LOG_HXX
#include "sal/config.h"
#include <cstdlib>
#include <sstream>
#include <string>
#include "sal/detail/log.h"
#include "sal/saldllapi.h"
#include "sal/types.h"
// Avoid the use of other sal code in this header as much as possible, so that
// this code can be called from other sal code without causing endless
// recursion.
/// @cond INTERNAL
enum sal_detail_LogAction
{
SAL_DETAIL_LOG_ACTION_IGNORE,
SAL_DETAIL_LOG_ACTION_LOG,
SAL_DETAIL_LOG_ACTION_FATAL
};
extern "C" SAL_DLLPUBLIC void SAL_CALL sal_detail_log(
sal_detail_LogLevel level, char const * area, char const * where,
char const * message, sal_uInt32 backtraceDepth);
extern "C" SAL_DLLPUBLIC void SAL_CALL sal_detail_set_log_selector(char const *logSelector);
// the return value is actually "enum sal_detail_LogAction", but due to ABI
// compatibility, it's left as the original "sal_Bool" / "unsigned char".
extern "C" SAL_DLLPUBLIC unsigned char SAL_CALL sal_detail_log_report(
sal_detail_LogLevel level, char const * area);
namespace sal { namespace detail {
inline void log(
sal_detail_LogLevel level, char const * area, char const * where,
std::ostringstream const & stream, sal_uInt32 backtraceDepth)
{
// An alternative would be to have sal_detail_log take a std::ostringstream
// pointer (via a C void pointer); the advantage would be smaller client
// code (the ".str().c_str()" part would move into the implementation of
// sal_detail_log) and potential for proper support of embedded null
// characters within the message, but the disadvantage would be dependence
// on the C++ ABI; as a compromise, the ".str().c_str()" part has been moved
// to this inline function so that it is potentially only emitted once per
// dynamic library:
sal_detail_log(level, area, where, stream.str().c_str(), backtraceDepth);
}
// Special handling of the common case where the message consists of just a
// string literal, to produce smaller call-site code:
struct StreamStart {};
struct StreamString {
StreamString(char const * s): string(s) {}
char const * string;
typedef char Result;
};
struct StreamIgnore {
typedef struct { char a[2 ]; } Result;
};
inline StreamString operator <<(
SAL_UNUSED_PARAMETER StreamStart const &, char const * s)
{
return StreamString(s);
}
template < typename T > inline StreamIgnore operator <<(
SAL_UNUSED_PARAMETER StreamStart const &, SAL_UNUSED_PARAMETER T const &)
{
std::abort();
#if defined _MSC_VER && _MSC_VER < 1700
return StreamIgnore();
#endif
}
template < typename T > inline StreamIgnore operator <<(
SAL_UNUSED_PARAMETER StreamString const &, SAL_UNUSED_PARAMETER T const &)
{
std::abort();
#if defined _MSC_VER && _MSC_VER < 1700
return StreamIgnore();
#endif
}
template < typename T > inline StreamIgnore operator <<(
SAL_UNUSED_PARAMETER StreamIgnore const &, SAL_UNUSED_PARAMETER T const &)
{
std::abort();
#if defined _MSC_VER && _MSC_VER < 1700
return StreamIgnore();
#endif
}
template < typename T > typename T::Result getResult(T const &);
inline char const * unwrapStream(StreamString const & s) { return s.string; }
inline char const * unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &) {
std::abort();
#if defined _MSC_VER && _MSC_VER < 1700
return 0 ;
#endif
}
} }
// to prevent using a local variable, which can eventually shadow,
// resulting in compiler warnings (or even errors with -Werror)
#define SAL_DETAIL_LOG_STREAM_PRIVATE_(level, area, where, stream) \
if (sizeof ::sal::detail::getResult( \
::sal::detail::StreamStart() << stream) == 1 ) \
{ \
::sal_detail_log( \
(level), (area), (where), \
::sal::detail::unwrapStream( \
::sal::detail::StreamStart() << stream), \
0 ); \
} else { \
::std::ostringstream sal_detail_stream; \
sal_detail_stream << stream; \
::sal::detail::log( \
(level), (area), (where), sal_detail_stream, 0 ); \
}
#define SAL_DETAIL_LOG_STREAM(condition, level, area, where, stream) \
do { \
if (SAL_UNLIKELY(condition)) \
{ \
switch (sal_detail_log_report(level, area)) \
{ \
case SAL_DETAIL_LOG_ACTION_IGNORE: break ; \
case SAL_DETAIL_LOG_ACTION_LOG: \
SAL_DETAIL_LOG_STREAM_PRIVATE_(level, area, where, stream); \
break ; \
case SAL_DETAIL_LOG_ACTION_FATAL: \
SAL_DETAIL_LOG_STREAM_PRIVATE_(level, area, where, stream); \
std::abort(); \
break ; \
} \
} \
} while (false )
/// @endcond
/** A simple macro to create a "file and line number" string.
Potentially not only useful within the log framework ( where it is used
automatically ) , but also when creating exception messages .
@ attention For now , this functionality should only be used internally within
LibreOffice . It may change again in a future version .
@ since LibreOffice 3 . 5
*/
#define SAL_WHERE SAL_DETAIL_WHERE
/** A facility for generating temporary string messages by piping items into a
C + + std : : ostringstream .
This can be useful for example in a call to SAL_INFO when depending on some
boolean condition data of incompatible types shall be streamed into the
message , as in :
SAL_INFO ( " foo " , " object : " < < ( hasName ? obj - > name : SAL_STREAM ( obj ) ) ) ;
@ attention For now , this functionality should only be used internally within
LibreOffice . It may change again in a future version .
@ since LibreOffice 3 . 5
*/
#if defined _LIBCPP_VERSION \
|| (defined _GLIBCXX_RELEASE \
&& (_GLIBCXX_RELEASE >= 12 || (_GLIBCXX_RELEASE == 11 && __GLIBCXX__ > 20210428 ))) \
|| (defined _MSC_VER && _MSC_VER >= 1915 )
#define SAL_STREAM(stream) \
(::std::ostringstream() << stream).str()
#else
#define SAL_STREAM(stream) \
(dynamic_cast < ::std::ostringstream & >(::std::ostringstream() << stream).str())
#endif
/**
@ page sal_log Basic logging functionality .
@ short Macros for logging .
SAL_INFO ( char const * area , expr ) ,
SAL_INFO_IF ( bool condition , char const * area , expr ) ,
SAL_WARN ( char const * area , expr ) ,
SAL_WARN_IF ( bool condition , char const * area , expr ) , and SAL_DEBUG ( expr )
produce an info , warning , or debug log entry with a message produced by
piping items into a C + + std : : ostringstream . The given expr must be so that
the full expression " stream < < expr " is valid , where stream is a variable of
type std : : ostringstream .
SAL_INFO ( " foo " , " string " < < s < < " of length " < < n )
would be an example of such a call .
The composed message should be in UTF - 8 and it should contain no vertical
formatting characters and no null characters
For the _ IF variants , log output is only generated if the given condition is
true ( in addition to the other conditions that have to be met ) .
The SAL_DEBUG macro is for temporary debug statements that are used while
working on code . It is never meant to remain in the code . It will always
simply output the given expression in debug builds .
For all the other macros , the given area argument must be non - null and must
match the regular expression
@ verbatim
< area > : : = < segment > ( " . " < segment > ) *
@ endverbatim
with
@ verbatim
< segment > : : = [ 0 - 9 a - z ] +
@ endverbatim
For a list of areas used see @ ref sal_log_areas " SAL debug areas " . Whenever
you use a new log area , add it to the file include / sal / log - areas . dox .
Whether these macros generate any log output is controlled in a two - stage
process .
First , at compile time the macros SAL_LOG_INFO and SAL_LOG_WARN ,
respectively , control whether the INFO and WARN macros , respectively ,
expand to actual code ( in case the macro is defined , to any value ) or to
no - ops ( in case the macro is not defined ) .
Second , at runtime the environment variable SAL_LOG further limits which
macro calls actually generate log output . The environment variable SAL_LOG
must either be unset or must match the regular expression
@ verbatim
< env > : : = < switch > *
@ endverbatim
with
@ verbatim
< switch > : : = < sense > < item >
< sense > : : = " + " | " - "
< item > : : = < flag > | < level > ( " . " < area > ) ?
< flag > : : = " TIMESTAMP " | " RELATIVETIMER " | " FATAL "
< level > : : = " INFO " | " WARN "
@ endverbatim
If the environment variable is unset , the setting " + WARN " is
assumed instead ( which results in all warnings being output but no
infos ) . If the given value does not match the regular expression ,
" + INFO + WARN " is used instead ( which in turn results in everything
being output ) .
The " + TIMESTAMP " flag causes each output line ( as selected by the level
switch ( es ) ) to be prefixed by a timestamp like 2016 - 08 - 18 : 14 : 04 : 43 .
The " + RELATIVETIMER " flag causes each output line ( as selected by
the level switch ( es ) ) to be prefixed by a relative timestamp in
seconds since the first output line like 1 . 312 .
The " + FATAL " flag will cause later matching rules to log and call
std : : abort . This can be disabled at some later point by using the
" - FATAL " flag before specifying additional rules . The flag will just
abort on positive rules , as it doesn ' t seem to make sense to abort
on ignored output .
If both + TIMESTAMP and + RELATIVETIMER are specified , they are
output in that order .
Specifying a flag with a negative sense has no effect . Specifying
the same flag multiple times has no extra effect .
A given macro call ' s level ( INFO or WARN ) and area is matched against the
given switches as follows : Only those switches for which the level matches
the given level and for which the area is a prefix ( including both empty and
full prefixes ) of the given area are considered . Log output is generated if
and only if among the longest such switches ( if any ) , there is at least one
that has a sense of " + " . ( That is , if both + INFO . foo and - INFO . foo are
present , + INFO . foo wins . )
If no WARN selection is specified , but an INFO selection is , the
INFO selection is used for WARN messages , too .
For example , if SAL_LOG is " + INFO - INFO . foo + INFO . foo . bar " , then calls like
SAL_INFO ( " foo . bar " , . . . ) , SAL_INFO ( " foo . bar . baz " , . . . ) , or
SAL_INFO ( " other " , . . . ) generate output , while calls like
SAL_INFO ( " foo " , . . . ) or SAL_INFO ( " foo . barzzz " , . . . ) do not .
The generated log output consists of the optional timestamp , the given level
( " info " or " warn " ) , the given area , the process ID , the thread ID , the
source file , and the source line number , each followed by a colon , followed
by a space , the given message , and a newline . The precise format of the log
output is subject to change . The log output is printed to stderr without
further text encoding conversion .
On some systems , log output can be redirected to other log sinks ,
notably a file provided as a system path and filename via
environment variable SAL_LOG_FILE ; or to a syslog facility if
LibreOffice is suitably built , by setting environment variable
SAL_LOG_SYSLOG .
@ see @ ref sal_log_areas
@ attention For now , this functionality should only be used internally within
LibreOffice . It may change again in a future version .
@ since LibreOffice 3 . 5
*/
/**
Produce log entry from stream in the given log area .
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_INFO(area, stream) \
SAL_DETAIL_LOG_STREAM( \
SAL_DETAIL_ENABLE_LOG_INFO, ::SAL_DETAIL_LOG_LEVEL_INFO, area, \
SAL_WHERE, stream)
/**
Produce log entry from stream in the given log area if condition is true .
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_INFO_IF(condition, area, stream) \
SAL_DETAIL_LOG_STREAM( \
SAL_DETAIL_ENABLE_LOG_INFO && (condition), \
::SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, stream)
/**
Produce warning entry from stream in the given log area .
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_WARN(area, stream) \
SAL_DETAIL_LOG_STREAM( \
SAL_DETAIL_ENABLE_LOG_WARN, ::SAL_DETAIL_LOG_LEVEL_WARN, area, \
SAL_WHERE, stream)
/**
Produce warning entry from stream in the given log area if condition is true .
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_WARN_IF(condition, area, stream) \
SAL_DETAIL_LOG_STREAM( \
SAL_DETAIL_ENABLE_LOG_WARN && (condition), \
::SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, stream)
/**
Produce temporary debugging output from stream . This macro is meant to be
used only while working on code and should never exist in production code .
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_DEBUG(stream) \
SAL_DETAIL_LOG_STREAM( \
SAL_LOG_TRUE, ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, stream)
/**
Produce temporary debugging output from stream , if condition is true . This
macro is meant to be used only while working on code and should never exist
in production code .
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_DEBUG_IF(condition, stream) \
SAL_DETAIL_LOG_STREAM( \
(condition), ::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, stream)
/**
Produce temporary debugging output from stream along with a backtrace of the
calling location .
This macro is meant to be used only while working on code and should never
exist in production code .
@ param stream input stream
@ param backtraceDepth a sal_uInt32 value indicating the maximum backtrace
depth ; zero means no backtrace
See @ ref sal_log " basic logging functionality " for details .
*/
#define SAL_DEBUG_BACKTRACE(stream, backtraceDepth) \
do { \
if (sizeof ::sal::detail::getResult( \
::sal::detail::StreamStart() << stream) == 1 ) \
{ \
::sal_detail_log( \
::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, \
::sal::detail::unwrapStream( \
::sal::detail::StreamStart() << stream), \
backtraceDepth); \
} else { \
::std::ostringstream sal_detail_stream; \
sal_detail_stream << stream; \
::sal::detail::log( \
::SAL_DETAIL_LOG_LEVEL_DEBUG, NULL, NULL, sal_detail_stream, \
backtraceDepth); \
} \
} while (false )
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=93 H=93 G=92
¤ Dauer der Verarbeitung: 0.20 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland