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