FIX: the glibc logger using nobug_log internally, no locking needed
[nobug.git] / src / nobug.c
blob551f26050cd0b2eba5c872d936f730ec8e5746ef
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C) 2007, 2008, Christian Thaeter <chth@gmx.net>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
20 #if NOBUG_USE_PTHREAD
21 #include <pthread.h>
22 #endif
24 #define NOBUG_LIBNOBUG_C
25 #include "nobug.h"
28 struct nobug_ringbuffer nobug_default_ringbuffer;
29 FILE* nobug_default_file = NULL;
30 unsigned long long nobug_counter = 0;
31 nobug_logging_cb nobug_logging_callback = NULL;
32 nobug_logging_cb nobug_postlogging_callback = NULL;
33 nobug_abort_cb nobug_abort_callback = NULL;
34 void* nobug_callback_data = NULL;
38 //predefflags HEAD~ Predefined Flags;;
39 //predefflags
40 //predefflags There are some debugging flags which are predefined by NoBug.
41 //predefflags
42 //predefflags PARA NOBUG_ON; NOBUG_ON; log flag which is always enabled
43 //predefflags
44 //predefflags The flag `NOBUG_ON` is always enabled at LOG_DEBUG level. This is
45 //predefflags static and can not be changed.
46 //predefflags
48 struct nobug_flag nobug_flag_NOBUG_ON =
49 {NULL, NULL, 0, {LOG_DEBUG, LOG_DEBUG, LOG_DEBUG, LOG_DEBUG, LOG_DEBUG}, NULL, NULL, NULL};
52 //predefflags PARA NOBUG_ANN; NOBUG_ANN; log flag for annotations
53 //predefflags
54 //predefflags The flag `NOBUG_ANN` is used for the source annotations. This is
55 //predefflags static and can not be changed. It differs from `NOBUG_ON` as in
56 //predefflags never logging to syslog and only define a LOG_WARNING limit for the
57 //predefflags application callback.
58 //predefflags
60 struct nobug_flag nobug_flag_NOBUG_ANN =
61 {NULL, NULL, 0, {LOG_DEBUG, LOG_DEBUG, LOG_DEBUG, -1, LOG_WARNING}, NULL, NULL, NULL};
64 //predefflags PARA nobug (flag); nobug_flag; log flag used to show nobug actions
65 //predefflags
66 //predefflags Actions on NoBug itself will be logged under the `nobug` flag itself.
67 //predefflags When you want to see whats going on (useful to check if you call
68 //predefflags `NOBUG_INIT_FLAG()` on all flags) you can enable it with `NOBUG_LOG=nobug:TRACE`.
69 //predefflags
71 struct nobug_flag nobug_flag_nobug =
72 {"nobug", NULL, 0, {LOG_DEBUG, LOG_WARNING, LOG_ERR, LOG_ERR, -1}, NULL, NULL, NULL};
75 #if NOBUG_USE_PTHREAD
76 static void
77 nobug_tls_free (void * tls)
79 free((void*)((struct nobug_tls_data*)tls)->thread_id);
80 free(tls);
82 #endif
85 default initialization
87 static volatile int nobug_initialized = 0;
89 void
90 nobug_init (void)
92 if (nobug_initialized)
93 return;
94 nobug_initialized = 1;
96 #if NOBUG_USE_PTHREAD
97 pthread_key_create (&nobug_tls_key, nobug_tls_free);
98 #endif
100 /* we initialize a minimal ringbuffer, if not already done */
101 if (!nobug_default_ringbuffer.start)
102 nobug_ringbuffer_init (&nobug_default_ringbuffer, 4096, NULL, NOBUG_RINGBUFFER_DEFAULT);
104 /* initialize the always-on flag*/
105 nobug_flag_NOBUG_ON.ringbuffer_target = &nobug_default_ringbuffer;
106 nobug_flag_NOBUG_ON.console_target = stderr;
107 nobug_flag_NOBUG_ON.file_target = nobug_default_file;
108 nobug_flag_NOBUG_ON.initialized = 1;
110 nobug_flag_NOBUG_ANN.ringbuffer_target = &nobug_default_ringbuffer;
111 nobug_flag_NOBUG_ANN.console_target = stderr;
112 nobug_flag_NOBUG_ANN.file_target = nobug_default_file;
113 nobug_flag_NOBUG_ANN.initialized = 1;
115 nobug_resource_init ();
117 nobug_env_init_flag (&nobug_flag_nobug, NOBUG_TARGET_CONSOLE, LOG_WARNING);
119 nobug_log (&nobug_flag_nobug, LOG_NOTICE, "NOBUG: INITIALIZED");
123 void
124 nobug_destroy (void)
126 if (nobug_initialized)
128 nobug_log (&nobug_flag_nobug, LOG_NOTICE, "NOBUG: DESTROYING");
130 nobug_resource_destroy ();
132 if (nobug_default_ringbuffer.start)
133 nobug_ringbuffer_destroy (&nobug_default_ringbuffer);
135 #if NOBUG_USE_PTHREAD
136 nobug_tls_free (nobug_thread_get ());
137 pthread_key_delete (nobug_tls_key);
138 #endif
140 nobug_initialized = 0;
145 void
146 nobug_log (struct nobug_flag* flag, int lvl, const char* fmt, ...)
148 NOBUG_LOGGING_LOCK;
150 char* log = nobug_ringbuffer_pos (flag->ringbuffer_target);
152 nobug_ringbuffer_printf (flag->ringbuffer_target, "%.10llu: ", ++nobug_counter);
153 nobug_ringbuffer_append (flag->ringbuffer_target);
155 va_list ap;
156 va_start (ap, fmt);
157 nobug_ringbuffer_vprintf (flag->ringbuffer_target, fmt, ap);
158 va_end (ap);
160 if (NOBUG_EXPECT_FALSE(lvl <= flag->limits[NOBUG_TARGET_CONSOLE]))
162 #if HAVE_VALGRIND
163 if (NOBUG_EXPECT_FALSE (NOBUG_ACTIVE_DBG == NOBUG_DBG_VALGRIND))
165 VALGRIND_PRINTF ("%s"VALGRIND_NEWLINE, log);
167 else
168 #endif
169 fprintf (flag->console_target?flag->console_target:stderr, "%s\n", log);
172 if (NOBUG_EXPECT_FALSE(lvl <= flag->limits[NOBUG_TARGET_FILE] && flag->file_target))
174 fprintf (flag->file_target, "%s\n", log);
177 if (NOBUG_EXPECT_FALSE(lvl <= flag->limits[NOBUG_TARGET_SYSLOG]))
179 syslog (lvl, "%s\n", log);
182 if (nobug_logging_callback)
183 nobug_logging_callback (flag, lvl, log, nobug_callback_data);
185 /* TODO
187 NOBUG_IF(NOBUG_USE_XXXX_TARGET ...
190 #if NOBUG_USE_PTHREAD
191 /* the resource tracker bails out with the resource lock held for logging it, we can release it here now */
192 if (nobug_resource_error)
194 nobug_resource_error = NULL;
195 NOBUG_RESOURCE_UNLOCK;
197 #endif
198 NOBUG_LOGGING_UNLOCK;
200 if (nobug_postlogging_callback)
201 nobug_postlogging_callback (flag, lvl, NULL, nobug_callback_data);
205 void
206 nobug_backtrace_glibc (void)
208 #ifdef HAVE_EXECINFO_H
209 void* nobug_backtrace_buffer[NOBUG_BACKTRACE_DEPTH];
211 int depth = backtrace (nobug_backtrace_buffer, NOBUG_BACKTRACE_DEPTH);
213 char** symbols = backtrace_symbols (nobug_backtrace_buffer, depth);
215 if (symbols)
217 /* start at [1] to suppress nobug_backtrace_glibc itself */
218 int i;
219 for (i = 1; i<depth; ++i)
220 nobug_log (&nobug_flag_NOBUG_ON, LOG_NOTICE, "%.10llu: %s", ++nobug_counter, symbols[i]);
222 free (symbols);
224 #endif
228 #if !NOBUG_USE_PTHREAD
229 static void* nobug_nothread_data = NULL;
231 void**
232 nobug_thread_data (void)
234 return &nobug_nothread_data;
237 #endif