1 /*
2   bctoolobx
3   Copyright (C) 2016 Belledonne Communications, France, Grenoble
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19 
20 /**
21  * \file logging.h
22  * \brief Logging API.
23  *
24 **/
25 
26 #ifndef BCTBX_LOGGING_H
27 #define BCTBX_LOGGING_H
28 
29 #include <bctoolbox/port.h>
30 #include "bctoolbox/list.h"
31 
32 #ifndef BCTBX_LOG_DOMAIN
33 #define BCTBX_LOG_DOMAIN NULL
34 #endif
35 
36 #ifdef __cplusplus
37 extern "C"
38 {
39 #endif
40 
41 typedef enum {
42 	BCTBX_LOG_DEBUG=1,
43 	BCTBX_LOG_TRACE=1<<1,
44 	BCTBX_LOG_MESSAGE=1<<2,
45 	BCTBX_LOG_WARNING=1<<3,
46 	BCTBX_LOG_ERROR=1<<4,
47 	BCTBX_LOG_FATAL=1<<5,
48 	BCTBX_LOG_LOGLEV_END=1<<6
49 } BctbxLogLevel;
50 
51 typedef struct _bctbx_log_handler_t bctbx_log_handler_t;
52 
53 typedef void (*BctbxLogFunc)(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args);
54 typedef void (*BctbxLogHandlerFunc)(void *info,const char *domain, BctbxLogLevel lev, const char *fmt, va_list args);
55 typedef void (*BctbxLogHandlerDestroyFunc)(bctbx_log_handler_t *handler);
56 
57 /*
58  initialise logging functions, add default log handler for stdout output.
59  @param[in] bool_t create : whether or not the initialisation should create a default logger in stdout or not.
60  */
61 BCTBX_PUBLIC void bctbx_init_logger(bool_t create);
62 
63 /*
64  free logging memory
65  */
66 BCTBX_PUBLIC void bctbx_uninit_logger(void);
67 
68 /*
69  Default functions to free log handlers
70  @param[in] bctbx_log_handler_t* handler : the handler to free
71 */
72 BCTBX_PUBLIC void bctbx_logv_out_destroy(bctbx_log_handler_t *handler);
73 BCTBX_PUBLIC void bctbx_logv_file_destroy(bctbx_log_handler_t *handler);
74 
75 /*
76  Function to create a log handler
77  @param[in] BctbxLogHandlerFunc func : the function to call to handle a new line of log
78  @param[in] BctbxLogHandlerDestroyFunc destroy : the function to call to free this handler particuler its user_info field
79  @param[in] void* user_info : complementary information to handle the logs if needed
80  @return a new bctbx_log_handler_t
81 */
82 BCTBX_PUBLIC bctbx_log_handler_t* bctbx_create_log_handler(BctbxLogHandlerFunc func, BctbxLogHandlerDestroyFunc destroy, void* user_info);
83 
84 /*
85  Function to create a file log handler
86  @param[in] uint64_t max_size : the maximum size of the log file before rotating to a new one (if 0 then no rotation)
87  @param[in] const char* path : the path where to put the log files
88  @param[in] const char* name : the name of the log files
89  @param[in] FILE* f : the file where to write the logs
90  @return a new bctbx_log_handler_t
91 */
92 BCTBX_PUBLIC bctbx_log_handler_t* bctbx_create_file_log_handler(uint64_t max_size, const char* path, const char* name, FILE* f);
93 
94 BCTBX_PUBLIC void bctbx_add_log_handler(bctbx_log_handler_t* handler);
95 BCTBX_PUBLIC BCTBX_DEPRECATED void bctbx_set_log_handler(BctbxLogFunc func);
96 BCTBX_PUBLIC BCTBX_DEPRECATED void bctbx_set_log_file(FILE* f);
97 BCTBX_PUBLIC bctbx_list_t* bctbx_get_log_handlers(void);
98 
99 BCTBX_PUBLIC void bctbx_logv_out(void* user_info, const char *domain, BctbxLogLevel level, const char *fmt, va_list args);
100 BCTBX_PUBLIC void bctbx_logv_file(void* user_info, const char *domain, BctbxLogLevel level, const char *fmt, va_list args);
101 
102 #define bctbx_log_level_enabled(domain, level)	(bctbx_get_log_level_mask(domain) & (level))
103 
104 BCTBX_PUBLIC void bctbx_logv(const char *domain, BctbxLogLevel level, const char *fmt, va_list args);
105 
106 /**
107  * Flushes the log output queue.
108  * WARNING: Must be called from the thread that has been defined with bctbx_set_log_thread_id().
109  */
110 BCTBX_PUBLIC void bctbx_logv_flush(void);
111 
112 /**
113  * Activate all log level greater or equal than specified level argument.
114 **/
115 BCTBX_PUBLIC void bctbx_set_log_level(const char *domain, BctbxLogLevel level);
116 
117 BCTBX_PUBLIC void bctbx_set_log_level_mask(const char *domain, int levelmask);
118 BCTBX_PUBLIC unsigned int bctbx_get_log_level_mask(const char *domain);
119 
120 /**
121  * Tell oRTP the id of the thread used to output the logs.
122  * This is meant to output all the logs from the same thread to prevent deadlock problems at the application level.
123  * @param[in] thread_id The id of the thread that will output the logs (can be obtained using bctbx_thread_self()).
124  */
125 BCTBX_PUBLIC void bctbx_set_log_thread_id(unsigned long thread_id);
126 
127 #ifdef __GNUC__
128 #define CHECK_FORMAT_ARGS(m,n) __attribute__((format(printf,m,n)))
129 #else
130 #define CHECK_FORMAT_ARGS(m,n)
131 #endif
132 #ifdef __clang__
133 /*in case of compile with -g static inline can produce this type of warning*/
134 #pragma GCC diagnostic ignored "-Wunused-function"
135 #endif
136 #ifdef BCTBX_DEBUG_MODE
bctbx_debug(const char * fmt,...)137 static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_debug(const char *fmt,...)
138 {
139   va_list args;
140   va_start (args, fmt);
141   bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_DEBUG, fmt, args);
142   va_end (args);
143 }
144 #else
145 
146 #define bctbx_debug(...)
147 
148 #endif
149 
150 #ifdef BCTBX_NOMESSAGE_MODE
151 
152 #define bctbx_log(...)
153 #define bctbx_message(...)
154 #define bctbx_warning(...)
155 
156 #else
157 
bctbx_log(const char * domain,BctbxLogLevel lev,const char * fmt,...)158 static BCTBX_INLINE void bctbx_log(const char* domain, BctbxLogLevel lev, const char *fmt,...) {
159 	va_list args;
160 	va_start (args, fmt);
161 	bctbx_logv(domain, lev, fmt, args);
162 	va_end (args);
163 }
164 
bctbx_message(const char * fmt,...)165 static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_message(const char *fmt,...)
166 {
167 	va_list args;
168 	va_start (args, fmt);
169 	bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_MESSAGE, fmt, args);
170 	va_end (args);
171 }
172 
bctbx_warning(const char * fmt,...)173 static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_warning(const char *fmt,...)
174 {
175 	va_list args;
176 	va_start (args, fmt);
177 	bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_WARNING, fmt, args);
178 	va_end (args);
179 }
180 
181 #endif
182 
bctbx_error(const char * fmt,...)183 static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_error(const char *fmt,...)
184 {
185 	va_list args;
186 	va_start (args, fmt);
187 	bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_ERROR, fmt, args);
188 	va_end (args);
189 }
190 
bctbx_fatal(const char * fmt,...)191 static BCTBX_INLINE void CHECK_FORMAT_ARGS(1,2) bctbx_fatal(const char *fmt,...)
192 {
193 	va_list args;
194 	va_start (args, fmt);
195 	bctbx_logv(BCTBX_LOG_DOMAIN, BCTBX_LOG_FATAL, fmt, args);
196 	va_end (args);
197 }
198 
199 
200 #ifdef __QNX__
201 void bctbx_qnx_log_handler(const char *domain, BctbxLogLevel lev, const char *fmt, va_list args);
202 #endif
203 
204 
205 #ifdef __cplusplus
206 }
207 
208 #include <string>
209 #include <iostream>
210 #include <sstream>
211 
212 #if !defined(_WIN32) && !defined(__QNX__)
213 #include <syslog.h>
214 #endif
215 
216 namespace bctoolbox {
217 	namespace log {
218 
219 		// Here we define our application severity levels.
220 		enum level { normal, trace, debug, info, warning, error, fatal };
221 
222 		// The formatting logic for the severity level
223 		template <typename CharT, typename TraitsT>
224 		inline std::basic_ostream<CharT, TraitsT> &operator<<(std::basic_ostream<CharT, TraitsT> &strm,
225 															  const bctoolbox::log::level &lvl) {
226 			static const char *const str[] = {"normal", "trace", "debug", "info", "warning", "error", "fatal"};
227 			if (static_cast<std::size_t>(lvl) < (sizeof(str) / sizeof(*str)))
228 				strm << str[lvl];
229 			else
230 				strm << static_cast<int>(lvl);
231 			return strm;
232 		}
233 
234 		template <typename CharT, typename TraitsT>
235 		inline std::basic_istream<CharT, TraitsT> &operator>>(std::basic_istream<CharT, TraitsT> &strm,
236 															  bctoolbox::log::level &lvl) {
237 			static const char *const str[] = {"normal", "trace", "debug", "info", "warning", "error", "fatal"};
238 
239 			std::string s;
240 			strm >> s;
241 			for (unsigned int n = 0; n < (sizeof(str) / sizeof(*str)); ++n) {
242 				if (s == str[n]) {
243 					lvl = static_cast<bctoolbox::log::level>(n);
244 					return strm;
245 				}
246 			}
247 			// Parse error
248 			strm.setstate(std::ios_base::failbit);
249 			return strm;
250 		}
251 	}
252 }
253 
254 
255 
256 #include <ostream>
257 
258 struct pumpstream : public std::ostringstream {
259 	const std::string mDomain;
260 	const BctbxLogLevel level;
pumpstreampumpstream261 	pumpstream(const std::string &domain, BctbxLogLevel l) : mDomain(domain), level(l) {}
262 
~pumpstreampumpstream263 	~pumpstream() {
264 		bctbx_log(mDomain.empty()?NULL:mDomain.c_str(), level, "%s", str().c_str());
265 	}
266 };
267 
268 #if (__GNUC__ == 4 && __GNUC_MINOR__ < 5 && __cplusplus > 199711L)
269 template <typename _Tp> inline pumpstream &operator<<(pumpstream &&__os, const _Tp &__x) {
270 	(static_cast<std::ostringstream &>(__os)) << __x;
271 	return __os;
272 }
273 #endif
274 
275 #define BCTBX_SLOG(domain, thelevel) \
276 \
277 if (bctbx_log_level_enabled((domain), (thelevel))) \
278 		pumpstream((domain != NULL ? domain : ""), (thelevel))
279 
280 #define BCTBX_SLOGD(DOMAIN) BCTBX_SLOG(DOMAIN, BCTBX_LOG_DEBUG)
281 #define BCTBX_SLOGI(DOMAIN) BCTBX_SLOG((DOMAIN), (BCTBX_LOG_MESSAGE))
282 #define BCTBX_SLOGW(DOMAIN) BCTBX_SLOG(DOMAIN, BCTBX_LOG_WARNING)
283 #define BCTBX_SLOGE(DOMAIN) BCTBX_SLOG(DOMAIN, BCTBX_LOG_ERROR)
284 
285 
286 #endif
287 
288 #endif
289