/*- * Copyright (c) 2017-2021 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include "message.h" #include "global.h" #include "string.h" #ifndef INTUITIONNAME #define INTUITIONNAME "intuition.library" #endif #ifndef UTILITYNAME #define UTILITYNAME "utility.library" #endif #define TIMELOGGER "TimeLogger 1.12 (31.01.2021)" #define ARGSFORMAT "D=DEBUG/K/N,M=MODULEOFF/S,S=SEVERITYOFF/S,H=HELP/S" #define MODULENAME "Logger" struct progargs { LONG level; LONG module; LONG severity; LONG help; }; static void LogMessage(enum LogSeverity, struct timeval *, const char *, const char *); static void MsgLoop(void); static void ShowHelp(void); struct IntuitionBase *IntuitionBase = NULL; struct UtilityBase *UtilityBase = NULL; static struct MsgPort *LoggerPort = NULL; static struct RDArgs *rdargs = NULL; static struct progargs args = {0, 0, 0, 0}; static long SeverityLevel; static char LogTemplate[50]; const char *vers = "\0$VER: " TIMELOGGER; static void Listen(void) { LogMessage(InfoMessage, NULL, MODULENAME, "Starting " TIMELOGGER); LoggerPort->mp_Node.ln_Name = LOGGER_PORT_NAME; LoggerPort->mp_Node.ln_Pri = 0; AddPort(LoggerPort); MsgLoop(); RemPort(LoggerPort); } static void ProcessArgs(void) { if (args.level != 0) SeverityLevel = *((LONG *)args.level); else SeverityLevel = 15; char *p = LogTemplate; p = AppendText(p, "%02ld:%02ld:%02ld.%03ld "); if (!args.module) p = AppendText(p, "[%-8s]"); else p = AppendText(p, "%s"); if (!args.severity) p = AppendText(p, "[%-5s]"); else p = AppendText(p, "%s"); if (!(args.severity && args.module)) p = AppendChar(p, ' ', 1); AppendText(p, "%s"); } bool Init(void) { rdargs = ReadArgs((STRPTR)ARGSFORMAT, (APTR)&args, NULL); if (!rdargs) return false; LoggerPort = CreateMsgPort(); if (LoggerPort == NULL) return false; if (!(UtilityBase = (struct UtilityBase *)OpenLibrary((STRPTR)UTILITYNAME, 0))) return false; if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary((STRPTR)INTUITIONNAME, 0))) return false; return true; } void Cleanup(void) { if (LoggerPort != NULL) DeleteMsgPort(LoggerPort); if (rdargs != NULL) FreeArgs(rdargs); if (IntuitionBase != NULL) CloseLibrary((struct Library *)IntuitionBase); if (UtilityBase != NULL) CloseLibrary((struct Library *)UtilityBase); } int main(int argc, char **argv) { if (!Init()) { Cleanup(); return RETURN_FAIL; } if (args.help) { ShowHelp(); } else { ProcessArgs(); Listen(); } Cleanup(); return RETURN_OK; } static const char *SeverityText(enum LogSeverity level) { switch (level) { case ErrorMessage: return "Error"; case WarningMessage: return "Warn"; case NoticeMessage: return "Notice"; case InfoMessage: return "Info"; case DebugMessage: return "Debug"; case TraceMessage: case MemTraceMessage: return "Trace"; default: return "Unspec"; } } static void LogMessage(enum LogSeverity level, struct timeval *tv, const char *module, const char *log) { if (SeverityLevel >= (long)level) { ULONG secs; ULONG micro; if (tv == NULL) { CurrentTime(&secs, µ); } else { secs = tv->tv_secs; micro = tv->tv_micro; } micro /= 1000; struct ClockData cd; Amiga2Date(secs, &cd); char line[MAXLOGLINESIZE + 32]; const char *severity = SeverityText(level); SNPrintf(line, MAXLOGLINESIZE + 32, LogTemplate, (long)cd.hour, (long)cd.min, (long)cd.sec, (long)micro, (args.module ? "" : module), (args.severity ? "" : severity), log); TrimRight(line); // TODO: Option to log using a file // TODO: Handle outout errors if (Output() != (BPTR)0) { Printf((STRPTR)line); Printf((STRPTR) "\n"); } } } static void MsgLoop(void) { bool loop = true; ULONG loggerSigMask = (1 << LoggerPort->mp_SigBit); ULONG sigMask = loggerSigMask | SIGBREAKF_CTRL_C; LogMessage(NoticeMessage, NULL, MODULENAME, "Waiting for log messages ..."); do { ULONG sigrcvd = Wait(sigMask); if (sigrcvd & sigMask) { struct LogMessage *msg; while ((msg = (struct LogMessage *)GetMsg(LoggerPort))) { struct timeval tv; struct LogMessage copy; CurrentTime(&tv.tv_secs, &tv.tv_micro); CopyMem(msg, ©, sizeof(struct LogMessage)); ReplyMsg((struct Message *)msg); LogMessage(copy.Severity, &tv, copy.Module, copy.Text); } } if (sigrcvd & SIGBREAKF_CTRL_C) { LogMessage(WarningMessage, NULL, MODULENAME, "Shutting down"); loop = false; } } while (loop); } static void ShowHelp(void) { Printf((STRPTR)TIMELOGGER "\n"); Printf((STRPTR) "Shows log messages from " APP_SHORT_NAME ".\n"); Printf((STRPTR) "Use arguments to control output.\n"); Printf((STRPTR) "Debug level (D or DEBUG):\n"); Printf((STRPTR) " 5 = Error conditions\n"); Printf((STRPTR) " 10 = Warning conditions\n"); Printf((STRPTR) " 15 = Normal but significant conditions\n"); Printf((STRPTR) " 20 = Informational messages\n"); Printf((STRPTR) " 30 = Debug-level messages\n"); Printf((STRPTR) " 40 = Trace program flow\n"); Printf((STRPTR) " 90 = Trace memory exceptions\n"); Printf((STRPTR) "MODULEOFF: Hide module name\n"); Printf((STRPTR) "SEVERITYOFF: Hide severity level\n"); Printf((STRPTR) "HELP: Show help text\n"); }