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#ifndef INCLUDED_SAL_LOG_HXX
11#define INCLUDED_SAL_LOG_HXX
12
13#include <sal/config.h>
14
15#include <cstdlib>
16#include <sstream>
17#include <string>
18
19#include <sal/detail/log.h>
20#include <sal/saldllapi.h>
21#include <sal/types.h>
22
23// Avoid the use of other sal code in this header as much as possible, so that
24// this code can be called from other sal code without causing endless
25// recursion.
26
27/// @cond INTERNAL
28
29extern "C" SAL_DLLPUBLIC void SAL_CALL sal_detail_log(
30 enum sal_detail_LogLevel level, char const * area, char const * where,
31 char const * message);
32
33namespace sal { namespace detail {
34
35inline void SAL_CALL log(
36 sal_detail_LogLevel level, char const * area, char const * where,
37 std::ostringstream const & stream)
38{
39 // An alternative would be to have sal_detail_log take a std::ostringstream
40 // pointer (via a C void pointer); the advantage would be smaller client
41 // code (the ".str().c_str()" part would move into the implementation of
42 // sal_detail_log) and potential for proper support of embedded null
43 // characters within the message, but the disadvantage would be dependence
44 // on the C++ ABI; as a compromise, the ".str().c_str()" part has been moved
45 // to this inline function so that it is potentially only emitted once per
46 // dynamic library:
47 sal_detail_log(level, area, where, stream.str().c_str());
48}
49
50// Special handling of the common case where the message consists of just a
51// string literal, to produce smaller call-site code:
52
53struct StreamStart {};
54
55struct StreamString {
56 StreamString(char const * s): string(s) {}
57
58 char const * string;
59
60 typedef char Result;
61};
62
63struct StreamIgnore {
64 typedef struct { char a[2]; } Result;
65};
66
67inline StreamString operator <<(
68 SAL_UNUSED_PARAMETER StreamStart const &, char const * s)
69{
70 return StreamString(s);
71}
72
73template< typename T > inline StreamIgnore operator <<(
74 SAL_UNUSED_PARAMETER StreamStart const &, SAL_UNUSED_PARAMETER T const &)
75{
76 std::abort();
77#if defined _MSC_VER && _MSC_VER < 1700
78 return StreamIgnore();
79#endif
80}
81
82template< typename T > inline StreamIgnore operator <<(
83 SAL_UNUSED_PARAMETER StreamString const &, SAL_UNUSED_PARAMETER T const &)
84{
85 std::abort();
86#if defined _MSC_VER && _MSC_VER < 1700
87 return StreamIgnore();
88#endif
89}
90
91template< typename T > inline StreamIgnore operator <<(
92 SAL_UNUSED_PARAMETER StreamIgnore 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
100template< typename T > typename T::Result getResult(T const &);
101
102inline char const * unwrapStream(StreamString const & s) { return s.string; }
103
104inline char const * unwrapStream(SAL_UNUSED_PARAMETER StreamIgnore const &) {
105 std::abort();
106#if defined _MSC_VER && _MSC_VER < 1700
107 return 0;
108#endif
109}
110
111} }
112
113#define SAL_DETAIL_LOG_STREAM(condition, level, area, where, stream) \
114 do { \
115 if (condition) { \
116 if (sizeof ::sal::detail::getResult( \
117 ::sal::detail::StreamStart() << stream) == 1) \
118 { \
119 ::sal_detail_log( \
120 (level), (area), (where), \
121 ::sal::detail::unwrapStream( \
122 ::sal::detail::StreamStart() << stream)); \
123 } else { \
124 ::std::ostringstream sal_detail_stream; \
125 sal_detail_stream << stream; \
126 ::sal::detail::log( \
127 (level), (area), (where), sal_detail_stream); \
128 } \
129 } \
130 } while (false)
131
132/// @endcond
133
134/** A simple macro to create a "file and line number" string.
135
136 Potentially not only useful within the log framework (where it is used
137 automatically), but also when creating exception messages.
138
139 @attention For now, this functionality should only be used internally within
140 LibreOffice. It may change again in a future version.
141
142 @since LibreOffice 3.5
143*/
144#define SAL_WHERE SAL_DETAIL_WHERE
145
146/** A facility for generating temporary string messages by piping items into a
147 C++ std::ostringstream.
148
149 This can be useful for example in a call to SAL_INFO when depending on some
150 boolean condition data of incompatible types shall be streamed into the
151 message, as in:
152
153 SAL_INFO("foo", "object: " << (hasName ? obj->name : SAL_STREAM(obj)));
154
155 @attention For now, this functionality should only be used internally within
156 LibreOffice. It may change again in a future version.
157
158 @since LibreOffice 3.5
159*/
160#ifdef _LIBCPP_VERSION
161#define SAL_STREAM(stream) \
162 (::std::ostringstream() << stream).str()
163#else
164#define SAL_STREAM(stream) \
165 (dynamic_cast< ::std::ostringstream & >(::std::ostringstream() << stream).str())
166#endif
167
168/**
169 @page sal_log Basic logging functionality.
170
171 @short Macros for logging.
172
173 SAL_INFO(char const * area, expr),
174 SAL_INFO_IF(bool condition, char const * area, expr),
175 SAL_WARN(char const * area, expr),
176 SAL_WARN_IF(bool condition, char const * area, expr), and SAL_DEBUG(expr)
177 produce an info, warning, or debug log entry with a message produced by
178 piping items into a C++ std::ostringstream. The given expr must be so that
179 the full expression "stream << expr" is valid, where stream is a variable of
180 type std::ostringstream.
181
182 SAL_INFO("foo", "string " << s << " of length " << n)
183
184 would be an example of such a call.
185
186 The composed message should be in UTF-8 and it should contain no vertical
187 formatting characters and no null characters
188
189 For the _IF variants, log output is only generated if the given condition is
190 true (in addition to the other conditions that have to be met).
191
192 The SAL_DEBUG macro is for temporary debug statements that are used while
193 working on code. It is never meant to remain in the code. It will always
194 simply output the given expression in debug builds.
195
196 For all the other macros, the given area argument must be non-null and must
197 match the regular expression
198
199 @verbatim
200 <area> ::= <segment>("."<segment>)*
201 @endverbatim
202
203 with
204
205 @verbatim
206 <segment> ::= [0-9a-z]+
207 @endverbatim
208
209 For a list of areas used see @ref sal_log_areas "SAL debug areas". Whenever
210 you use a new log area, add it to the file include/sal/log-areas.dox .
211
212 Whether these macros generate any log output is controlled in a two-stage
213 process.
214
215 First, at compile time the macros SAL_LOG_INFO and SAL_LOG_WARN,
216 respectively, control whether the INFO and WARN macros, respectively,
217 expand to actual code (in case the macro is defined, to any value) or to
218 no-ops (in case the macro is not defined).
219
220 Second, at runtime the environment variable SAL_LOG further limits which
221 macro calls actually generate log output. The environment variable SAL_LOG
222 must either be unset or must match the regular expression
223
224 @verbatim
225 <env> ::= <switch>*
226 @endverbatim
227
228 with
229
230 @verbatim
231 <switch> ::= <sense><level>("."<area>)?
232 <sense> ::= "+"|"-"
233 <level> ::= "INFO"|"WARN"
234 @endverbatim
235
236 If the environment variable is unset, "+WARN" is used instead (which results
237 in all warnings being output but no infos). If the given value does not
238 match the regular expression, "+INFO+WARN" is used instead (which in turn
239 results in everything being output).
240
241 A given macro call's level (INFO or WARN) and area is matched against the
242 given switches as follows: Only those switches for which the level matches
243 the given level and for which the area is a prefix (including both empty and
244 full prefixes) of the given area are considered. Log output is generated if
245 and only if among the longest such switches (if any), there is at least one
246 that has a sense of "+". (That is, if both +INFO.foo and -INFO.foo are
247 present, +INFO.foo wins.)
248
249 For example, if SAL_LOG is "+INFO-INFO.foo+INFO.foo.bar", then calls like
250 SAL_INFO("foo.bar", ...), SAL_INFO("foo.bar.baz", ...), or
251 SAL_INFO("other", ...) generate output, while calls like
252 SAL_INFO("foo", ...) or SAL_INFO("foo.barzzz", ...) do not.
253
254 The generated log output consists of the given level ("info" or "warn"), the
255 given area, the process ID, the thread ID, the source file, and the source
256 line number, each followed by a colon, followed by a space, the given
257 message, and a newline. The precise format of the log output is subject to
258 change. The log output is printed to stderr without further text encoding
259 conversion.
260
261 @see @ref sal_log_areas
262
263 @attention For now, this functionality should only be used internally within
264 LibreOffice. It may change again in a future version.
265
266 @since LibreOffice 3.5
267*/
268
269/**
270 Produce log entry from stream in the given log area.
271
272 See @ref sal_log "basic logging functionality" for details.
273*/
274#define SAL_INFO(area, stream) \
275 SAL_DETAIL_LOG_STREAM( \
276 SAL_DETAIL_ENABLE_LOG_INFO, ::SAL_DETAIL_LOG_LEVEL_INFO, area, \
277 SAL_WHERE, stream)
278
279/**
280 Produce log entry from stream in the given log area if condition is true.
281
282 See @ref sal_log "basic logging functionality" for details.
283*/
284#define SAL_INFO_IF(condition, area, stream) \
285 SAL_DETAIL_LOG_STREAM( \
286 SAL_DETAIL_ENABLE_LOG_INFO && (condition), \
287 ::SAL_DETAIL_LOG_LEVEL_INFO, area, SAL_WHERE, stream)
288
289/**
290 Produce warning entry from stream in the given log area.
291
292 See @ref sal_log "basic logging functionality" for details.
293*/
294#define SAL_WARN(area, stream) \
295 SAL_DETAIL_LOG_STREAM( \
296 SAL_DETAIL_ENABLE_LOG_WARN, ::SAL_DETAIL_LOG_LEVEL_WARN, area, \
297 SAL_WHERE, stream)
298
299/**
300 Produce warning entry from stream in the given log area if condition is true.
301
302 See @ref sal_log "basic logging functionality" for details.
303*/
304#define SAL_WARN_IF(condition, area, stream) \
305 SAL_DETAIL_LOG_STREAM( \
306 SAL_DETAIL_ENABLE_LOG_WARN && (condition), \
307 ::SAL_DETAIL_LOG_LEVEL_WARN, area, SAL_WHERE, stream)
308
309/**
310 Produce temporary debugging output from stream. This macro is meant to be
311 used only while working on code and should never exist in production code.
312
313 See @ref sal_log "basic logging functionality" for details.
314*/
315#define SAL_DEBUG(stream) \
316 SAL_DETAIL_LOG_STREAM( \
317 SAL_LOG_TRUE, ::SAL_DETAIL_LOG_LEVEL_DEBUG, 0, 0, stream)
318
319#endif
320
321/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
322