1 /*
2 * Copyright (C) Tildeslash Ltd. All rights reserved.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU Affero General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
14 *
15 * In addition, as a special exception, the copyright holders give
16 * permission to link the code of portions of this program with the
17 * OpenSSL library under certain conditions as described in each
18 * individual source file, and distribute linked combinations
19 * including the two.
20 *
21 * You must obey the GNU Affero General Public License in all respects
22 * for all of the code used other than OpenSSL.
23 */
24
25 #include "config.h"
26
27 #ifdef HAVE_STDIO_H
28 #include <stdio.h>
29 #endif
30
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34
35 #ifdef HAVE_ERRNO_H
36 #include <errno.h>
37 #endif
38
39 #ifdef HAVE_STDARG_H
40 #include <stdarg.h>
41 #endif
42
43 #ifdef HAVE_SYSLOG_H
44 #include <syslog.h>
45 #endif
46
47 #ifdef HAVE_STRING_H
48 #include <string.h>
49 #endif
50
51 #ifdef HAVE_STRINGS_H
52 #include <strings.h>
53 #endif
54
55 #ifdef HAVE_UNISTD_H
56 #include <unistd.h>
57 #endif
58
59 #ifdef HAVE_EXECINFO_H
60 #include <execinfo.h>
61 #endif
62
63 #ifdef HAVE_SYS_TYPES_H
64 #include <sys/types.h>
65 #endif
66
67 #ifdef HAVE_SYS_STAT_H
68 #include <sys/stat.h>
69 #endif
70
71 #include "monit.h"
72
73 // libmonit
74 #include "system/Time.h"
75
76
77 /**
78 * Implementation of a logger that appends log messages to a file
79 * with a preceding timestamp. Methods support both syslog or own
80 * logfile.
81 *
82 * @file
83 */
84
85
86 /* ------------------------------------------------------------- Definitions */
87
88
89 static FILE *_LOG = NULL;
90 static Mutex_T _mutex = PTHREAD_MUTEX_INITIALIZER;
91
92
93 static struct mylogpriority {
94 int priority;
95 const char *description;
96 } logPriority[] = {
97 {LOG_EMERG, "emergency"},
98 {LOG_ALERT, "alert"},
99 {LOG_CRIT, "critical"},
100 {LOG_ERR, "error"},
101 {LOG_WARNING, "warning"},
102 {LOG_NOTICE, "notice"},
103 {LOG_INFO, "info"},
104 {LOG_DEBUG, "debug"},
105 {-1, NULL}
106 };
107
108
109 /* ----------------------------------------------------------------- Private */
110
111
112 /**
113 * Open a log file or syslog
114 */
_open(void)115 static bool _open(void) {
116 if (Run.flags & Run_UseSyslog) {
117 openlog(prog, LOG_PID, Run.facility);
118 } else {
119 _LOG = fopen(Run.files.log, "a");
120 if (! _LOG) {
121 Log_error("Error opening the log file '%s' for writing -- %s\n", Run.files.log, STRERROR);
122 return false;
123 }
124 /* Set logger in unbuffered mode */
125 setvbuf(_LOG, NULL, _IONBF, 0);
126 }
127 return true;
128 }
129
130
131 /**
132 * Get a textual description of the actual log priority.
133 * @param p The log priority
134 * @return A string describing the log priority in clear text. If the
135 * priority is not found NULL is returned.
136 */
_priorityDescription(int p)137 static const char *_priorityDescription(int p) {
138 struct mylogpriority *lp = logPriority;
139 while ((*lp).description) {
140 if (p == (*lp).priority) {
141 return (*lp).description;
142 }
143 lp++;
144 }
145 return "unknown";
146 }
147
148
149 /**
150 * Log a message to monits logfile or syslog.
151 * @param priority A message priority
152 * @param s A formatted (printf-style) string to log
153 */
154 __attribute__((format (printf, 2, 0)))
_log(int priority,const char * s,va_list ap)155 static void _log(int priority, const char *s, va_list ap) {
156 ASSERT(s);
157 va_list ap_copy;
158 LOCK(_mutex)
159 {
160
161 FILE *output = priority < LOG_INFO ? stderr : stdout;
162 va_copy(ap_copy, ap);
163 vfprintf(output, s, ap_copy);
164 va_end(ap_copy);
165 fflush(output);
166 if (Run.flags & Run_Log) {
167 if (Run.flags & Run_UseSyslog) {
168 va_copy(ap_copy, ap);
169 vsyslog(priority, s, ap_copy);
170 va_end(ap_copy);
171 } else if (_LOG) {
172 fprintf(_LOG, "[%s] %-8s : ", Time_fmt((char[STRLEN]){}, STRLEN, TIMEFORMAT, Time_now()), _priorityDescription(priority));
173 va_copy(ap_copy, ap);
174 vfprintf(_LOG, s, ap_copy);
175 va_end(ap_copy);
176 }
177 }
178 }
179 END_LOCK;
180 }
181
182
_backtrace(void)183 static void _backtrace(void) {
184 #ifdef HAVE_BACKTRACE
185 int i, frames;
186 void *callstack[128];
187 char **strs;
188
189 if (Run.debug >= 2) {
190 frames = backtrace(callstack, 128);
191 strs = backtrace_symbols(callstack, frames);
192 Log_debug("-------------------------------------------------------------------------------\n");
193 for (i = 0; i < frames; ++i)
194 Log_debug(" %s\n", strs[i]);
195 Log_debug("-------------------------------------------------------------------------------\n");
196 FREE(strs);
197 }
198 #endif
199 }
200
201
202 /* ------------------------------------------------------------------------- */
203
204
205 #ifndef HAVE_VSYSLOG
206 #ifdef HAVE_SYSLOG
vsyslog(int facility_priority,const char * format,va_list arglist)207 void vsyslog(int facility_priority, const char *format, va_list arglist) {
208 char msg[STRLEN+1];
209 vsnprintf(msg, STRLEN, format, arglist);
210 syslog(facility_priority, "%s", msg);
211 }
212 #endif /* HAVE_SYSLOG */
213 #endif /* HAVE_VSYSLOG */
214
215
216 /* ------------------------------------------------------------------ Public */
217
218
219 /**
220 * Initialize the log system and 'log' function
221 * @return true if the log system was successfully initialized
222 */
Log_init()223 bool Log_init() {
224 if (! (Run.flags & Run_Log))
225 return true;
226 if (! _open())
227 return false;
228 /* Register Log_close to be called at program termination */
229 atexit(Log_close);
230 return true;
231 }
232
233
234 /**
235 * Logging interface with priority support
236 * @param s A formatted (printf-style) string to log
237 */
Log_emergency(const char * s,...)238 void Log_emergency(const char *s, ...) {
239 ASSERT(s);
240 va_list ap;
241 va_start(ap, s);
242 _log(LOG_EMERG, s, ap);
243 va_end(ap);
244 _backtrace();
245 }
246
247
248 /**
249 * Logging interface with priority support
250 * @param s A formatted (printf-style) string to log
251 * @param ap A variable argument list
252 */
Log_vemergency(const char * s,va_list ap)253 void Log_vemergency(const char *s, va_list ap) {
254 ASSERT(s);
255 va_list ap_copy;
256 va_copy(ap_copy, ap);
257 _log(LOG_EMERG, s, ap);
258 va_end(ap_copy);
259 _backtrace();
260 }
261
262
263 /**
264 * Logging interface with priority support
265 * @param s A formatted (printf-style) string to log
266 */
Log_alert(const char * s,...)267 void Log_alert(const char *s, ...) {
268 ASSERT(s);
269 va_list ap;
270 va_start(ap, s);
271 _log(LOG_ALERT, s, ap);
272 va_end(ap);
273 _backtrace();
274 }
275
276
277 /**
278 * Logging interface with priority support
279 * @param s A formatted (printf-style) string to log
280 * @param ap A variable argument list
281 */
Log_valert(const char * s,va_list ap)282 void Log_valert(const char *s, va_list ap) {
283 ASSERT(s);
284 va_list ap_copy;
285 va_copy(ap_copy, ap);
286 _log(LOG_ALERT, s, ap);
287 va_end(ap_copy);
288 _backtrace();
289 }
290
291
292 /**
293 * Logging interface with priority support
294 * @param s A formatted (printf-style) string to log
295 */
Log_critical(const char * s,...)296 void Log_critical(const char *s, ...) {
297 ASSERT(s);
298 va_list ap;
299 va_start(ap, s);
300 _log(LOG_CRIT, s, ap);
301 va_end(ap);
302 _backtrace();
303 }
304
305
306 /**
307 * Logging interface with priority support
308 * @param s A formatted (printf-style) string to log
309 * @param ap A variable argument list
310 */
Log_vcritical(const char * s,va_list ap)311 void Log_vcritical(const char *s, va_list ap) {
312 ASSERT(s);
313 va_list ap_copy;
314 va_copy(ap_copy, ap);
315 _log(LOG_CRIT, s, ap);
316 va_end(ap_copy);
317 _backtrace();
318 }
319
320
321 /*
322 * Called by libmonit on Exception. Log
323 * error and abort the application
324 */
Log_abort_handler(const char * s,va_list ap)325 void Log_abort_handler(const char *s, va_list ap) {
326 ASSERT(s);
327 va_list ap_copy;
328 va_copy(ap_copy, ap);
329 _log(LOG_CRIT, s, ap);
330 va_end(ap_copy);
331 if (Run.debug)
332 abort();
333 exit(1);
334 }
335
336
337 /**
338 * Logging interface with priority support
339 * @param s A formatted (printf-style) string to log
340 */
Log_error(const char * s,...)341 void Log_error(const char *s, ...) {
342 ASSERT(s);
343 va_list ap;
344 va_start(ap, s);
345 _log(LOG_ERR, s, ap);
346 va_end(ap);
347 _backtrace();
348 }
349
350
351 /**
352 * Logging interface with priority support
353 * @param s A formatted (printf-style) string to log
354 * @param ap A variable argument list
355 */
Log_verror(const char * s,va_list ap)356 void Log_verror(const char *s, va_list ap) {
357 ASSERT(s);
358 va_list ap_copy;
359 va_copy(ap_copy, ap);
360 _log(LOG_ERR, s, ap);
361 va_end(ap_copy);
362 _backtrace();
363 }
364
365
366 /**
367 * Logging interface with priority support
368 * @param s A formatted (printf-style) string to log
369 */
Log_warning(const char * s,...)370 void Log_warning(const char *s, ...) {
371 ASSERT(s);
372 va_list ap;
373 va_start(ap, s);
374 _log(LOG_WARNING, s, ap);
375 va_end(ap);
376 }
377
378
379 /**
380 * Logging interface with priority support
381 * @param s A formatted (printf-style) string to log
382 * @param ap A variable argument list
383 */
Log_vwarning(const char * s,va_list ap)384 void Log_vwarning(const char *s, va_list ap) {
385 ASSERT(s);
386 va_list ap_copy;
387 va_copy(ap_copy, ap);
388 _log(LOG_WARNING, s, ap);
389 va_end(ap_copy);
390 }
391
392
393 /**
394 * Logging interface with priority support
395 * @param s A formatted (printf-style) string to log
396 */
Log_notice(const char * s,...)397 void Log_notice(const char *s, ...) {
398 ASSERT(s);
399 va_list ap;
400 va_start(ap, s);
401 _log(LOG_NOTICE, s, ap);
402 va_end(ap);
403 }
404
405
406 /**
407 * Logging interface with priority support
408 * @param s A formatted (printf-style) string to log
409 * @param ap A variable argument list
410 */
Log_vnotice(const char * s,va_list ap)411 void Log_vnotice(const char *s, va_list ap) {
412 ASSERT(s);
413 va_list ap_copy;
414 va_copy(ap_copy, ap);
415 _log(LOG_NOTICE, s, ap);
416 va_end(ap_copy);
417 }
418
419
420 /**
421 * Logging interface with priority support
422 * @param s A formatted (printf-style) string to log
423 */
Log_info(const char * s,...)424 void Log_info(const char *s, ...) {
425 ASSERT(s);
426 va_list ap;
427 va_start(ap, s);
428 _log(LOG_INFO, s, ap);
429 va_end(ap);
430 }
431
432
433 /**
434 * Logging interface with priority support
435 * @param s A formatted (printf-style) string to log
436 * @param ap A variable argument list
437 */
Log_vinfo(const char * s,va_list ap)438 void Log_vinfo(const char *s, va_list ap) {
439 ASSERT(s);
440 va_list ap_copy;
441 va_copy(ap_copy, ap);
442 _log(LOG_INFO, s, ap);
443 va_end(ap_copy);
444 }
445
446
447 /**
448 * Logging interface with priority support
449 * @param s A formatted (printf-style) string to log
450 */
Log_debug(const char * s,...)451 void Log_debug(const char *s, ...) {
452 ASSERT(s);
453 if (Run.debug) {
454 va_list ap;
455 va_start(ap, s);
456 _log(LOG_DEBUG, s, ap);
457 va_end(ap);
458 }
459 }
460
461
462 /**
463 * Logging interface with priority support
464 * @param s A formatted (printf-style) string to log
465 * @param ap A variable argument list
466 */
Log_vdebug(const char * s,va_list ap)467 void Log_vdebug(const char *s, va_list ap) {
468 ASSERT(s);
469 if (Run.debug) {
470 va_list ap_copy;
471 va_copy(ap_copy, ap);
472 _log(LOG_NOTICE, s, ap);
473 va_end(ap_copy);
474 }
475 }
476
477
478 /**
479 * Close the log file or syslog
480 */
Log_close()481 void Log_close() {
482 if (Run.flags & Run_UseSyslog) {
483 closelog();
484 }
485 if (_LOG && (0 != fclose(_LOG))) {
486 Log_error("Error closing the log file -- %s\n", STRERROR);
487 }
488 _LOG = NULL;
489 }
490