]> git.ipfire.org Git - people/ms/strongswan.git/blame - Source/lib/utils/logger.c
- fixed bad bugs in kernel interface
[people/ms/strongswan.git] / Source / lib / utils / logger.c
CommitLineData
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
40typedef struct private_logger_t private_logger_t;
41
61c3cdc2 42/**
d794bcdb 43 * @brief Private data of a logger_t object.
61c3cdc2 44 */
5796aa16 45struct 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 80static 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 140static 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 172static 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 274static 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 282static 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 290static 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 */
298static 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 */
306static 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 314static 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 323logger_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}