Show elog.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR
* CONTRIBUTORS 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.
*
*/
/*
* elog -- the embedded logger
*
* this module emits log messages to standard error in a format,
* encoded in such a way as to allow other programs such as emrun to
* easily parse them.
*
* $Id: elog.c,v 1.20 2007/01/08 01:44:15 mlukac Exp $
*/
#include <stdio.h>
#include <string.h>
#include "misc.h"
#include <time.h>
char elog_c_cvsid[] = "$Id: elog.c,v 1.20 2007/01/08 01:44:15 mlukac Exp $";
/* elog now does local filtering as instructed by emrun */
int elog_loglevel = DEFAULT_STDOUT_THRESHOLD;
/* if set, will insert logging level and time stamp in messages */
int elog_displaystamp = 0;
/* if set, will insert function name in messages */
int elog_displayfunction = 1;
/* if we're running under emrun, emit a specially formatted message */
int elog_in_emrun = 1;
/**************************************************************/
static struct {
char *name;
int level;
} lognames[] = {
/* the parse will allow prefixes, so here we spell out the complete
* word. That way, either the complete word or the prefix will be
* accepted. */
{ "Default", LOG_UNDEFINED},
{ "OFF", LOG_OFF},
{ "EMERGENCY", LOG_EMERG},
{ "ALERT", LOG_ALERT},
{ "CRITICAL", LOG_CRIT},
{ "ERROR", LOG_ERR},
{ "WARNING", LOG_WARNING},
{ "NOTICE", LOG_NOTICE},
{ "INFORMATIONAL", LOG_INFO},
{ "DEBUG", LOG_DEBUG(0)},
{ NULL, 0 }
};
/*
* Go from a string to a numeric log level. The parsed loglevel is
* written to "newlevel". Function returns 0 if parse was successful,
* -1 if not.
*/
int get_loglevel_by_name(char *loglevel, int *newlevel)
{
int i, loglevel_len;
/* strip off LOG_ or LOG, if either is provided */
if (!strncasecmp(loglevel, "LOG_", 4))
loglevel += 4;
if (!strncasecmp(loglevel, "LOG", 3))
loglevel += 3;
loglevel_len = strlen(loglevel);
/* check for debug levels with numeric arguments. This should
* accept "LOG_DEBUG_5", "LOG_DEBUG(5)", "LOG_DEBUG 5", etc. */
if (loglevel_len >= 6 && !strncasecmp(loglevel, "DEBUG", 5)) {
*newlevel = LOG_DEBUG(atoi(loglevel+6));
return 0;
}
/* no joy, just check the whole list */
for (i = 0; lognames[i].name != NULL; i++) {
if (!strncasecmp(loglevel, lognames[i].name, loglevel_len)) {
*newlevel = lognames[i].level;
return 0;
}
}
/* oh well, better luck next time */
return -1;
}
/*
* print the name of a loglevel
*/
char *loglevel_name(int level)
{
int i;
DECLARE_STATIC_BUF_RING(buf, 5, 32);
if (level > 1000)
return "LOG_ALL";
if (level >= LOG_DEBUG(0)) {
sprintf(buf, "LOG_DEBUG(%d)", level - LOG_DEBUG(0));
return buf;
}
for (i = 0; lognames[i].name != NULL; i++)
if (lognames[i].level == level)
return lognames[i].name;
return "<UNKNOWN!!>";
}
/**
** Functions that help propagating loglevels from parents to children
** using environment variables
**/
/* record a loglevel in the environment */
void loglevel_to_env(char *name, int level)
{
setenv(name, loglevel_name(level), 1);
}
/* get a loglevel out of the environment */
int loglevel_from_env(char *name, int *level)
{
int new_level;
char *value;
if (name == NULL || (value = getenv(name)) == NULL)
return -1;
if (get_loglevel_by_name(value, &new_level) < 0) {
elog(LOG_ALERT, "invalid loglevel variable %s=%s", name, value);
return -1;
}
*level = new_level;
return 0;
}
/***************************************************************/
/*
* Construct a log message. This is the function that actually gets
* called by the elog() macro, if the loglevel is sufficiently high.
* (We use the macro because if the loglevel isn't high enough, we
* don't even want the remaining arguments of elog() to be evaluated.)
*/
void elog_real(int level, const char *function, char *fmt, ...)
{
va_list ap;
char buf[4096] = {};
int buflen = 0;
struct timeval tv;
va_start(ap, fmt);
if (level > 99)
level = 99;
if (level < LOG_OFF)
level = LOG_ALERT;
/* prepend the string parsed by emrun, if needed */
gettimeofday(&tv, NULL);
if (elog_displaystamp || elog_in_emrun) {
BUFPRINTF("<%02d,%010ld.%06ld>", level, tv.tv_sec, tv.tv_usec);
} else {
char timebuf[64];
time_t tmp = tv.tv_sec;
strcpy(timebuf, asctime(localtime(&tmp)));
memmove(timebuf+24, timebuf+20, 4);
sprintf(timebuf+19, ".%03d", (int) tv.tv_usec/1000);
timebuf[23] = ' ';
timebuf[28] = 0;
BUFPRINTF("%s: ", timebuf);
}
/* and add the function name, if available */
if (elog_displayfunction && function)
BUFPRINTF("%s: ", function);
vsnprintf(buf+buflen, sizeof(buf)-buflen-1, fmt, ap);
buflen = strlen(buf); // retval from vsprintf is wacky
/* take off extra CRLFs, if there (some messages have them, some don't) */
while (buf[buflen-1] == '\n' || buf[buflen-1] == '\r')
buflen--;
/* make room for trailing CR */
if (buflen >= (sizeof(buf)-2))
buflen = sizeof(buf)-2;
/* and append a final CR: */
buf[buflen++] = '\n';
buf[buflen] = 0;
/* call the "emit" routine, which may either be from the libmisc
* library (in elog_emit), or in a program if it has provided a
* replacement (emrun does this) */
elog_emit(buf, buflen);
va_end(ap);
}
#define PRINTABLE_OFFSET 56
void elog_raw_real(int level, const void *input_void, int count)
{
char buf[120];
char *input = (char *) input_void, *output=NULL;
int i;
for (i=0; i<count; i++) {
if (i%16 == 0) {
memset(buf, ' ', sizeof(buf));
output = buf + sprintf(buf, " %04d: ", i);
}
output += sprintf(output, "%02X ", (uint8_t)input[i]);
buf[PRINTABLE_OFFSET+(i%16)] = isprint(input[i]) ? input[i] : '.';
if (i%16 == 15) {
*output = ' ';
buf[PRINTABLE_OFFSET+(i%16)+1] = 0;
elog_g(level, "%s", buf);
}
}
if (i % 16) {
*output = ' ';
buf[PRINTABLE_OFFSET+(i%16)+1] = 0;
elog_g(level, "%s", buf);
}
}
#undef PRINTABLE_OFFSET
void elog_set_loglevel(int new_level)
{
elog_loglevel = new_level;
}
See more files for this project here