/src/resiprocate/rutil/Logger.hxx
Line | Count | Source (jump to first uncovered line) |
1 | | #ifndef RESIP_Logger_hxx |
2 | | #define RESIP_Logger_hxx |
3 | | |
4 | | #include "rutil/Log.hxx" |
5 | | #include "rutil/Lock.hxx" |
6 | | #include "rutil/DataStream.hxx" |
7 | | #include "rutil/Data.hxx" |
8 | | #include "rutil/Subsystem.hxx" |
9 | | |
10 | | #ifdef WIN32 |
11 | | #include <windows.h> |
12 | | #endif |
13 | | |
14 | | /** |
15 | | @file Defines a set of logging macros, one for each level of logging. |
16 | | |
17 | | <h2>Simple usage</h2> |
18 | | |
19 | | Each source file which uses logging facilities, must set RESIPROCATE_SUBSYSTEM |
20 | | preprocessor define to one of resip subsystems. This define will be used by |
21 | | logging macros to mark log entries, generated from this source file, with |
22 | | appropriate subsystem tag. For the list of available resip subsystems refer |
23 | | to static variables list in resip::Subsystem class. Note, that those standard |
24 | | resip::Subsystem variables are just the most commonly used ones. Nothing |
25 | | prevents you from creating your own resip::Subsystem instance and set |
26 | | RESIPROCATE_SUBSYSTEM to point to it. That custom resip::Subsystem variable |
27 | | can even be local to a file or private class member variable, you just must |
28 | | ensure that it exist in all places you use logging this file. Creating own |
29 | | resip::Subsystem will allow you to create own subsystem tag and set specific |
30 | | logging level for it. |
31 | | |
32 | | Once you have RESIPROCATE_SUBSYSTEM defined you can start logging with any |
33 | | of StackLog(), DebugLog(), InfoLog(), WarningLog(), ErrLog(), CritLog(). These |
34 | | preprocessor macros provide a convenient way to log your data. Look at this |
35 | | piece of code as an example: |
36 | | |
37 | | <code> |
38 | | #include Logger.hxx |
39 | | #define RESIPROCATE_SUBSYSTEM resip::Subsystem::SIP |
40 | | ... |
41 | | DebugLog(<< "hi there " << mix << 4 << types); // note leading << and no endl |
42 | | </code> |
43 | | |
44 | | |
45 | | <h2>Initialization</h2> |
46 | | |
47 | | Logging may be used without (or prior to) initialization, in which case all |
48 | | log data will be printed right to console (to std::cout). Likely, you will |
49 | | want to use more advanced logging features like output to syslog or a file. |
50 | | In this case you need to call Log::initialize() with appropriate parameters. |
51 | | E.g., following example tells logger to write data to a file with the name |
52 | | "resip.log". It will write only entries with logging priority Log::Info or |
53 | | higher. Application name is taken from argv[0], and no external logger is |
54 | | specified (last parameter is NULL). |
55 | | |
56 | | <code> |
57 | | Log::initialize(Log::File, Log::Info, argv[0], "resip.log", NULL); |
58 | | </code> |
59 | | |
60 | | Refer to Log::Type for a list of possible logging types and to Log::Level |
61 | | for a list of available logging levels. |
62 | | |
63 | | |
64 | | <h2>External loggers</h2> |
65 | | |
66 | | Sometimes you may need to provide your own, application specific way of |
67 | | logging. E.g. you may want to output log data to a GUI window. This may be |
68 | | implemented using external loggers. To create an external logger you just |
69 | | need to inherit from ExternalLogger class and pass an object of your external |
70 | | logger to Log::initialize() as the last parameter. |
71 | | |
72 | | |
73 | | <h2Subsystem-specific logging level></h2> |
74 | | |
75 | | You may set logging level to output for a specific subsystem inside resip. |
76 | | The recommended way to do this is with <code>Log::setLevel(level, subsystem)</code> |
77 | | static function. If you set a concrete logging level for the subsystem, it |
78 | | will be used instead of all other logging level settings, like global logging |
79 | | level setting and thread local logger level setting. To set subsystem-specific |
80 | | logging level back to default logging level, call |
81 | | <code>Log::setLevel(Log::None, subsystem)</code> |
82 | | |
83 | | |
84 | | <h2>Thread local loggers</h2> |
85 | | |
86 | | If your application uses several threads for resip, e.g. uses separate thread |
87 | | for each resip instance, then you may want to split your log streams to be |
88 | | separate too. E.g. you may use different log files for different instances. |
89 | | In this case you need to use thread local loggers. |
90 | | |
91 | | First, you need to create a thread local logger with Log::localLoggerCreate() |
92 | | static function call with desired parameters (they're closely following |
93 | | Log::initialize() meaning). You will receive LocalLoggerId in response which |
94 | | you will use later to refer to created local logger. If you need to change |
95 | | local logger's parameters later, you should use Log::localLoggerReinitialize() |
96 | | static function. And when you're done with it, free it with Log::localLoggerRemove() |
97 | | static function. To actually use a created local logger, you need to call |
98 | | Log::setThreadLocalLogger() from the target thread context. If you need to |
99 | | remove thread local logger from a thread, just call |
100 | | <code>Log::setThreadLocalLogger(0)</code> |
101 | | |
102 | | Note, that thread local logger may be safely used from multiple threads. |
103 | | So if each of your resip instances have two threads, both of them can just |
104 | | share the same local logger - just pass its LocalLoggerId to them both. |
105 | | |
106 | | |
107 | | <h2>Still not sure?</h2> |
108 | | |
109 | | If you still can't get something, just look how it is used in existing code. |
110 | | One particular place to look into is rutil/test/testLogger.cxx which is |
111 | | a unittest for logging facility. |
112 | | */ |
113 | | |
114 | | |
115 | | #define DELIM |
116 | | |
117 | | |
118 | | |
119 | | // unconditionally output to cerr -- easily change back and forth |
120 | | #define CerrLog(args_) \ |
121 | | resip::Log::tags(resip::Log::StdErr, RESIPROCATE_SUBSYSTEM, \ |
122 | | __FILE__, __LINE__, __func__, resipCerr, resip::Log::Unstructured) << ' ' << '|' << ' ' \ |
123 | | args_ << std::endl; |
124 | | |
125 | 0 | #define StackLog(args_) \ |
126 | 0 | GenericLog(RESIPROCATE_SUBSYSTEM, resip::Log::Stack, args_) |
127 | | |
128 | 0 | #define DebugLog(args_) \ |
129 | 0 | GenericLog(RESIPROCATE_SUBSYSTEM, resip::Log::Debug, args_) |
130 | | |
131 | 0 | #define InfoLog(args_) \ |
132 | 0 | GenericLog(RESIPROCATE_SUBSYSTEM, resip::Log::Info, args_) |
133 | | |
134 | 0 | #define WarningLog(args_) \ |
135 | 0 | GenericLog(RESIPROCATE_SUBSYSTEM, resip::Log::Warning, args_) |
136 | | |
137 | 0 | #define ErrLog(args_) \ |
138 | 0 | GenericLog(RESIPROCATE_SUBSYSTEM, resip::Log::Err, args_) |
139 | | |
140 | 0 | #define CritLog(args_) \ |
141 | 0 | GenericLog(RESIPROCATE_SUBSYSTEM, resip::Log::Crit, args_) |
142 | | |
143 | | static inline bool |
144 | | genericLogCheckLevel(resip::Log::Level level, const resip::Subsystem& sub) |
145 | 2 | { |
146 | 2 | return resip::Log::isLogging(level, sub); |
147 | 2 | } Unexecuted instantiation: fuzzUtil.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Unexecuted instantiation: DnsUtil.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Log.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Line | Count | Source | 145 | 2 | { | 146 | 2 | return resip::Log::isLogging(level, sub); | 147 | 2 | } |
Unexecuted instantiation: ParseBuffer.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Unexecuted instantiation: Socket.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Unexecuted instantiation: ThreadIf.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Unexecuted instantiation: BaseException.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) Unexecuted instantiation: ConfigParse.cxx:genericLogCheckLevel(resip::Log::Level, resip::Subsystem const&) |
148 | | |
149 | | // do/while allows a {} block in an expression |
150 | | #define GenericLog(system_, level_, args_) \ |
151 | 2 | do \ |
152 | 2 | { \ |
153 | 2 | if (genericLogCheckLevel(level_, system_)) \ |
154 | 2 | { \ |
155 | 0 | resip::Log::Guard _resip_log_guard(level_, system_, __FILE__, __LINE__, __func__); \ |
156 | 0 | _resip_log_guard.asStream() args_; \ |
157 | 0 | } \ |
158 | 2 | } while (false) |
159 | | |
160 | | #ifdef NO_DEBUG |
161 | | // Suppress debug logging at compile time |
162 | | #undef DebugLog |
163 | | #define DebugLog(args_) |
164 | | #undef StackLog |
165 | | #define StackLog(args_) |
166 | | #endif |
167 | | |
168 | | namespace resip |
169 | | { |
170 | | /// DEPRECATED! Left for backward compatibility. |
171 | | typedef Log GenericLogImpl; |
172 | | } |
173 | | |
174 | | #endif |
175 | | |
176 | | /* ==================================================================== |
177 | | * The Vovida Software License, Version 1.0 |
178 | | * |
179 | | * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. |
180 | | * |
181 | | * Redistribution and use in source and binary forms, with or without |
182 | | * modification, are permitted provided that the following conditions |
183 | | * are met: |
184 | | * |
185 | | * 1. Redistributions of source code must retain the above copyright |
186 | | * notice, this list of conditions and the following disclaimer. |
187 | | * |
188 | | * 2. Redistributions in binary form must reproduce the above copyright |
189 | | * notice, this list of conditions and the following disclaimer in |
190 | | * the documentation and/or other materials provided with the |
191 | | * distribution. |
192 | | * |
193 | | * 3. The names "VOCAL", "Vovida Open Communication Application Library", |
194 | | * and "Vovida Open Communication Application Library (VOCAL)" must |
195 | | * not be used to endorse or promote products derived from this |
196 | | * software without prior written permission. For written |
197 | | * permission, please contact vocal@vovida.org. |
198 | | * |
199 | | * 4. Products derived from this software may not be called "VOCAL", nor |
200 | | * may "VOCAL" appear in their name, without prior written |
201 | | * permission of Vovida Networks, Inc. |
202 | | * |
203 | | * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
204 | | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
205 | | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND |
206 | | * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA |
207 | | * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES |
208 | | * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, |
209 | | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
210 | | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
211 | | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
212 | | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
213 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE |
214 | | * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
215 | | * DAMAGE. |
216 | | * |
217 | | * ==================================================================== |
218 | | * |
219 | | * This software consists of voluntary contributions made by Vovida |
220 | | * Networks, Inc. and many individuals on behalf of Vovida Networks, |
221 | | * Inc. For more information on Vovida Networks, Inc., please see |
222 | | * <http://www.vovida.org/>. |
223 | | * |
224 | | */ |