File:  [Coherent Logic Development] / freem / src / log.c
Revision 1.10: download - view: text, annotated - select for diffs
Tue Apr 15 14:39:06 2025 UTC (2 months, 2 weeks ago) by snw
Branches: MAIN
CVS tags: HEAD
Further improvements to logging

/*
 *   $Id: log.c,v 1.10 2025/04/15 14:39:06 snw Exp $
 *    freem error logging
 *
 *  
 *   Author: Serena Willis <snw@coherent-logic.com>
 *    Copyright (C) 1998 MUG Deutschland
 *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
 *
 *
 *   This file is part of FreeM.
 *
 *   FreeM is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU Affero Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   FreeM is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU Affero Public License for more details.
 *
 *   You should have received a copy of the GNU Affero Public License
 *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
 *
 *   $Log: log.c,v $
 *   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 <stdio.h>
#include <string.h>
#if defined(__linux__) | defined(__FreeBSD__) | defined(__sun__)
# include <syslog.h>
#endif
#include <stdlib.h>
#include <stdarg.h>

#if defined(USE_SYS_TIME_H) && !defined(MSDOS) && !defined(__osf__)
# include <sys/time.h>
#else
# include <time.h> 
#endif

#include "mpsdef.h"

short log_threshold_file;
short log_threshold_syslog;
short log_threshold_stderr;


void init_log(void)
{
    log_threshold_file = LOG_INFO;
    log_threshold_syslog = LOG_INFO;
    log_threshold_stderr = LOG_WARNING;
}

void log_level_to_text(int level, char *buf)
{
    switch (level) {

        case LOG_DEBUG:
            sprintf (buf, "DEBUG");
            break;

        case LOG_INFO:
            sprintf (buf, "INFO");
            break;

        case LOG_WARNING:
            sprintf (buf, "WARNING");
            break;

        case LOG_ERROR:
            sprintf (buf, "ERROR");
            break;

        case 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, pid, msg);
            fclose (fp);
        }
    }
    
#if defined(__linux__) | defined(__FreeBSD__) | defined(__sun__)
    if (level >= log_threshold_syslog) {
        syslog (level, "%s", msg);
    }
#endif

    if (level >= log_threshold_stderr) fprintf (stderr, "%s\r\n", msg);

    if (level >= LOG_FATAL) {
        cleanup ();
        exit (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;

    for (i = 0; fmt[i] != '\0'; i++) {
        ch = fmt[i];

        switch (ch) {
            
            case '%':
                typ = fmt[++i];

                switch (typ) {
                    
                    case '%': /* literal percent sign */
                        strcat (logmsg, "%");
                        break;

                    case 'c': /* char */
                        sprintf (tmps, "%c", va_arg (ptr, int));
                        strcat (logmsg, tmps);
                        break;

                    case 's': /* C string */
                        strcat (logmsg, va_arg (ptr, char *));
                        break;

                    case 'S': /* FreeM string */
                        stcpy (tmps, va_arg (ptr, char *));
                        stcnv_m2c (tmps);
                        strcat (logmsg, tmps);
                        break;

                    case 'd': /* int */
                        sprintf (tmps, "%d", va_arg (ptr, int));
                        strcat (logmsg, tmps);
                        break;

                    case 'l': /* long... */
                        subtyp = fmt[++i];
                        switch (subtyp) {
                            
                            case 'd': /* long int */
                                sprintf (tmps, "%ld", va_arg (ptr, long));
                                strcat (logmsg, tmps);
                                break;

                            case 'f': /* float */
                                sprintf (tmps, "%lf", va_arg (ptr, double));
                                strcat (logmsg, tmps);
                                break;
                                
                        }
                        break;
                }
                
            case '\\':
                typ = fmt[++i];
                switch (typ) {
                    case 'n':
                        sprintf (tmps, "\n");
                        strcat (logmsg, tmps);
                        break;
                        
                    case 'r':
                        sprintf (tmps, "\r");
                        strcat (logmsg, tmps);
                        break;

                    case 't':
                        sprintf (tmps, "\t");
                        strcat (logmsg, tmps);
                        break;
                        
                    case '\\':
                        sprintf (tmps, "\\");
                        strcat (logmsg, tmps);
                        break;
                }
                
            default:
                sprintf (tmps, "%c", ch);
                strcat (logmsg, tmps);
                break;
        }
    }

    m_log (level, logmsg);
        
    va_end (ptr);
    return;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>