log.c (3468B)
1 /*
2 * Copyright (c) 2022 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/types.h>
18
19 #include <time.h>
20 #include <syslog.h>
21
22 #include "kore.h"
23
24 struct kore_wlog {
25 int prio;
26 u_int16_t wid;
27 size_t loglen;
28 char logmsg[];
29 };
30
31 static void log_print(int, const char *, ...);
32 static void log_from_worker(struct kore_msg *, const void *);
33
34 static FILE *fp = NULL;
35
36 void
37 kore_log_init(void)
38 {
39 #if defined(KORE_SINGLE_BINARY)
40 extern const char *__progname;
41 const char *name = kore_strdup(__progname);
42 #else
43 const char *name = "kore";
44 #endif
45
46 fp = stdout;
47
48 if (!kore_foreground)
49 openlog(name, LOG_NDELAY | LOG_PID, LOG_DAEMON);
50
51 kore_msg_register(KORE_MSG_WORKER_LOG, log_from_worker);
52 }
53
54 void
55 kore_log_file(const char *path)
56 {
57 if ((fp = fopen(path, "a")) == NULL) {
58 fp = stdout;
59 fatal("fopen(%s): %s", path, errno_s);
60 }
61 }
62
63 void
64 kore_log(int prio, const char *fmt, ...)
65 {
66 va_list args;
67 const char *str;
68 struct kore_wlog wlog;
69 struct kore_buf buf, pkt;
70
71 kore_buf_init(&buf, 128);
72
73 va_start(args, fmt);
74 kore_buf_appendv(&buf, fmt, args);
75 va_end(args);
76
77 if (worker != NULL) {
78 kore_buf_init(&pkt, sizeof(wlog) + buf.offset);
79
80 memset(&wlog, 0, sizeof(wlog));
81
82 wlog.prio = prio;
83 wlog.wid = worker->id;
84 wlog.loglen = buf.offset;
85
86 kore_buf_append(&pkt, &wlog, sizeof(wlog));
87 kore_buf_append(&pkt, buf.data, buf.offset);
88
89 kore_msg_send(KORE_MSG_PARENT, KORE_MSG_WORKER_LOG,
90 pkt.data, pkt.offset);
91
92 kore_buf_cleanup(&pkt);
93 } else {
94 str = kore_buf_stringify(&buf, NULL);
95
96 if (kore_foreground || fp != stdout)
97 log_print(prio, "[parent]: %s\n", str);
98 else
99 syslog(prio, "[parent]: %s", str);
100 }
101
102 kore_buf_cleanup(&buf);
103 }
104
105 static void
106 log_from_worker(struct kore_msg *msg, const void *data)
107 {
108 const char *name;
109 const struct kore_wlog *wlog;
110
111 if (msg->length < sizeof(*wlog)) {
112 kore_log(LOG_NOTICE,
113 "too short worker log received (%zu < %zu)",
114 msg->length, sizeof(*wlog));
115 return;
116 }
117
118 wlog = data;
119 name = kore_worker_name(wlog->wid);
120
121 if (kore_foreground || fp != stdout) {
122 log_print(wlog->prio, "%s: %.*s\n",
123 name, (int)wlog->loglen, wlog->logmsg);
124 } else {
125 syslog(wlog->prio, "%s: %.*s",
126 name, (int)wlog->loglen, wlog->logmsg);
127 }
128 }
129
130 static void
131 log_print(int prio, const char *fmt, ...)
132 {
133 struct tm *t;
134 struct timespec ts;
135 va_list args;
136 char tbuf[32];
137
138 va_start(args, fmt);
139
140 switch (prio) {
141 case LOG_ERR:
142 case LOG_WARNING:
143 case LOG_NOTICE:
144 case LOG_INFO:
145 case LOG_DEBUG:
146 break;
147 }
148
149 (void)clock_gettime(CLOCK_REALTIME, &ts);
150 t = gmtime(&ts.tv_sec);
151
152 if (strftime(tbuf, sizeof(tbuf), "%Y-%m-%d %H:%M:%S", t) > 0)
153 fprintf(fp, "%s.%03ld UTC ", tbuf, ts.tv_nsec / 1000000);
154
155 vfprintf(fp, fmt, args);
156 fflush(fp);
157
158 va_end(args);
159 }