formatting fix for init_flag
[nobug.git] / src / nobug.c
blobf9f0663900e86828f155a31ab419cd3d895cf429
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C)
5 2007, 2008, 2009, 2010 Christian Thaeter <ct@pipapo.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
21 #if NOBUG_USE_PTHREAD
22 #include <pthread.h>
23 #endif
25 #define NOBUG_LIBNOBUG_C
26 #include "nobug.h"
29 struct nobug_ringbuffer nobug_default_ringbuffer;
30 FILE* nobug_default_file = NULL;
31 unsigned long long nobug_counter = 0;
32 nobug_logging_cb nobug_logging_callback = NULL;
33 nobug_logging_cb nobug_postlogging_callback = NULL;
34 nobug_abort_cb nobug_abort_callback = NULL;
35 void* nobug_callback_data = NULL;
39 //predefflags HEAD~ Predefined Flags;;
40 //predefflags
41 //predefflags There are some debugging flags which are predefined by NoBug.
42 //predefflags
43 //predefflags PARA NOBUG_ON; NOBUG_ON; log flag which is always enabled
44 //predefflags
45 //predefflags The flag `NOBUG_ON` is always enabled at LOG_DEBUG level. This is
46 //predefflags static and can not be changed.
47 //predefflags
49 struct nobug_flag nobug_flag_NOBUG_ON =
50 {NULL, NULL, 0, {LOG_DEBUG, LOG_DEBUG, LOG_DEBUG, LOG_DEBUG, LOG_DEBUG}, NULL, NULL, NULL};
53 //predefflags PARA NOBUG_ANN; NOBUG_ANN; log flag for annotations
54 //predefflags
55 //predefflags The flag `NOBUG_ANN` is used for the source annotations. This is
56 //predefflags static and can not be changed. It differs from `NOBUG_ON` as in
57 //predefflags never logging to syslog and only define a LOG_WARNING limit for the
58 //predefflags application callback.
59 //predefflags
61 struct nobug_flag nobug_flag_NOBUG_ANN =
62 {NULL, NULL, 0, {LOG_DEBUG, LOG_DEBUG, LOG_DEBUG, -1, LOG_WARNING}, NULL, NULL, NULL};
65 //predefflags PARA nobug (flag); nobug_flag; log flag used to show nobug actions
66 //predefflags
67 //predefflags Actions on NoBug itself will be logged under the `nobug` flag itself.
68 //predefflags When you want to see whats going on (useful to check if you call
69 //predefflags `NOBUG_INIT_FLAG()` on all flags) you can enable it with `NOBUG_LOG=nobug:TRACE`.
70 //predefflags
72 struct nobug_flag nobug_flag_nobug =
73 {"nobug", NULL, 0, {LOG_DEBUG, LOG_WARNING, LOG_ERR, LOG_ERR, -1}, NULL, NULL, NULL};
76 #if NOBUG_USE_PTHREAD
77 static void
78 nobug_tls_free (void * tls)
80 free((void*)((struct nobug_tls_data*)tls)->thread_id);
81 free(tls);
83 #endif
86 default initialization
88 static volatile int nobug_initialized = 0;
90 void
91 nobug_init (const struct nobug_context context)
93 if (nobug_initialized)
94 return;
95 nobug_initialized = 1;
97 #if NOBUG_USE_PTHREAD
98 pthread_key_create (&nobug_tls_key, nobug_tls_free);
99 #endif
101 /* we initialize a minimal ringbuffer, if not already done */
102 if (!nobug_default_ringbuffer.start)
103 nobug_ringbuffer_init (&nobug_default_ringbuffer, 4096, NULL, NOBUG_RINGBUFFER_DEFAULT);
105 /* initialize the always-on flag*/
106 nobug_flag_NOBUG_ON.ringbuffer_target = &nobug_default_ringbuffer;
107 nobug_flag_NOBUG_ON.console_target = stderr;
108 nobug_flag_NOBUG_ON.file_target = nobug_default_file;
109 nobug_flag_NOBUG_ON.initialized = 1;
111 nobug_flag_NOBUG_ANN.ringbuffer_target = &nobug_default_ringbuffer;
112 nobug_flag_NOBUG_ANN.console_target = stderr;
113 nobug_flag_NOBUG_ANN.file_target = nobug_default_file;
114 nobug_flag_NOBUG_ANN.initialized = 1;
116 nobug_resource_init ();
118 nobug_env_init_flag (&nobug_flag_nobug, NOBUG_TARGET_CONSOLE, LOG_WARNING, context);
120 nobug_log (&nobug_flag_nobug, LOG_NOTICE, "NOBUG", context, " INITIALIZED");
124 void
125 nobug_destroy (const struct nobug_context context)
127 if (nobug_initialized)
129 nobug_log (&nobug_flag_nobug, LOG_NOTICE, "NOBUG" , context, " DESTROYING");
131 nobug_resource_destroy ();
133 if (nobug_default_ringbuffer.start)
134 nobug_ringbuffer_destroy (&nobug_default_ringbuffer);
136 #if NOBUG_USE_PTHREAD
137 nobug_tls_free (nobug_thread_get ());
138 pthread_key_delete (nobug_tls_key);
139 #endif
141 nobug_initialized = 0;
145 const char*
146 nobug_basename (const char* const file)
148 return strrchr(file, '/') ? strrchr(file, '/') + 1 : file;
152 void
153 nobug_log (struct nobug_flag* flag, int lvl, const char* what, const struct nobug_context ctx, const char* fmt, ...)
155 NOBUG_LOGGING_LOCK;
157 char* log = nobug_ringbuffer_pos (flag->ringbuffer_target);
159 // standard log header:
160 // counter: FACILITY: file:line: thread: function: ...
162 nobug_ringbuffer_printf (flag->ringbuffer_target, "%.10llu: %s: %s:%d: "
163 #if NOBUG_USE_PTHREAD
164 "%s: "
165 #endif
166 "%s:",
167 ++nobug_counter,
168 what?what:"NOBUG",
169 nobug_basename(ctx.file),
170 ctx.line,
171 #if NOBUG_USE_PTHREAD
172 nobug_thread_id_get(),
173 #endif
174 ctx.func);
175 nobug_ringbuffer_append (flag->ringbuffer_target);
177 va_list ap;
178 va_start (ap, fmt);
179 nobug_ringbuffer_vprintf (flag->ringbuffer_target, fmt, ap);
180 va_end (ap);
182 if (NOBUG_EXPECT_FALSE(lvl <= flag->limits[NOBUG_TARGET_CONSOLE]))
184 #if HAVE_VALGRIND
185 if (NOBUG_EXPECT_FALSE (NOBUG_ACTIVE_DBG == NOBUG_DBG_VALGRIND))
187 VALGRIND_PRINTF ("%s"VALGRIND_NEWLINE, log);
189 else
190 #endif
191 fprintf (flag->console_target?flag->console_target:stderr, "%s\n", log);
194 if (NOBUG_EXPECT_FALSE(lvl <= flag->limits[NOBUG_TARGET_FILE] && flag->file_target))
196 fprintf (flag->file_target, "%s\n", log);
199 if (NOBUG_EXPECT_FALSE(lvl <= flag->limits[NOBUG_TARGET_SYSLOG]))
201 syslog (lvl, "%s\n", log);
204 if (nobug_logging_callback)
205 nobug_logging_callback (flag, lvl, log, nobug_callback_data);
207 /* TODO
209 NOBUG_IF(NOBUG_USE_XXXX_TARGET ...
212 #if NOBUG_USE_PTHREAD
213 /* the resource tracker bails out with the resource lock held for logging it, we can release it here now */
214 if (nobug_resource_error)
216 nobug_resource_error = NULL;
217 NOBUG_RESOURCE_UNLOCK;
219 #endif
220 NOBUG_LOGGING_UNLOCK;
222 if (nobug_postlogging_callback)
223 nobug_postlogging_callback (flag, lvl, NULL, nobug_callback_data);
227 void
228 nobug_backtrace_glibc (const struct nobug_context context)
230 #ifdef HAVE_EXECINFO_H
231 void* nobug_backtrace_buffer[NOBUG_BACKTRACE_DEPTH];
233 int depth = backtrace (nobug_backtrace_buffer, NOBUG_BACKTRACE_DEPTH);
235 char** symbols = backtrace_symbols (nobug_backtrace_buffer, depth);
237 if (symbols)
239 /* start at [1] to suppress nobug_backtrace_glibc itself */
240 int i;
241 for (i = 1; i<depth; ++i)
242 nobug_log (&nobug_flag_NOBUG_ON, LOG_NOTICE, "BACKTRACE", context, " %s", symbols[i]);
244 free (symbols);
246 #endif
250 #if !NOBUG_USE_PTHREAD
251 static void* nobug_nothread_data = NULL;
253 void**
254 nobug_thread_data (void)
256 return &nobug_nothread_data;
259 #endif