2 This file is part of the NoBug debugging library.
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>.
25 #define NOBUG_LIBNOBUG_C
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;;
40 //predefflags There are some debugging flags which are predefined by NoBug.
42 //predefflags PARA NOBUG_ON; NOBUG_ON; log flag which is always enabled
44 //predefflags The flag `NOBUG_ON` is always enabled at LOG_DEBUG level. This is
45 //predefflags static and can not be changed.
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
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.
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; nobugflag; log flag used to show nobug actions
66 //predefflags Actions on NoBug itself will be logged under the `nobug` flag itself.
67 //predefflags To see whats going on you can enable it with `NOBUG_LOG=nobug:TRACE`.
68 //predefflags This is particulary useful to check if `NOBUG_INIT_FLAG()` is called on all flags.
71 struct nobug_flag nobug_flag_nobug
=
72 {"nobug", NULL
, 0, {LOG_DEBUG
, LOG_WARNING
, LOG_ERR
, LOG_ERR
, -1}, NULL
, NULL
, NULL
};
77 nobug_tls_free (void * tls
)
79 free((void*)((struct nobug_tls_data
*)tls
)->thread_id
);
85 default initialization
87 static int nobug_initialized
= 0;
90 nobug_init (const struct nobug_context context
)
92 if (nobug_initialized
)
94 nobug_initialized
= 1;
97 pthread_key_create (&nobug_tls_key
, nobug_tls_free
);
100 /* we initialize a minimal ringbuffer, if not already done */
101 if (!nobug_default_ringbuffer
.start
)
102 nobug_ringbuffer_init (&nobug_default_ringbuffer
, 4096, 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
, context
);
119 nobug_log (&nobug_flag_nobug
, LOG_NOTICE
, "NOBUG", context
, " INITIALIZED");
121 nobug_coverage_init (context
);
126 nobug_destroy (const struct nobug_context context
)
128 if (nobug_initialized
)
130 nobug_log (&nobug_flag_nobug
, LOG_NOTICE
, "NOBUG" , context
, " DESTROYING");
132 nobug_resource_destroy ();
134 if (nobug_default_ringbuffer
.start
)
135 nobug_ringbuffer_destroy (&nobug_default_ringbuffer
);
137 #if NOBUG_USE_PTHREAD
138 nobug_tls_free (nobug_thread_get ());
139 pthread_key_delete (nobug_tls_key
);
142 nobug_initialized
= 0;
147 nobug_basename (const char* const file
)
149 return strrchr(file
, '/') ? strrchr(file
, '/') + 1 : file
;
154 nobug_log_targets (const char* start
, struct nobug_flag
* flag
, int lvl
)
156 if (NOBUG_EXPECT_FALSE(lvl
<= flag
->limits
[NOBUG_TARGET_CONSOLE
]))
159 if (NOBUG_EXPECT_FALSE (NOBUG_ACTIVE_DBG
== NOBUG_DBG_VALGRIND
))
161 VALGRIND_PRINTF ("%s"VALGRIND_NEWLINE
, start
);
165 fprintf (flag
->console_target
?flag
->console_target
:stderr
, "%s\n", start
);
168 if (NOBUG_EXPECT_FALSE(lvl
<= flag
->limits
[NOBUG_TARGET_FILE
] && flag
->file_target
))
170 fprintf (flag
->file_target
, "%s\n", start
);
173 if (NOBUG_EXPECT_FALSE(lvl
<= flag
->limits
[NOBUG_TARGET_SYSLOG
]))
175 syslog (lvl
, "%s\n", start
);
178 if (nobug_logging_callback
)
179 nobug_logging_callback (flag
, lvl
, start
, nobug_callback_data
);
184 nobug_log_va_ (char* start
, char* header
, struct nobug_flag
* flag
, int lvl
, const char* fmt
, va_list ap
)
186 nobug_ringbuffer_printf (flag
->ringbuffer_target
, "%s", header
);
187 nobug_ringbuffer_append (flag
->ringbuffer_target
);
189 nobug_ringbuffer_vprintf (flag
->ringbuffer_target
, fmt
, ap
);
191 char* lines_in
[NOBUG_MAX_LOG_LINES
];
192 char* lines_out
[NOBUG_MAX_LOG_LINES
];
193 lines_in
[0] = lines_out
[0] = start
-1;
196 while (n
<NOBUG_MAX_LOG_LINES
-1 &&(lines_in
[n
] = strchr(lines_in
[n
-1]+1, '\n')))
201 lines_in
[n
] = lines_in
[n
-1] + strlen(lines_in
[n
-1]+1) + 1;
203 size_t newlen
= lines_in
[n
]-lines_in
[0] - 1 + (strlen (header
)+1) * (n
-1);
205 if (nobug_ringbuffer_extend (flag
->ringbuffer_target
, newlen
, 0))
209 size_t headerlen
= strlen(header
);
211 for (int i
= n
-1; i
>0; --i
)
213 size_t len
= lines_in
[i
+1] - lines_in
[i
] - 1;
214 char* dst
= start
+newlen
-len
;
216 memmove (dst
, lines_in
[i
]+1, len
);
219 dst
-= (headerlen
+1);
221 memmove (dst
, header
, headerlen
);
224 lines_out
[i
] = dst
-1;
225 newlen
-= (len
+headerlen
+2);
230 for (int i
= 0; i
< n
; ++i
)
231 nobug_log_targets (lines_out
[i
]+1, flag
, lvl
);
236 nobug_log_begin (char* header
, struct nobug_flag
* flag
, const char* what
, const struct nobug_context ctx
)
238 #if NOBUG_USE_PTHREAD
239 pthread_mutex_lock (&nobug_logging_mutex
);
242 snprintf (header
, NOBUG_MAX_LOG_HEADER_SIZE
, "%.10llu: %s: %s:%d: "
243 #if NOBUG_USE_PTHREAD
246 "-: " /*no thread id*/
251 nobug_basename(ctx
.file
),
253 #if NOBUG_USE_PTHREAD
254 nobug_thread_id_get(),
258 return nobug_ringbuffer_pos (flag
->ringbuffer_target
);
263 nobug_log_end (struct nobug_flag
* flag
, int lvl
)
265 #if NOBUG_USE_PTHREAD
266 /* the resource tracker bails out with the resource lock held for logging it, we can release it here now */
267 if (nobug_resource_error
)
269 nobug_resource_error
= NULL
;
270 pthread_mutex_unlock (&nobug_resource_mutex
);
273 pthread_mutex_unlock (&nobug_logging_mutex
);
276 if (nobug_postlogging_callback
)
277 nobug_postlogging_callback (flag
, lvl
, NULL
, nobug_callback_data
);
280 /* must be called inbetween log_begin and log_end */
282 nobug_log_line (char** start
, char* header
, struct nobug_flag
* flag
, int lvl
, const char* fmt
, ...)
286 nobug_log_va_ (*start
, header
, flag
, lvl
, fmt
, ap
);
289 *start
= nobug_ringbuffer_pos (flag
->ringbuffer_target
);
294 nobug_log (struct nobug_flag
* flag
, int lvl
, const char* what
, const struct nobug_context ctx
, const char* fmt
, ...)
296 char header
[NOBUG_MAX_LOG_HEADER_SIZE
];
298 char* start
= nobug_log_begin (header
, flag
, what
, ctx
);
302 nobug_log_va_ (start
, header
, flag
, lvl
, fmt
, ap
);
305 nobug_log_end (flag
, lvl
);
310 nobug_backtrace_glibc (const struct nobug_context context
)
312 #ifdef HAVE_EXECINFO_H
313 void* nobug_backtrace_buffer
[NOBUG_BACKTRACE_DEPTH
];
315 int depth
= backtrace (nobug_backtrace_buffer
, NOBUG_BACKTRACE_DEPTH
);
317 char** symbols
= backtrace_symbols (nobug_backtrace_buffer
, depth
);
321 /* start at [1] to suppress nobug_backtrace_glibc itself */
323 for (i
= 1; i
<depth
; ++i
)
324 nobug_log (&nobug_flag_NOBUG_ON
, LOG_NOTICE
, "BACKTRACE", context
, " %s", symbols
[i
]);
332 nobug_backtrace_valgrind (const struct nobug_context context
)
334 #if NOBUG_USE_VALGRIND
335 #if NOBUG_USE_PTHREAD
336 pthread_mutex_lock (&nobug_logging_mutex
);
338 VALGRIND_PRINTF_BACKTRACE("----------: BACKTRACE: %s@%d %s",
339 nobug_basename(context
.file
),
342 #if NOBUG_USE_PTHREAD
343 pthread_mutex_unlock (&nobug_logging_mutex
);