WIP: Rework logging #48

Draft
Levitating wants to merge 2 commits from Levitating/Cytoplasm:log into master
2 changed files with 62 additions and 63 deletions
Showing only changes of commit 36575b947f - Show all commits

View file

@ -46,6 +46,7 @@
#define LOG_FLAG_COLOR (1 << 0) #define LOG_FLAG_COLOR (1 << 0)
#define LOG_FLAG_SYSLOG (1 << 1) #define LOG_FLAG_SYSLOG (1 << 1)
#define LOG_FLAG_STDOUT (1 << 2)
/** /**
* A log is defined as a configuration that describes the properties * A log is defined as a configuration that describes the properties
@ -110,15 +111,9 @@ extern void LogConfigUnindent(LogConfig *);
extern void LogConfigIndentSet(LogConfig *, size_t); extern void LogConfigIndentSet(LogConfig *, size_t);
/** /**
* Set the file stream that logging output should be written to. This * Set the file stream that logging output should be written to.
* defaults to standard output, but it can be set to standard error,
* or any other arbitrary stream. Passing a NULL value for the stream
* pointer sets the log output to the standard output. Note that the
* output stream is only used if
* .Va LOG_FLAG_SYSLOG
* is not set.
*/ */
extern void LogConfigOutputSet(LogConfig *, Stream *); extern void LogConfigFileSet(LogConfig *, Stream *);
/** /**
* Set a number of boolean options on a log configuration. This * Set a number of boolean options on a log configuration. This
@ -135,12 +130,7 @@ extern void LogConfigOutputSet(LogConfig *, Stream *);
* is checked before writing any terminal sequences. * is checked before writing any terminal sequences.
* .It LOG_FLAG_SYSLOG * .It LOG_FLAG_SYSLOG
* When set, log output to the syslog using * When set, log output to the syslog using
* .Xr syslog 3 , * .Xr syslog 3
* instead of logging to the file set by
* .Fn LogConfigOutputSet .
* This flag always overrides the stream set by that function,
* regardless of when it was set, even if it was set after this flag
* was set.
* .El * .El
*/ */
extern void LogConfigFlagSet(LogConfig *, int); extern void LogConfigFlagSet(LogConfig *, int);

107
src/Log.c
View file

