summaryrefslogtreecommitdiffstats
path: root/src/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/log.c')
-rw-r--r--src/log.c481
1 files changed, 292 insertions, 189 deletions
diff --git a/src/log.c b/src/log.c
index 717126a69..e952c5724 100644
--- a/src/log.c
+++ b/src/log.c
@@ -1,241 +1,344 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <time.h>
-#include <syslog.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "log.h"
#include "common.h"
-
-// ----------------------------------------------------------------------------
-// LOG
-
const char *program_name = "";
unsigned long long debug_flags = DEBUG;
-int silent = 0;
+int access_log_syslog = 1;
+int error_log_syslog = 1;
+int output_log_syslog = 1; // debug log
-int access_fd = -1;
+int stdaccess_fd = -1;
FILE *stdaccess = NULL;
-int access_log_syslog = 1;
-int error_log_syslog = 1;
-int output_log_syslog = 1; // debug log
+const char *stdaccess_filename = NULL;
+const char *stderr_filename = NULL;
+const char *stdout_filename = NULL;
+
+void syslog_init(void) {
+ static int i = 0;
+
+ if(!i) {
+ openlog(program_name, LOG_PID, LOG_DAEMON);
+ i = 1;
+ }
+}
+
+int open_log_file(int fd, FILE **fp, const char *filename, int *enabled_syslog) {
+ int f, t;
+
+ if(!filename || !*filename || !strcmp(filename, "none"))
+ filename = "/dev/null";
+
+ if(!strcmp(filename, "syslog")) {
+ filename = "/dev/null";
+ syslog_init();
+ if(enabled_syslog) *enabled_syslog = 1;
+ }
+ else if(enabled_syslog) *enabled_syslog = 0;
+
+ // don't do anything if the user is willing
+ // to have the standard one
+ if(!strcmp(filename, "system")) {
+ if(fd != -1) return fd;
+ filename = "stdout";
+ }
+
+ if(!strcmp(filename, "stdout"))
+ f = STDOUT_FILENO;
+
+ else if(!strcmp(filename, "stderr"))
+ f = STDERR_FILENO;
+
+ else {
+ f = open(filename, O_WRONLY | O_APPEND | O_CREAT, 0664);
+ if(f == -1) {
+ error("Cannot open file '%s'. Leaving %d to its default.", filename, fd);
+ return fd;
+ }
+ }
+
+ // if there is a level-2 file pointer
+ // flush it before switching the level-1 fds
+ if(fp && *fp)
+ fflush(*fp);
+
+ if(fd != f && fd != -1) {
+ // it automatically closes
+ t = dup2(f, fd);
+ if (t == -1) {
+ error("Cannot dup2() new fd %d to old fd %d for '%s'", f, fd, filename);
+ close(f);
+ return fd;
+ }
+ // info("dup2() new fd %d to old fd %d for '%s'", f, fd, filename);
+ close(f);
+ }
+ else fd = f;
+
+ if(fp && !*fp) {
+ *fp = fdopen(fd, "a");
+ if (!*fp)
+ error("Cannot fdopen() fd %d ('%s')", fd, filename);
+ else {
+ if (setvbuf(*fp, NULL, _IOLBF, 0) != 0)
+ error("Cannot set line buffering on fd %d ('%s')", fd, filename);
+ }
+ }
+
+ return fd;
+}
+
+void reopen_all_log_files() {
+ if(stdout_filename)
+ open_log_file(STDOUT_FILENO, &stdout, stdout_filename, &output_log_syslog);
+
+ if(stderr_filename)
+ open_log_file(STDERR_FILENO, &stderr, stderr_filename, &error_log_syslog);
+
+ if(stdaccess_filename)
+ stdaccess_fd = open_log_file(stdaccess_fd, &stdaccess, stdaccess_filename, &access_log_syslog);
+}
+
+void open_all_log_files() {
+ // disable stdin
+ open_log_file(STDIN_FILENO, &stdin, "/dev/null", NULL);
+
+ open_log_file(STDOUT_FILENO, &stdout, stdout_filename, &output_log_syslog);
+ open_log_file(STDERR_FILENO, &stderr, stderr_filename, &error_log_syslog);
+ stdaccess_fd = open_log_file(stdaccess_fd, &stdaccess, stdaccess_filename, &access_log_syslog);
+}
+
+// ----------------------------------------------------------------------------
+// error log throttling
time_t error_log_throttle_period = 1200;
unsigned long error_log_errors_per_period = 200;
int error_log_limit(int reset) {
- static time_t start = 0;
- static unsigned long counter = 0, prevented = 0;
-
- // do not throttle if the period is 0
- if(error_log_throttle_period == 0)
- return 0;
-
- // prevent all logs if the errors per period is 0
- if(error_log_errors_per_period == 0)
- return 1;
-
- time_t now = time(NULL);
- if(!start) start = now;
-
- if(reset) {
- if(prevented) {
- log_date(stderr);
- fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
- , program_name
- , program_name
- , prevented
- , now - start
- );
- }
-
- start = now;
- counter = 0;
- prevented = 0;
- }
-
- // detect if we log too much
- counter++;
-
- if(now - start > error_log_throttle_period) {
- if(prevented) {
- log_date(stderr);
- fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
- , program_name
- , program_name
- , prevented
- , error_log_throttle_period
- );
- }
-
- // restart the period accounting
- start = now;
- counter = 1;
- prevented = 0;
-
- // log this error
- return 0;
- }
-
- if(counter > error_log_errors_per_period) {
- if(!prevented) {
- log_date(stderr);
- 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"
- , program_name
- , counter
- , now - start
- , error_log_errors_per_period
- , error_log_throttle_period
- , program_name
- , start + error_log_throttle_period - now);
- }
-
- prevented++;
-
- // prevent logging this error
- return 1;
- }
-
- return 0;
+ static time_t start = 0;
+ static unsigned long counter = 0, prevented = 0;
+
+ // do not throttle if the period is 0
+ if(error_log_throttle_period == 0)
+ return 0;
+
+ // prevent all logs if the errors per period is 0
+ if(error_log_errors_per_period == 0)
+ return 1;
+
+ time_t now = time(NULL);
+ if(!start) start = now;
+
+ if(reset) {
+ if(prevented) {
+ log_date(stderr);
+ fprintf(stderr, "%s: Resetting logging for process '%s' (prevented %lu logs in the last %ld seconds).\n"
+ , program_name
+ , program_name
+ , prevented
+ , now - start
+ );
+ }
+
+ start = now;
+ counter = 0;
+ prevented = 0;
+ }
+
+ // detect if we log too much
+ counter++;
+
+ if(now - start > error_log_throttle_period) {
+ if(prevented) {
+ log_date(stderr);
+ fprintf(stderr, "%s: Resuming logging from process '%s' (prevented %lu logs in the last %ld seconds).\n"
+ , program_name
+ , program_name
+ , prevented
+ , error_log_throttle_period
+ );
+ }
+
+ // restart the period accounting
+ start = now;
+ counter = 1;
+ prevented = 0;
+
+ // log this error
+ return 0;
+ }
+
+ if(counter > error_log_errors_per_period) {
+ if(!prevented) {
+ log_date(stderr);
+ 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"
+ , program_name
+ , counter
+ , now - start
+ , error_log_errors_per_period
+ , error_log_throttle_period
+ , program_name
+ , start + error_log_throttle_period - now);
+ }
+
+ prevented++;
+
+ // prevent logging this error
+ return 1;
+ }
+
+ return 0;
}
+// ----------------------------------------------------------------------------
+// print the date
+
+// FIXME
+// this should print the date in a buffer the way it
+// is now, logs from multiple threads may be multiplexed
+
void log_date(FILE *out)
{
- char outstr[200];
- time_t t;
- struct tm *tmp, tmbuf;
+ char outstr[24];
+ time_t t;
+ struct tm *tmp, tmbuf;
- t = time(NULL);
- tmp = localtime_r(&t, &tmbuf);
+ t = time(NULL);
+ tmp = localtime_r(&t, &tmbuf);
- if (tmp == NULL) return;
- if (strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0) return;
+ if (tmp == NULL) return;
+ if (unlikely(strftime(outstr, sizeof(outstr), "%y-%m-%d %H:%M:%S", tmp) == 0)) return;
- fprintf(out, "%s: ", outstr);
+ fprintf(out, "%s: ", outstr);
}
+// ----------------------------------------------------------------------------
+// debug log
+
void debug_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
{
- va_list args;
-
- log_date(stdout);
- va_start( args, fmt );
- fprintf(stdout, "DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
- vfprintf( stdout, fmt, args );
- va_end( args );
- fprintf(stdout, "\n");
- // fflush( stdout );
-
- if(output_log_syslog) {
- va_start( args, fmt );
- vsyslog(LOG_ERR, fmt, args );
- va_end( args );
- }
+ va_list args;
+
+ log_date(stdout);
+ va_start( args, fmt );
+ printf("DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
+ vprintf(fmt, args);
+ va_end( args );
+ putchar('\n');
+
+ if(output_log_syslog) {
+ va_start( args, fmt );
+ vsyslog(LOG_ERR, fmt, args );
+ va_end( args );
+ }
+
+ fflush(stdout);
}
+// ----------------------------------------------------------------------------
+// info log
+
void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
{
- va_list args;
+ va_list args;
- // prevent logging too much
- if(error_log_limit(0)) return;
+ // prevent logging too much
+ if(error_log_limit(0)) return;
- log_date(stderr);
+ log_date(stderr);
- va_start( args, fmt );
- if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
- else fprintf(stderr, "INFO: %s: ", program_name);
- vfprintf( stderr, fmt, args );
- va_end( args );
+ va_start( args, fmt );
+ if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
+ else fprintf(stderr, "INFO: %s: ", program_name);
+ vfprintf( stderr, fmt, args );
+ va_end( args );
- fprintf(stderr, "\n");
+ fputc('\n', stderr);
- if(error_log_syslog) {
- va_start( args, fmt );
- vsyslog(LOG_INFO, fmt, args );
- va_end( args );
- }
+ if(error_log_syslog) {
+ va_start( args, fmt );
+ vsyslog(LOG_INFO, fmt, args );
+ va_end( args );
+ }
}
+// ----------------------------------------------------------------------------
+// error log
+
void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... )
{
- va_list args;
-
- // prevent logging too much
- if(error_log_limit(0)) return;
-
- log_date(stderr);
-
- va_start( args, fmt );
- if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
- else fprintf(stderr, "%s: %s: ", prefix, program_name);
- vfprintf( stderr, fmt, args );
- va_end( args );
-
- if(errno) {
- char buf[200];
- char *s = strerror_r(errno, buf, 200);
- fprintf(stderr, " (errno %d, %s)\n", errno, s);
- errno = 0;
- }
- else fprintf(stderr, "\n");
-
- if(error_log_syslog) {
- va_start( args, fmt );
- vsyslog(LOG_ERR, fmt, args );
- va_end( args );
- }
+ va_list args;
+
+ // prevent logging too much
+ if(error_log_limit(0)) return;
+
+ log_date(stderr);
+
+ va_start( args, fmt );
+ if(debug_flags) fprintf(stderr, "%s (%04lu@%-10.10s:%-15.15s): %s: ", prefix, line, file, function, program_name);
+ else fprintf(stderr, "%s: %s: ", prefix, program_name);
+ vfprintf( stderr, fmt, args );
+ va_end( args );
+
+ if(errno) {
+ char buf[1024];
+ fprintf(stderr, " (errno %d, %s)\n", errno, strerror_r(errno, buf, 1023));
+ errno = 0;
+ }
+ else
+ fputc('\n', stderr);
+
+ if(error_log_syslog) {
+ va_start( args, fmt );
+ vsyslog(LOG_ERR, fmt, args );
+ va_end( args );
+ }
}
void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
{
- va_list args;
+ va_list args;
- log_date(stderr);
+ log_date(stderr);
- va_start( args, fmt );
- if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
- else fprintf(stderr, "FATAL: %s: ", program_name);
- vfprintf( stderr, fmt, args );
- va_end( args );
+ va_start( args, fmt );
+ if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
+ else fprintf(stderr, "FATAL: %s: ", program_name);
+ vfprintf( stderr, fmt, args );
+ va_end( args );
- perror(" # ");
- fprintf(stderr, "\n");
+ perror(" # ");
+ fputc('\n', stderr);
- if(error_log_syslog) {
- va_start( args, fmt );
- vsyslog(LOG_CRIT, fmt, args );
- va_end( args );
- }
+ if(error_log_syslog) {
+ va_start( args, fmt );
+ vsyslog(LOG_CRIT, fmt, args );
+ va_end( args );
+ }
- exit(1);
+ netdata_cleanup_and_exit(1);
}
+// ----------------------------------------------------------------------------
+// access log
+
void log_access( const char *fmt, ... )
{
- va_list args;
-
- if(stdaccess) {
- log_date(stdaccess);
-
- va_start( args, fmt );
- vfprintf( stdaccess, fmt, args );
- va_end( args );
- fprintf( stdaccess, "\n");
- // fflush( stdaccess );
- }
-
- if(access_log_syslog) {
- va_start( args, fmt );
- vsyslog(LOG_INFO, fmt, args );
- va_end( args );
- }
+ va_list args;
+
+ if(stdaccess) {
+ log_date(stdaccess);
+
+ va_start( args, fmt );
+ vfprintf( stdaccess, fmt, args );
+ va_end( args );
+ fputc('\n', stdaccess);
+ }
+
+ if(access_log_syslog) {
+ va_start( args, fmt );
+ vsyslog(LOG_INFO, fmt, args );
+ va_end( args );
+ }
}