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