2013-05-03 06:02:03 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2007-2012, Timothy Stack
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-05-03 06:02:03 +00:00
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-05-03 06:02:03 +00:00
|
|
|
* * Redistributions of source code must retain the above copyright notice, this
|
|
|
|
* list of conditions and the following disclaimer.
|
|
|
|
* * 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.
|
|
|
|
* * Neither the name of Timothy Stack nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-05-03 06:02:03 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2009-10-14 19:42:58 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2010-01-29 23:17:08 +00:00
|
|
|
#include <stdio.h>
|
2009-10-14 19:42:58 +00:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "log_format.hh"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Supported formats:
|
|
|
|
* generic
|
|
|
|
* syslog
|
|
|
|
* apache
|
|
|
|
* tcpdump
|
|
|
|
* strace
|
|
|
|
* vstrace
|
|
|
|
* csv (?)
|
|
|
|
* file system (?)
|
|
|
|
* plugins
|
|
|
|
* vmstat
|
|
|
|
* iostat
|
|
|
|
*/
|
|
|
|
|
|
|
|
static time_t BAD_DATE = -1;
|
|
|
|
|
2012-06-05 20:18:59 +00:00
|
|
|
time_t tm2sec(const struct tm *t)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
|
|
|
int year;
|
|
|
|
time_t days;
|
|
|
|
const int dayoffset[12] =
|
|
|
|
{ 306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275 };
|
|
|
|
|
|
|
|
year = t->tm_year;
|
|
|
|
|
|
|
|
if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138))) {
|
2013-05-28 04:35:00 +00:00
|
|
|
return BAD_DATE;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* shift new year to 1st March in order to make leap year calc easy */
|
|
|
|
|
|
|
|
if (t->tm_mon < 2) {
|
2013-05-28 04:35:00 +00:00
|
|
|
year--;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Find number of days since 1st March 1900 (in the Gregorian calendar). */
|
|
|
|
|
|
|
|
days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
|
|
|
|
days += dayoffset[t->tm_mon] + t->tm_mday - 1;
|
|
|
|
days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
|
|
|
|
|
|
|
|
days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;
|
|
|
|
|
|
|
|
if (days < 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
return BAD_DATE;
|
2009-09-14 01:07:32 +00:00
|
|
|
} /* must have overflowed */
|
|
|
|
else {
|
2013-05-28 04:35:00 +00:00
|
|
|
if (t->tm_zone) {
|
|
|
|
days -= t->tm_gmtoff;
|
|
|
|
}
|
|
|
|
return days;
|
2009-09-14 01:07:32 +00:00
|
|
|
} /* must be a valid time */
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *logline::level_names[LEVEL__MAX] = {
|
|
|
|
"unknown",
|
|
|
|
"trace",
|
|
|
|
"debug",
|
|
|
|
"info",
|
|
|
|
"warning",
|
|
|
|
"error",
|
2013-05-18 00:44:55 +00:00
|
|
|
"critical",
|
|
|
|
"fatal",
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2013-06-04 13:53:25 +00:00
|
|
|
static int strcasestr_i(const char *s1, const char *s2)
|
|
|
|
{
|
2013-06-06 02:34:48 +00:00
|
|
|
return strcasestr(s1, s2) == NULL;
|
2013-06-04 13:53:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
logline::level_t logline::string2level(const char *levelstr, bool exact)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
|
|
|
logline::level_t retval = logline::LEVEL_UNKNOWN;
|
2013-06-04 13:53:25 +00:00
|
|
|
int (*cmpfunc)(const char *, const char *);
|
|
|
|
|
|
|
|
if (exact)
|
|
|
|
cmpfunc = strcasecmp;
|
|
|
|
else
|
|
|
|
cmpfunc = strcasestr_i;
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-06-06 02:34:48 +00:00
|
|
|
if (cmpfunc(levelstr, "TRACE") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_TRACE;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "VERBOSE") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_DEBUG;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "DEBUG") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_DEBUG;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "INFO") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_INFO;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "WARNING") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_WARNING;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "ERROR") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_ERROR;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "CRITICAL") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_CRITICAL;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
2013-06-06 02:34:48 +00:00
|
|
|
else if (cmpfunc(levelstr, "FATAL") == 0) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = logline::LEVEL_FATAL;
|
2013-05-18 00:44:55 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
vector<log_format *> log_format::lf_root_formats;
|
|
|
|
|
|
|
|
vector<log_format *> &log_format::get_root_formats(void)
|
|
|
|
{
|
|
|
|
return lf_root_formats;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool next_format(const char *fmt[], int &index, int &locked_index)
|
|
|
|
{
|
|
|
|
bool retval = true;
|
|
|
|
|
|
|
|
if (locked_index == -1) {
|
2013-05-28 04:35:00 +00:00
|
|
|
index += 1;
|
|
|
|
if (fmt[index] == NULL) {
|
|
|
|
retval = false;
|
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
else if (index == locked_index) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = false;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-05-28 04:35:00 +00:00
|
|
|
index = locked_index;
|
2009-09-14 01:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2012-07-03 19:01:09 +00:00
|
|
|
char *log_format::log_scanf(const char *line,
|
2013-05-28 04:35:00 +00:00
|
|
|
const char *fmt[],
|
|
|
|
int expected_matches,
|
|
|
|
const char *time_fmt[],
|
|
|
|
char *time_dest,
|
|
|
|
struct tm *tm_out,
|
|
|
|
time_t &time_out,
|
|
|
|
...)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
|
|
|
static const char *std_time_fmt[] = {
|
2013-05-28 04:35:00 +00:00
|
|
|
"%Y-%m-%d %H:%M:%S",
|
|
|
|
"%Y-%m-%d %H:%M",
|
|
|
|
"%Y-%m-%dT%H:%M:%S",
|
2013-06-08 13:10:18 +00:00
|
|
|
"%Y-%m-%dT%H:%M:%SZ",
|
2013-05-28 04:35:00 +00:00
|
|
|
"%Y/%m/%d %H:%M:%S",
|
|
|
|
"%Y/%m/%d %H:%M",
|
|
|
|
|
|
|
|
"%a %b %d %H:%M:%S %Y",
|
|
|
|
|
|
|
|
"%d/%b/%Y:%H:%M:%S %z",
|
|
|
|
|
|
|
|
"%b %d %H:%M:%S",
|
|
|
|
|
|
|
|
NULL,
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
2013-05-28 04:35:00 +00:00
|
|
|
|
|
|
|
int curr_fmt = -1;
|
|
|
|
char * retval = NULL;
|
2009-09-14 01:07:32 +00:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
while (next_format(fmt, curr_fmt, this->lf_fmt_lock)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
va_start(args, time_out);
|
|
|
|
int matches;
|
|
|
|
|
|
|
|
time_dest[0] = '\0';
|
|
|
|
|
|
|
|
matches = vsscanf(line, fmt[curr_fmt], args);
|
|
|
|
if (matches < expected_matches) {
|
|
|
|
retval = NULL;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (time_dest[0] == '\0') {
|
|
|
|
retval = NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int curr_time_fmt = -1;
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
if (!time_fmt) {
|
|
|
|
time_fmt = std_time_fmt;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (next_format(time_fmt,
|
|
|
|
curr_time_fmt,
|
|
|
|
this->lf_time_fmt_lock)) {
|
|
|
|
memset(tm_out, 0, sizeof(struct tm));
|
|
|
|
if ((retval = strptime(time_dest,
|
|
|
|
time_fmt[curr_time_fmt],
|
|
|
|
tm_out)) != NULL) {
|
|
|
|
if (tm_out->tm_year < 70) {
|
|
|
|
/* XXX We should pull the time from the file mtime (?) */
|
|
|
|
tm_out->tm_year = 80;
|
|
|
|
}
|
|
|
|
time_out = tm2sec(tm_out);
|
|
|
|
|
|
|
|
this->lf_fmt_lock = curr_fmt;
|
|
|
|
this->lf_time_fmt_lock = curr_time_fmt;
|
|
|
|
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
retval = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end(args);
|
2011-05-14 19:06:32 +00:00
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
/* XXX */
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "log_format_impls.cc"
|