@ -26,6 +26,7 @@
#include <Memory.h> #include <Memory.h>
#include <Util.h> #include <Util.h>
#include <cstdarg>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
@ -39,7 +40,7 @@ struct LogConfig
{ {
int level; int level;
size_t indent; size_t indent;
Stream *out; Stream *file;
int flags; int flags;
char *tsFmt; char *tsFmt;
@ -65,8 +66,8 @@ LogConfigCreate(void)
LogConfigLevelSet(config, LOG_INFO); LogConfigLevelSet(config, LOG_INFO);
LogConfigIndentSet(config, 0); LogConfigIndentSet(config, 0);
LogConfigOutputSet(config, NULL); /* Will set to stdout */ LogConfigFileSet(config, NULL);
LogConfigFlagSet(config, LOG_FLAG_COLOR); LogConfigFlagSet(config, LOG_FLAG_COLOR | LOG_FLAG_STDOUT);
LogConfigTimeStampFormatSet(config, "%y-%m-%d %H:%M:%S"); LogConfigTimeStampFormatSet(config, "%y-%m-%d %H:%M:%S");
return config; return config;
@ -185,20 +186,20 @@ LogConfigLevelSet(LogConfig * config, int level)
} }
void void
LogConfigOutputSet(LogConfig * config, Stream * out) LogConfigFileSet(LogConfig * config, Stream * file)
{ {
if (!config) if (!config)
{ {
return; return;
} }
if (out) if (file)
{ {
config->out = out; config->file = file;
} }
else else
{ {
config->out = StreamStdout(); config->file = StreamStdout();
} }
} }
@ -222,42 +223,14 @@ LogConfigUnindent(LogConfig * config)
} }
void void
Logv(LogConfig * config, int level, const char *msg, va_list argp) LogPrint(Stream * stream, LogConfig * config, int level, const char *msg, va_list argp)
{ {
size_t i; size_t i;
int doColor; int doColor;
char indicator; char indicator;
/*
* Only proceed if we have a config and its log level is set to a
* value that permits us to log. This is as close as we can get
* to a no-op function if we aren't logging anything, without doing
* some crazy macro magic.
*/
if (!config || level > config->level)
{
return;
}
/* Misconfiguration */
if (!config->out)
{
return;
}
pthread_mutex_lock(&config->lock);
if (LogConfigFlagGet(config, LOG_FLAG_SYSLOG))
{
/* No further print logic is needed; syslog will handle it all
* for us. */
vsyslog(level, msg, argp);
pthread_mutex_unlock(&config->lock);
return;
}
doColor = LogConfigFlagGet(config, LOG_FLAG_COLOR) doColor = LogConfigFlagGet(config, LOG_FLAG_COLOR)
&& isatty(StreamFileno(config->out)); && isatty(StreamFileno(stream));
if (doColor) if (doColor)
{ {
@ -293,10 +266,10 @@ Logv(LogConfig * config, int level, const char *msg, va_list argp)
break; break;
} }
StreamPuts(config->out, ansi); StreamPuts(stream, ansi);
} }
StreamPutc(config->out, '['); StreamPutc(stream, '[');
if (config->tsFmt) if (config->tsFmt)
{ {
@ -309,15 +282,15 @@ Logv(LogConfig * config, int level, const char *msg, va_list argp)
if (tsLength) if (tsLength)
{ {
StreamPuts(config->out, tsBuffer); StreamPuts(stream, tsBuffer);
if (!isspace((unsigned char) tsBuffer[tsLength - 1])) if (!isspace((unsigned char) tsBuffer[tsLength - 1]))
{ {
StreamPutc(config->out, ' '); StreamPutc(stream, ' ');
} }
} }
} }
StreamPrintf(config->out, "(%lu) ", UtilThreadNo()); StreamPrintf(stream, "(%lu) ", UtilThreadNo());
switch (level) switch (level)
{ {
@ -350,24 +323,60 @@ Logv(LogConfig * config, int level, const char *msg, va_list argp)
break; break;
} }
StreamPrintf(config->out, "%c]", indicator); StreamPrintf(stream, "%c]", indicator);
if (doColor) if (doColor)
{ {
/* ANSI Reset */ /* ANSI Reset */
StreamPuts(config->out, "\033[0m"); StreamPuts(stream, "\033[0m");
} }
StreamPutc(config->out, ' '); StreamPutc(stream, ' ');
for (i = 0; i < config->indent; i++) for (i = 0; i < config->indent; i++)
{ {
StreamPutc(config->out, ' '); StreamPutc(config->file, ' ');
} }
StreamVprintf(config->out, msg, argp); StreamVprintf(stream, msg, argp);
StreamPutc(config->out, '\n'); StreamPutc(stream, '\n');
StreamFlush(config->out); StreamFlush(stream);
}
void
Logv(LogConfig * config, int level, const char *msg, va_list argp)
{
/*
* Only proceed if we have a config and its log level is set to a
* value that permits us to log. This is as close as we can get
* to a no-op function if we aren't logging anything, without doing
* some crazy macro magic.
*/
if (!config || level > config->level)
{
return;
}
/* Misconfiguration */
if (!config->file)
{
return;
}
pthread_mutex_lock(&config->lock);
if (LogConfigFlagGet(config, LOG_FLAG_SYSLOG))
{
vsyslog(level, msg, argp);
}
if (LogConfigFlagGet(config, LOG_FLAG_STDOUT)) {
LogPrint(StreamStdout(), config, level, msg, argp);
}
if (config->file) {
LogPrint(config->file, config, level, msg, argp);
}
pthread_mutex_unlock(&config->lock); pthread_mutex_unlock(&config->lock);
} }