Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * debug print |
3 | | * |
4 | | * Copyright (C) 2001-2003 FhG Fokus |
5 | | * |
6 | | * This file is part of opensips, a free SIP server. |
7 | | * |
8 | | * opensips is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU General Public License as published by |
10 | | * the Free Software Foundation; either version 2 of the License, or |
11 | | * (at your option) any later version |
12 | | * |
13 | | * opensips is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU General Public License |
19 | | * along with this program; if not, write to the Free Software |
20 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | | */ |
22 | | |
23 | | /*! |
24 | | * \file |
25 | | * \brief OpenSIPS Debug console print functions |
26 | | */ |
27 | | |
28 | | #include "dprint.h" |
29 | | #include "log_interface.h" |
30 | | #include "globals.h" |
31 | | #include "pt.h" |
32 | | |
33 | | #include <stdarg.h> |
34 | | #include <stdio.h> |
35 | | #include <strings.h> |
36 | | |
37 | | #if !defined(HOST_NAME_MAX) |
38 | | #define HOST_NAME_MAX 255 |
39 | | #endif |
40 | | |
41 | | /* used internally by the log interface */ |
42 | | typedef void (*log_print_pre_fmt_f)(log_print_f gen_print_func, int log_level, |
43 | | int facility, const char *module, const char *func, |
44 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap); |
45 | | |
46 | | struct log_consumer_t { |
47 | | str name; |
48 | | log_print_f gen_print_func; |
49 | | log_print_pre_fmt_f pre_fmt_print_func; |
50 | | int level_filter; |
51 | | int muted; |
52 | | }; |
53 | | |
54 | | static int log_level_holder = L_NOTICE; |
55 | | enum log_format stderr_log_format = LOG_FORMAT_PLAIN; |
56 | | enum log_format syslog_log_format = LOG_FORMAT_PLAIN; |
57 | | |
58 | | /* shared holder with the globally set log_level */ |
59 | | static int *log_level_global = NULL; |
60 | | |
61 | | /* current logging level for this process */ |
62 | | int *log_level = &log_level_holder; |
63 | | char *log_prefix = ""; |
64 | | |
65 | | /* used when resetting the logging level of this process */ |
66 | | static int *default_log_level; |
67 | | |
68 | | static char *log_json_buf = NULL; |
69 | | int log_json_buf_size = 6144; |
70 | | static char *log_msg_buf = NULL; |
71 | | int log_msg_buf_size = 4096; |
72 | | |
73 | | str log_cee_hostname; |
74 | | |
75 | | static void stderr_dprint(int log_level, int facility, const char *module, const char *func, |
76 | | char *format, va_list ap); |
77 | | static void syslog_dprint(int log_level, int facility, const char *module, const char *func, |
78 | | char *format, va_list ap); |
79 | | |
80 | | static void stderr_pre_fmt_func(log_print_f gen_print_func, int log_level, |
81 | | int facility, const char *module, const char *func, |
82 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap); |
83 | | static void syslog_pre_fmt_func(log_print_f gen_print_func, int log_level, |
84 | | int facility, const char *module, const char *func, |
85 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap); |
86 | | |
87 | | /* static consumer table to be used until a shm one is alloc'ed; |
88 | | * only stderror is enabled initially */ |
89 | | static struct log_consumer_t default_log_consumers[2] ={ |
90 | | {str_init(STDERR_CONSUMER_NAME), stderr_dprint, stderr_pre_fmt_func, 0, 0}, |
91 | | {str_init(SYSLOG_CONSUMER_NAME), syslog_dprint, syslog_pre_fmt_func, 0, 1} |
92 | | }; |
93 | | |
94 | | struct log_consumer_t *log_consumers = default_log_consumers; |
95 | | int log_consumers_no = 2; |
96 | | |
97 | | int log_event_enabled = 0; |
98 | | int log_event_level_filter = 0; |
99 | | static str evi_log_name = str_init("E_CORE_LOG"); |
100 | | static event_id_t evi_log_id; |
101 | | |
102 | | static char* str_fac[]={"LOG_AUTH","LOG_CRON","LOG_DAEMON", |
103 | | "LOG_KERN","LOG_LOCAL0","LOG_LOCAL1", |
104 | | "LOG_LOCAL2","LOG_LOCAL3","LOG_LOCAL4","LOG_LOCAL5", |
105 | | "LOG_LOCAL6","LOG_LOCAL7","LOG_LPR","LOG_MAIL", |
106 | | "LOG_NEWS","LOG_USER","LOG_UUCP", |
107 | | #ifndef __OS_solaris |
108 | | "LOG_AUTHPRIV","LOG_FTP","LOG_SYSLOG", |
109 | | #endif |
110 | | 0}; |
111 | | static int int_fac[]={LOG_AUTH , LOG_CRON , LOG_DAEMON , |
112 | | LOG_KERN , LOG_LOCAL0 , LOG_LOCAL1 , |
113 | | LOG_LOCAL2 , LOG_LOCAL3 , LOG_LOCAL4 , LOG_LOCAL5 , |
114 | | LOG_LOCAL6 , LOG_LOCAL7 , LOG_LPR , LOG_MAIL , |
115 | | LOG_NEWS , LOG_USER , LOG_UUCP |
116 | | #ifndef __OS_solaris |
117 | | ,LOG_AUTHPRIV,LOG_FTP,LOG_SYSLOG |
118 | | #endif |
119 | | }; |
120 | | |
121 | | char ctime_buf[256]; |
122 | | |
123 | | int str2facility(char *s) |
124 | 0 | { |
125 | 0 | int i; |
126 | |
|
127 | 0 | for( i=0; str_fac[i] ; i++) { |
128 | 0 | if (!strcasecmp(s,str_fac[i])) |
129 | 0 | return int_fac[i]; |
130 | 0 | } |
131 | 0 | return -1; |
132 | 0 | } |
133 | | |
134 | | |
135 | | int dp_my_pid(void) |
136 | 0 | { |
137 | 0 | return my_pid(); |
138 | 0 | } |
139 | | |
140 | | int parse_log_format(str *format) |
141 | 0 | { |
142 | 0 | if (str_match(format, (&str_init(LOG_PLAIN_NAME)))) |
143 | 0 | return LOG_FORMAT_PLAIN; |
144 | 0 | else if (str_match(format, (&str_init(LOG_JSON_NAME)))) |
145 | 0 | return LOG_FORMAT_JSON; |
146 | 0 | else if (str_match(format, (&str_init(LOG_JSON_CEE_NAME)))) |
147 | 0 | return LOG_FORMAT_JSON_CEE; |
148 | 0 | else |
149 | 0 | return -1; |
150 | 0 | } |
151 | | |
152 | | void stderr_dprint_tmp(char *format, ...) |
153 | 0 | { |
154 | 0 | va_list ap; |
155 | |
|
156 | 0 | va_start(ap, format); |
157 | 0 | vfprintf(stderr,format,ap); |
158 | 0 | fflush(stderr); |
159 | 0 | va_end(ap); |
160 | 0 | } |
161 | | |
162 | | int init_log_cee_hostname(void) |
163 | 0 | { |
164 | 0 | struct addrinfo hints, *info = NULL; |
165 | 0 | char hostname[HOST_NAME_MAX+1]; |
166 | 0 | int rc; |
167 | 0 | str cname; |
168 | |
|
169 | 0 | if (log_cee_hostname.s) |
170 | 0 | return 0; |
171 | | |
172 | 0 | gethostname (hostname, HOST_NAME_MAX); |
173 | |
|
174 | 0 | memset(&hints, 0, sizeof hints); |
175 | 0 | hints.ai_family = AF_UNSPEC; |
176 | 0 | hints.ai_socktype = SOCK_STREAM; |
177 | 0 | hints.ai_flags = AI_CANONNAME; |
178 | |
|
179 | 0 | rc = getaddrinfo(hostname, 0, &hints, &info); |
180 | 0 | if (!rc && info) { |
181 | 0 | init_str(&cname, info->ai_canonname); |
182 | 0 | if (pkg_str_dup(&log_cee_hostname, &cname) < 0) { |
183 | 0 | LM_ERR("no more pkg memory\n"); |
184 | 0 | freeaddrinfo(info); |
185 | 0 | return -1; |
186 | 0 | } |
187 | 0 | } |
188 | | |
189 | 0 | if (info) |
190 | 0 | freeaddrinfo(info); |
191 | |
|
192 | 0 | return 0; |
193 | 0 | } |
194 | | |
195 | | #define append_string(_d,_s,_len) \ |
196 | 0 | do{\ |
197 | 0 | memcpy((_d),(_s),(_len));\ |
198 | 0 | (_d) += (_len);\ |
199 | 0 | len += (_len);\ |
200 | 0 | }while(0) |
201 | | |
202 | | #define append_string_st(_d,_s) \ |
203 | 0 | do{\ |
204 | 0 | memcpy((_d),(_s),sizeof(_s) - 1);\ |
205 | 0 | (_d) += sizeof(_s) - 1;\ |
206 | 0 | len += sizeof(_s) - 1;\ |
207 | 0 | }while(0) |
208 | | |
209 | 0 | #define S_LEN(_s) (sizeof(_s) - 1) |
210 | | |
211 | | #define DP_JSON_TIME_KEY "{\"time\": \"" |
212 | | #define DP_JSON_PID_KEY "\", \"pid\": " |
213 | | #define DP_JSON_LEVEL_KEY ", \"level\": \"" |
214 | | #define DP_JSON_MODULE_KEY "\", \"module\": \"" |
215 | | #define DP_JSON_FUNC_KEY "\", \"function\": \"" |
216 | | #define DP_JSON_PREFIX_KEY "\", \"prefix\": \"" |
217 | | #define DP_JSON_MSG_KEY "\", \"message\": \"" |
218 | | |
219 | | #define DP_JSON_CEE_AT_PREFIX "@cee: " |
220 | | #define DP_JSON_CEE_TIME_KEY "{\"time\": \"" |
221 | | #define DP_JSON_CEE_PID_KEY "\", \"proc\": {\"id\": \"" |
222 | | #define DP_JSON_CEE_LEVEL_KEY "\"}, \"pri\": \"" |
223 | | #define DP_JSON_CEE_MODULE_KEY "\", \"subsys\": \"" |
224 | | #define DP_JSON_CEE_FUNC_KEY "\", \"native\": {\"function\": \"" |
225 | | #define DP_JSON_CEE_PREFIX_KEY "\", \"log_prefix\": \"" |
226 | | #define DP_JSON_CEE_PREFIX_O_KEY "\", \"native\": {\"log_prefix\": \"" |
227 | | #define DP_JSON_CEE_MSG_B_KEY "\"}, \"msg\": \"" |
228 | | #define DP_JSON_CEE_MSG_KEY "\", \"msg\": \"" |
229 | | #define DP_JSON_CEE_PNAME_KEY "\", \"pname\": \"" |
230 | | #define DP_JSON_CEE_PNAME_VAL "opensips" |
231 | | #define DP_JSON_CEE_HOST_KEY "\", \"hostname\": \"" |
232 | | |
233 | | #define DP_JSON_MSG_END "\"}" |
234 | | |
235 | | static int log_escape_json_buf(char *src, int src_len, char *dst, int dst_max_len) |
236 | 0 | { |
237 | 0 | int i, j = 0; |
238 | 0 | int rlen = 0; |
239 | | |
240 | | /* calculate the required length in the dst buffer */ |
241 | 0 | for (i=0; i<src_len; i++) { |
242 | 0 | rlen++; |
243 | |
|
244 | 0 | switch (src[i]) { |
245 | 0 | case '\\': |
246 | 0 | case '\"': |
247 | 0 | case '\b': |
248 | 0 | case '\f': |
249 | 0 | case '\n': |
250 | 0 | case '\r': |
251 | 0 | case '\t': |
252 | 0 | rlen++; /* +1 for the backslash */ |
253 | 0 | break; |
254 | 0 | default: |
255 | 0 | if (src[i] < 32) |
256 | 0 | rlen += 6; /* +6 for \uXXXX */ |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | 0 | if (rlen>dst_max_len) { |
261 | 0 | stderr_dprint_tmp_err("buffer too small! needed: %d\n", rlen); |
262 | 0 | return -1; |
263 | 0 | } else if (rlen == src_len) { |
264 | | /* nothing needs to be escaped */ |
265 | 0 | memcpy(dst, src, src_len); |
266 | 0 | return src_len; |
267 | 0 | } |
268 | | |
269 | 0 | for (i=0; i<src_len; i++) { |
270 | 0 | if (src[i] > 31 && src[i] != '\\' && src[i] != '\"') { |
271 | 0 | dst[j++] = src[i]; |
272 | 0 | } else { |
273 | 0 | dst[j++] = '\\'; |
274 | |
|
275 | 0 | switch (src[i]) { |
276 | 0 | case '\\': |
277 | 0 | dst[j++] = '\\'; |
278 | 0 | break; |
279 | 0 | case '\"': |
280 | 0 | dst[j++] = '\"'; |
281 | 0 | break; |
282 | 0 | case '\b': |
283 | 0 | dst[j++] = 'b'; |
284 | 0 | break; |
285 | 0 | case '\f': |
286 | 0 | dst[j++] = 'f'; |
287 | 0 | break; |
288 | 0 | case '\n': |
289 | 0 | dst[j++] = 'n'; |
290 | 0 | break; |
291 | 0 | case '\r': |
292 | 0 | dst[j++] = 'r'; |
293 | 0 | break; |
294 | 0 | case '\t': |
295 | 0 | dst[j++] = 't'; |
296 | 0 | break; |
297 | 0 | default: |
298 | | /* escape and print as unicode codepoint */ |
299 | 0 | sprintf(dst+j, "u%04x", src[i]); |
300 | 0 | j += 5; |
301 | 0 | } |
302 | 0 | } |
303 | 0 | } |
304 | | |
305 | 0 | return j; |
306 | 0 | } |
307 | | |
308 | | enum log_json_format { |
309 | | LOG_JSON_SCHEMA_BASIC, |
310 | | LOG_JSON_SCHEMA_CEE, |
311 | | LOG_JSON_SCHEMA_CEE_PREFIX /* for syslog, JSON prefixed with "@cee: " */ |
312 | | }; |
313 | | |
314 | | static int log_print_json(str *buf, enum log_json_format json_fmt, char *time, |
315 | | int pid, char *prefix, const char *level, const char *module, const char *func, |
316 | | char *format, va_list ap) |
317 | 0 | { |
318 | 0 | char *p, *tmp; |
319 | 0 | int len = 0, rlen; |
320 | 0 | int l; |
321 | |
|
322 | 0 | if (json_fmt > LOG_JSON_SCHEMA_BASIC) { |
323 | 0 | rlen = S_LEN(DP_JSON_CEE_PNAME_KEY) + (log_name ? strlen(log_name) : |
324 | 0 | S_LEN(DP_JSON_CEE_PNAME_VAL)) + S_LEN(DP_JSON_CEE_HOST_KEY) + |
325 | 0 | log_cee_hostname.len + S_LEN(DP_JSON_MSG_END) + 1; |
326 | |
|
327 | 0 | if (json_fmt == LOG_JSON_SCHEMA_CEE_PREFIX) |
328 | 0 | len = S_LEN(DP_JSON_CEE_AT_PREFIX); |
329 | |
|
330 | 0 | len += S_LEN(DP_JSON_CEE_TIME_KEY) + strlen(time) + |
331 | 0 | S_LEN(DP_JSON_CEE_PID_KEY) + INT2STR_MAX_LEN + |
332 | 0 | S_LEN(DP_JSON_CEE_LEVEL_KEY) + strlen(level) + |
333 | 0 | (module && func ? |
334 | 0 | S_LEN(DP_JSON_CEE_MODULE_KEY) + strlen(module) + |
335 | 0 | S_LEN(DP_JSON_CEE_FUNC_KEY) + strlen(func) : 0) + |
336 | 0 | S_LEN(DP_JSON_CEE_PREFIX_O_KEY) + strlen(prefix) + |
337 | 0 | S_LEN(DP_JSON_MSG_KEY) + rlen; |
338 | 0 | } else { |
339 | 0 | rlen = S_LEN(DP_JSON_MSG_END) + 1; |
340 | |
|
341 | 0 | len = S_LEN(DP_JSON_TIME_KEY) + strlen(time) + S_LEN(DP_JSON_PID_KEY) + |
342 | 0 | INT2STR_MAX_LEN + S_LEN(DP_JSON_LEVEL_KEY) + strlen(level) + |
343 | 0 | (module && func ? S_LEN(DP_JSON_MODULE_KEY) + strlen(module) + |
344 | 0 | S_LEN(DP_JSON_FUNC_KEY) + strlen(func) : 0) + |
345 | 0 | S_LEN(DP_JSON_PREFIX_KEY) + strlen(prefix) + |
346 | 0 | S_LEN(DP_JSON_CEE_MSG_B_KEY) + rlen; |
347 | 0 | } |
348 | |
|
349 | 0 | if (len >= buf->len) { |
350 | 0 | stderr_dprint_tmp_err("buffer too small! needed: %d\n", len); |
351 | 0 | return -1; |
352 | 0 | } |
353 | | |
354 | 0 | len = 0; |
355 | 0 | p = buf->s; |
356 | |
|
357 | 0 | if (json_fmt > LOG_JSON_SCHEMA_BASIC) { |
358 | 0 | if (json_fmt == LOG_JSON_SCHEMA_CEE_PREFIX) |
359 | 0 | append_string_st(p, DP_JSON_CEE_AT_PREFIX); |
360 | |
|
361 | 0 | append_string_st(p, DP_JSON_CEE_TIME_KEY); |
362 | 0 | append_string(p, time, strlen(time)); |
363 | |
|
364 | 0 | append_string_st(p, DP_JSON_CEE_PID_KEY); |
365 | 0 | tmp = int2str(pid, &l); |
366 | 0 | append_string(p, tmp, l); |
367 | |
|
368 | 0 | append_string_st(p, DP_JSON_CEE_LEVEL_KEY); |
369 | 0 | append_string(p, level, strlen(level)); |
370 | |
|
371 | 0 | if (module && func) { |
372 | 0 | append_string_st(p, DP_JSON_CEE_MODULE_KEY); |
373 | 0 | append_string(p, module, strlen(module)); |
374 | |
|
375 | 0 | append_string_st(p, DP_JSON_CEE_FUNC_KEY); |
376 | 0 | append_string(p, func, strlen(func)); |
377 | 0 | } |
378 | |
|
379 | 0 | if (strlen(prefix) != 0) { |
380 | 0 | if (module && func) |
381 | 0 | append_string_st(p, DP_JSON_CEE_PREFIX_KEY); |
382 | 0 | else |
383 | 0 | append_string_st(p, DP_JSON_CEE_PREFIX_O_KEY); |
384 | 0 | append_string(p, prefix, strlen(prefix)-1/*skip the ':'*/); |
385 | 0 | } |
386 | |
|
387 | 0 | if ((module && func) || strlen(prefix) != 0) |
388 | 0 | append_string_st(p, DP_JSON_CEE_MSG_B_KEY); |
389 | 0 | else |
390 | 0 | append_string_st(p, DP_JSON_CEE_MSG_KEY); |
391 | 0 | } else { |
392 | 0 | append_string_st(p, DP_JSON_TIME_KEY); |
393 | 0 | append_string(p, time, strlen(time)); |
394 | |
|
395 | 0 | append_string_st(p, DP_JSON_PID_KEY); |
396 | 0 | tmp = int2str(pid, &l); |
397 | 0 | append_string(p, tmp, l); |
398 | |
|
399 | 0 | append_string_st(p, DP_JSON_LEVEL_KEY); |
400 | 0 | append_string(p, level, strlen(level)); |
401 | |
|
402 | 0 | if (module && func) { |
403 | 0 | append_string_st(p, DP_JSON_MODULE_KEY); |
404 | 0 | append_string(p, module, strlen(module)); |
405 | |
|
406 | 0 | append_string_st(p, DP_JSON_FUNC_KEY); |
407 | 0 | append_string(p, func, strlen(func)); |
408 | 0 | } |
409 | |
|
410 | 0 | if (strlen(prefix) != 0) { |
411 | 0 | append_string_st(p, DP_JSON_PREFIX_KEY); |
412 | 0 | append_string(p, prefix, strlen(prefix)-1/*skip the ':'*/); |
413 | 0 | } |
414 | |
|
415 | 0 | append_string_st(p, DP_JSON_MSG_KEY); |
416 | 0 | } |
417 | |
|
418 | 0 | l = vsnprintf(log_msg_buf, log_msg_buf_size, format, ap); |
419 | 0 | if (l < 0) { |
420 | 0 | stderr_dprint_tmp_err("vsnprintf() failed!\n"); |
421 | 0 | return -1; |
422 | 0 | } |
423 | 0 | if (l >= log_msg_buf_size) { |
424 | 0 | stderr_dprint_tmp_err("warning: buffer too small, log message truncated\n"); |
425 | 0 | l = log_msg_buf_size; |
426 | 0 | } |
427 | |
|
428 | 0 | l = log_escape_json_buf(log_msg_buf, l, p, |
429 | 0 | buf->len - len - rlen - 1); |
430 | 0 | if (l < 0) { |
431 | 0 | stderr_dprint_tmp_err("failed to escape log message!\n"); |
432 | 0 | return -1; |
433 | 0 | } |
434 | | |
435 | 0 | p += l; |
436 | 0 | len += l; |
437 | |
|
438 | 0 | if (json_fmt == LOG_JSON_SCHEMA_BASIC) { |
439 | 0 | append_string_st(p, DP_JSON_MSG_END); |
440 | 0 | } else { |
441 | 0 | append_string_st(p, DP_JSON_CEE_PNAME_KEY); |
442 | 0 | if (log_name) |
443 | 0 | append_string(p, log_name, strlen(log_name)); |
444 | 0 | else |
445 | 0 | append_string_st(p, DP_JSON_CEE_PNAME_VAL); |
446 | |
|
447 | 0 | append_string_st(p, DP_JSON_CEE_HOST_KEY); |
448 | 0 | append_string(p, log_cee_hostname.s, log_cee_hostname.len); |
449 | |
|
450 | 0 | append_string_st(p, DP_JSON_MSG_END); |
451 | 0 | } |
452 | |
|
453 | 0 | *p = '\0'; |
454 | |
|
455 | 0 | return len; |
456 | 0 | } |
457 | | |
458 | | static void stderr_dprint(int log_level, int facility, const char *module, const char *func, |
459 | | char *format, va_list ap) |
460 | 0 | { |
461 | 0 | char *time; |
462 | 0 | int pid; |
463 | 0 | char *prefix; |
464 | 0 | int len; |
465 | 0 | str buf = {log_json_buf, log_json_buf_size}; |
466 | |
|
467 | 0 | if (stderr_log_format != LOG_FORMAT_PLAIN) { |
468 | 0 | time = va_arg(ap, char *); |
469 | 0 | pid = va_arg(ap, int); |
470 | 0 | prefix = va_arg(ap, char *); |
471 | 0 | if (module && func) |
472 | 0 | va_arg(ap, char *); |
473 | |
|
474 | 0 | if ((len = log_print_json(&buf, stderr_log_format==LOG_FORMAT_JSON_CEE ? |
475 | 0 | LOG_JSON_SCHEMA_CEE : LOG_JSON_SCHEMA_BASIC, |
476 | 0 | time, pid, prefix, dp_log_level_str(log_level), module, func, |
477 | 0 | format, ap)) < 0) { |
478 | 0 | stderr_dprint_tmp_err("failed to print JSON log!\n"); |
479 | 0 | return; |
480 | 0 | } |
481 | | |
482 | 0 | fprintf(stderr, "%.*s\n", len, log_json_buf); |
483 | 0 | fflush(stderr); |
484 | 0 | } else { |
485 | 0 | vfprintf(stderr,format,ap); |
486 | 0 | fflush(stderr); |
487 | 0 | } |
488 | 0 | } |
489 | | |
490 | | static void syslog_dprint(int log_level, int facility, const char *module, const char *func, |
491 | | char *format, va_list ap) |
492 | 0 | { |
493 | 0 | int level; |
494 | 0 | char *time; |
495 | 0 | int pid; |
496 | 0 | char *prefix; |
497 | 0 | int len; |
498 | 0 | str buf = {log_json_buf, log_json_buf_size}; |
499 | |
|
500 | 0 | switch (log_level) { |
501 | 0 | case L_ALERT: |
502 | 0 | level = LOG_ALERT; |
503 | 0 | break; |
504 | 0 | case L_CRIT: |
505 | 0 | level = LOG_CRIT; |
506 | 0 | break; |
507 | 0 | case L_ERR: |
508 | 0 | level = LOG_ERR; |
509 | 0 | break; |
510 | 0 | case L_WARN: |
511 | 0 | level = LOG_WARNING; |
512 | 0 | break; |
513 | 0 | case L_NOTICE: |
514 | 0 | level = LOG_NOTICE; |
515 | 0 | break; |
516 | 0 | case L_INFO: |
517 | 0 | level = LOG_INFO; |
518 | 0 | break; |
519 | 0 | case L_DBG: |
520 | 0 | default: |
521 | 0 | level = LOG_DEBUG; |
522 | 0 | } |
523 | | |
524 | 0 | if (syslog_log_format != LOG_FORMAT_PLAIN) { |
525 | 0 | time = va_arg(ap, char *); |
526 | 0 | pid = va_arg(ap, int); |
527 | 0 | prefix = va_arg(ap, char *); |
528 | 0 | if (module && func) |
529 | 0 | va_arg(ap, char *); |
530 | |
|
531 | 0 | if ((len = log_print_json(&buf, syslog_log_format==LOG_FORMAT_JSON_CEE ? |
532 | 0 | LOG_JSON_SCHEMA_CEE_PREFIX : LOG_JSON_SCHEMA_BASIC, |
533 | 0 | time, pid, prefix, dp_log_level_str(log_level), module, func, |
534 | 0 | format, ap)) < 0) { |
535 | 0 | stderr_dprint_tmp_err("failed to print JSON log!\n"); |
536 | 0 | return; |
537 | 0 | } |
538 | | |
539 | 0 | syslog(level|facility, "%.*s\n", len, log_json_buf); |
540 | 0 | } else { |
541 | | /* skip the time and pid arguments from va_list */ |
542 | 0 | va_arg(ap, char *); |
543 | 0 | va_arg(ap, int); |
544 | |
|
545 | 0 | vsyslog(level|facility, format, ap); |
546 | 0 | } |
547 | 0 | } |
548 | | |
549 | | static str evi_time_str = str_init("time"); |
550 | | static str evi_pid_str = str_init("pid"); |
551 | | static str evi_level_str = str_init("level"); |
552 | | static str evi_module_str = str_init("module"); |
553 | | static str evi_func_str = str_init("function"); |
554 | | static str evi_prefix_str = str_init("prefix"); |
555 | | static str evi_msg_str = str_init("message"); |
556 | | |
557 | | static void event_dprint(int level, int facility, const char *module, const char *func, |
558 | | char *format, va_list ap) |
559 | 0 | { |
560 | 0 | evi_params_p list = NULL; |
561 | 0 | str s; |
562 | 0 | int n; |
563 | 0 | int suppressed; |
564 | |
|
565 | 0 | suppressed = pt[process_no].suppress_log_event; |
566 | |
|
567 | 0 | if (suppressed) |
568 | 0 | return; |
569 | | |
570 | 0 | pt[process_no].suppress_log_event = 1; |
571 | |
|
572 | 0 | if (!evi_probe_event(evi_log_id)) { |
573 | 0 | pt[process_no].suppress_log_event = suppressed; |
574 | 0 | return; |
575 | 0 | } |
576 | | |
577 | 0 | if (!(list = evi_get_params())) { |
578 | 0 | pt[process_no].suppress_log_event = suppressed; |
579 | 0 | return; |
580 | 0 | } |
581 | | |
582 | 0 | init_str(&s, dp_time()); |
583 | 0 | if (evi_param_add_str(list, &evi_time_str, &s)) { |
584 | 0 | LM_ERR("unable to add event parameter\n"); |
585 | 0 | goto end_free; |
586 | 0 | } |
587 | 0 | n = dp_my_pid(); |
588 | 0 | if (evi_param_add_int(list, &evi_pid_str, &n)) { |
589 | 0 | LM_ERR("unable to add event parameter\n"); |
590 | 0 | goto end_free; |
591 | 0 | } |
592 | 0 | init_str(&s, dp_log_level_str(level)); |
593 | 0 | if (evi_param_add_str(list, &evi_level_str, &s)) { |
594 | 0 | LM_ERR("unable to add event parameter\n"); |
595 | 0 | goto end_free; |
596 | 0 | } |
597 | | |
598 | 0 | if (module && func) { |
599 | 0 | init_str(&s, module); |
600 | 0 | if (evi_param_add_str(list, &evi_module_str, &s)) { |
601 | 0 | LM_ERR("unable to add event parameter\n"); |
602 | 0 | goto end_free; |
603 | 0 | } |
604 | 0 | init_str(&s, func); |
605 | 0 | if (evi_param_add_str(list, &evi_func_str, &s)) { |
606 | 0 | LM_ERR("unable to add event parameter\n"); |
607 | 0 | goto end_free; |
608 | 0 | } |
609 | 0 | } |
610 | | |
611 | 0 | init_str(&s, log_prefix); |
612 | 0 | if (s.len) { |
613 | 0 | if (evi_param_add_str(list, &evi_prefix_str, &s)) { |
614 | 0 | LM_ERR("unable to add event parameter\n"); |
615 | 0 | goto end_free; |
616 | 0 | } |
617 | 0 | } |
618 | | |
619 | 0 | s.len = vsnprintf(log_msg_buf, log_msg_buf_size, format, ap); |
620 | 0 | if (s.len < 0) { |
621 | 0 | LM_ERR("vsnprintf() failed!\n"); |
622 | 0 | goto end_free; |
623 | 0 | } |
624 | 0 | if (s.len>=log_msg_buf_size) { |
625 | 0 | LM_WARN("log message truncated\n"); |
626 | 0 | s.len = log_msg_buf_size; |
627 | 0 | } |
628 | | |
629 | | /* try to strip \n from the end of the "message" param */ |
630 | 0 | if (log_msg_buf[s.len-1] == '\n') { |
631 | 0 | log_msg_buf[s.len-1] = '\0'; |
632 | 0 | s.len--; |
633 | 0 | } |
634 | |
|
635 | 0 | s.s = log_msg_buf; |
636 | 0 | if (evi_param_add_str(list, &evi_msg_str, &s)) { |
637 | 0 | LM_ERR("unable to add event parameter\n"); |
638 | 0 | goto end_free; |
639 | 0 | } |
640 | | |
641 | 0 | if (evi_raise_event(evi_log_id, list)) { |
642 | 0 | LM_ERR("unable to raise '%.*s' event\n", |
643 | 0 | evi_log_name.len, evi_log_name.s); |
644 | 0 | } |
645 | |
|
646 | 0 | pt[process_no].suppress_log_event = suppressed; |
647 | |
|
648 | 0 | return; |
649 | 0 | end_free: |
650 | 0 | evi_free_params(list); |
651 | 0 | pt[process_no].suppress_log_event = suppressed; |
652 | 0 | } |
653 | | |
654 | | /* generic consumer that registers to the log interface */ |
655 | | static void gen_consumer_pre_fmt_func(log_print_f gen_print_func, int log_level, |
656 | | int facility, const char *module, const char *func, |
657 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap) |
658 | 0 | { |
659 | | /* skip the time, pid, prefix and function arguments from va_list */ |
660 | 0 | va_arg(ap, char *); |
661 | 0 | va_arg(ap, int); |
662 | 0 | va_arg(ap, char *); |
663 | 0 | if (module && func) |
664 | 0 | va_arg(ap, char *); |
665 | |
|
666 | 0 | gen_print_func(log_level, facility, module, func, format, ap); |
667 | 0 | } |
668 | | |
669 | | static void stderr_pre_fmt_func(log_print_f gen_print_func, int log_level, |
670 | | int facility, const char *module, const char *func, |
671 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap) |
672 | 0 | { |
673 | 0 | char *fmt = stderr_log_format == LOG_FORMAT_PLAIN ? stderr_plain_fmt : format; |
674 | |
|
675 | 0 | gen_print_func(log_level, facility, module, func, fmt, ap); |
676 | 0 | } |
677 | | |
678 | | static void syslog_pre_fmt_func(log_print_f gen_print_func, int log_level, |
679 | | int facility, const char *module, const char *func, |
680 | | char *stderr_plain_fmt, char *syslog_plain_fmt, char *format, va_list ap) |
681 | 0 | { |
682 | 0 | char *fmt = syslog_log_format == LOG_FORMAT_PLAIN ? syslog_plain_fmt : format; |
683 | |
|
684 | 0 | gen_print_func(log_level, facility, module, func, fmt, ap); |
685 | 0 | } |
686 | | |
687 | | void dprint(int log_level, int facility, const char *module, const char *func, |
688 | | char *stderr_fmt, char *syslog_fmt, char *format, ...) |
689 | 0 | { |
690 | 0 | va_list ap, ap_copy; |
691 | 0 | int i; |
692 | |
|
693 | 0 | va_start(ap, format); |
694 | |
|
695 | 0 | for (i=0; i<log_consumers_no; i++) |
696 | 0 | if (!log_consumers[i].muted && (!log_consumers[i].level_filter || |
697 | 0 | log_consumers[i].level_filter >= log_level)) { |
698 | 0 | va_copy(ap_copy, ap); |
699 | 0 | log_consumers[i].pre_fmt_print_func(log_consumers[i].gen_print_func, |
700 | 0 | log_level, facility, module, func, stderr_fmt, syslog_fmt, |
701 | 0 | format, ap_copy); |
702 | 0 | va_end(ap_copy); |
703 | 0 | } |
704 | |
|
705 | 0 | va_end(ap); |
706 | 0 | } |
707 | | |
708 | | int register_log_consumer(char *name, log_print_f print_func, |
709 | | int level_filter, int muted) |
710 | 0 | { |
711 | 0 | if (log_consumers_no == MAX_LOG_CONS_NO) { |
712 | 0 | LM_ERR("Maximum number of logging consumers already registered\n"); |
713 | 0 | return -1; |
714 | 0 | } |
715 | | |
716 | 0 | init_str(&log_consumers[log_consumers_no].name, name); |
717 | 0 | log_consumers[log_consumers_no].gen_print_func = print_func; |
718 | 0 | log_consumers[log_consumers_no].pre_fmt_print_func = gen_consumer_pre_fmt_func; |
719 | 0 | log_consumers[log_consumers_no].level_filter = level_filter; |
720 | 0 | log_consumers[log_consumers_no].muted = muted; |
721 | |
|
722 | 0 | log_consumers_no++; |
723 | |
|
724 | 0 | return 0; |
725 | 0 | } |
726 | | |
727 | | int init_log_json_buf(int realloc_buf) |
728 | 0 | { |
729 | 0 | if (realloc_buf && log_json_buf) { |
730 | 0 | log_json_buf = pkg_realloc(log_json_buf, log_json_buf_size+1); |
731 | 0 | if (!log_json_buf) { |
732 | 0 | LM_ERR("no pkg memory left\n"); |
733 | 0 | return -1; |
734 | 0 | } |
735 | 0 | } else if (!log_json_buf) { |
736 | 0 | log_json_buf = pkg_malloc(log_json_buf_size+1); |
737 | 0 | if (!log_json_buf) { |
738 | 0 | LM_ERR("no pkg memory left\n"); |
739 | 0 | return -1; |
740 | 0 | } |
741 | 0 | } |
742 | | |
743 | 0 | return 0; |
744 | 0 | } |
745 | | |
746 | | int init_log_msg_buf(int realloc_buf) |
747 | 0 | { |
748 | 0 | if (realloc_buf && log_msg_buf) { |
749 | 0 | log_msg_buf = pkg_realloc(log_msg_buf, log_msg_buf_size+1); |
750 | 0 | if (!log_msg_buf) { |
751 | 0 | LM_ERR("no pkg memory left\n"); |
752 | 0 | return -1; |
753 | 0 | } |
754 | 0 | } else if (!log_msg_buf) { |
755 | 0 | log_msg_buf = pkg_malloc(log_msg_buf_size+1); |
756 | 0 | if (!log_msg_buf) { |
757 | 0 | LM_ERR("no pkg memory left\n"); |
758 | 0 | return -1; |
759 | 0 | } |
760 | 0 | } |
761 | | |
762 | 0 | return 0; |
763 | 0 | } |
764 | | |
765 | | /* replaces the default consumer table with a shm allocated one */ |
766 | | int init_log_cons_shm_table(void) |
767 | 0 | { |
768 | 0 | struct log_consumer_t *cons; |
769 | |
|
770 | 0 | cons = shm_malloc(MAX_LOG_CONS_NO * sizeof(struct log_consumer_t)); |
771 | 0 | if (!cons) { |
772 | 0 | LM_ERR("no more shm memory\n"); |
773 | 0 | return -1; |
774 | 0 | } |
775 | 0 | memset(cons, 0, MAX_LOG_CONS_NO * sizeof(struct log_consumer_t)); |
776 | |
|
777 | 0 | cons[0] = log_consumers[0]; |
778 | 0 | cons[1] = log_consumers[1]; |
779 | |
|
780 | 0 | log_consumers = cons; |
781 | |
|
782 | 0 | return 0; |
783 | 0 | } |
784 | | |
785 | | void cleanup_log_cons_shm_table(void) |
786 | 0 | { |
787 | 0 | struct log_consumer_t *cons = log_consumers; |
788 | |
|
789 | 0 | log_consumers = default_log_consumers; |
790 | 0 | log_consumers_no = 2; |
791 | | |
792 | | /* even if we are reusing the static default_log_consumers table, |
793 | | * inherit the latest settings for the consumers */ |
794 | 0 | log_consumers[0].level_filter = cons[0].level_filter; |
795 | 0 | log_consumers[0].muted = cons[0].muted; |
796 | |
|
797 | 0 | log_consumers[1].level_filter = cons[1].level_filter; |
798 | 0 | log_consumers[1].muted = cons[1].muted; |
799 | |
|
800 | 0 | shm_free(cons); |
801 | 0 | } |
802 | | |
803 | | int init_log_event_cons(void) |
804 | 0 | { |
805 | 0 | evi_log_id = evi_publish_event(evi_log_name); |
806 | 0 | if (evi_log_id == EVI_ERROR) { |
807 | 0 | LM_ERR("cannot register '%.*s' event\n", |
808 | 0 | evi_log_name.len, evi_log_name.s); |
809 | 0 | return -1; |
810 | 0 | } |
811 | | |
812 | 0 | log_msg_buf = pkg_malloc(log_msg_buf_size+1); |
813 | 0 | if (!log_msg_buf) { |
814 | 0 | LM_ERR("no pkg memory left\n"); |
815 | 0 | return -1; |
816 | 0 | } |
817 | | |
818 | 0 | if (register_log_consumer(EVENT_CONSUMER_NAME, event_dprint, |
819 | 0 | log_event_level_filter, 1) < 0) { |
820 | 0 | LM_ERR("Failed to register 'event' log consumer\n"); |
821 | 0 | return -1; |
822 | 0 | } |
823 | | |
824 | 0 | return 0; |
825 | 0 | } |
826 | | |
827 | | static struct log_consumer_t *get_log_consumer_by_name(str *name) |
828 | 0 | { |
829 | 0 | int i; |
830 | |
|
831 | 0 | for (i=0; i<log_consumers_no; i++) |
832 | 0 | if (str_match(&log_consumers[i].name, name)) |
833 | 0 | return log_consumers+i; |
834 | | |
835 | 0 | return NULL; |
836 | 0 | } |
837 | | |
838 | | int set_log_consumer_level_filter(str *name, int level) |
839 | 0 | { |
840 | 0 | struct log_consumer_t *cons; |
841 | |
|
842 | 0 | cons = get_log_consumer_by_name(name); |
843 | 0 | if (!cons) { |
844 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
845 | 0 | return -1; |
846 | 0 | } |
847 | | |
848 | 0 | cons->level_filter = level; |
849 | |
|
850 | 0 | return 0; |
851 | 0 | } |
852 | | |
853 | | int get_log_consumer_level_filter(str *name, int *level_filter) |
854 | 0 | { |
855 | 0 | struct log_consumer_t *cons; |
856 | |
|
857 | 0 | cons = get_log_consumer_by_name(name); |
858 | 0 | if (!cons) { |
859 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
860 | 0 | return -1; |
861 | 0 | } |
862 | | |
863 | 0 | *level_filter = cons->level_filter; |
864 | |
|
865 | 0 | return 0; |
866 | 0 | } |
867 | | |
868 | | int set_log_consumer_mute_state(str *name, int state) |
869 | 0 | { |
870 | 0 | struct log_consumer_t *cons; |
871 | |
|
872 | 0 | cons = get_log_consumer_by_name(name); |
873 | 0 | if (!cons) { |
874 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
875 | 0 | return -1; |
876 | 0 | } |
877 | | |
878 | 0 | cons->muted = state; |
879 | |
|
880 | 0 | return 0; |
881 | 0 | } |
882 | | |
883 | | int get_log_consumer_mute_state(str *name, int *state) |
884 | 0 | { |
885 | 0 | struct log_consumer_t *cons; |
886 | |
|
887 | 0 | cons = get_log_consumer_by_name(name); |
888 | 0 | if (!cons) { |
889 | 0 | LM_ERR("Unknown consumer: %.*s\n", name->len, name->s); |
890 | 0 | return -1; |
891 | 0 | } |
892 | | |
893 | 0 | *state = cons->muted; |
894 | |
|
895 | 0 | return 0; |
896 | 0 | } |
897 | | |
898 | | int set_log_event_cons_cfg_state(void) |
899 | 0 | { |
900 | 0 | if (set_log_consumer_mute_state(&str_init(EVENT_CONSUMER_NAME), |
901 | 0 | !log_event_enabled) < 0) { |
902 | 0 | LM_ERR("Failed to set mute state for event consumer\n"); |
903 | 0 | return -1; |
904 | 0 | } |
905 | | |
906 | 0 | return 0; |
907 | 0 | } |
908 | | |
909 | | void distroy_log_event_cons(void) |
910 | 0 | { |
911 | 0 | set_log_consumer_mute_state(&str_init(EVENT_CONSUMER_NAME), 1); |
912 | 0 | } |
913 | | |
914 | | int init_log_level(void) |
915 | 0 | { |
916 | 0 | log_level = &pt[process_no].log_level; |
917 | 0 | default_log_level = &pt[process_no].default_log_level; |
918 | |
|
919 | 0 | if (process_no==0) { |
920 | | /* this is done only by the first process */ |
921 | 0 | log_level_global = (int*)shm_malloc(sizeof(int)); |
922 | 0 | if (log_level_global==NULL) { |
923 | 0 | LM_ERR("Failed to allocate shm memory for global log_level\n"); |
924 | 0 | return -1; |
925 | 0 | } |
926 | 0 | *log_level_global = log_level_holder; |
927 | 0 | } |
928 | | |
929 | 0 | *log_level = *log_level_global; |
930 | 0 | *default_log_level = *log_level_global; |
931 | |
|
932 | 0 | return 0; |
933 | 0 | } |
934 | | |
935 | | /* call before pt is freed */ |
936 | | void cleanup_log_level(void) |
937 | 0 | { |
938 | 0 | static int my_log_level; |
939 | |
|
940 | 0 | my_log_level = *log_level; |
941 | 0 | log_level = &my_log_level; |
942 | 0 | } |
943 | | |
944 | | |
945 | | void reset_proc_log_level(void) |
946 | 0 | { |
947 | 0 | *log_level = *default_log_level; |
948 | 0 | } |
949 | | |
950 | | /* |
951 | | * set the (default) log level of a given process |
952 | | * |
953 | | * Note: the index param is not validated! |
954 | | */ |
955 | | void __set_proc_log_level(int proc_idx, int level) |
956 | 0 | { |
957 | 0 | pt[proc_idx].log_level = level; |
958 | 0 | } |
959 | | |
960 | | void __set_proc_default_log_level(int proc_idx, int level) |
961 | 0 | { |
962 | 0 | pt[proc_idx].default_log_level = level; |
963 | 0 | } |
964 | | |
965 | | /* set the current and default log levels for all OpenSIPS processes */ |
966 | | void set_global_log_level(int level) |
967 | 0 | { |
968 | 0 | int i; |
969 | |
|
970 | 0 | for (i = 0; i < counted_max_processes; i++) { |
971 | 0 | __set_proc_default_log_level(i, level); |
972 | 0 | __set_proc_log_level(i, level); |
973 | 0 | } |
974 | 0 | *log_level_global = level; |
975 | 0 | } |
976 | | |
977 | | /* set the log level of the current process */ |
978 | | void set_proc_log_level(int level) |
979 | 0 | { |
980 | 0 | __set_proc_log_level(process_no, level); |
981 | 0 | } |
982 | | |
983 | | void suppress_proc_log_event(void) |
984 | 0 | { |
985 | 0 | pt[process_no].suppress_log_event = 1; |
986 | 0 | } |
987 | | |
988 | | void reset_proc_log_event(void) |
989 | 0 | { |
990 | 0 | pt[process_no].suppress_log_event = 0; |
991 | 0 | } |