Line data Source code
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 :
29 : extern "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 :
33 : namespace sal { namespace detail {
34 :
35 : inline 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 :
53 : struct StreamStart {};
54 :
55 : struct StreamString {
56 0 : StreamString(char const * s): string(s) {}
57 :
58 : char const * string;
59 :
60 : typedef char Result;
61 : };
62 :
63 : struct StreamIgnore {
64 : typedef struct { char a[2]; } Result;
65 : };
66 :
67 0 : inline StreamString operator <<(
68 : SAL_UNUSED_PARAMETER StreamStart const &, char const * s)
69 : {
70 0 : return StreamString(s);
71 : }
72 :
73 : template< 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 :
82 : template< 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 :
91 : template< 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 :
100 : template< typename T > typename T::Result getResult(T const &);
101 :
102 0 : inline char const * unwrapStream(StreamString const & s) { return s.string; }
103 :
104 : inline 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: */
|