File: log.c

package info (click to toggle)
gkrellm 2.3.5-3
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 4,552 kB
  • sloc: ansic: 56,915; makefile: 729; sh: 264
file content (309 lines) | stat: -rw-r--r-- 7,892 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/* GKrellM
|  Copyright (C) 1999-2010 Bill Wilson
|
|  Author:  Stefan Gehn    stefan+gkrellm@srcbox.net
|  Latest versions might be found at:  http://gkrellm.net
|
|
|  GKrellM is free software: you can redistribute it and/or modify it
|  under the terms of the GNU General Public License as published by
|  the Free Software Foundation, either version 3 of the License, or
|  (at your option) any later version.
|
|  GKrellM is distributed in the hope that it will be useful, but WITHOUT
|  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|  License for more details.
|
|  You should have received a copy of the GNU General Public License
|  along with this program. If not, see http://www.gnu.org/licenses/
|
|
|  Additional permission under GNU GPL version 3 section 7
|
|  If you modify this program, or any covered work, by linking or
|  combining it with the OpenSSL project's OpenSSL library (or a
|  modified version of that library), containing parts covered by
|  the terms of the OpenSSL or SSLeay licenses, you are granted
|  additional permission to convey the resulting work.
|  Corresponding Source for a non-source form of such a combination
|  shall include the source code for the parts of OpenSSL used as well
|  as that of the covered work.
*/

/*
Wanted logic:

- g_print for user-visible messages, --version and --help fall into this category.
  g_print usage should be kept at a minimum because
  gkrellm is a gui-app, while gkrellmd is a daemon. Neither of them is suited
  for terminal-interaction.

- gkrellm_debug(DEBUG_FOO, "msg"); for all debug messages.

- g_warning("msg") for all failed function calls etc.

Output should go to:
  - g_print        : gui-window or stdout where applicable
  - gkrellm_debug  : gui-window or logfile if set
  - gkrellm_warning: gui-window or logfile if set
  */


#include "log.h"
#include "log-private.h"

#include <stdio.h>

// Include gkrellm headers to access _GK struct inside gkrellm_debug()
#if defined(GKRELLM_SERVER)
	#include "../server/gkrellmd.h"
	#include "../server/gkrellmd-private.h"
#else
	#include "../src/gkrellm.h"
	#include "../src/gkrellm-private.h"
#endif

typedef struct _GkrellmLogFacility
{
	GkrellmLogFunc log;
	GkrellmLogCleanupFunc cleanup;
} GkrellmLogFacility;

static GPtrArray *s_log_facility_ptr_array = NULL;


// ----------------------------------------------------------------------------
// Logging into a logfile

/**
 * Handle to a logfile.
 * Set by gkrellm_log_set_filename() and used by gkrellm_log_to_file()
 **/
static FILE *s_gkrellm_logfile = NULL;

static gboolean
gkrellm_log_file_cleanup()
	{
	if (s_gkrellm_logfile)
		fclose(s_gkrellm_logfile);
	s_gkrellm_logfile = NULL;
	return TRUE;
	}

static void
gkrellm_log_file_log(GLogLevelFlags log_level, const gchar *message)
	{
	time_t raw_time;
	char *local_time_str;

	if (!s_gkrellm_logfile)
		return;

	// Prepend log message with current date/time
	time(&raw_time);
	local_time_str = ctime(&raw_time);
	local_time_str[24] = ' '; // overwrite newline with space
	fputs(local_time_str, s_gkrellm_logfile);

	fputs(message, s_gkrellm_logfile);
	fflush(s_gkrellm_logfile);
	}

void
gkrellm_log_set_filename(const gchar* filename)
	{
	// Remove from logging chain if we already had been registered before
	// This also cleans up an open logfile.
	gkrellm_log_unregister(gkrellm_log_file_log);

	if (filename && filename[0] != '\0')
		{
		// Open the file to log into
		s_gkrellm_logfile = g_fopen(filename, "at");
		// Add our callbacks to logging chain
		if (s_gkrellm_logfile)
			{
			gkrellm_log_register(gkrellm_log_file_log, NULL,
				gkrellm_log_file_cleanup);
			}
		}
	}


// ----------------------------------------------------------------------------

//! Logs onto stdout/stderr
static void
gkrellm_log_to_terminal(GLogLevelFlags log_level, const gchar *message)
	{
	// warning, error or critical go to stderr
	if (log_level & G_LOG_LEVEL_WARNING
		|| log_level & G_LOG_LEVEL_CRITICAL
		|| log_level & G_LOG_LEVEL_ERROR)
		{
		fputs(message, stderr);
		return;
		}
#if defined(WIN32)
	// debug on windows gets special treatment
	if (log_level & G_LOG_LEVEL_DEBUG)
		OutputDebugStringA(message);
#endif
	// Everything also ends up on stdout
	// (may be invisible on most desktop-systems, especially on windows!)
	fputs(message, stdout);
	}


