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