]> arthur.barton.de Git - netdata.git/blob - src/log.c
Merge pull request #775 from ktsaou/health
[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) {
79         *fp = fdopen(fd, "a");
80         if (!*fp)
81             error("Cannot fdopen() fd %d ('%s')", fd, filename);
82         else {
83             if (setvbuf(*fp, NULL, _IOLBF, 0) != 0)
84                 error("Cannot set line buffering on fd %d ('%s')", fd, filename);
85         }
86     }
87
88     return fd;
89 }
90
91 void reopen_all_log_files() {
92     if(stdout_filename)
93         open_log_file(STDOUT_FILENO, &stdout, stdout_filename, &output_log_syslog);
94
95     if(stderr_filename)
96         open_log_file(STDERR_FILENO, &stderr, stderr_filename, &error_log_syslog);
97
98     if(stdaccess_filename)
99         stdaccess_fd = open_log_file(stdaccess_fd, &stdaccess, stdaccess_filename, &access_log_syslog);
100 }
101
102 void open_all_log_files() {
103     // disable stdin
104     open_log_file(STDIN_FILENO, &stdin, "/dev/null", NULL);
105
106     open_log_file(STDOUT_FILENO, &stdout, stdout_filename, &output_log_syslog);
107     open_log_file(STDERR_FILENO, &stderr, stderr_filename, &error_log_syslog);
108     stdaccess_fd = open_log_file(stdaccess_fd, &stdaccess, stdaccess_filename, &access_log_syslog);
109 }
110
111 // ----------------------------------------------------------------------------
112 // error log throttling
113
114 time_t error_log_throttle_period = 1200;
115 unsigned long error_log_errors_per_period = 200;
116
117 int error_log_limit(int reset) {
118     static time_t start = 0;
119     static unsigned long counter = 0, prevented = 0;
120
121     // do not throttle if the period is 0
122     if(error_log_throttle_period == 0)
123         return 0;
124
125     // prevent all logs if the errors per period is 0
126     if(error_log_errors_per_period == 0)
127         return 1;
128
129     time_t now = time(NULL);
130     if(!start) start = now;
131
132     if(reset) {
133         if(prevented) {
134             log_date(stderr);
135             fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
136                     , program_name
137                     , program_name
138                     , prevented
139                     , now - start
140             );
141         }
142
143         start = now;
144         counter = 0;
145         prevented = 0;
146     }
147
148     // detect if we log too much
149     counter++;
150
151     if(now - start > error_log_throttle_period) {
152         if(prevented) {
153             log_date(stderr);
154             fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
155                     , program_name
156                     , program_name
157                     , prevented
158                     , error_log_throttle_period
159             );
160         }
161
162         // restart the period accounting
163         start = now;
164         counter = 1;
165         prevented = 0;
166
167         // log this error
168         return 0;
169     }
170
171     if(counter > error_log_errors_per_period) {
172         if(!prevented) {
173             log_date(stderr);
174             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"
175                     , program_name
176                     , counter
177                     , now - start
178                     , error_log_errors_per_period
179                     , error_log_throttle_period
180                     , program_name
181                     , start + error_log_throttle_period - now);
182         }
183
184         prevented++;
185
186         // prevent logging this error
187         return 1;
188     }
189
190     return 0;
191 }
192
193 // ----------------------------------------------------------------------------
194 // print the date
195
196 // FIXME
197 // this should print the date in a buffer the way it
198 // is now, logs from multiple threads may be multiplexed
199
200 void log_date(FILE *out)
201 {
202         char outstr[24];
203         time_t t;
204         struct tm *tmp, tmbuf;
205
206         t = time(NULL);
207         tmp = localtime_r(&t, &tmbuf);
208
209         if (tmp == NULL) return;
210         if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
211
212         fprintf(out, "%s: ", outstr);
213 }
214
215 // ----------------------------------------------------------------------------
216 // debug log
217
218 void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
219 {
220     va_list args;
221
222     log_date(stdout);
223     va_start( args, fmt );
224     printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
225     vprintf(fmt, args);
226     va_end( args );
227     putchar('\n');
228
229     if(output_log_syslog) {
230         va_start( args, fmt );
231         vsyslog(LOG_ERR,  fmt, args );
232         va_end( args );
233     }
234
235     fflush(stdout);
236 }
237
238 // ----------------------------------------------------------------------------
239 // info log
240
241 void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
242 {
243     va_list args;
244
245     // prevent logging too much
246     if(error_log_limit(0)) return;
247
248     log_date(stderr);
249
250     va_start( args, fmt );
251     if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
252     else            fprintf(stderr, "INFO: %s: ", program_name);
253     vfprintf( stderr, fmt, args );
254     va_end( args );
255
256     fputc('\n', stderr);
257
258     if(error_log_syslog) {
259         va_start( args, fmt );
260         vsyslog(LOG_INFO,  fmt, args );
261         va_end( args );
262     }
263 }
264
265 // ----------------------------------------------------------------------------
266 // error log
267
268 void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... )
269 {
270     va_list args;
271
272     // prevent logging too much
273     if(error_log_limit(0)) return;
274
275     log_date(stderr);
276
277     va_start( args, fmt );
278     if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
279     else            fprintf(stderr, "%s: %s: ", prefix, program_name);
280     vfprintf( stderr, fmt, args );
281     va_end( args );
282
283     if(errno) {
284         char buf[1024];
285         fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
286         errno = 0;
287     }
288     else
289         fputc('\n', stderr);
290
291     if(error_log_syslog) {
292         va_start( args, fmt );
293         vsyslog(LOG_ERR,  fmt, args );
294         va_end( args );
295     }
296 }
297
298 void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
299 {
300     va_list args;
301
302     log_date(stderr);
303
304     va_start( args, fmt );
305     if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
306     else            fprintf(stderr, "FATAL: %s: ", program_name);
307     vfprintf( stderr, fmt, args );
308     va_end( args );
309
310     perror(" # ");
311     fputc('\n', stderr);
312
313     if(error_log_syslog) {
314         va_start( args, fmt );
315         vsyslog(LOG_CRIT,  fmt, args );
316         va_end( args );
317     }
318
319     netdata_cleanup_and_exit(1);
320 }
321
322 // ----------------------------------------------------------------------------
323 // access log
324
325 void log_access( const char *fmt, ... )
326 {
327     va_list args;
328
329     if(stdaccess) {
330         log_date(stdaccess);
331
332         va_start( args, fmt );
333         vfprintf( stdaccess, fmt, args );
334         va_end( args );
335         fputc('\n', stdaccess);
336     }
337
338     if(access_log_syslog) {
339         va_start( args, fmt );
340         vsyslog(LOG_INFO,  fmt, args );
341         va_end( args );
342     }
343 }
344