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)
Levitating marked this conversation as resolved Outdated
Outdated
Review

I'd probably consider making LogPrint static here, as it's not even part of the public includes.

I'd probably consider making LogPrint static here, as it's not even part of the public includes.

Yes it should be static!

Yes it should be static!
{
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);
}