- startet importing pluto ASN1 stuff
[strongswan.git] / Source / lib / utils / logger.c
1 /**
2 * @file logger.c
3 *
4 * @brief Implementation of logger_t.
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
23 #include <syslog.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <time.h>
28 #include <pthread.h>
29
30 #include "logger.h"
31
32 #include <daemon.h>
33
34 /**
35 * Maximum length of a log entry (only used for logger_s.log).
36 */
37 #define MAX_LOG 8192
38
39
40 typedef struct private_logger_t private_logger_t;
41
42 /**
43 * @brief Private data of a logger_t object.
44 */
45 struct private_logger_t {
46 /**
47 * Public data.
48 */
49 logger_t public;
50 /**
51 * Detail-level of logger.
52 */
53 log_level_t level;
54 /**
55 * Name of logger.
56 */
57 char *name;
58 /**
59 * File to write log output to.
60 * NULL for syslog.
61 */
62 FILE *output;
63
64 /**
65 * Should a thread_id be included in the log?
66 */
67 bool log_thread_id;
68
69 /**
70 * Applies a prefix to string and stores it in buffer.
71 *
72 * @warning: buffer must be at least have MAX_LOG size.
73 */
74 void (*prepend_prefix) (private_logger_t *this, log_level_t loglevel, char *string, char *buffer);
75 };
76
77 /**
78 * Implementation of private_logger_t.prepend_prefix.
79 */
80 static void prepend_prefix(private_logger_t *this, log_level_t loglevel, char *string, char *buffer)
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 }
99 else if (loglevel & AUDIT)
100 {
101 log_type = '>';
102 }
103 else
104 {
105 log_type = '-';
106 }
107
108 if (loglevel & (LEVEL3 - LEVEL2))
109 {
110 log_details = '3';
111 }
112 else if (loglevel & (LEVEL2 - LEVEL1))
113 {
114 log_details = '2';
115 }
116 else if (loglevel & LEVEL1)
117 {
118 log_details = '1';
119 }
120 else
121 {
122 log_details = '0';
123 }
124
125 if (this->log_thread_id)
126 {
127 snprintf(buffer, MAX_LOG, "[%c%c] [%s] @%u %s", log_type, log_details, this->name, (int)pthread_self(), string);
128 }
129 else
130 {
131 snprintf(buffer, MAX_LOG, "[%c%c] [%s] %s", log_type, log_details, this->name, string);
132 }
133 }
134
135 /**
136 * Implementation of logger_t.log.
137 *
138 * Yes, logg is wrong written :-).
139 */
140 static void logg(private_logger_t *this, log_level_t loglevel, char *format, ...)
141 {
142 if ((this->level & loglevel) == loglevel)
143 {
144 char buffer[MAX_LOG];
145 va_list args;
146
147
148 if (this->output == NULL)
149 {
150 /* syslog */
151 this->prepend_prefix(this, loglevel, format, buffer);
152 va_start(args, format);
153 vsyslog(LOG_INFO, buffer, args);
154 va_end(args);
155 }
156 else
157 {
158 /* File output */
159 this->prepend_prefix(this, loglevel, format, buffer);
160 va_start(args, format);
161 vfprintf(this->output, buffer, args);
162 va_end(args);
163 fprintf(this->output, "\n");
164 }
165
166 }
167 }
168
169 /**
170 * Implementation of logger_t.log_bytes.
171 */
172 static void log_bytes(private_logger_t *this, log_level_t loglevel, char *label, char *bytes, size_t len)
173 {
174 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
175
176
177 if ((this->level & loglevel) == loglevel)
178 {
179 char buffer[MAX_LOG];
180 char ascii_buffer[17];
181 char *format;
182 char *buffer_pos;
183 char *bytes_pos, *bytes_roof;
184 int i;
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);
192
193
194 format = "%s (%d bytes @%p)";
195 this->prepend_prefix(this, loglevel, format, buffer);
196
197 if (this->output == NULL)
198 {
199 syslog(LOG_INFO, buffer, label, len);
200 }
201 else
202 {
203 fprintf(this->output, buffer, label, len, bytes);
204 fprintf(this->output, "\n");
205 }
206
207 bytes_pos = bytes;
208 bytes_roof = bytes + len;
209 buffer_pos = buffer;
210 memset(ascii_buffer, 0, 17);
211
212 for (i = 1; bytes_pos < bytes_roof; i++)
213 {
214 static char hexdig[] = "0123456789ABCDEF";
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;
221 if (this->output == NULL)
222 {
223 syslog(LOG_INFO, "[=>] [%5d] %s %s", line_start, buffer, ascii_buffer);
224 }
225 else
226 {
227 fprintf(this->output, "[=>] [%5d] %s %s\n", line_start, buffer, ascii_buffer);
228 }
229 memset(ascii_buffer, 0, 16);
230 line_start += 16;
231 }
232 else if ((i % 4) == 0)
233 {
234 *buffer_pos++ = ' ';
235 // *buffer_pos++ = ' ';
236 }
237 else
238 {
239 *buffer_pos++ = ' ';
240 }
241
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
251 bytes_pos++;
252 }
253
254 *buffer_pos++ = '\0';
255 if (buffer_pos > buffer + 1)
256 {
257 buffer_pos = buffer;
258 if (this->output == NULL)
259 {
260 syslog(LOG_INFO, "[=>] [%5d] %s %16s", line_start, buffer, ascii_buffer);
261 }
262 else
263 {
264 fprintf(this->output, "[=>] [%5d] %s %16s\n", line_start, buffer, ascii_buffer);
265 }
266 }
267 pthread_mutex_unlock(&mutex);
268 }
269 }
270
271 /**
272 * Implementation of logger_t.log_chunk.
273 */
274 static void log_chunk(logger_t *this, log_level_t loglevel, char *label, chunk_t chunk)
275 {
276 this->log_bytes(this, loglevel, label, chunk.ptr, chunk.len);
277 }
278
279 /**
280 * Implementation of logger_t.enable_level.
281 */
282 static void enable_level(private_logger_t *this, log_level_t log_level)
283 {
284 this->level |= log_level;
285 }
286
287 /**
288 * Implementation of logger_t.disable_level.
289 */
290 static void disable_level(private_logger_t *this, log_level_t log_level)
291 {
292 this->level &= ~log_level;
293 }
294
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
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
311 /**
312 * Implementation of logger_t.destroy.
313 */
314 static void destroy(private_logger_t *this)
315 {
316 free(this->name);
317 free(this);
318 }
319
320 /*
321 * Described in header.
322 */
323 logger_t *logger_create(char *logger_name, log_level_t log_level, bool log_thread_id, FILE * output)
324 {
325 private_logger_t *this = malloc_thing(private_logger_t);
326
327 /* public functions */
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;
330 this->public.log_chunk = log_chunk;
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;
334 this->public.set_output = (void(*)(logger_t*,FILE*))set_output;
335 this->public.destroy = (void(*)(logger_t*))destroy;
336
337 /* private functions */
338 this->prepend_prefix = prepend_prefix;
339
340 if (logger_name == NULL)
341 {
342 logger_name = "";
343 }
344
345 /* private variables */
346 this->level = log_level;
347 this->log_thread_id = log_thread_id;
348 this->name = malloc(strlen(logger_name) + 1);
349
350 strcpy(this->name,logger_name);
351 this->output = output;
352
353 if (output == NULL)
354 {
355 openlog(DAEMON_NAME, 0, LOG_DAEMON);
356 }
357
358 return (logger_t*)this;
359 }