WIP: Rework logging #48

Draft
Levitating wants to merge 2 commits from Levitating/Cytoplasm:log into master
2 changed files with 62 additions and 64 deletions

View file

@ -46,6 +46,7 @@
#define LOG_FLAG_COLOR (1 << 0)
#define LOG_FLAG_SYSLOG (1 << 1)
#define LOG_FLAG_STDOUT (1 << 2)
/**
* 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);
/**
* Set the file stream that logging output should be written to. This
* 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.
* Set the file stream that logging output should be written to.
*/
extern void LogConfigOutputSet(LogConfig *, Stream *);
extern void LogConfigFileSet(LogConfig *, Stream *);
/**
* 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.
* .It LOG_FLAG_SYSLOG
* When set, log output to the syslog using
* .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.
* .Xr syslog 3
* .El
*/
extern void LogConfigFlagSet(LogConfig *, int);

108
src/Log.c
View file

@ -39,7 +39,7 @@ struct LogConfig
{
int level;
size_t indent;
Stream *out;
Stream *file;
int flags;
char *tsFmt;
@ -65,8 +65,8 @@ LogConfigCreate(void)
LogConfigLevelSet(config, LOG_INFO);
LogConfigIndentSet(config, 0);
LogConfigOutputSet(config, NULL); /* Will set to stdout */
LogConfigFlagSet(config, LOG_FLAG_COLOR);
LogConfigFileSet(config, NULL);
LogConfigFlagSet(config, LOG_FLAG_COLOR | LOG_FLAG_STDOUT);
LogConfigTimeStampFormatSet(config, "%y-%m-%d %H:%M:%S");
return config;
@ -185,20 +185,20 @@ LogConfigLevelSet(LogConfig * config, int level)
}
void
LogConfigOutputSet(LogConfig * config, Stream * out)
LogConfigFileSet(LogConfig * config, Stream * file)
{
if (!config)
{
return;
}
if (out)
if (file)
{
config->out = out;
config->file = file;
}
else
{
config->out = StreamStdout();
config->file = StreamStdout();
}
}
@ -221,43 +221,15 @@ LogConfigUnindent(LogConfig * config)
}
}
void
Logv(LogConfig * config, int level, const char *msg, va_list argp)
static void
LogPrint(Stream * stream, LogConfig * config, int level, const char *msg, va_list argp)
{
size_t i;
int doColor;
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)
&& isatty(StreamFileno(config->out));
&& isatty(StreamFileno(stream));
if (doColor)
{
@ -293,10 +265,10 @@ Logv(LogConfig * config, int level, const char *msg, va_list argp)
break;
}
StreamPuts(config->out, ansi);
StreamPuts(stream, ansi);
}
StreamPutc(config->out, '[');
StreamPutc(stream, '[');
if (config->tsFmt)
{
@ -309,15 +281,15 @@ Logv(LogConfig * config, int level, const char *msg, va_list argp)
if (tsLength)
{
StreamPuts(config->out, tsBuffer);
StreamPuts(stream, tsBuffer);
if (!isspace((unsigned char) tsBuffer[tsLength - 1]))
{
StreamPutc(config->out, ' ');
StreamPutc(stream, ' ');
}
}
}
StreamPrintf(config->out, "(%lu) ", UtilThreadNo());
StreamPrintf(stream, "(%lu) ", UtilThreadNo());
switch (level)
{
@ -350,24 +322,60 @@ Logv(LogConfig * config, int level, const char *msg, va_list argp)
break;
}
StreamPrintf(config->out, "%c]", indicator);
StreamPrintf(stream, "%c]", indicator);
if (doColor)
{
/* ANSI Reset */
StreamPuts(config->out, "\033[0m");
StreamPuts(stream, "\033[0m");
}
StreamPutc(config->out, ' ');
StreamPutc(stream, ' ');
for (i = 0; i < config->indent; i++)
{
StreamPutc(config->out, ' ');
StreamPutc(config->file, ' ');
}
StreamVprintf(config->out, msg, argp);
StreamPutc(config->out, '\n');
StreamVprintf(stream, msg, argp);
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);
}