// ----------------------------------------------------------------------------

//! Handler that receives all the log-messages first
static void
gkrellm_log_handler(const gchar *log_domain, GLogLevelFlags log_level,
	const gchar *message, gpointer user_data)
	{
	gchar *localized_message;
	gint i;
	GkrellmLogFacility *f;

	localized_message = g_locale_from_utf8(message, -1, NULL, NULL, NULL);
	if (localized_message == NULL)
		{
		for (i = 0; i < s_log_facility_ptr_array->len; i++)
			{
			f = (g_ptr_array_index(s_log_facility_ptr_array, i));
			f->log(log_level, message);
			}
		}
	else
		{
		for (i = 0; i < s_log_facility_ptr_array->len; i++)
			{
			f = (g_ptr_array_index(s_log_facility_ptr_array, i));
			f->log(log_level, localized_message);
			}

		g_free(localized_message);
		}
	}


// ----------------------------------------------------------------------------
// Non-Static functions that can be used in gkrellm

void
gkrellm_log_init()
	{
	if (s_log_facility_ptr_array)
		return; // already initialized
	s_log_facility_ptr_array = g_ptr_array_new();
	g_log_set_handler (NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL
		| G_LOG_FLAG_RECURSION, gkrellm_log_handler, NULL);
	gkrellm_log_register(gkrellm_log_to_terminal, NULL, NULL);
	}

void
gkrellm_log_cleanup()
	{
	gint i;
	GkrellmLogFacility *f;

	if (!s_log_facility_ptr_array)
		return; // gkrellm_log_init() not called yet

	// Call cleanup on all log-facilities and free our internal struct
	for (i = 0; i < s_log_facility_ptr_array->len; i++)
		{
		f = (g_ptr_array_index(s_log_facility_ptr_array, i));
		if (f->cleanup != NULL)
			f->cleanup();
		g_free(f);
		}
	g_ptr_array_free(s_log_facility_ptr_array, TRUE);
	s_log_facility_ptr_array = NULL;
	}

gboolean
gkrellm_log_register(
	GkrellmLogFunc log,
	GkrellmLogInitFunc init,
	GkrellmLogCleanupFunc cleanup)
	{
	GkrellmLogFacility *f;
	gint i;

	if (!s_log_facility_ptr_array)
		return FALSE; // gkrellm_log_init() not called yet

	// Check if log callback is already regisrered
	for (i = 0; i < s_log_facility_ptr_array->len; i++)
		{
		f = (g_ptr_array_index(s_log_facility_ptr_array, i));
		if (f->log == log)
			return TRUE;
		}

	if (init != NULL && init() == FALSE)
		return FALSE;

	// remember logging function and cleanup function in a struct
	f = g_new0(GkrellmLogFacility, 1);
	f->log = log;
	f->cleanup = cleanup;

	// add struct to list of log facilities
	g_ptr_array_add(s_log_facility_ptr_array, (gpointer)f);
	return TRUE;
	}

gboolean
gkrellm_log_unregister(GkrellmLogFunc log)
	{
	gint i;
	GkrellmLogFacility *f;

	if (!s_log_facility_ptr_array)
		return FALSE; // gkrellm_log_init() not called yet

	for (i = 0; i < s_log_facility_ptr_array->len; i++)
		{
		f = (g_ptr_array_index(s_log_facility_ptr_array, i));
		if (f->log == log)
			{
			if (f->cleanup != NULL)
				f->cleanup();
			g_ptr_array_remove_index(s_log_facility_ptr_array, i);
			g_free(f);
			return TRUE;
			}
		}
	return FALSE;
	}


// ----------------------------------------------------------------------------
// Public functions that can be used in gkrellm and plugins

void
gkrellm_debug(guint debug_level, const gchar *format, ...)
	{
	if (_GK.debug_level & debug_level)
		{
		va_list varargs;
		va_start(varargs, format);

		g_logv(NULL, G_LOG_LEVEL_DEBUG, format, varargs);

		va_end(varargs);
		}
	}

void
gkrellm_debugv(guint debug_level, const gchar *format, va_list arg)
	{
	if (_GK.debug_level & debug_level)
		{
		g_logv(NULL, G_LOG_LEVEL_DEBUG, format, arg);
		}
	}