]>
Commit | Line | Data |
---|---|---|
61c3cdc2 MW |
1 | /** |
2 | * @file logger.c | |
3 | * | |
adad211c | 4 | * @brief Implementation of logger_t. |
61c3cdc2 MW |
5 | * |
6 | */ | |
7 | ||
8 | /* | |
9 | * Copyright (C) 2005 Jan Hutter, Martin Willi | |
10 | * Hochschule fuer Technik Rapperswil | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify it | |
13 | * under the terms of the GNU General Public License as published by the | |
14 | * Free Software Foundation; either version 2 of the License, or (at your | |
15 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, but | |
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
20 | * for more details. | |
21 | */ | |
22 | ||
61c3cdc2 MW |
23 | #include <syslog.h> |
24 | #include <stdarg.h> | |
69dd9581 | 25 | #include <string.h> |
dba9cf64 | 26 | #include <stdio.h> |
ffd555f5 | 27 | #include <time.h> |
41fc4f74 | 28 | #include <pthread.h> |
ffd555f5 JH |
29 | |
30 | #include "logger.h" | |
88878242 | 31 | |
021c2322 | 32 | #include <daemon.h> |
61c3cdc2 | 33 | |
69dd9581 | 34 | /** |
d794bcdb | 35 | * Maximum length of a log entry (only used for logger_s.log). |
69dd9581 MW |
36 | */ |
37 | #define MAX_LOG 8192 | |
61c3cdc2 | 38 | |
d794bcdb | 39 | |
5796aa16 MW |
40 | typedef struct private_logger_t private_logger_t; |
41 | ||
61c3cdc2 | 42 | /** |
d794bcdb | 43 | * @brief Private data of a logger_t object. |
61c3cdc2 | 44 | */ |
5796aa16 | 45 | struct private_logger_t { |
61c3cdc2 | 46 | /** |
d794bcdb | 47 | * Public data. |
61c3cdc2 MW |
48 | */ |
49 | logger_t public; | |
61c3cdc2 | 50 | /** |
ffd555f5 | 51 | * Detail-level of logger. |
61c3cdc2 | 52 | */ |
dec59822 | 53 | log_level_t level; |
61c3cdc2 | 54 | /** |
ffd555f5 | 55 | * Name of logger. |
61c3cdc2 MW |
56 | */ |
57 | char *name; | |
ffd555f5 | 58 | /** |
adad211c | 59 | * File to write log output to. |
ffd555f5 JH |
60 | * NULL for syslog. |
61 | */ | |
62 | FILE *output; | |
63 | ||
41fc4f74 | 64 | /** |
25c41f4d | 65 | * Should a thread_id be included in the log? |
41fc4f74 | 66 | */ |
25c41f4d | 67 | bool log_thread_id; |
41fc4f74 | 68 | |
41fc4f74 | 69 | /** |
adad211c | 70 | * Applies a prefix to string and stores it in buffer. |
41fc4f74 | 71 | * |
adad211c | 72 | * @warning: buffer must be at least have MAX_LOG size. |
41fc4f74 | 73 | */ |
dec59822 | 74 | void (*prepend_prefix) (private_logger_t *this, log_level_t loglevel, char *string, char *buffer); |
61c3cdc2 MW |
75 | }; |
76 | ||
41fc4f74 | 77 | /** |
adad211c | 78 | * Implementation of private_logger_t.prepend_prefix. |
41fc4f74 | 79 | */ |
dec59822 | 80 | static void prepend_prefix(private_logger_t *this, log_level_t loglevel, char *string, char *buffer) |
41fc4f74 MW |
81 | { |
82 | char log_type, log_details; | |
83 | if (loglevel & CONTROL) | |
84 | { | |
85 | log_type = '~'; | |
86 | } | |
87 | else if (loglevel & ERROR) | |
88 | { | |
89 | log_type = '!'; | |
90 | } | |
91 | else if (loglevel & RAW) | |
92 | { | |
93 | log_type = '#'; | |
94 | } | |
95 | else if (loglevel & PRIVATE) | |
96 | { | |
97 | log_type = '?'; | |
98 | } | |
39b2903f JH |
99 | else if (loglevel & AUDIT) |
100 | { | |
101 | log_type = '>'; | |
102 | } | |
41fc4f74 MW |
103 | else |
104 | { | |
105 | log_type = '-'; | |
106 | } | |
107 | ||
aee3eb52 | 108 | if (loglevel & (LEVEL3 - LEVEL2)) |
41fc4f74 MW |
109 | { |
110 | log_details = '3'; | |
111 | } | |
aee3eb52 | 112 | else if (loglevel & (LEVEL2 - LEVEL1)) |
41fc4f74 MW |
113 | { |
114 | log_details = '2'; | |
115 | } | |
aee3eb52 | 116 | else if (loglevel & LEVEL1) |
41fc4f74 MW |
117 | { |
118 | log_details = '1'; | |
119 | } | |
120 | else | |
121 | { | |
122 | log_details = '0'; | |
123 | } | |
124 | ||
25c41f4d | 125 | if (this->log_thread_id) |
41fc4f74 | 126 | { |
8f1c27ba | 127 | snprintf(buffer, MAX_LOG, "[%c%c:%s] @%u %s", log_type, log_details, this->name, (int)pthread_self(), string); |
41fc4f74 MW |
128 | } |
129 | else | |
130 | { | |
8f1c27ba | 131 | snprintf(buffer, MAX_LOG, "[%c%c:%s] %s", log_type, log_details, this->name, string); |
41fc4f74 | 132 | } |
41fc4f74 MW |
133 | } |
134 | ||
6ae4efda | 135 | /** |
adad211c JH |
136 | * Implementation of logger_t.log. |
137 | * | |
ffd555f5 | 138 | * Yes, logg is wrong written :-). |
6ae4efda | 139 | */ |
dec59822 | 140 | static void logg(private_logger_t *this, log_level_t loglevel, char *format, ...) |
61c3cdc2 MW |
141 | { |
142 | if ((this->level & loglevel) == loglevel) | |
143 | { | |
69dd9581 | 144 | char buffer[MAX_LOG]; |
61c3cdc2 | 145 | va_list args; |
41fc4f74 | 146 | |
69dd9581 | 147 | |
ffd555f5 JH |
148 | if (this->output == NULL) |
149 | { | |
150 | /* syslog */ | |
41fc4f74 | 151 | this->prepend_prefix(this, loglevel, format, buffer); |
ffd555f5 JH |
152 | va_start(args, format); |
153 | vsyslog(LOG_INFO, buffer, args); | |
154 | va_end(args); | |
155 | } | |
156 | else | |
157 | { | |
158 | /* File output */ | |
41fc4f74 | 159 | this->prepend_prefix(this, loglevel, format, buffer); |
ffd555f5 | 160 | va_start(args, format); |
d6209900 | 161 | vfprintf(this->output, buffer, args); |
ffd555f5 | 162 | va_end(args); |
d6209900 | 163 | fprintf(this->output, "\n"); |
ffd555f5 JH |
164 | } |
165 | ||
166 | } | |
69dd9581 MW |
167 | } |
168 | ||
69dd9581 | 169 | /** |
adad211c | 170 | * Implementation of logger_t.log_bytes. |
69dd9581 | 171 | */ |
dec59822 | 172 | static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label, char *bytes, size_t len) |
69dd9581 | 173 | { |
d6209900 | 174 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
aeda79ff | 175 | |
d6209900 | 176 | |
69dd9581 MW |
177 | if ((this->level & loglevel) == loglevel) |
178 | { | |
41fc4f74 | 179 | char buffer[MAX_LOG]; |
87a217f9 | 180 | char ascii_buffer[17]; |
41fc4f74 | 181 | char *format; |
69dd9581 MW |
182 | char *buffer_pos; |
183 | char *bytes_pos, *bytes_roof; | |
184 | int i; | |
aeda79ff MW |
185 | int line_start = 0; |
186 | ||
187 | /* since me can't do multi-line output to syslog, | |
188 | * we must do multiple syslogs. To avoid | |
189 | * problems in output order, lock this by a mutex. | |
190 | */ | |
191 | pthread_mutex_lock(&mutex); | |
41fc4f74 MW |
192 | |
193 | ||
efadbf79 | 194 | format = "%s (%d bytes @%p)"; |
41fc4f74 | 195 | this->prepend_prefix(this, loglevel, format, buffer); |
69dd9581 | 196 | |
ffd555f5 JH |
197 | if (this->output == NULL) |
198 | { | |
41fc4f74 | 199 | syslog(LOG_INFO, buffer, label, len); |
d6209900 MW |
200 | } |
201 | else | |
ffd555f5 | 202 | { |
efadbf79 | 203 | fprintf(this->output, buffer, label, len, bytes); |
d6209900 | 204 | fprintf(this->output, "\n"); |
ffd555f5 | 205 | } |
61c3cdc2 | 206 | |
69dd9581 MW |
207 | bytes_pos = bytes; |
208 | bytes_roof = bytes + len; | |
209 | buffer_pos = buffer; | |
87a217f9 | 210 | memset(ascii_buffer, 0, 17); |
69dd9581 MW |
211 | |
212 | for (i = 1; bytes_pos < bytes_roof; i++) | |
213 | { | |
d6209900 | 214 | static char hexdig[] = "0123456789ABCDEF"; |
69dd9581 MW |
215 | *buffer_pos++ = hexdig[(*bytes_pos >> 4) & 0xF]; |
216 | *buffer_pos++ = hexdig[ *bytes_pos & 0xF]; | |
217 | if ((i % 16) == 0) | |
218 | { | |
219 | *buffer_pos++ = '\0'; | |
220 | buffer_pos = buffer; | |
ffd555f5 JH |
221 | if (this->output == NULL) |
222 | { | |
8f1c27ba | 223 | syslog(LOG_INFO, "[ :%5d] %s %s", line_start, buffer, ascii_buffer); |
ffd555f5 JH |
224 | } |
225 | else | |
226 | { | |
8f1c27ba | 227 | fprintf(this->output, "[ :%5d] %s %s\n", line_start, buffer, ascii_buffer); |
ffd555f5 | 228 | } |
87a217f9 | 229 | memset(ascii_buffer, 0, 16); |
aeda79ff | 230 | line_start += 16; |
69dd9581 | 231 | } |
69dd9581 MW |
232 | else if ((i % 4) == 0) |
233 | { | |
234 | *buffer_pos++ = ' '; | |
87a217f9 | 235 | // *buffer_pos++ = ' '; |
69dd9581 MW |
236 | } |
237 | else | |
238 | { | |
239 | *buffer_pos++ = ' '; | |
240 | } | |
241 | ||
87a217f9 MW |
242 | if (*bytes_pos > 31 && *bytes_pos < 127) |
243 | { | |
244 | ascii_buffer[(i % 16)] = *bytes_pos; | |
245 | } | |
246 | else | |
247 | { | |
248 | ascii_buffer[(i % 16)] = '*'; | |
249 | } | |
250 | ||
69dd9581 MW |
251 | bytes_pos++; |
252 | } | |
253 | ||
254 | *buffer_pos++ = '\0'; | |
d6209900 | 255 | if (buffer_pos > buffer + 1) |
ffd555f5 | 256 | { |
d6209900 MW |
257 | buffer_pos = buffer; |
258 | if (this->output == NULL) | |
259 | { | |
8f1c27ba | 260 | syslog(LOG_INFO, "[ :%5d] %s %16s", line_start, buffer, ascii_buffer); |
d6209900 MW |
261 | } |
262 | else | |
263 | { | |
8f1c27ba | 264 | fprintf(this->output, "[ :%5d] %s %16s\n", line_start, buffer, ascii_buffer); |
d6209900 | 265 | } |
ffd555f5 | 266 | } |
aeda79ff | 267 | pthread_mutex_unlock(&mutex); |
69dd9581 | 268 | } |
61c3cdc2 | 269 | } |
6ae4efda | 270 | |
69dd9581 | 271 | /** |
adad211c | 272 | * Implementation of logger_t.log_chunk. |
69dd9581 | 273 | */ |
dec59822 | 274 | static void log_chunk(logger_t *this, log_level_t loglevel, char *label, chunk_t chunk) |
69dd9581 | 275 | { |
16b9a73c | 276 | this->log_bytes(this, loglevel, label, chunk.ptr, chunk.len); |
69dd9581 MW |
277 | } |
278 | ||
6ae4efda | 279 | /** |
adad211c | 280 | * Implementation of logger_t.enable_level. |
6ae4efda | 281 | */ |
dec59822 | 282 | static void enable_level(private_logger_t *this, log_level_t log_level) |
61c3cdc2 MW |
283 | { |
284 | this->level |= log_level; | |
61c3cdc2 | 285 | } |
6ae4efda JH |
286 | |
287 | /** | |
adad211c | 288 | * Implementation of logger_t.disable_level. |
6ae4efda | 289 | */ |
dec59822 | 290 | static void disable_level(private_logger_t *this, log_level_t log_level) |
61c3cdc2 | 291 | { |
69dd9581 | 292 | this->level &= ~log_level; |
61c3cdc2 | 293 | } |
6ae4efda | 294 | |
efadbf79 MW |
295 | /** |
296 | * Implementation of logger_t.set_output. | |
297 | */ | |
298 | static void set_output(private_logger_t *this, FILE * output) | |
299 | { | |
300 | this->output = output; | |
301 | } | |
302 | ||
dec59822 MW |
303 | /** |
304 | * Implementation of logger_t.get_level. | |
305 | */ | |
306 | static log_level_t get_level(private_logger_t *this) | |
307 | { | |
308 | return this->level; | |
309 | } | |
310 | ||
6ae4efda | 311 | /** |
adad211c | 312 | * Implementation of logger_t.destroy. |
69dd9581 | 313 | */ |
d048df5c | 314 | static void destroy(private_logger_t *this) |
61c3cdc2 | 315 | { |
5113680f MW |
316 | free(this->name); |
317 | free(this); | |
61c3cdc2 MW |
318 | } |
319 | ||
6ae4efda | 320 | /* |
adad211c | 321 | * Described in header. |
6ae4efda | 322 | */ |
dec59822 | 323 | logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output) |
61c3cdc2 | 324 | { |
5113680f | 325 | private_logger_t *this = malloc_thing(private_logger_t); |
61c3cdc2 | 326 | |
d794bcdb | 327 | /* public functions */ |
dec59822 MW |
328 | this->public.log = (void(*)(logger_t*,log_level_t,char*,...))logg; |
329 | this->public.log_bytes = (void(*)(logger_t*, log_level_t, char*,char*,size_t))log_bytes; | |
69dd9581 | 330 | this->public.log_chunk = log_chunk; |
dec59822 MW |
331 | this->public.enable_level = (void(*)(logger_t*,log_level_t))enable_level; |
332 | this->public.disable_level = (void(*)(logger_t*,log_level_t))disable_level; | |
333 | this->public.get_level = (log_level_t(*)(logger_t*))get_level; | |
efadbf79 | 334 | this->public.set_output = (void(*)(logger_t*,FILE*))set_output; |
d048df5c | 335 | this->public.destroy = (void(*)(logger_t*))destroy; |
61c3cdc2 | 336 | |
d794bcdb | 337 | /* private functions */ |
41fc4f74 | 338 | this->prepend_prefix = prepend_prefix; |
ffd555f5 | 339 | |
d794bcdb JH |
340 | if (logger_name == NULL) |
341 | { | |
342 | logger_name = ""; | |
343 | } | |
344 | ||
ffd555f5 | 345 | /* private variables */ |
61c3cdc2 | 346 | this->level = log_level; |
25c41f4d | 347 | this->log_thread_id = log_thread_id; |
5113680f | 348 | this->name = malloc(strlen(logger_name) + 1); |
d048df5c | 349 | |
96d72d32 | 350 | strcpy(this->name,logger_name); |
ffd555f5 | 351 | this->output = output; |
61c3cdc2 | 352 | |
ffd555f5 JH |
353 | if (output == NULL) |
354 | { | |
db715454 | 355 | openlog(DAEMON_NAME, 0, LOG_DAEMON); |
ffd555f5 | 356 | } |
61c3cdc2 MW |
357 | |
358 | return (logger_t*)this; | |
359 | } |