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