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