1 #include "logger.h"
2 
3 int logger_verbosity = LOG_INFO;
4 char *logger_logfile = NULL;
5 int logger_fd = -1;
6 
7 #define LOGGER_LINESIZE 1024
8 
9 // priority names (from <syslog.h>)
10 #define INTERNAL_NOPRI 0x10     /* the "no priority" priority */
11 typedef struct _code {
12     const char *c_name;
13     int c_val;
14 } CODE;
15 
16 CODE prioritynames[] = {
17     {"emerg", LOG_EMERG},
18     {"alert", LOG_ALERT},
19     {"crit", LOG_CRIT},
20     {"err", LOG_ERR},
21     {"warning", LOG_WARNING},
22     {"notice", LOG_NOTICE},
23     {"info", LOG_INFO},
24     {"debug", LOG_DEBUG},
25     {"none", INTERNAL_NOPRI},   /* INTERNAL */
26     {NULL, -1}
27 };
28 
29 void
_logger(int priority,const char * fmt,...)30 _logger(int priority, const char *fmt, ...)
31 {
32     va_list ap;
33     char msg[LOGGER_MAXLEN];
34 
35     if (priority > logger_verbosity)
36         return;
37 
38     va_start(ap, fmt);
39     vsnprintf(msg, sizeof(msg), fmt, ap);
40     va_end(ap);
41 
42     logger_lograw(priority, msg);
43 }
44 
45 void
_logger_with_fileline(int priority,const char * fmt,const char * file,int line,...)46 _logger_with_fileline(int priority, const char *fmt, const char *file, int line,
47                       ...)
48 {
49     va_list ap;
50     char msg[LOGGER_MAXLEN];
51 
52     if (priority > logger_verbosity)
53         return;
54 
55     size_t n = snprintf(msg, sizeof(msg), "[%s:%d] ", file, line);
56 
57     va_start(ap, line);
58     vsnprintf(msg + n, sizeof(msg), fmt, ap);
59     va_end(ap);
60 
61     logger_lograw(priority, msg);
62 }
63 
64 /*
65  * Low-level logging. It's only used when you want to log arbitrary length message.
66  */
67 void
logger_lograw(int priority,const char * msg)68 logger_lograw(int priority, const char *msg)
69 {
70     FILE *fp;
71     const char *priority_flag = NULL;
72 
73     if (priority > logger_verbosity)
74         return;
75 
76     // invalid priority?
77     if (priority < 0 || priority > LOG_PRIMASK)
78         priority = INTERNAL_NOPRI;
79 
80     if (logger_fd == -1) {
81         logger_reopen();
82     }
83     if (logger_fd == -1) {
84         return;
85     }
86     fp = (logger_logfile == NULL) ? stdout : fopen(logger_logfile, "a");
87     if (!fp)
88         return;
89 
90     for (int i = 0; i < ARRAY_SIZE(prioritynames); i++) {
91         CODE c = prioritynames[i];
92         if (c.c_val == priority) {
93             priority_flag = c.c_name;
94         }
95     }
96     assert(priority_flag);
97 
98     // prefix
99     int off;
100     struct timeval tv;
101     gettimeofday(&tv, NULL);
102     char buf[64];
103     off = strftime(buf, sizeof(buf), "%d %b %H:%M:%S.", localtime(&tv.tv_sec));
104     snprintf(buf + off, sizeof(buf) - off, "%03d", (int)tv.tv_usec / 1000);
105     // format log
106     char logbuf[LOGGER_LINESIZE];
107     size_t len = snprintf(logbuf, LOGGER_LINESIZE, "[%d] %s [%s] %s\n",
108                           (int)getpid(), buf, priority_flag, msg);
109     // write
110     write(logger_fd, logbuf, len);
111 }
112 
113 void
logger_reopen(void)114 logger_reopen(void)
115 {
116     if (logger_logfile) {
117         logger_fd = open(logger_logfile, O_APPEND | O_CREAT | O_WRONLY, 0644);
118     } else {
119         logger_fd = STDOUT_FILENO;
120     }
121 }
122 
123 void
logger_close(void)124 logger_close(void)
125 {
126     if (logger_fd >= 0) {
127         close(logger_fd);
128     }
129     logger_fd = -1;
130 }
131