]> arthur.barton.de Git - netdata.git/blob - src/log.c
health configuration now parses templates too
[netdata.git] / src / log.c
1 #include "common.h"
2
3 const char *program_name = "";
4 unsigned long long debug_flags = DEBUG;
5
6 int access_log_syslog = 1;
7 int error_log_syslog = 1;
8 int output_log_syslog = 1;  // debug log
9
10 int stdaccess_fd = -1;
11 FILE *stdaccess = NULL;
12
13 const char *stdaccess_filename = NULL;
14 const char *stderr_filename = NULL;
15 const char *stdout_filename = NULL;
16
17 void syslog_init(void) {
18     static int i = 0;
19
20     if(!i) {
21         openlog(program_name, LOG_PID, LOG_DAEMON);
22         i = 1;
23     }
24 }
25
26 int open_log_file(int fd, FILE **fp, const char *filename, int *enabled_syslog) {
27     int f, t;
28
29     if(!filename || !*filename || !strcmp(filename, "none"))
30         filename = "/dev/null";
31
32     if(!strcmp(filename, "syslog")) {
33         filename = "/dev/null";
34         syslog_init();
35         if(enabled_syslog) *enabled_syslog = 1;
36     }
37     else if(enabled_syslog) *enabled_syslog = 0;
38
39     // don't do anything if the user is willing
40     // to have the standard one
41     if(!strcmp(filename, "system")) {
42         if(fd != -1) return fd;
43         filename = "stdout";
44     }
45
46     if(!strcmp(filename, "stdout"))
47         f = STDOUT_FILENO;
48
49     else if(!strcmp(filename, "stderr"))
50         f = STDERR_FILENO;
51
52     else {
53         f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
54         if(f == -1) {
55             error("Cannot open file '%s'. Leaving %d to its default.", filename, fd);
56             return fd;
57         }
58     }
59
60     // if there is a level-2 file pointer
61     // flush it before switching the level-1 fds
62     if(fp && *fp)
63         fflush(*fp);
64
65     if(fd != f && fd != -1) {
66         // it automatically closes
67         t = dup2(f, fd);
68         if (t == -1) {
69             error("Cannot dup2() new fd %d to old fd %d for '%s'", f, fd, filename);
70             close(f);
71             return fd;
72         }
73         // info("dup2() new fd %d to old fd %d for '%s'", f, fd, filename);
74         close(f);
75     }
76     else fd = f;
77
78     if(fp && *fp == NULL) {
79         // info("fdopen(%d) on filename '%s'", fd, filename);
80
81         FILE *n = fdopen(fd, "a");
82         if (!n)
83             error("Cannot fdopen() fd %d ('%s')", fd, filename);
84
85         else {
86             if (setvbuf(n, NULL, _IOLBF, 0) != 0)
87                 error("Cannot set line buffering on fd %d ('%s')", fd, filename);
88
89             if(!*fp)
90                 *fp = n;
91             else {
92                 FILE *o = *fp;
93                 *fp = n;
94                 fclose(o);
95             }
96         }
97     }
98
99     return fd;
100 }
101
102 void reopen_all_log_files() {
103     if(stdout_filename)
104         open_log_file(STDOUT_FILENO, &stdout, stdout_filename, &output_log_syslog);
105
106     if(stderr_filename)
107         open_log_file(STDERR_FILENO, &stderr, stderr_filename, &error_log_syslog);
108
109     if(stdaccess_filename)
110         stdaccess_fd = open_log_file(stdaccess_fd, &stdaccess, stdaccess_filename, &access_log_syslog);
111 }
112
113 void open_all_log_files() {
114     // disable stdin
115     open_log_file(STDIN_FILENO, &stdin, "/dev/null", NULL);
116
117     open_log_file(STDOUT_FILENO, &stdout, stdout_filename, &output_log_syslog);
118     open_log_file(STDERR_FILENO, &stderr, stderr_filename, &error_log_syslog);
119     stdaccess_fd = open_log_file(stdaccess_fd, &stdaccess, stdaccess_filename, &access_log_syslog);
120 }
121
122 // ----------------------------------------------------------------------------
123 // error log throttling
124
125 time_t error_log_throttle_period = 1200;
126 unsigned long error_log_errors_per_period = 200;
127
128 int error_log_limit(int reset) {
129     static time_t start = 0;
130     static unsigned long counter = 0, prevented = 0;
131
132     // do not throttle if the period is 0
133     if(error_log_throttle_period == 0)
134         return 0;
135
136     // prevent all logs if the errors per period is 0
137     if(error_log_errors_per_period == 0)
138         return 1;
139
140     time_t now = time(NULL);
141     if(!start) start = now;
142
143     if(reset) {
144         if(prevented) {
145             log_date(stderr);
146             fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
147                     , program_name
148                     , program_name
149                     , prevented
150                     , now - start
151             );
152         }
153
154         start = now;
155         counter = 0;
156         prevented = 0;
157     }
158
159     // detect if we log too much
160     counter++;
161
162     if(now - start > error_log_throttle_period) {
163         if(prevented) {
164             log_date(stderr);
165             fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
166                     , program_name
167                     , program_name
168                     , prevented
169                     , error_log_throttle_period
170             );
171         }
172
173         // restart the period accounting
174         start = now;
175         counter = 1;
176         prevented = 0;
177
178         // log this error
179         return 0;
180     }
181
182     if(counter > error_log_errors_per_period) {
183         if(!prevented) {
184             log_date(stderr);
185             fprintf(stderr, "%s: Too many logs (%lu logs in %ld seconds, threshold is set to %lu logs in %ld seconds). Preventing more logs from process '%s' for %ld seconds.\n"
186                     , program_name
187                     , counter
188                     , now - start
189                     , error_log_errors_per_period
190                     , error_log_throttle_period
191                     , program_name
192                     , start + error_log_throttle_period - now);
193         }
194
195         prevented++;
196
197         // prevent logging this error
198         return 1;
199     }
200
201     return 0;
202 }
203
204 // ----------------------------------------------------------------------------
205 // print the date
206
207 // FIXME
208 // this should print the date in a buffer the way it
209 // is now, logs from multiple threads may be multiplexed
210
211 void log_date(FILE *out)
212 {
213         char outstr[24];
214         time_t t;
215         struct tm *tmp, tmbuf;
216
217         t = time(NULL);
218         tmp = localtime_r(&t, &tmbuf);
219
220         if (tmp == NULL) return;
221         if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
222
223         fprintf(out, "%s: ", outstr);
224 }
225
226 // ----------------------------------------------------------------------------
227 // debug log
228
229 void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
230 {
231     va_list args;
232
233     log_date(stdout);
234     va_start( args, fmt );
235     printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
236     vprintf(fmt, args);
237     va_end( args );
238     putchar('\n');
239
240     if(output_log_syslog) {
241         va_start( args, fmt );
242         vsyslog(LOG_ERR,  fmt, args );
243         va_end( args );
244     }
245
246     fflush(stdout);
247 }
248
249 // ----------------------------------------------------------------------------
250 // info log
251
252 void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
253 {
254     va_list args;
255
256     // prevent logging too much
257     if(error_log_limit(0)) return;
258
259     log_date(stderr);
260
261     va_start( args, fmt );
262     if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
263     else            fprintf(stderr, "INFO: %s: ", program_name);
264     vfprintf( stderr, fmt, args );
265     va_end( args );
266
267     fputc('\n', stderr);
268
269     if(error_log_syslog) {
270         va_start( args, fmt );
271         vsyslog(LOG_INFO,  fmt, args );
272         va_end( args );
273     }
274 }
275
276 // ----------------------------------------------------------------------------
277 // error log
278
279 void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... )
280 {
281     va_list args;
282
283     // prevent logging too much
284     if(error_log_limit(0)) return;
285
286     log_date(stderr);
287
288     va_start( args, fmt );
289     if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
290     else            fprintf(stderr, "%s: %s: ", prefix, program_name);
291     vfprintf( stderr, fmt, args );
292     va_end( args );
293
294     if(errno) {
295         char buf[1024];
296         fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
297         errno = 0;
298     }
299     else
300         fputc('\n', stderr);
301
302     if(error_log_syslog) {
303         va_start( args, fmt );
304         vsyslog(LOG_ERR,  fmt, args );
305         va_end( args );
306     }
307 }
308
309 void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
310 {
311     va_list args;
312
313     log_date(stderr);
314
315     va_start( args, fmt );
316     if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
317     else            fprintf(stderr, "FATAL: %s: ", program_name);
318     vfprintf( stderr, fmt, args );
319     va_end( args );
320
321     perror(" # ");
322     fputc('\n', stderr);
323
324     if(error_log_syslog) {
325         va_start( args, fmt );
326         vsyslog(LOG_CRIT,  fmt, args );
327         va_end( args );
328     }
329
330     netdata_cleanup_and_exit(1);
331 }
332
333 // ----------------------------------------------------------------------------
334 // access log
335
336 void log_access( const char *fmt, ... )
337 {
338     va_list args;
339
340     if(stdaccess) {
341         log_date(stdaccess);
342
343         va_start( args, fmt );
344         vfprintf( stdaccess, fmt, args );
345         va_end( args );
346         fputc('\n', stdaccess);
347     }
348
349     if(access_log_syslog) {
350         va_start( args, fmt );
351         vsyslog(LOG_INFO,  fmt, args );
352         va_end( args );
353     }
354 }
355