12
#undef DS_LOG_SUPPORT_THREADS
14
#define DS_MAX_LOG_STRING 1024
15
#define DS_MAX_FORMAT_CHARS 32
17
static int ds_log_time = 0;
18
static int ds_log_thread = 0;
19
static int ds_log_level = ((G_LOG_LEVEL_DEBUG<<1) - 1)&G_LOG_LEVEL_MASK;
21
static int ds_log_exception_message = 1;
22
static int ds_exception_level = G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL;
23
static DSExceptionHandler ds_exception_handler = NULL;
25
static char printf_integer_keys[] = "diouxX";
26
static char printf_accepted_flags[] = "#0- +'I*$123456789.hlLqjzt";
28
#ifdef DS_LOG_SUPPORT_THREADS
29
GStaticMutex ds_log_mutex = G_STATIC_MUTEX_INIT;
30
#endif /* DS_LOG_SUPPORT_THREADS */
33
static void ds_log_handler_dummy(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) {
37
static void ds_log_handler_stderr(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) {
38
fprintf(stderr, "%s\n", message);
42
//static void (*ds_log_handler)(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) = ds_log_handler_stderr;
45
void ds_log_set_handler(GLogFunc handler, gpointer arg) {
46
g_log_set_default_handler(handler?handler:g_log_default_handler, arg);
49
void ds_log_set_level(GLogLevelFlags log_level) {
50
ds_log_level = ((log_level<<1) - 1)&G_LOG_LEVEL_MASK;
53
void ds_configure_logger(GLogLevelFlags log_level, const char *sink) {
54
ds_log_set_level(log_level);
55
// Ignoring at the moment
56
ds_log_set_handler(ds_log_handler_stderr, NULL);
59
void ds_log_enable_timestamps() {
63
void ds_log_enable_threads() {
67
void ds_log_configure_exception_handler(GLogLevelFlags log_level, DSExceptionHandler handler, int log_exception_message) {
68
ds_exception_level = log_level;
69
ds_exception_handler = handler;
70
ds_log_exception_message = log_exception_message;
74
void ds_log_set_domain_level(const gchar *log_domain, GLogLevelFlags log_level) {
75
ds_log_level = ((log_level<<1) - 1)&G_LOG_LEVEL_MASK;
76
//g_log_set_handler(log_domain, (~ds_log_level&G_LOG_LEVEL_MASK), &ds_log_handler_dummy);
79
void ds_log_set_domain_handler(const gchar *log_domain, GLogFunc handler, gpointer arg) {
82
id = g_log_set_handler(log_domain, G_LOG_LEVEL_MASK, handler, arg);
84
// assuming current implementation using sequential uid numbers starting from 1, the handler should not be set directly after that
85
if (id > 1) g_log_remove_handler(log_domain, id - 1);
88
int ds_configure_domain_logger(GLogLevelFlags log_level, const char *sink) {
89
ds_log_set_level(log_domain, log_level);
90
// Ignoring at the moment
91
ds_log_set_handler(log_domain, ds_log_handler_stderr, NULL);
95
void _ds_gen_message(int msglen, /* the buffer should be one byte longer for null termination */
100
const gchar *service,
110
int hoffset, moffset;
114
size_t length, prefixlength;
115
gchar *prefixptr, *ppos;
117
char subformat[DS_MAX_FORMAT_CHARS + 1] = "";
121
g_get_current_time(&ts);
123
if ((localtime_r(&ts.tv_sec, &t))&&(!gmtime_r(&ts.tv_sec, &gm))) {
124
offset = (t.tm_sec - gm.tm_sec) + 60*((t.tm_min - gm.tm_min) + 60*(t.tm_hour - gm.tm_hour));
125
if ((t.tm_mday != gm.tm_mday)||(t.tm_mon != gm.tm_mon)||(t.tm_year != gm.tm_year)) {
126
if (t.tm_year > gm.tm_year) offset += 86400;
127
else if (t.tm_year < gm.tm_year) offset -= 86400;
128
else if (t.tm_mon > gm.tm_mon) offset += 86400;
129
else if (t.tm_mon < gm.tm_mon) offset -= 86400;
130
else if (t.tm_mday > gm.tm_mday) offset += 86400;
131
else offset -= 86400;
134
g_snprintf(msg + pos, msglen - pos + 1,
135
"%04u-%02u-%02uT%02u:%02u:%02u.%07lu",
136
t.tm_year+1900,t.tm_mon+1,t.tm_mday,
137
t.tm_hour,t.tm_min,t.tm_sec,
141
pos += strlen(msg + pos);
143
if ((offset==0)&&(pos < msglen)) msg[pos++] = 'Z';
146
moffset=abs(offset/60-hoffset*60);
147
g_snprintf(msg + pos, msglen - pos + 1, "%+03i:%02u", hoffset, moffset);
148
pos += strlen(msg + pos);
151
g_snprintf(msg + pos, msglen - pos + 1,
152
"%04u-%02u-%02uT%02u:%02u:%02u.%07uZ",
157
pos += strlen(msg + pos);
159
if (pos < msglen) msg[pos++] = ' ';
164
if (ds_log_thread) g_snprintf(msg + pos, msglen - pos + 1, "%s(%p)", service, g_thread_self());
165
else g_snprintf(msg + pos, msglen - pos + 1, "%s", service);
166
pos += strlen(msg + pos);
170
if ((flag)&&(pos < msglen)) msg[pos++] = '/';
172
if (ptr) g_snprintf(msg + pos, msglen - pos + 1, "%s(%p): ", module, ptr);
173
else g_snprintf(msg + pos, msglen - pos + 1, "%s: ", module);
175
pos += strlen(msg + pos);
176
} else if ((flag)&&(pos < msglen)) msg[pos++] = '/';
180
#if (defined(_WIN32)||defined(_WIN64))
181
err = GetLastError();
189
for (ppos = strchr(prefix, '%');ppos;) {
190
length = strspn(ppos + 1, printf_accepted_flags) + 1;
191
if ((length < DS_MAX_FORMAT_CHARS)&&((ppos[length]=='s')||(strspn(ppos+length, printf_integer_keys)>0))) {
192
prefixlength = (ppos - prefixptr);
194
if ((msglen - pos) > prefixlength) g_strlcpy(msg + pos, prefixptr, prefixlength + 1);
195
else g_strlcpy(msg + pos, prefixptr, msglen - pos + 1);
196
pos += strlen(msg + pos);
199
if (ppos[length]=='s') g_vsnprintf(msg + pos, msglen - pos + 1, format, ap);
201
strncpy(subformat, ppos, length + 1); subformat[length + 1] = 0;
202
g_snprintf(msg + pos, msglen - pos + 1, subformat, err);
204
pos += strlen(msg + pos);
206
prefixptr = ppos + length + 1;
207
ppos = strchr(prefixptr, '%');
208
} else if (ppos[length]) {
209
ppos = strchr(ppos + length + 1, '%');
216
g_strlcpy(msg + pos, prefixptr, msglen - pos + 1);
217
pos += strlen(msg + pos);
221
#if (defined(_WIN32)||defined(_WIN64))
224
errmsg = g_strerror(err);
227
if (errmsg) g_snprintf(msg + pos, msglen - pos + 1, "Error %i(%s): ", err, errmsg);
228
else g_snprintf(msg + pos, msglen - pos + 1, "Error %i: ", err);
230
pos += strlen(msg + pos);
234
g_vsnprintf(msg + pos, msglen - pos + 1, format, ap);
236
pos += strlen(msg + pos);
241
if (func) g_snprintf(msg + pos, msglen - pos + 1, " <%s:%s:%u>", file, func, line);
242
else g_snprintf(msg + pos, msglen - pos + 1, " <%s:%u>", file, line);
243
pos += strlen(msg + pos);
246
// if (pos < msglen) msg[pos++] = '\n';
250
int _ds_log_message(int condition,
251
const gchar *log_domain,
252
GLogLevelFlags log_levels,
256
const gchar *service,
265
char msg[DS_MAX_LOG_STRING + 1] = "";
267
if (condition) return 0;
268
if ((ds_log_level&log_levels)==0) return 1;
270
va_start(ap, format);
271
_ds_gen_message(DS_MAX_LOG_STRING, msg, file, func, line, service, module, ptr, prefix, err, format, ap);
274
if (log_levels&DS_LOG_CLEAN_MESSAGE) {
275
if (prefix) g_free(prefix);
276
else if (format) g_free(format);
279
if ((!ds_exception_handler)||(log_levels&ds_exception_level==0)||(ds_log_exception_message)) {
280
#ifdef DS_LOG_SUPPORT_THREADS
281
g_static_mutex_lock(g_log_mutex);
282
#endif /* DS_LOG_SUPPORT_THREADS */
283
g_log(log_domain, log_levels&DS_LOG_LEVEL_MASK, msg);
284
#ifdef DS_LOG_SUPPORT_THREADS
285
g_static_mutex_unlock(g_log_mutex);
286
#endif /* DS_LOG_SUPPORT_THREADS */
289
if ((ds_exception_handler)&&(log_levels&ds_exception_level)) {
290
ds_exception_handler(err, msg);
293
if (log_levels&DS_LOG_FATAL_MESSAGE) {
294
if (file) g_error(" Program stops at %s:%u. Bye\n", file, line);
295
else g_error(" Program stops. Bye\n");