1 /***************************************************************************
2 * logging.c
3 *
4 * Log handling routines for libmseed
5 *
6 * Chad Trabant
7 * IRIS Data Management Center
8 *
9 * modified: 2014.197
10 ***************************************************************************/
11
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "libmseed.h"
18
19 void ms_loginit_main (MSLogParam *logp,
20 void (*log_print) (char *), const char *logprefix,
21 void (*diag_print) (char *), const char *errprefix);
22
23 int ms_log_main (MSLogParam *logp, int level, va_list *varlist);
24
25 /* Initialize the global logging parameters */
26 MSLogParam gMSLogParam = {NULL, NULL, NULL, NULL};
27
28 /***************************************************************************
29 * ms_loginit:
30 *
31 * Initialize the global logging parameters.
32 *
33 * See ms_loginit_main() description for usage.
34 ***************************************************************************/
35 void
ms_loginit(void (* log_print)(char *),const char * logprefix,void (* diag_print)(char *),const char * errprefix)36 ms_loginit (void (*log_print) (char *), const char *logprefix,
37 void (*diag_print) (char *), const char *errprefix)
38 {
39 ms_loginit_main (&gMSLogParam, log_print, logprefix, diag_print, errprefix);
40 } /* End of ms_loginit() */
41
42 /***************************************************************************
43 * ms_loginit_l:
44 *
45 * Initialize MSLogParam specific logging parameters. If the logging parameters
46 * have not been initialized (log == NULL) new parameter space will
47 * be allocated.
48 *
49 * See ms_loginit_main() description for usage.
50 *
51 * Returns a pointer to the created/re-initialized MSLogParam struct
52 * on success and NULL on error.
53 ***************************************************************************/
54 MSLogParam *
ms_loginit_l(MSLogParam * logp,void (* log_print)(char *),const char * logprefix,void (* diag_print)(char *),const char * errprefix)55 ms_loginit_l (MSLogParam *logp,
56 void (*log_print) (char *), const char *logprefix,
57 void (*diag_print) (char *), const char *errprefix)
58 {
59 MSLogParam *llog;
60
61 if (logp == NULL)
62 {
63 llog = (MSLogParam *)malloc (sizeof (MSLogParam));
64
65 if (llog == NULL)
66 {
67 ms_log (2, "ms_loginit_l(): Cannot allocate memory\n");
68 return NULL;
69 }
70
71 llog->log_print = NULL;
72 llog->logprefix = NULL;
73 llog->diag_print = NULL;
74 llog->errprefix = NULL;
75 }
76 else
77 {
78 llog = logp;
79 }
80
81 ms_loginit_main (llog, log_print, logprefix, diag_print, errprefix);
82
83 return llog;
84 } /* End of ms_loginit_l() */
85
86 /***************************************************************************
87 * ms_loginit_main:
88 *
89 * Initialize the logging subsystem. Given values determine how ms_log()
90 * and ms_log_l() emit messages.
91 *
92 * This function modifies the logging parameters in the passed MSLogParam.
93 *
94 * Any log/error printing functions indicated must except a single
95 * argument, namely a string (char *). The ms_log() and
96 * ms_log_r() functions format each message and then pass the result
97 * on to the log/error printing functions.
98 *
99 * If the log/error prefixes have been set they will be pre-pended to the
100 * message.
101 *
102 * Use NULL for the function pointers or the prefixes if they should not
103 * be changed from previously set or default values. The default behavior
104 * of the logging subsystem is given in the example below.
105 *
106 * Example: ms_loginit_main (0, (void*)&printf, NULL, (void*)&printf, "error: ");
107 ***************************************************************************/
108 void
ms_loginit_main(MSLogParam * logp,void (* log_print)(char *),const char * logprefix,void (* diag_print)(char *),const char * errprefix)109 ms_loginit_main (MSLogParam *logp,
110 void (*log_print) (char *), const char *logprefix,
111 void (*diag_print) (char *), const char *errprefix)
112 {
113 if (!logp)
114 return;
115
116 if (log_print)
117 logp->log_print = log_print;
118
119 if (logprefix)
120 {
121 if (strlen (logprefix) >= MAX_LOG_MSG_LENGTH)
122 {
123 ms_log_l (logp, 2, 0, "log message prefix is too large\n");
124 }
125 else
126 {
127 logp->logprefix = logprefix;
128 }
129 }
130
131 if (diag_print)
132 logp->diag_print = diag_print;
133
134 if (errprefix)
135 {
136 if (strlen (errprefix) >= MAX_LOG_MSG_LENGTH)
137 {
138 ms_log_l (logp, 2, 0, "error message prefix is too large\n");
139 }
140 else
141 {
142 logp->errprefix = errprefix;
143 }
144 }
145
146 return;
147 } /* End of ms_loginit_main() */
148
149 /***************************************************************************
150 * ms_log:
151 *
152 * A wrapper to ms_log_main() that uses the global logging parameters.
153 *
154 * See ms_log_main() description for return values.
155 ***************************************************************************/
156 int
ms_log(int level,...)157 ms_log (int level, ...)
158 {
159 int retval;
160 va_list varlist;
161
162 va_start (varlist, level);
163
164 retval = ms_log_main (&gMSLogParam, level, &varlist);
165
166 va_end (varlist);
167
168 return retval;
169 } /* End of ms_log() */
170
171 /***************************************************************************
172 * ms_log_l:
173 *
174 * A wrapper to ms_log_main() that uses the logging parameters in a
175 * supplied MSLogParam. If the supplied pointer is NULL the global logging
176 * parameters will be used.
177 *
178 * See ms_log_main() description for return values.
179 ***************************************************************************/
180 int
ms_log_l(MSLogParam * logp,int level,...)181 ms_log_l (MSLogParam *logp, int level, ...)
182 {
183 int retval;
184 va_list varlist;
185 MSLogParam *llog;
186
187 if (!logp)
188 llog = &gMSLogParam;
189 else
190 llog = logp;
191
192 va_start (varlist, level);
193
194 retval = ms_log_main (llog, level, &varlist);
195
196 va_end (varlist);
197
198 return retval;
199 } /* End of ms_log_l() */
200
201 /***************************************************************************
202 * ms_log_main:
203 *
204 * A standard logging/printing routine.
205 *
206 * The function uses logging parameters specified in the supplied
207 * MSLogParam.
208 *
209 * This function expects 2+ arguments: message level, fprintf format,
210 * and fprintf arguments.
211 *
212 * Three levels are recognized:
213 * 0 : Normal log messages, printed using log_print with logprefix
214 * 1 : Diagnostic messages, printed using diag_print with logprefix
215 * 2+ : Error messagess, printed using diag_print with errprefix
216 *
217 * This function builds the log/error message and passes to it as a
218 * string (char *) to the functions defined with ms_loginit() or
219 * ms_loginit_l(). If the log/error printing functions have not been
220 * defined messages will be printed with fprintf, log messages to
221 * stdout and error messages to stderr.
222 *
223 * If the log/error prefix's have been set with ms_loginit() or
224 * ms_loginit_l() they will be pre-pended to the message.
225 *
226 * All messages will be truncated to the MAX_LOG_MSG_LENGTH, this includes
227 * any set prefix.
228 *
229 * Returns the number of characters formatted on success, and a
230 * a negative value on error.
231 ***************************************************************************/
232 int
ms_log_main(MSLogParam * logp,int level,va_list * varlist)233 ms_log_main (MSLogParam *logp, int level, va_list *varlist)
234 {
235 static char message[MAX_LOG_MSG_LENGTH];
236 int retvalue = 0;
237 int presize;
238 const char *format;
239
240 if (!logp)
241 {
242 fprintf (stderr, "ms_log_main() called without specifying log parameters");
243 return -1;
244 }
245
246 message[0] = '\0';
247
248 format = va_arg (*varlist, const char *);
249
250 if (level >= 2) /* Error message */
251 {
252 if (logp->errprefix != NULL)
253 {
254 strncpy (message, logp->errprefix, MAX_LOG_MSG_LENGTH);
255 message[MAX_LOG_MSG_LENGTH - 1] = '\0';
256 }
257 else
258 {
259 strncpy (message, "Error: ", MAX_LOG_MSG_LENGTH);
260 }
261
262 presize = strlen (message);
263 retvalue = vsnprintf (&message[presize],
264 MAX_LOG_MSG_LENGTH - presize,
265 format, *varlist);
266
267 message[MAX_LOG_MSG_LENGTH - 1] = '\0';
268
269 if (logp->diag_print != NULL)
270 {
271 logp->diag_print (message);
272 }
273 else
274 {
275 fprintf (stderr, "%s", message);
276 }
277 }
278 else if (level == 1) /* Diagnostic message */
279 {
280 if (logp->logprefix != NULL)
281 {
282 strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
283 message[MAX_LOG_MSG_LENGTH - 1] = '\0';
284 }
285
286 presize = strlen (message);
287 retvalue = vsnprintf (&message[presize],
288 MAX_LOG_MSG_LENGTH - presize,
289 format, *varlist);
290
291 message[MAX_LOG_MSG_LENGTH - 1] = '\0';
292
293 if (logp->diag_print != NULL)
294 {
295 logp->diag_print (message);
296 }
297 else
298 {
299 fprintf (stderr, "%s", message);
300 }
301 }
302 else if (level == 0) /* Normal log message */
303 {
304 if (logp->logprefix != NULL)
305 {
306 strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
307 message[MAX_LOG_MSG_LENGTH - 1] = '\0';
308 }
309
310 presize = strlen (message);
311 retvalue = vsnprintf (&message[presize],
312 MAX_LOG_MSG_LENGTH - presize,
313 format, *varlist);
314
315 message[MAX_LOG_MSG_LENGTH - 1] = '\0';
316
317 if (logp->log_print != NULL)
318 {
319 logp->log_print (message);
320 }
321 else
322 {
323 fprintf (stdout, "%s", message);
324 }
325 }
326
327 return retvalue;
328 } /* End of ms_log_main() */
329