aboutsummaryrefslogtreecommitdiff
path: root/src/util/common_logging.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-05-29 00:46:26 +0000
committerChristian Grothoff <christian@grothoff.org>2009-05-29 00:46:26 +0000
commit0a217a8df1657b4334b55b0e4a6c7837a8dbcfd9 (patch)
tree6b552f40eb089db96409a312a98d9b12bd669102 /src/util/common_logging.c
downloadgnunet-0a217a8df1657b4334b55b0e4a6c7837a8dbcfd9.tar.gz
gnunet-0a217a8df1657b4334b55b0e4a6c7837a8dbcfd9.zip
ng
Diffstat (limited to 'src/util/common_logging.c')
-rw-r--r--src/util/common_logging.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/src/util/common_logging.c b/src/util/common_logging.c
new file mode 100644
index 000000000..4068ed94b
--- /dev/null
+++ b/src/util/common_logging.c
@@ -0,0 +1,401 @@
1/*
2 This file is part of GNUnet.
3 (C) 2006, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file util/common_logging.c
23 * @brief error handling API
24 *
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_common.h"
29#include "gnunet_crypto_lib.h"
30#include "gnunet_strings_lib.h"
31#include "gnunet_time_lib.h"
32
33/**
34 * After how many seconds do we always print
35 * that "message X was repeated N times"? Use 12h.
36 */
37#define BULK_DELAY_THRESHOLD (12 * 60 * 60 * 1000)
38
39/**
40 * After how many repetitions do we always print
41 * that "message X was repeated N times"? (even if
42 * we have not yet reached the delay threshold)
43 */
44#define BULK_REPEAT_THRESHOLD 1000
45
46/**
47 * How many characters do we use for matching of
48 * bulk messages?
49 */
50#define BULK_TRACK_SIZE 256
51
52/**
53 * How many characters can a date/time string
54 * be at most?
55 */
56#define DATE_STR_SIZE 64
57
58/**
59 * Linked list of active loggers.
60 */
61struct CustomLogger
62{
63 /**
64 * This is a linked list.
65 */
66 struct CustomLogger *next;
67
68 /**
69 * Log function.
70 */
71 GNUNET_Logger logger;
72
73 /**
74 * Closure for logger.
75 */
76 void *logger_cls;
77};
78
79/**
80 * The last "bulk" error message that we have been logging.
81 * Note that this message maybe truncated to the first BULK_TRACK_SIZE
82 * characters, in which case it is NOT 0-terminated!
83 */
84static char last_bulk[BULK_TRACK_SIZE];
85
86/**
87 * Type of the last bulk message.
88 */
89static enum GNUNET_ErrorType last_bulk_kind;
90
91/**
92 * Time of the last bulk error message (0 for none)
93 */
94static struct GNUNET_TIME_Absolute last_bulk_time;
95
96/**
97 * Number of times that bulk message has been repeated since.
98 */
99static unsigned int last_bulk_repeat;
100
101/**
102 * Component when the last bulk was logged.
103 */
104static const char *last_bulk_comp;
105
106/**
107 * Running component.
108 */
109static const char *component;
110
111/**
112 * Minimum log level.
113 */
114static enum GNUNET_ErrorType min_level;
115
116/**
117 * Linked list of our custom loggres.
118 */
119static struct CustomLogger *loggers;
120
121/**
122 * Number of log calls to ignore.
123 */
124static unsigned int skip_log;
125
126/**
127 * Convert a textual description of a loglevel
128 * to the respective GNUNET_GE_KIND.
129 * @returns GNUNET_GE_INVALID if log does not parse
130 */
131static enum GNUNET_ErrorType
132get_type (const char *log)
133{
134 if (0 == strcasecmp (log, _("DEBUG")))
135 return GNUNET_ERROR_TYPE_DEBUG;
136 if (0 == strcasecmp (log, _("INFO")))
137 return GNUNET_ERROR_TYPE_INFO;
138 if (0 == strcasecmp (log, _("WARNING")))
139 return GNUNET_ERROR_TYPE_WARNING;
140 if (0 == strcasecmp (log, _("ERROR")))
141 return GNUNET_ERROR_TYPE_ERROR;
142 return GNUNET_ERROR_TYPE_INVALID;
143}
144
145/**
146 * Setup logging.
147 *
148 * @param comp default component to use
149 * @param loglevel what types of messages should be logged
150 */
151int
152GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
153{
154 FILE *altlog;
155
156 component = comp;
157 min_level = get_type (loglevel);
158 if (logfile == NULL)
159 return GNUNET_OK;
160 altlog = fopen (logfile, "a");
161 if (altlog == NULL)
162 {
163 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fopen", logfile);
164 return GNUNET_SYSERR;
165 }
166 if (stderr != NULL)
167 fclose (stderr);
168 stderr = altlog;
169 return GNUNET_OK;
170}
171
172/**
173 * Add a custom logger.
174 *
175 * @param logger log function
176 * @param logger_cls closure for logger
177 */
178void
179GNUNET_logger_add (GNUNET_Logger logger, void *logger_cls)
180{
181 struct CustomLogger *entry;
182
183 entry = GNUNET_malloc (sizeof (struct CustomLogger));
184 entry->logger = logger;
185 entry->logger_cls = logger_cls;
186 entry->next = loggers;
187 loggers = entry;
188}
189
190/**
191 * Remove a custom logger.
192 *
193 * @param logger log function
194 * @param logger_cls closure for logger
195 */
196void
197GNUNET_logger_remove (GNUNET_Logger logger, void *logger_cls)
198{
199 struct CustomLogger *pos;
200 struct CustomLogger *prev;
201
202 prev = NULL;
203 pos = loggers;
204 while ((pos != NULL) &&
205 ((pos->logger != logger) || (pos->logger_cls != logger_cls)))
206 {
207 prev = pos;
208 pos = pos->next;
209 }
210 GNUNET_assert (pos != NULL);
211 if (prev == NULL)
212 loggers = pos->next;
213 else
214 prev->next = pos->next;
215 GNUNET_free (pos);
216}
217
218static void
219output_message (enum GNUNET_ErrorType kind,
220 const char *comp, const char *datestr, const char *msg)
221{
222 struct CustomLogger *pos;
223 if (stderr != NULL)
224 fprintf (stderr, "%s %s %s %s", datestr, comp,
225 GNUNET_error_type_to_string (kind), msg);
226 pos = loggers;
227 while (pos != NULL)
228 {
229 pos->logger (pos->logger_cls, kind, comp, datestr, msg);
230 pos = pos->next;
231 }
232}
233
234static void
235flush_bulk (const char *datestr)
236{
237 char msg[DATE_STR_SIZE + BULK_TRACK_SIZE + 256];
238 int rev;
239 char *last;
240 char *ft;
241
242 if ((last_bulk_time.value == 0) || (last_bulk_repeat == 0))
243 return;
244 rev = 0;
245 last = memchr (last_bulk, '\0', BULK_TRACK_SIZE);
246 if (last == NULL)
247 last = &last_bulk[BULK_TRACK_SIZE - 1];
248 else if (last != last_bulk)
249 last--;
250 if (last[0] == '\n')
251 {
252 rev = 1;
253 last[0] = '\0';
254 }
255 ft =
256 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration
257 (last_bulk_time));
258 snprintf (msg, sizeof (msg),
259 _("Message `%.*s' repeated %u times in the last %s\n"),
260 BULK_TRACK_SIZE, last_bulk, last_bulk_repeat, ft);
261 GNUNET_free (ft);
262 if (rev == 1)
263 last[0] = '\n';
264 output_message (last_bulk_kind, last_bulk_comp, datestr, msg);
265 last_bulk_time = GNUNET_TIME_absolute_get ();
266 last_bulk_repeat = 0;
267}
268
269
270/**
271 * Ignore the next n calls to the log function.
272 *
273 * @param n number of log calls to ignore
274 */
275void
276GNUNET_log_skip (unsigned int n)
277{
278 int ok;
279
280 if (n == 0)
281 {
282 ok = (0 == skip_log);
283 skip_log = 0;
284 GNUNET_assert (ok);
285 }
286 skip_log += n;
287}
288
289
290static void
291mylog (enum GNUNET_ErrorType kind,
292 const char *comp, const char *message, va_list va)
293{
294 char date[DATE_STR_SIZE];
295 time_t timetmp;
296 struct tm *tmptr;
297 size_t size;
298 char *buf;
299 va_list vacp;
300
301 if (skip_log > 0)
302 {
303 skip_log--;
304 return;
305 }
306 if ((kind & (~GNUNET_ERROR_TYPE_BULK)) > min_level)
307 return;
308 va_copy (vacp, va);
309 size = VSNPRINTF (NULL, 0, message, vacp) + 1;
310 va_end (vacp);
311 buf = malloc (size);
312 if (buf == NULL)
313 return; /* oops */
314 VSNPRINTF (buf, size, message, va);
315 time (&timetmp);
316 memset (date, 0, DATE_STR_SIZE);
317 tmptr = localtime (&timetmp);
318 strftime (date, DATE_STR_SIZE, "%b %d %H:%M:%S", tmptr);
319 if ((0 != (kind & GNUNET_ERROR_TYPE_BULK)) &&
320 (last_bulk_time.value != 0) &&
321 (0 == strncmp (buf, last_bulk, sizeof (last_bulk))))
322 {
323 last_bulk_repeat++;
324 if ((GNUNET_TIME_absolute_get_duration (last_bulk_time).value >
325 BULK_DELAY_THRESHOLD)
326 || (last_bulk_repeat > BULK_REPEAT_THRESHOLD))
327 flush_bulk (date);
328 free (buf);
329 return;
330 }
331 flush_bulk (date);
332 strncpy (last_bulk, buf, sizeof (last_bulk));
333 last_bulk_repeat = 0;
334 last_bulk_kind = kind;
335 last_bulk_time = GNUNET_TIME_absolute_get ();
336 last_bulk_comp = comp;
337 output_message (kind, comp, date, buf);
338 free (buf);
339}
340
341
342void
343GNUNET_log (enum GNUNET_ErrorType kind, const char *message, ...)
344{
345 va_list va;
346 va_start (va, message);
347 mylog (kind, component, message, va);
348 va_end (va);
349}
350
351
352void
353GNUNET_log_from (enum GNUNET_ErrorType kind,
354 const char *comp, const char *message, ...)
355{
356 va_list va;
357 va_start (va, message);
358 mylog (kind, comp, message, va);
359 va_end (va);
360}
361
362
363/**
364 * Convert KIND to String
365 */
366const char *
367GNUNET_error_type_to_string (enum GNUNET_ErrorType kind)
368{
369 if ((kind & GNUNET_ERROR_TYPE_ERROR) > 0)
370 return _("ERROR");
371 if ((kind & GNUNET_ERROR_TYPE_WARNING) > 0)
372 return _("WARNING");
373 if ((kind & GNUNET_ERROR_TYPE_INFO) > 0)
374 return _("INFO");
375 if ((kind & GNUNET_ERROR_TYPE_DEBUG) > 0)
376 return _("DEBUG");
377 return _("INVALID");
378}
379
380
381/**
382 * Convert a peer identity to a string (for printing debug messages).
383 * This is one of the very few calls in the entire API that is
384 * NOT reentrant!
385 *
386 * @param pid the peer identity
387 * @return string form of the pid; will be overwritten by next
388 * call to GNUNET_i2s.
389 */
390const char *
391GNUNET_i2s (const struct GNUNET_PeerIdentity *pid)
392{
393 static struct GNUNET_CRYPTO_HashAsciiEncoded ret;
394 GNUNET_CRYPTO_hash_to_enc (&pid->hashPubKey, &ret);
395 ret.encoding[4] = '\0';
396 return (const char *) ret.encoding;
397}
398
399
400
401/* end of common_logging.c */