You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
7.4 KiB
282 lines
7.4 KiB
/*- |
|
* Copyright (c) 2017-2021 Carsten Sonne Larsen <cs@innolan.net> |
|
* 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 <stddef.h> |
|
#include <stdarg.h> |
|
#include <stdbool.h> |
|
|
|
#include <proto/dos.h> |
|
#include <proto/exec.h> |
|
#include <proto/intuition.h> |
|
#include <exec/ports.h> |
|
#include <exec/memory.h> |
|
|
|
#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"); |
|
} |