--- freem/src/log.c 2025/03/08 06:11:05 1.2 +++ freem/src/log.c 2025/05/14 12:22:04 1.14 @@ -1,23 +1,11 @@ /* - * * - * * * - * * * - * *************** - * * * * * - * * MUMPS * - * * * * * - * *************** - * * * - * * * - * * - * - * log.c - * freem error logging + * $Id: log.c,v 1.14 2025/05/14 12:22:04 snw Exp $ + * freem error logging * * - * Author: Serena Willis + * Author: Serena Willis * Copyright (C) 1998 MUG Deutschland - * Copyright (C) 2020 Coherent Logic Development LLC + * Copyright (C) 2020, 2025 Coherent Logic Development LLC * * * This file is part of FreeM. @@ -35,6 +23,43 @@ * You should have received a copy of the GNU Affero Public License * along with FreeM. If not, see . * + * $Log: log.c,v $ + * Revision 1.14 2025/05/14 12:22:04 snw + * Further work on shared memory + * + * Revision 1.13 2025/04/16 17:36:12 snw + * Add FreeBSD shm cleanup script + * + * Revision 1.12 2025/04/15 16:49:36 snw + * Make use of logprintf throughout codebase + * + * Revision 1.11 2025/04/15 14:56:20 snw + * Fix broken build due to missing declarations + * + * Revision 1.10 2025/04/15 14:39:06 snw + * Further improvements to logging + * + * Revision 1.9 2025/04/15 02:24:43 snw + * Improve FreeM logging capabilities + * + * Revision 1.8 2025/04/04 02:12:25 snw + * Bump to 0.63.0-rc5 and make sure m_log function is never empty + * + * Revision 1.7 2025/04/04 01:18:21 snw + * Remove vestigial logging code and bump to 0.63.0-rc4 + * + * Revision 1.6 2025/04/01 23:21:45 snw + * fmadm commands for stopping, starting, and restarting environments now functional + * + * Revision 1.5 2025/04/01 20:11:46 snw + * Further work on fmadm + * + * Revision 1.4 2025/03/09 19:50:47 snw + * Second phase of REUSE compliance and header reformat + * + * + * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC + * SPDX-License-Identifier: AGPL-3.0-or-later **/ #include @@ -43,14 +68,349 @@ # include #endif #include +#include +#include + +#if defined(USE_SYS_TIME_H) && !defined(MSDOS) && !defined(__osf__) +# include +#else +# include +#endif #include "mpsdef.h" +#include "log.h" /* for logging constants */ +#include "init.h" /* for cleanup() */ +#include "iniconf.h" /* for read_profile_string() */ +#include "shmmgr.h" /* for shm_exit() */ + +short log_threshold_file; +short log_threshold_syslog; +short log_threshold_stderr; + + +void init_log(void) +{ + char buf[4096]; + char *env_value; + + if (read_profile_string (env_config_file, shm_env, "log_threshold_file", buf) == TRUE) { + if (strcmp (buf, "debug") == 0) { + log_threshold_file = FM_LOG_DEBUG; + } + else if (strcmp (buf, "info") == 0) { + log_threshold_file = FM_LOG_INFO; + } + else if (strcmp (buf, "warning") == 0) { + log_threshold_file = FM_LOG_WARNING; + } + else if (strcmp (buf, "error") == 0) { + log_threshold_file = FM_LOG_ERROR; + } + else if (strcmp (buf, "fatal") == 0) { + log_threshold_file = FM_LOG_FATAL; + } + else { + log_threshold_file = FM_LOG_INFO; + } + } + else { + log_threshold_file = FM_LOG_INFO; + } + + if (read_profile_string (env_config_file, shm_env, "log_threshold_syslog", buf) == TRUE) { + if (strcmp (buf, "debug") == 0) { + log_threshold_syslog = FM_LOG_DEBUG; + } + else if (strcmp (buf, "info") == 0) { + log_threshold_syslog = FM_LOG_INFO; + } + else if (strcmp (buf, "warning") == 0) { + log_threshold_syslog = FM_LOG_WARNING; + } + else if (strcmp (buf, "error") == 0) { + log_threshold_syslog = FM_LOG_ERROR; + } + else if (strcmp (buf, "fatal") == 0) { + log_threshold_syslog = FM_LOG_FATAL; + } + else { + log_threshold_syslog = FM_LOG_INFO; + } + } + else { + log_threshold_syslog = FM_LOG_INFO; + } + + if (read_profile_string (env_config_file, shm_env, "log_threshold_stderr", buf) == TRUE) { + if (strcmp (buf, "debug") == 0) { + log_threshold_stderr = FM_LOG_DEBUG; + } + else if (strcmp (buf, "info") == 0) { + log_threshold_stderr = FM_LOG_INFO; + } + else if (strcmp (buf, "warning") == 0) { + log_threshold_stderr = FM_LOG_WARNING; + } + else if (strcmp (buf, "error") == 0) { + log_threshold_stderr = FM_LOG_ERROR; + } + else if (strcmp (buf, "fatal") == 0) { + log_threshold_stderr = FM_LOG_FATAL; + } + else { + log_threshold_stderr = FM_LOG_INFO; + } + } + else { + log_threshold_stderr = FM_LOG_WARNING; + } + + if ((env_value = getenv ("FREEM_LOG_THRESHOLD_FILE")) != NULL) { + if (strcmp (env_value, "debug") == 0) { + log_threshold_file = FM_LOG_DEBUG; + } + else if (strcmp (env_value, "info") == 0) { + log_threshold_file = FM_LOG_INFO; + } + else if (strcmp (env_value, "warning") == 0) { + log_threshold_file = FM_LOG_WARNING; + } + else if (strcmp (env_value, "error") == 0) { + log_threshold_file = FM_LOG_ERROR; + } + else if (strcmp (env_value, "fatal") == 0) { + log_threshold_file = FM_LOG_FATAL; + } + else { + log_threshold_file = FM_LOG_INFO; + } + } + + if ((env_value = getenv ("FREEM_LOG_THRESHOLD_SYSLOG")) != NULL) { + if (strcmp (env_value, "debug") == 0) { + log_threshold_syslog = FM_LOG_DEBUG; + } + else if (strcmp (env_value, "info") == 0) { + log_threshold_syslog = FM_LOG_INFO; + } + else if (strcmp (env_value, "warning") == 0) { + log_threshold_syslog = FM_LOG_WARNING; + } + else if (strcmp (env_value, "error") == 0) { + log_threshold_syslog = FM_LOG_ERROR; + } + else if (strcmp (env_value, "fatal") == 0) { + log_threshold_syslog = FM_LOG_FATAL; + } + else { + log_threshold_syslog = FM_LOG_INFO; + } + } + + if ((env_value = getenv ("FREEM_LOG_THRESHOLD_STDERR")) != NULL) { + if (strcmp (env_value, "debug") == 0) { + log_threshold_stderr = FM_LOG_DEBUG; + } + else if (strcmp (env_value, "info") == 0) { + log_threshold_stderr = FM_LOG_INFO; + } + else if (strcmp (env_value, "warning") == 0) { + log_threshold_stderr = FM_LOG_WARNING; + } + else if (strcmp (env_value, "error") == 0) { + log_threshold_stderr = FM_LOG_ERROR; + } + else if (strcmp (env_value, "fatal") == 0) { + log_threshold_stderr = FM_LOG_FATAL; + } + else { + log_threshold_stderr = FM_LOG_INFO; + } + } + + + +} + +void log_level_to_text(int level, char *buf) +{ + switch (level) { -void m_log (int level, const char *msg) + case FM_LOG_DEBUG: + sprintf (buf, "DEBUG"); + break; + + case FM_LOG_INFO: + sprintf (buf, "INFO"); + break; + + case FM_LOG_WARNING: + sprintf (buf, "WARNING"); + break; + + case FM_LOG_ERROR: + sprintf (buf, "ERROR"); + break; + + case FM_LOG_FATAL: + sprintf (buf, "FATAL"); + break; + + default: + sprintf (buf, "LEVEL %d", level); + break; + + } +} + +void m_log(int level, const char *msg) { + FILE *fp; + time_t unix_epoch; + char timeval[255]; + char filename[4096]; + char lvl[20]; + struct tm *logtime; + + log_level_to_text (level, lvl); + + if (level >= log_threshold_file) { + snprintf (filename, sizeof (filename) - 1, "/var/log/freem/%s.log", shm_env); + + if ((fp = fopen (filename, "a+")) != NULL) { + unix_epoch = time (0L); + logtime = localtime (&unix_epoch); + strftime (timeval, sizeof (timeval) - 1, "%F %T", logtime); + fprintf (fp, "%s [LEVEL %s PID %ld]: %s\n", timeval, lvl, getpid (), msg); + fclose (fp); + } + } + #if defined(__linux__) | defined(__FreeBSD__) | defined(__sun__) - syslog (level, "%s", msg); + if (level >= log_threshold_syslog) { + syslog (level, "%s", msg); + } #endif + + if (level >= log_threshold_stderr) fprintf (stderr, "%s [%s]\r\n", msg, lvl); + + if (level >= FM_LOG_FATAL) { + cleanup (); + exit (FM_LOG_FATAL); + } + return; +} + +void logprintf(int level, char *fmt, ...) +{ + va_list ptr; + va_start (ptr, fmt); + + char logmsg[BIGSTR]; + char tmps[BIGSTR]; + + char ch; + char typ; + char subtyp; + + register int i; + + logmsg[0] = '\0'; + + for (i = 0; fmt[i] != '\0'; i++) { + ch = fmt[i]; + + tmps[0] = '\0'; + + switch (ch) { + + case '%': + typ = fmt[++i]; + + switch (typ) { + + case '%': /* literal percent sign */ + strcat (logmsg, "%"); + continue; + + case 'c': /* char */ + sprintf (tmps, "%c", va_arg (ptr, int)); + strcat (logmsg, tmps); + continue; + + case 's': /* C string */ + strcat (logmsg, va_arg (ptr, char *)); + continue; + + case 'S': /* FreeM string */ + stcpy (tmps, va_arg (ptr, char *)); + stcnv_m2c (tmps); + strcat (logmsg, tmps); + continue; + + case 'd': /* int */ + sprintf (tmps, "%d", va_arg (ptr, int)); + strcat (logmsg, tmps); + continue; + + case 'p': /* pointer */ + sprintf (tmps, "%p", va_arg (ptr, void *)); + strcat (logmsg, tmps); + continue; + + case 'l': /* long... */ + subtyp = fmt[++i]; + switch (subtyp) { + + case 'd': /* long int */ + sprintf (tmps, "%ld", va_arg (ptr, long)); + strcat (logmsg, tmps); + continue; + + case 'f': /* float */ + sprintf (tmps, "%lf", va_arg (ptr, double)); + strcat (logmsg, tmps); + continue; + + } + continue; + } + + case '\\': + typ = fmt[++i]; + switch (typ) { + case 'n': + sprintf (tmps, "\n"); + strcat (logmsg, tmps); + continue; + + case 'r': + sprintf (tmps, "\r"); + strcat (logmsg, tmps); + continue; + + case 't': + sprintf (tmps, "\t"); + strcat (logmsg, tmps); + continue; + + case '\\': + sprintf (tmps, "\\"); + strcat (logmsg, tmps); + continue; + } + + default: + sprintf (tmps, "%c", ch); + strcat (logmsg, tmps); + break; + } + } + + m_log (level, logmsg); + + va_end (ptr); + return; }