Annotation of freem/src/log.c, revision 1.13
1.1 snw 1: /*
1.13 ! snw 2: * $Id: log.c,v 1.12 2025/04/15 16:49:36 snw Exp $
1.4 snw 3: * freem error logging
1.1 snw 4: *
5: *
1.3 snw 6: * Author: Serena Willis <snw@coherent-logic.com>
1.1 snw 7: * Copyright (C) 1998 MUG Deutschland
1.4 snw 8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
1.1 snw 9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
1.5 snw 26: * $Log: log.c,v $
1.13 ! snw 27: * Revision 1.12 2025/04/15 16:49:36 snw
! 28: * Make use of logprintf throughout codebase
! 29: *
1.12 snw 30: * Revision 1.11 2025/04/15 14:56:20 snw
31: * Fix broken build due to missing declarations
32: *
1.11 snw 33: * Revision 1.10 2025/04/15 14:39:06 snw
34: * Further improvements to logging
35: *
1.10 snw 36: * Revision 1.9 2025/04/15 02:24:43 snw
37: * Improve FreeM logging capabilities
38: *
1.9 snw 39: * Revision 1.8 2025/04/04 02:12:25 snw
40: * Bump to 0.63.0-rc5 and make sure m_log function is never empty
41: *
1.8 snw 42: * Revision 1.7 2025/04/04 01:18:21 snw
43: * Remove vestigial logging code and bump to 0.63.0-rc4
44: *
1.7 snw 45: * Revision 1.6 2025/04/01 23:21:45 snw
46: * fmadm commands for stopping, starting, and restarting environments now functional
47: *
1.6 snw 48: * Revision 1.5 2025/04/01 20:11:46 snw
49: * Further work on fmadm
50: *
1.5 snw 51: * Revision 1.4 2025/03/09 19:50:47 snw
52: * Second phase of REUSE compliance and header reformat
53: *
1.4 snw 54: *
55: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
56: * SPDX-License-Identifier: AGPL-3.0-or-later
1.1 snw 57: **/
58:
59: #include <stdio.h>
60: #include <string.h>
1.2 snw 61: #if defined(__linux__) | defined(__FreeBSD__) | defined(__sun__)
1.1 snw 62: # include <syslog.h>
63: #endif
64: #include <stdlib.h>
1.9 snw 65: #include <stdarg.h>
1.12 snw 66: #include <unistd.h>
1.9 snw 67:
68: #if defined(USE_SYS_TIME_H) && !defined(MSDOS) && !defined(__osf__)
69: # include <sys/time.h>
70: #else
71: # include <time.h>
72: #endif
1.1 snw 73:
74: #include "mpsdef.h"
1.11 snw 75: #include "log.h" /* for logging constants */
76: #include "init.h" /* for cleanup() */
1.12 snw 77: #include "iniconf.h" /* for read_profile_string() */
1.1 snw 78:
1.10 snw 79: short log_threshold_file;
80: short log_threshold_syslog;
81: short log_threshold_stderr;
82:
83:
84: void init_log(void)
85: {
1.12 snw 86: char buf[4096];
87: char *env_value;
88:
89: if (read_profile_string (env_config_file, shm_env, "log_threshold_file", buf) == TRUE) {
90: if (strcmp (buf, "debug") == 0) {
91: log_threshold_file = FM_LOG_DEBUG;
92: }
93: else if (strcmp (buf, "info") == 0) {
94: log_threshold_file = FM_LOG_INFO;
95: }
96: else if (strcmp (buf, "warning") == 0) {
97: log_threshold_file = FM_LOG_WARNING;
98: }
99: else if (strcmp (buf, "error") == 0) {
100: log_threshold_file = FM_LOG_ERROR;
101: }
102: else if (strcmp (buf, "fatal") == 0) {
103: log_threshold_file = FM_LOG_FATAL;
104: }
105: else {
106: log_threshold_file = FM_LOG_INFO;
107: }
108: }
109: else {
110: log_threshold_file = FM_LOG_INFO;
111: }
112:
113: if (read_profile_string (env_config_file, shm_env, "log_threshold_syslog", buf) == TRUE) {
114: if (strcmp (buf, "debug") == 0) {
115: log_threshold_syslog = FM_LOG_DEBUG;
116: }
117: else if (strcmp (buf, "info") == 0) {
118: log_threshold_syslog = FM_LOG_INFO;
119: }
120: else if (strcmp (buf, "warning") == 0) {
121: log_threshold_syslog = FM_LOG_WARNING;
122: }
123: else if (strcmp (buf, "error") == 0) {
124: log_threshold_syslog = FM_LOG_ERROR;
125: }
126: else if (strcmp (buf, "fatal") == 0) {
127: log_threshold_syslog = FM_LOG_FATAL;
128: }
129: else {
130: log_threshold_syslog = FM_LOG_INFO;
131: }
132: }
133: else {
134: log_threshold_syslog = FM_LOG_INFO;
135: }
136:
137: if (read_profile_string (env_config_file, shm_env, "log_threshold_stderr", buf) == TRUE) {
138: if (strcmp (buf, "debug") == 0) {
139: log_threshold_stderr = FM_LOG_DEBUG;
140: }
141: else if (strcmp (buf, "info") == 0) {
142: log_threshold_stderr = FM_LOG_INFO;
143: }
144: else if (strcmp (buf, "warning") == 0) {
145: log_threshold_stderr = FM_LOG_WARNING;
146: }
147: else if (strcmp (buf, "error") == 0) {
148: log_threshold_stderr = FM_LOG_ERROR;
149: }
150: else if (strcmp (buf, "fatal") == 0) {
151: log_threshold_stderr = FM_LOG_FATAL;
152: }
153: else {
154: log_threshold_stderr = FM_LOG_INFO;
155: }
156: }
157: else {
158: log_threshold_stderr = FM_LOG_WARNING;
159: }
160:
161: if ((env_value = getenv ("FREEM_LOG_THRESHOLD_FILE")) != NULL) {
162: if (strcmp (env_value, "debug") == 0) {
163: log_threshold_file = FM_LOG_DEBUG;
164: }
165: else if (strcmp (env_value, "info") == 0) {
166: log_threshold_file = FM_LOG_INFO;
167: }
168: else if (strcmp (env_value, "warning") == 0) {
169: log_threshold_file = FM_LOG_WARNING;
170: }
171: else if (strcmp (env_value, "error") == 0) {
172: log_threshold_file = FM_LOG_ERROR;
173: }
174: else if (strcmp (env_value, "fatal") == 0) {
175: log_threshold_file = FM_LOG_FATAL;
176: }
177: else {
178: log_threshold_file = FM_LOG_INFO;
179: }
180: }
181:
182: if ((env_value = getenv ("FREEM_LOG_THRESHOLD_SYSLOG")) != NULL) {
183: if (strcmp (env_value, "debug") == 0) {
184: log_threshold_syslog = FM_LOG_DEBUG;
185: }
186: else if (strcmp (env_value, "info") == 0) {
187: log_threshold_syslog = FM_LOG_INFO;
188: }
189: else if (strcmp (env_value, "warning") == 0) {
190: log_threshold_syslog = FM_LOG_WARNING;
191: }
192: else if (strcmp (env_value, "error") == 0) {
193: log_threshold_syslog = FM_LOG_ERROR;
194: }
195: else if (strcmp (env_value, "fatal") == 0) {
196: log_threshold_syslog = FM_LOG_FATAL;
197: }
198: else {
199: log_threshold_syslog = FM_LOG_INFO;
200: }
201: }
202:
203: if ((env_value = getenv ("FREEM_LOG_THRESHOLD_STDERR")) != NULL) {
204: if (strcmp (env_value, "debug") == 0) {
205: log_threshold_stderr = FM_LOG_DEBUG;
206: }
207: else if (strcmp (env_value, "info") == 0) {
208: log_threshold_stderr = FM_LOG_INFO;
209: }
210: else if (strcmp (env_value, "warning") == 0) {
211: log_threshold_stderr = FM_LOG_WARNING;
212: }
213: else if (strcmp (env_value, "error") == 0) {
214: log_threshold_stderr = FM_LOG_ERROR;
215: }
216: else if (strcmp (env_value, "fatal") == 0) {
217: log_threshold_stderr = FM_LOG_FATAL;
218: }
219: else {
220: log_threshold_stderr = FM_LOG_INFO;
221: }
222: }
223:
224:
225:
1.10 snw 226: }
227:
228: void log_level_to_text(int level, char *buf)
229: {
230: switch (level) {
231:
1.12 snw 232: case FM_LOG_DEBUG:
1.10 snw 233: sprintf (buf, "DEBUG");
234: break;
235:
1.12 snw 236: case FM_LOG_INFO:
1.10 snw 237: sprintf (buf, "INFO");
238: break;
239:
1.12 snw 240: case FM_LOG_WARNING:
1.10 snw 241: sprintf (buf, "WARNING");
242: break;
243:
1.12 snw 244: case FM_LOG_ERROR:
1.10 snw 245: sprintf (buf, "ERROR");
246: break;
247:
1.12 snw 248: case FM_LOG_FATAL:
1.10 snw 249: sprintf (buf, "FATAL");
250: break;
251:
252: default:
253: sprintf (buf, "LEVEL %d", level);
254: break;
255:
256: }
257: }
1.9 snw 258:
1.10 snw 259: void m_log(int level, const char *msg)
1.1 snw 260: {
261:
1.9 snw 262: FILE *fp;
263: time_t unix_epoch;
264: char timeval[255];
265: char filename[4096];
1.10 snw 266: char lvl[20];
1.9 snw 267: struct tm *logtime;
268:
1.10 snw 269: log_level_to_text (level, lvl);
1.9 snw 270:
1.10 snw 271: if (level >= log_threshold_file) {
272: snprintf (filename, sizeof (filename) - 1, "/var/log/freem/%s.log", shm_env);
273:
274: if ((fp = fopen (filename, "a+")) != NULL) {
275: unix_epoch = time (0L);
276: logtime = localtime (&unix_epoch);
277: strftime (timeval, sizeof (timeval) - 1, "%F %T", logtime);
1.12 snw 278: fprintf (fp, "%s [LEVEL %s PID %ld]: %s\n", timeval, lvl, getpid (), msg);
1.10 snw 279: fclose (fp);
1.13 ! snw 280: }
1.9 snw 281: }
1.5 snw 282:
1.2 snw 283: #if defined(__linux__) | defined(__FreeBSD__) | defined(__sun__)
1.10 snw 284: if (level >= log_threshold_syslog) {
285: syslog (level, "%s", msg);
286: }
1.1 snw 287: #endif
1.10 snw 288:
1.12 snw 289: if (level >= log_threshold_stderr) fprintf (stderr, "%s [%s]\r\n", msg, lvl);
1.10 snw 290:
1.12 snw 291: if (level >= FM_LOG_FATAL) {
1.10 snw 292: cleanup ();
1.12 snw 293: exit (FM_LOG_FATAL);
1.10 snw 294: }
1.9 snw 295:
1.10 snw 296: return;
1.9 snw 297: }
298:
299: void logprintf(int level, char *fmt, ...)
300: {
301: va_list ptr;
302: va_start (ptr, fmt);
303:
304: char logmsg[BIGSTR];
305: char tmps[BIGSTR];
306:
307: char ch;
308: char typ;
309: char subtyp;
310:
311: register int i;
312:
1.12 snw 313: logmsg[0] = '\0';
314:
1.9 snw 315: for (i = 0; fmt[i] != '\0'; i++) {
316: ch = fmt[i];
317:
1.12 snw 318: tmps[0] = '\0';
319:
1.9 snw 320: switch (ch) {
321:
322: case '%':
323: typ = fmt[++i];
324:
325: switch (typ) {
326:
327: case '%': /* literal percent sign */
328: strcat (logmsg, "%");
1.12 snw 329: continue;
1.9 snw 330:
331: case 'c': /* char */
332: sprintf (tmps, "%c", va_arg (ptr, int));
333: strcat (logmsg, tmps);
1.12 snw 334: continue;
1.9 snw 335:
336: case 's': /* C string */
337: strcat (logmsg, va_arg (ptr, char *));
1.12 snw 338: continue;
1.9 snw 339:
340: case 'S': /* FreeM string */
341: stcpy (tmps, va_arg (ptr, char *));
342: stcnv_m2c (tmps);
343: strcat (logmsg, tmps);
1.12 snw 344: continue;
1.9 snw 345:
346: case 'd': /* int */
347: sprintf (tmps, "%d", va_arg (ptr, int));
348: strcat (logmsg, tmps);
1.12 snw 349: continue;
1.9 snw 350:
1.12 snw 351: case 'p': /* pointer */
352: sprintf (tmps, "%p", va_arg (ptr, void *));
353: strcat (logmsg, tmps);
354: continue;
355:
1.9 snw 356: case 'l': /* long... */
357: subtyp = fmt[++i];
358: switch (subtyp) {
359:
360: case 'd': /* long int */
361: sprintf (tmps, "%ld", va_arg (ptr, long));
362: strcat (logmsg, tmps);
1.12 snw 363: continue;
1.9 snw 364:
365: case 'f': /* float */
366: sprintf (tmps, "%lf", va_arg (ptr, double));
367: strcat (logmsg, tmps);
1.12 snw 368: continue;
1.9 snw 369:
370: }
1.12 snw 371: continue;
1.9 snw 372: }
373:
374: case '\\':
375: typ = fmt[++i];
376: switch (typ) {
377: case 'n':
378: sprintf (tmps, "\n");
379: strcat (logmsg, tmps);
1.12 snw 380: continue;
1.9 snw 381:
382: case 'r':
383: sprintf (tmps, "\r");
384: strcat (logmsg, tmps);
1.12 snw 385: continue;
1.9 snw 386:
387: case 't':
388: sprintf (tmps, "\t");
389: strcat (logmsg, tmps);
1.12 snw 390: continue;
1.9 snw 391:
392: case '\\':
393: sprintf (tmps, "\\");
394: strcat (logmsg, tmps);
1.12 snw 395: continue;
1.9 snw 396: }
397:
398: default:
399: sprintf (tmps, "%c", ch);
400: strcat (logmsg, tmps);
401: break;
402: }
403: }
404:
405: m_log (level, logmsg);
406:
407: va_end (ptr);
1.8 snw 408: return;
1.1 snw 409: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>