i3
src/log.c
Go to the documentation of this file.
00001 /*
00002  * vim:ts=4:sw=4:expandtab
00003  *
00004  * i3 - an improved dynamic tiling window manager
00005  * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
00006  *
00007  * log.c: Setting of loglevels, logging functions.
00008  *
00009  */
00010 #include <stdarg.h>
00011 #include <stdio.h>
00012 #include <string.h>
00013 #include <stdbool.h>
00014 #include <stdlib.h>
00015 #include <sys/time.h>
00016 #include <unistd.h>
00017 #include <fcntl.h>
00018 
00019 #include "util.h"
00020 #include "log.h"
00021 
00022 /* loglevels.h is autogenerated at make time */
00023 #include "loglevels.h"
00024 
00025 static uint64_t loglevel = 0;
00026 static bool verbose = false;
00027 static FILE *errorfile;
00028 char *errorfilename;
00029 
00030 /*
00031  * Initializes logging by creating an error logfile in /tmp (or
00032  * XDG_RUNTIME_DIR, see get_process_filename()).
00033  *
00034  */
00035 void init_logging() {
00036     errorfilename = get_process_filename("errorlog");
00037     if (errorfilename == NULL) {
00038         ELOG("Could not initialize errorlog\n");
00039         return;
00040     }
00041 
00042     errorfile = fopen(errorfilename, "w");
00043     if (fcntl(fileno(errorfile), F_SETFD, FD_CLOEXEC)) {
00044         ELOG("Could not set close-on-exec flag\n");
00045     }
00046 }
00047 
00048 /*
00049  * Set verbosity of i3. If verbose is set to true, informative messages will
00050  * be printed to stdout. If verbose is set to false, only errors will be
00051  * printed.
00052  *
00053  */
00054 void set_verbosity(bool _verbose) {
00055     verbose = _verbose;
00056 }
00057 
00058 /*
00059  * Enables the given loglevel.
00060  *
00061  */
00062 void add_loglevel(const char *level) {
00063     /* Handle the special loglevel "all" */
00064     if (strcasecmp(level, "all") == 0) {
00065         loglevel = UINT64_MAX;
00066         return;
00067     }
00068 
00069     for (int i = 0; i < sizeof(loglevels) / sizeof(char*); i++) {
00070         if (strcasecmp(loglevels[i], level) != 0)
00071             continue;
00072 
00073         /* The position in the array (plus one) is the amount of times
00074          * which we need to shift 1 to the left to get our bitmask for
00075          * the specific loglevel. */
00076         loglevel |= (1 << (i+1));
00077         break;
00078     }
00079 }
00080 
00081 /*
00082  * Logs the given message to stdout while prefixing the current time to it.
00083  * This is to be called by *LOG() which includes filename/linenumber/function.
00084  *
00085  */
00086 void vlog(char *fmt, va_list args) {
00087     static char timebuf[64];
00088     static struct tm result;
00089 
00090     /* Get current time */
00091     time_t t = time(NULL);
00092     /* Convert time to local time (determined by the locale) */
00093     struct tm *tmp = localtime_r(&t, &result);
00094     /* Generate time prefix */
00095     strftime(timebuf, sizeof(timebuf), "%x %X - ", tmp);
00096 #ifdef DEBUG_TIMING
00097     struct timeval tv;
00098     gettimeofday(&tv, NULL);
00099     printf("%s%d.%d - ", timebuf, tv.tv_sec, tv.tv_usec);
00100 #else
00101     printf("%s", timebuf);
00102 #endif
00103     vprintf(fmt, args);
00104 }
00105 
00106 /*
00107  * Logs the given message to stdout while prefixing the current time to it,
00108  * but only if verbose mode is activated.
00109  *
00110  */
00111 void verboselog(char *fmt, ...) {
00112     va_list args;
00113 
00114     if (!verbose)
00115         return;
00116 
00117     va_start(args, fmt);
00118     vlog(fmt, args);
00119     va_end(args);
00120 }
00121 
00122 /*
00123  * Logs the given message to stdout while prefixing the current time to it.
00124  *
00125  */
00126 void errorlog(char *fmt, ...) {
00127     va_list args;
00128 
00129     va_start(args, fmt);
00130     vlog(fmt, args);
00131     va_end(args);
00132 
00133     /* also log to the error logfile, if opened */
00134     va_start(args, fmt);
00135     vfprintf(errorfile, fmt, args);
00136     fflush(errorfile);
00137     va_end(args);
00138 }
00139 
00140 /*
00141  * Logs the given message to stdout while prefixing the current time to it,
00142  * but only if the corresponding debug loglevel was activated.
00143  * This is to be called by DLOG() which includes filename/linenumber
00144  *
00145  */
00146 void debuglog(uint64_t lev, char *fmt, ...) {
00147     va_list args;
00148 
00149     if ((loglevel & lev) == 0)
00150         return;
00151 
00152     va_start(args, fmt);
00153     vlog(fmt, args);
00154     va_end(args);
00155 }