Skip to content

Commit 0716421

Browse files
committed
replaces simplelog.c
1 parent 121e28e commit 0716421

File tree

1 file changed

+343
-0
lines changed

1 file changed

+343
-0
lines changed

src/simplelog.cxx

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
/** Simple logging facility.
2+
*
3+
* @file simplelog.c
4+
* @see simplelog.h
5+
6+
*
7+
* History:
8+
* - 29/10/2004 File created.
9+
*/
10+
11+
#include "simplelog.h"
12+
13+
//#define _GNU_SOURCE
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <stdarg.h>
17+
#include <time.h>
18+
#include <string.h>
19+
#include <pthread.h>
20+
21+
#include <Common/SimpleLog.h>
22+
23+
SimpleLog *theLog=NULL;
24+
25+
26+
void setSimpleLog(void *ptr) {
27+
theLog=(SimpleLog *)ptr;
28+
}
29+
30+
31+
/*************/
32+
/* Constants */
33+
/*************/
34+
#define SLOG_MAX_SIZE 300 /**< Maximum size of a formatted log message */
35+
36+
#define SLOG_STR_FATAL "[FATAL]" /**< String for severity FATAL */
37+
#define SLOG_STR_ERROR "[ERROR]" /**< String for severity ERROR */
38+
#define SLOG_STR_WARNING "[WARN] " /**< String for severity WARNING */
39+
#define SLOG_STR_INFO "[INFO] " /**< String for severity INFO */
40+
#define SLOG_STR_DEBUG "[DEBUG]" /**< String for severity DEBUG */
41+
#define SLOG_STR_UNKNOWN "[????] " /**< String for unknown severity */
42+
43+
44+
/********************/
45+
/* Global variables */
46+
/********************/
47+
int slog_no_debug=1; /**< DEBUG messages discarded if non-zero */
48+
FILE* slog_file=NULL; /**< Log file */
49+
int slog_file_opened=0; /**< set to 1 when file opened */
50+
int slog_file_options; /**< file creation options */
51+
char* slog_file_path; /**< file path */
52+
pthread_mutex_t mutex_log=PTHREAD_MUTEX_INITIALIZER; /**< Mutex so that only one thread can configure slog() at a time */
53+
void (*slog_exit)(void); /**< Callback for FATAL messages before exit() */
54+
55+
56+
/******************/
57+
/* Implementation */
58+
/******************/
59+
60+
/* create log file - uses slog_file_path and slog_file_options */
61+
static int slog_file_open();
62+
63+
64+
/** Format a log message.
65+
* @param buffer char buffer to store the message in.
66+
* @param size buffer size. Should be at least SLOG_MAX_SIZE.
67+
* @param severity message severity.
68+
* @param message message to format.
69+
* @param ap additionnal parameters (if message printf-like formatted).
70+
* @return 0 if success, or the number of characters discarded because buffer too small (-1 if unknown).
71+
*
72+
* buffer is filled with a formatted log message.
73+
*/
74+
int slog_vformat(char *buffer, size_t size, slog_Severity severity, const char *message, va_list ap){
75+
76+
const char *level_msg; /* message severity string */
77+
time_t now; /* time now */
78+
struct tm tm_str; /* time struct for now */
79+
int len; /* current message length */
80+
int len_available; /* number of characters left in buffer */
81+
int n; /* counter */
82+
83+
/* select string for message severity */
84+
switch (severity) {
85+
case SLOG_FATAL:
86+
level_msg=SLOG_STR_FATAL;
87+
break;
88+
case SLOG_ERROR:
89+
level_msg=SLOG_STR_ERROR;
90+
break;
91+
case SLOG_WARNING:
92+
level_msg=SLOG_STR_WARNING;
93+
break;
94+
case SLOG_INFO:
95+
level_msg=SLOG_STR_INFO;
96+
break;
97+
case SLOG_DEBUG:
98+
level_msg=SLOG_STR_DEBUG;
99+
break;
100+
default:
101+
level_msg=SLOG_STR_UNKNOWN;
102+
break;
103+
}
104+
105+
/* format message timestamp */
106+
now = time(NULL);
107+
localtime_r(&now,&tm_str);
108+
len=strftime(buffer, size, "%Y-%m-%d %T ", &tm_str);
109+
if ((len>=(int)size)||(len<=0)) return -1;
110+
snprintf(&buffer[len],size-len,"%s ",level_msg);
111+
len+=strlen(level_msg)+1;
112+
113+
/* keep space for \n */
114+
len_available = size-len-1;
115+
if (len_available<=0) return -1;
116+
117+
/* Format message */
118+
n=vsnprintf(&buffer[len],len_available,message,ap);
119+
120+
/* Add return char if none */
121+
len=strlen(buffer);
122+
if (buffer[len-1]!='\n') {
123+
sprintf(&buffer[len],"\n");
124+
}
125+
126+
/* return missing space, or -1 if unknown */
127+
if (n<0) return -1;
128+
if (n>=len_available) return (n-len_available+1);
129+
return 0;
130+
}
131+
132+
133+
/** Format a log message.
134+
* @param buffer char buffer to store the message in.
135+
* @param size buffer size. Should be at least SLOG_MAX_SIZE.
136+
* @param severity message severity.
137+
* @param message message to format.
138+
* @param .. additionnal parameters (if message printf-like formatted).
139+
* @return 0 if success, or the number of characters discarded because buffer too small (-1 if unknown).
140+
*
141+
* buffer is filled with a formatted log message.
142+
*/
143+
int slog_format(char *buffer, size_t size, slog_Severity severity, const char *message, ...){
144+
145+
int err; /* error code */
146+
va_list ap; /* list of additionnal params */
147+
148+
va_start(ap, message);
149+
err=slog_vformat(buffer,size,severity,message, ap);
150+
va_end(ap);
151+
return err;
152+
}
153+
154+
155+
/** Log a message.
156+
*/
157+
void slog(slog_Severity severity, const char *message, ...){
158+
159+
va_list ap; /* list of additionnal params */
160+
char buffer[SLOG_MAX_SIZE]; /* buffer to format message */
161+
int buffer_short; /* missing space in buffer */
162+
FILE *fp; /* output file */
163+
void (*checked_exit)(void); /* callback for FATAL messages */
164+
165+
/* skip debug messages if needed */
166+
if ((severity==SLOG_DEBUG) && slog_no_debug) return;
167+
168+
/* special handling - redirection to SimpleLog when available */
169+
if (theLog!=NULL) {
170+
va_start(ap, message);
171+
vsnprintf(buffer,sizeof(buffer),message,ap);
172+
va_end(ap);
173+
switch(severity) {
174+
case SLOG_WARNING:
175+
theLog->warning("%s",buffer);
176+
break;
177+
case SLOG_ERROR:
178+
case SLOG_FATAL:
179+
theLog->warning("%s",buffer);
180+
break;
181+
default:
182+
theLog->info("%s",buffer);
183+
break;
184+
}
185+
return;
186+
}
187+
188+
189+
/* format message */
190+
va_start(ap, message);
191+
buffer_short=slog_vformat(buffer,sizeof(buffer),severity,message,ap);
192+
va_end(ap);
193+
194+
/* CRITICAL SECTION - start */
195+
pthread_mutex_lock(&mutex_log);
196+
197+
/* create file if not done yet */
198+
if (slog_file_opened==0) {
199+
slog_file_open();
200+
}
201+
202+
fp=slog_file;
203+
if (fp==NULL) fp=stdout;
204+
205+
/* print message */
206+
fprintf(fp,"%s",buffer);
207+
208+
/* check if the buffer was big enough for the message */
209+
if (buffer_short) {
210+
slog_format(buffer,sizeof(buffer),SLOG_WARNING,"Last log truncated - %d bytes lost",buffer_short);
211+
fprintf(fp,"%s",buffer);
212+
}
213+
214+
/* flush file */
215+
fflush(fp);
216+
217+
/* exit on fatal messages */
218+
if (severity==SLOG_FATAL) {
219+
if (slog_exit!=NULL) {
220+
checked_exit=slog_exit;
221+
slog_exit=NULL; /* to avoid recursive calls of slog(FATAL) */
222+
checked_exit();
223+
}
224+
if (slog_file!=NULL) {
225+
slog_format(buffer,sizeof(buffer),SLOG_INFO,"Closing log file");
226+
fprintf(slog_file,"%s",buffer);
227+
fclose(slog_file);
228+
}
229+
exit(1);
230+
}
231+
232+
/* CRITICAL SECTION - end */
233+
pthread_mutex_unlock(&mutex_log);
234+
235+
return;
236+
}
237+
238+
239+
/** Turns on logging of debugging messages.
240+
*/
241+
void slog_debug_on(){
242+
pthread_mutex_lock(&mutex_log);
243+
slog_no_debug=0;
244+
pthread_mutex_unlock(&mutex_log);
245+
}
246+
247+
248+
/** Turns off logging of debugging messages. This is the default mode.
249+
*/
250+
void slog_debug_off(){
251+
pthread_mutex_lock(&mutex_log);
252+
slog_no_debug=1;
253+
pthread_mutex_unlock(&mutex_log);
254+
}
255+
256+
257+
258+
/* uses slog_file_options */
259+
static int slog_file_open() {
260+
char buffer[SLOG_MAX_SIZE]; /* buffer for log messages */
261+
int err=0; /* error code */
262+
263+
/* Open new log file */
264+
if (slog_file_path!=NULL) {
265+
if (slog_file_options & SLOG_FILE_OPT_CLEAR_IF_EXISTS) {
266+
slog_file=fopen(slog_file_path,"w");
267+
} else {
268+
slog_file=fopen(slog_file_path,"a");
269+
}
270+
if (slog_file==NULL) err=-1;
271+
}
272+
273+
/* Info on the new log file */
274+
if (err==-1) {
275+
slog_format(buffer,sizeof(buffer),SLOG_ERROR,"Could not open log file %s, using stdout",slog_file_path);
276+
fprintf(stdout,"%s",buffer);
277+
fflush(stdout);
278+
} else {
279+
if (slog_file!=NULL) {
280+
slog_format(buffer,sizeof(buffer),SLOG_INFO,"Opening log file");
281+
fprintf(slog_file,"%s",buffer);
282+
fflush(slog_file);
283+
}
284+
}
285+
286+
slog_file_opened=1;
287+
return err;
288+
}
289+
290+
291+
292+
/** Set file where log messages are written. By default, stdout is used.
293+
*/
294+
int slog_set_file(char *file, int options){
295+
char buffer[SLOG_MAX_SIZE]; /* buffer for log messages */
296+
int err=0; /* error code */
297+
298+
/* CRITICAL SECTION - start */
299+
pthread_mutex_lock(&mutex_log);
300+
301+
if ((options & SLOG_FILE_OPT_IF_UNSET) && (slog_file!=NULL)) {
302+
pthread_mutex_unlock(&mutex_log);
303+
return err;
304+
}
305+
306+
/* First close existing file */
307+
if (slog_file!=NULL) {
308+
slog_format(buffer,sizeof(buffer),SLOG_INFO,"Closing log file");
309+
fprintf(slog_file,"%s",buffer);
310+
fclose(slog_file);
311+
slog_file=NULL;
312+
}
313+
slog_file_opened=0;
314+
slog_file_options=options;
315+
if (slog_file_path!=NULL) {
316+
free(slog_file_path);
317+
slog_file_path=NULL;
318+
}
319+
320+
if (file!=NULL) {
321+
if (strlen(file)!=0) {
322+
slog_file_path=strdup(file);
323+
}
324+
}
325+
326+
if (!(options & SLOG_FILE_OPT_DONT_CREATE_NOW)) {
327+
err=slog_file_open();
328+
}
329+
330+
/* CRITICAL SECTION - end */
331+
pthread_mutex_unlock(&mutex_log);
332+
333+
return err;
334+
}
335+
336+
337+
/** Define callback function to be called before exiting, when a FATAL message is received.
338+
*/
339+
void slog_set_exit(void (*callback)(void )) {
340+
pthread_mutex_lock(&mutex_log);
341+
slog_exit=callback;
342+
pthread_mutex_unlock(&mutex_log);
343+
}

0 commit comments

Comments
 (0)