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
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;;
41 //predefflags There are some debugging flags which are predefined by NoBug.
43 //predefflags PARA NOBUG_ON; NOBUG_ON; log flag which is always enabled
45 //predefflags The flag `NOBUG_ON` is always enabled at LOG_DEBUG level. This is
46 //predefflags static and can not be changed.
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
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.
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
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`.
72 struct nobug_flag nobug_flag_nobug
=
73 {"nobug", NULL
, 0, {LOG_DEBUG
, LOG_WARNING
, LOG_ERR
, LOG_ERR
, -1}, NULL
, NULL
, NULL
};
78 nobug_tls_free (void * tls
)
80 free((void*)((struct nobug_tls_data
*)tls
)->thread_id
);
86 default initialization
88 static volatile int nobug_initialized
= 0;
91 nobug_init (const struct nobug_context context
)
93 if (nobug_initialized
)
95 nobug_initialized
= 1;
98 pthread_key_create (&nobug_tls_key
, nobug_tls_free
);
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");
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
);
141 nobug_initialized
= 0;
146 nobug_basename (const char* const file
)
148 return strrchr(file
, '/') ? strrchr(file
, '/') + 1 : file
;
153 nobug_log (struct nobug_flag
* flag
, int lvl
, const char* what
, const struct nobug_context ctx
, const char* fmt
, ...)
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
169 nobug_basename(ctx
.file
),
171 #if NOBUG_USE_PTHREAD
172 nobug_thread_id_get(),
175 nobug_ringbuffer_append (flag
->ringbuffer_target
);
179 nobug_ringbuffer_vprintf (flag
->ringbuffer_target
, fmt
, ap
);
182 if (NOBUG_EXPECT_FALSE(lvl
<= flag
->limits
[NOBUG_TARGET_CONSOLE
]))
185 if (NOBUG_EXPECT_FALSE (NOBUG_ACTIVE_DBG
== NOBUG_DBG_VALGRIND
))
187 VALGRIND_PRINTF ("%s"VALGRIND_NEWLINE
, log
);
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
);
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
;
220 NOBUG_LOGGING_UNLOCK
;
222 if (nobug_postlogging_callback
)
223 nobug_postlogging_callback (flag
, lvl
, NULL
, nobug_callback_data
);
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
);
239 /* start at [1] to suppress nobug_backtrace_glibc itself */
241 for (i
= 1; i
<depth
; ++i
)
242 nobug_log (&nobug_flag_NOBUG_ON
, LOG_NOTICE
, "BACKTRACE", context
, " %s", symbols
[i
]);
250 #if !NOBUG_USE_PTHREAD
251 static void* nobug_nothread_data
= NULL
;
254 nobug_thread_data (void)
256 return &nobug_nothread_data
;