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"
|
|
|
|
|
2014-03-11 10:49:52 +00:00
|
|
|
#include <math.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>
|
2013-09-10 13:20:37 +00:00
|
|
|
#include <strings.h>
|
2009-10-14 19:42:58 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
#include "yajlpp.hh"
|
|
|
|
#include "sql_util.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "log_format.hh"
|
2013-06-29 13:22:24 +00:00
|
|
|
#include "log_vtab_impl.hh"
|
2014-06-18 04:29:42 +00:00
|
|
|
#include "ptimec.hh"
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Supported formats:
|
|
|
|
* generic
|
|
|
|
* syslog
|
|
|
|
* apache
|
|
|
|
* tcpdump
|
|
|
|
* strace
|
|
|
|
* vstrace
|
|
|
|
* csv (?)
|
|
|
|
* file system (?)
|
|
|
|
* plugins
|
|
|
|
* vmstat
|
|
|
|
* iostat
|
|
|
|
*/
|
|
|
|
|
2014-01-25 17:29:35 +00:00
|
|
|
string_attr_type logline::L_PREFIX;
|
|
|
|
string_attr_type logline::L_TIMESTAMP;
|
|
|
|
string_attr_type logline::L_FILE;
|
|
|
|
string_attr_type logline::L_PARTITION;
|
|
|
|
|
2014-03-16 09:46:17 +00:00
|
|
|
const char *logline::level_names[LEVEL__MAX + 1] = {
|
2009-09-14 01:07:32 +00:00
|
|
|
"unknown",
|
|
|
|
"trace",
|
|
|
|
"debug",
|
|
|
|
"info",
|
|
|
|
"warning",
|
|
|
|
"error",
|
2013-05-18 00:44:55 +00:00
|
|
|
"critical",
|
|
|
|
"fatal",
|
2014-03-16 09:46:17 +00:00
|
|
|
|
|
|
|
NULL
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
static pcrepp LEVEL_RE(
|
|
|
|
"(?i)(TRACE|VERBOSE|DEBUG|INFO|WARN(?:ING)?|ERROR|CRITICAL|SEVERE|FATAL)");
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
static int strncasestr_i(const char *s1, const char *s2, size_t len)
|
2013-06-04 13:53:25 +00:00
|
|
|
{
|
2013-06-06 02:34:48 +00:00
|
|
|
return strcasestr(s1, s2) == NULL;
|
2013-06-04 13:53:25 +00:00
|
|
|
}
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
logline::level_t logline::string2level(const char *levelstr, ssize_t len, bool exact)
|
2009-09-14 01:07:32 +00:00
|
|
|
{
|
|
|
|
logline::level_t retval = logline::LEVEL_UNKNOWN;
|
2013-06-16 01:07:50 +00:00
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
if (len == (size_t)-1) {
|
2013-09-10 13:20:37 +00:00
|
|
|
len = strlen(levelstr);
|
2013-06-16 01:07:50 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-03-02 00:35:30 +00:00
|
|
|
if (((len == 1) || ((len > 1) && (levelstr[1] == ' '))) &&
|
|
|
|
(retval = abbrev2level(levelstr, len)) != LEVEL_UNKNOWN) {
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
pcre_input pi(levelstr, 0, len);
|
|
|
|
pcre_context_static<10> pc;
|
|
|
|
|
|
|
|
if (LEVEL_RE.match(pc, pi)) {
|
|
|
|
retval = abbrev2level(pi.get_substr_start(pc.begin()), 1);
|
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;
|
|
|
|
}
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
logline::level_t logline::abbrev2level(const char *levelstr, ssize_t len)
|
2014-02-18 17:06:50 +00:00
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (len == 0 || levelstr[0] == '\0') {
|
2014-02-18 17:06:50 +00:00
|
|
|
return LEVEL_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (toupper(levelstr[0])) {
|
|
|
|
case 'T':
|
2014-10-20 05:16:40 +00:00
|
|
|
return LEVEL_TRACE;
|
2014-02-18 17:06:50 +00:00
|
|
|
case 'D':
|
2014-10-28 14:02:27 +00:00
|
|
|
case 'V':
|
2014-10-20 05:16:40 +00:00
|
|
|
return LEVEL_DEBUG;
|
2014-02-18 17:06:50 +00:00
|
|
|
case 'I':
|
2014-10-20 05:16:40 +00:00
|
|
|
return LEVEL_INFO;
|
2014-02-18 17:06:50 +00:00
|
|
|
case 'W':
|
2014-10-20 05:16:40 +00:00
|
|
|
return LEVEL_WARNING;
|
2014-02-18 17:06:50 +00:00
|
|
|
case 'E':
|
2014-10-20 05:16:40 +00:00
|
|
|
return LEVEL_ERROR;
|
2014-02-18 17:06:50 +00:00
|
|
|
case 'C':
|
2014-10-20 05:16:40 +00:00
|
|
|
case 'S':
|
|
|
|
return LEVEL_CRITICAL;
|
2014-02-18 17:06:50 +00:00
|
|
|
case 'F':
|
2014-10-20 05:16:40 +00:00
|
|
|
return LEVEL_FATAL;
|
|
|
|
default:
|
|
|
|
return LEVEL_UNKNOWN;
|
2014-02-18 17:06:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
int logline::levelcmp(const char *l1, ssize_t l1_len, const char *l2, ssize_t l2_len)
|
2014-02-18 17:06:50 +00:00
|
|
|
{
|
|
|
|
return abbrev2level(l1, l1_len) - abbrev2level(l2, l2_len);
|
|
|
|
}
|
|
|
|
|
2014-01-18 14:46:51 +00:00
|
|
|
const char *logline_value::value_names[VALUE__MAX] = {
|
|
|
|
"null",
|
|
|
|
"text",
|
|
|
|
"int",
|
|
|
|
"float",
|
2014-05-05 13:44:58 +00:00
|
|
|
"bool",
|
|
|
|
"json"
|
2014-01-18 14:46:51 +00:00
|
|
|
};
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
logline_value::kind_t logline_value::string2kind(const char *kindstr)
|
|
|
|
{
|
|
|
|
if (strcmp(kindstr, "string") == 0) {
|
|
|
|
return VALUE_TEXT;
|
|
|
|
}
|
|
|
|
else if (strcmp(kindstr, "integer") == 0) {
|
|
|
|
return VALUE_INTEGER;
|
|
|
|
}
|
|
|
|
else if (strcmp(kindstr, "float") == 0) {
|
|
|
|
return VALUE_FLOAT;
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
else if (strcmp(kindstr, "boolean") == 0) {
|
|
|
|
return VALUE_BOOLEAN;
|
|
|
|
}
|
2014-05-05 13:44:58 +00:00
|
|
|
else if (strcmp(kindstr, "json") == 0) {
|
|
|
|
return VALUE_JSON;
|
|
|
|
}
|
2014-06-18 04:29:42 +00:00
|
|
|
else if (strcmp(kindstr, "quoted") == 0) {
|
|
|
|
return VALUE_QUOTED;
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
return VALUE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
vector<log_format *> log_format::lf_root_formats;
|
|
|
|
|
|
|
|
vector<log_format *> &log_format::get_root_formats(void)
|
|
|
|
{
|
|
|
|
return lf_root_formats;
|
|
|
|
}
|
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
static bool next_format(const std::vector<external_log_format::pattern *> &patterns,
|
2013-06-29 18:00:34 +00:00
|
|
|
int &index,
|
|
|
|
int &locked_index)
|
|
|
|
{
|
|
|
|
bool retval = true;
|
|
|
|
|
|
|
|
if (locked_index == -1) {
|
|
|
|
index += 1;
|
|
|
|
if (index >= (int)patterns.size()) {
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (index == locked_index) {
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = locked_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
bool log_format::next_format(pcre_format *fmt, int &index, int &locked_index)
|
|
|
|
{
|
|
|
|
bool retval = true;
|
|
|
|
|
|
|
|
if (locked_index == -1) {
|
|
|
|
index += 1;
|
|
|
|
if (fmt[index].name == NULL) {
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (index == locked_index) {
|
|
|
|
retval = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
index = locked_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
const char *log_format::log_scanf(const char *line,
|
2014-10-20 05:16:40 +00:00
|
|
|
size_t len,
|
|
|
|
pcre_format *fmt,
|
2013-06-26 01:45:07 +00:00
|
|
|
const char *time_fmt[],
|
2014-06-18 04:29:42 +00:00
|
|
|
struct exttm *tm_out,
|
2013-06-30 23:43:08 +00:00
|
|
|
struct timeval &tv_out,
|
2013-06-26 01:45:07 +00:00
|
|
|
...)
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
int curr_fmt = -1;
|
2013-06-26 01:45:07 +00:00
|
|
|
const char * retval = NULL;
|
2014-09-29 05:36:07 +00:00
|
|
|
bool done = false;
|
2014-10-20 05:16:40 +00:00
|
|
|
pcre_input pi(line, 0, len);
|
|
|
|
pcre_context_static<128> pc;
|
2009-09-14 01:07:32 +00:00
|
|
|
va_list args;
|
|
|
|
|
2014-09-29 05:36:07 +00:00
|
|
|
while (!done && next_format(fmt, curr_fmt, this->lf_fmt_lock)) {
|
2013-06-30 23:43:08 +00:00
|
|
|
va_start(args, tv_out);
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
if (!fmt[curr_fmt].pcre.match(pc, pi)) {
|
2013-05-28 04:35:00 +00:00
|
|
|
retval = NULL;
|
|
|
|
}
|
|
|
|
else {
|
2014-10-20 05:16:40 +00:00
|
|
|
pcre_context::capture_t *ts = pc["timestamp"];
|
|
|
|
|
|
|
|
for (pcre_context::iterator iter = pc.begin();
|
|
|
|
iter != pc.end();
|
|
|
|
++iter) {
|
|
|
|
pcre_context::capture_t *cap = va_arg(
|
|
|
|
args, pcre_context::capture_t *);
|
|
|
|
|
|
|
|
*cap = *iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = this->lf_date_time.scan(
|
|
|
|
pi.get_substr_start(ts), ts->length(), NULL, tm_out, tv_out);
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
if (retval) {
|
|
|
|
this->lf_fmt_lock = curr_fmt;
|
2014-09-29 05:36:07 +00:00
|
|
|
done = true;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end(args);
|
2011-05-14 19:06:32 +00:00
|
|
|
}
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-04-07 05:11:04 +00:00
|
|
|
void log_format::check_for_new_year(std::vector<logline> &dst,
|
|
|
|
const struct timeval &log_tv)
|
|
|
|
{
|
|
|
|
if (dst.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t diff = dst.back().get_time() - log_tv.tv_sec;
|
|
|
|
|
|
|
|
if (diff > (5 * 60)) {
|
|
|
|
int off_year = 0, off_month = 0, off_day = 0, off_hour = 0;
|
|
|
|
std::vector<logline>::iterator iter;
|
|
|
|
|
|
|
|
if (diff > (60 * 24 * 60 * 60)) {
|
|
|
|
off_year = 1;
|
|
|
|
} else if (diff > (15 * 24 * 60 * 60)) {
|
|
|
|
off_month = 1;
|
|
|
|
} else if (diff > (12 * 60 * 60)) {
|
|
|
|
off_day = 1;
|
|
|
|
} else {
|
|
|
|
off_hour = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (iter = dst.begin(); iter != dst.end(); iter++) {
|
|
|
|
time_t ot = iter->get_time();
|
|
|
|
struct tm *otm;
|
|
|
|
|
|
|
|
otm = gmtime(&ot);
|
|
|
|
otm->tm_year -= off_year;
|
|
|
|
otm->tm_mon -= off_month;
|
|
|
|
otm->tm_yday -= off_day;
|
|
|
|
otm->tm_hour -= off_hour;
|
|
|
|
iter->set_time(tm2sec(otm));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
/*
|
|
|
|
* XXX This needs some cleanup.
|
|
|
|
*/
|
|
|
|
struct json_log_userdata {
|
|
|
|
json_log_userdata() : jlu_sub_line_count(1) { };
|
|
|
|
|
|
|
|
external_log_format *jlu_format;
|
|
|
|
const logline *jlu_line;
|
|
|
|
logline *jlu_base_line;
|
|
|
|
int jlu_sub_line_count;
|
|
|
|
yajl_handle jlu_handle;
|
|
|
|
const char *jlu_line_value;
|
2014-10-28 14:02:27 +00:00
|
|
|
size_t jlu_line_size;
|
2013-09-10 13:20:37 +00:00
|
|
|
size_t jlu_sub_start;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct json_field_cmp {
|
|
|
|
json_field_cmp(external_log_format::json_log_field type,
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t name)
|
2013-09-10 13:20:37 +00:00
|
|
|
: jfc_type(type), jfc_field_name(name) {
|
|
|
|
};
|
|
|
|
|
|
|
|
bool operator()(const external_log_format::json_format_element &jfe) const {
|
|
|
|
return (this->jfc_type == jfe.jfe_type &&
|
|
|
|
this->jfc_field_name == jfe.jfe_value);
|
|
|
|
};
|
|
|
|
|
|
|
|
external_log_format::json_log_field jfc_type;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t jfc_field_name;
|
2013-09-10 13:20:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int read_json_field(yajlpp_parse_context *ypc, const unsigned char *str, size_t len);
|
|
|
|
|
|
|
|
static int read_json_null(yajlpp_parse_context *ypc)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
vector<external_log_format::json_format_element> &line_format =
|
|
|
|
jlu->jlu_format->jlf_line_format;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
if (find_if(line_format.begin(), line_format.end(),
|
|
|
|
json_field_cmp(external_log_format::JLF_VARIABLE,
|
|
|
|
field_name)) == line_format.end()) {
|
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_json_bool(yajlpp_parse_context *ypc, int val)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
vector<external_log_format::json_format_element> &line_format =
|
|
|
|
jlu->jlu_format->jlf_line_format;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
if (find_if(line_format.begin(), line_format.end(),
|
2014-10-28 14:02:27 +00:00
|
|
|
json_field_cmp(external_log_format::JLF_VARIABLE,
|
|
|
|
field_name)) == line_format.end()) {
|
2013-09-10 13:20:37 +00:00
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_json_int(yajlpp_parse_context *ypc, long long val)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
vector<external_log_format::json_format_element> &line_format =
|
|
|
|
jlu->jlu_format->jlf_line_format;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
if (jlu->jlu_format->lf_timestamp_field == field_name) {
|
2014-03-11 10:49:52 +00:00
|
|
|
long long divisor = jlu->jlu_format->elf_timestamp_divisor;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
tv.tv_sec = val / divisor;
|
|
|
|
tv.tv_usec = (val % divisor) * (1000000.0 / divisor);
|
|
|
|
jlu->jlu_base_line->set_time(tv);
|
|
|
|
}
|
|
|
|
else if (find_if(line_format.begin(), line_format.end(),
|
|
|
|
json_field_cmp(external_log_format::JLF_VARIABLE,
|
|
|
|
field_name)) == line_format.end()) {
|
2013-09-10 13:20:37 +00:00
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int read_json_double(yajlpp_parse_context *ypc, double val)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
vector<external_log_format::json_format_element> &line_format =
|
|
|
|
jlu->jlu_format->jlf_line_format;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
if (jlu->jlu_format->lf_timestamp_field == field_name) {
|
2014-03-11 10:49:52 +00:00
|
|
|
double divisor = jlu->jlu_format->elf_timestamp_divisor;
|
|
|
|
struct timeval tv;
|
|
|
|
|
|
|
|
tv.tv_sec = val / divisor;
|
|
|
|
tv.tv_usec = fmod(val, divisor) * (1000000.0 / divisor);
|
|
|
|
jlu->jlu_base_line->set_time(tv);
|
|
|
|
}
|
|
|
|
else if (find_if(line_format.begin(), line_format.end(),
|
|
|
|
json_field_cmp(external_log_format::JLF_VARIABLE,
|
|
|
|
field_name)) == line_format.end()) {
|
2013-09-10 13:20:37 +00:00
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int json_array_start(void *ctx)
|
|
|
|
{
|
|
|
|
yajlpp_parse_context *ypc = (yajlpp_parse_context *)ctx;
|
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
vector<external_log_format::json_format_element> &line_format =
|
|
|
|
jlu->jlu_format->jlf_line_format;
|
|
|
|
|
|
|
|
if (ypc->ypc_path_index_stack.size() == 2) {
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
if (find_if(line_format.begin(), line_format.end(),
|
|
|
|
json_field_cmp(external_log_format::JLF_VARIABLE,
|
|
|
|
field_name)) == line_format.end()) {
|
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
jlu->jlu_sub_start = yajl_get_bytes_consumed(jlu->jlu_handle) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int json_array_end(void *ctx)
|
|
|
|
{
|
|
|
|
yajlpp_parse_context *ypc = (yajlpp_parse_context *)ctx;
|
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
|
|
|
|
if (ypc->ypc_path_index_stack.size() == 1) {
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
size_t sub_end = yajl_get_bytes_consumed(jlu->jlu_handle);
|
2014-02-01 14:41:11 +00:00
|
|
|
tmp_shared_buffer tsb(&jlu->jlu_line_value[jlu->jlu_sub_start],
|
|
|
|
sub_end - jlu->jlu_sub_start);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
jlu->jlu_format->jlf_line_values.push_back(
|
2014-02-01 14:41:11 +00:00
|
|
|
logline_value(field_name, tsb.tsb_ref));
|
2014-05-05 13:44:58 +00:00
|
|
|
jlu->jlu_format->jlf_line_values.back().lv_kind = logline_value::VALUE_JSON;
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2014-01-25 20:13:41 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
static struct json_path_handler json_log_handlers[] = {
|
|
|
|
json_path_handler("^/\\w+$").
|
|
|
|
add_cb(read_json_null).
|
|
|
|
add_cb(read_json_bool).
|
|
|
|
add_cb(read_json_int).
|
|
|
|
add_cb(read_json_double).
|
|
|
|
add_cb(read_json_field),
|
|
|
|
|
|
|
|
json_path_handler()
|
|
|
|
};
|
|
|
|
|
|
|
|
static int rewrite_json_field(yajlpp_parse_context *ypc, const unsigned char *str, size_t len);
|
|
|
|
|
|
|
|
static int rewrite_json_null(yajlpp_parse_context *ypc)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(field_name));
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rewrite_json_bool(yajlpp_parse_context *ypc, int val)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(field_name, (bool)val));
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rewrite_json_int(yajlpp_parse_context *ypc, long long val)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2013-09-10 13:45:48 +00:00
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(field_name, (int64_t)val));
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rewrite_json_double(yajlpp_parse_context *ypc, double val)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(field_name, val));
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct json_path_handler json_log_rewrite_handlers[] = {
|
|
|
|
json_path_handler("^/\\w+$").
|
|
|
|
add_cb(rewrite_json_null).
|
|
|
|
add_cb(rewrite_json_bool).
|
|
|
|
add_cb(rewrite_json_int).
|
|
|
|
add_cb(rewrite_json_double).
|
|
|
|
add_cb(rewrite_json_field),
|
|
|
|
|
|
|
|
json_path_handler()
|
|
|
|
};
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
bool external_log_format::scan(std::vector<logline> &dst,
|
|
|
|
off_t offset,
|
2014-10-20 05:16:40 +00:00
|
|
|
shared_buffer_ref &sbr)
|
2013-06-29 13:22:24 +00:00
|
|
|
{
|
2013-09-10 13:20:37 +00:00
|
|
|
if (this->jlf_json) {
|
|
|
|
auto_mem<yajl_handle_t> handle(yajl_free);
|
2013-09-14 13:36:31 +00:00
|
|
|
yajlpp_parse_context &ypc = *(this->jlf_parse_context);
|
2013-09-10 13:20:37 +00:00
|
|
|
logline ll(offset, 0, 0, logline::LEVEL_INFO);
|
|
|
|
json_log_userdata jlu;
|
|
|
|
bool retval = false;
|
|
|
|
|
2013-09-14 13:36:31 +00:00
|
|
|
handle = yajl_alloc(&this->jlf_parse_context->ypc_callbacks,
|
|
|
|
NULL,
|
|
|
|
this->jlf_parse_context.get());
|
2014-10-28 14:02:27 +00:00
|
|
|
yajl_config(handle, yajl_dont_validate_strings, 0);
|
|
|
|
ypc.set_static_handler(json_log_handlers[0]);
|
2013-09-10 13:20:37 +00:00
|
|
|
ypc.ypc_userdata = &jlu;
|
|
|
|
ypc.ypc_ignore_unused = true;
|
|
|
|
ypc.ypc_alt_callbacks.yajl_start_array = json_array_start;
|
|
|
|
ypc.ypc_alt_callbacks.yajl_start_map = json_array_start;
|
|
|
|
jlu.jlu_format = this;
|
|
|
|
jlu.jlu_base_line = ≪
|
2014-10-20 05:16:40 +00:00
|
|
|
jlu.jlu_line_value = sbr.get_data();
|
2014-10-28 14:02:27 +00:00
|
|
|
jlu.jlu_line_size = sbr.length();
|
2013-09-10 13:20:37 +00:00
|
|
|
jlu.jlu_handle = handle;
|
2013-09-14 13:36:31 +00:00
|
|
|
if (yajl_parse(handle.in(),
|
2014-10-20 05:16:40 +00:00
|
|
|
(const unsigned char *)sbr.get_data(), sbr.length()) == yajl_status_ok &&
|
2013-09-10 13:20:37 +00:00
|
|
|
yajl_complete_parse(handle.in()) == yajl_status_ok) {
|
|
|
|
for (int lpc = 0; lpc < jlu.jlu_sub_line_count; lpc++) {
|
|
|
|
ll.set_sub_offset(lpc);
|
|
|
|
if (lpc > 0) {
|
|
|
|
ll.set_level((logline::level_t) (ll.get_level() |
|
|
|
|
logline::LEVEL_CONTINUED));
|
|
|
|
}
|
|
|
|
dst.push_back(ll);
|
|
|
|
}
|
|
|
|
retval = true;
|
|
|
|
}
|
2014-10-28 14:02:27 +00:00
|
|
|
else {
|
|
|
|
unsigned char *msg = yajl_get_error(handle.in(), 1, (const unsigned char *)sbr.get_data(), sbr.length());
|
|
|
|
log_debug("bad line %s", msg);
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
pcre_input pi(sbr.get_data(), 0, sbr.length());
|
2013-07-18 04:24:33 +00:00
|
|
|
pcre_context_static<128> pc;
|
2013-06-29 13:22:24 +00:00
|
|
|
bool retval = false;
|
2013-06-29 18:00:34 +00:00
|
|
|
int curr_fmt = -1;
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
while (::next_format(this->elf_pattern_order, curr_fmt, this->lf_fmt_lock)) {
|
2014-02-09 15:11:58 +00:00
|
|
|
pcrepp *pat = this->elf_pattern_order[curr_fmt]->p_pcre;
|
|
|
|
|
|
|
|
if (!pat->match(pc, pi)) {
|
2013-06-29 18:00:34 +00:00
|
|
|
continue;
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2014-02-09 15:11:58 +00:00
|
|
|
if (this->lf_fmt_lock == -1) {
|
2014-03-11 10:49:52 +00:00
|
|
|
this->lf_timestamp_field_index = pat->name_index(
|
2014-10-28 14:02:27 +00:00
|
|
|
this->lf_timestamp_field.to_string());
|
|
|
|
if (!this->elf_level_field.empty()) {
|
|
|
|
this->elf_level_field_index = pat->name_index(
|
|
|
|
this->elf_level_field.to_string());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->elf_level_field_index = -1;
|
|
|
|
}
|
|
|
|
if (!this->elf_body_field.empty()) {
|
|
|
|
this->elf_body_field_index = pat->name_index(
|
|
|
|
this->elf_body_field.to_string());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->elf_body_field_index = -1;
|
|
|
|
}
|
2014-02-09 15:11:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pcre_context::capture_t *ts = pc[this->lf_timestamp_field_index];
|
|
|
|
pcre_context::capture_t *level_cap = pc[this->elf_level_field_index];
|
2013-06-29 13:22:24 +00:00
|
|
|
const char *ts_str = pi.get_substr_start(ts);
|
|
|
|
const char *last;
|
2014-06-18 04:29:42 +00:00
|
|
|
struct exttm log_time_tm;
|
2013-06-30 23:43:08 +00:00
|
|
|
struct timeval log_tv;
|
2013-06-29 13:22:24 +00:00
|
|
|
logline::level_t level = logline::LEVEL_INFO;
|
|
|
|
|
2013-06-30 23:43:08 +00:00
|
|
|
if ((last = this->lf_date_time.scan(ts_str,
|
2014-10-20 05:16:40 +00:00
|
|
|
ts->length(),
|
2013-06-30 23:43:08 +00:00
|
|
|
NULL,
|
|
|
|
&log_time_tm,
|
|
|
|
log_tv)) == NULL) {
|
2013-06-29 18:00:34 +00:00
|
|
|
continue;
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (level_cap != NULL && level_cap->c_begin != -1) {
|
2013-07-18 04:24:33 +00:00
|
|
|
pcre_context_static<128> pc_level;
|
2013-06-29 13:22:24 +00:00
|
|
|
pcre_input pi_level(pi.get_substr_start(level_cap),
|
|
|
|
0,
|
|
|
|
level_cap->length());
|
|
|
|
|
|
|
|
for (std::map<logline::level_t, level_pattern>::iterator iter = this->elf_level_patterns.begin();
|
|
|
|
iter != this->elf_level_patterns.end();
|
|
|
|
++iter) {
|
|
|
|
if (iter->second.lp_pcre->match(pc_level, pi_level)) {
|
|
|
|
level = iter->first;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-16 05:33:56 +00:00
|
|
|
this->check_for_new_year(dst, log_tv);
|
2013-06-29 18:00:34 +00:00
|
|
|
|
2013-06-30 23:43:08 +00:00
|
|
|
dst.push_back(logline(offset, log_tv, level));
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
this->lf_fmt_lock = curr_fmt;
|
2013-06-29 13:22:24 +00:00
|
|
|
retval = true;
|
2013-06-29 18:00:34 +00:00
|
|
|
break;
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
void external_log_format::annotate(shared_buffer_ref &line,
|
2013-06-29 13:22:24 +00:00
|
|
|
string_attrs_t &sa,
|
|
|
|
std::vector<logline_value> &values) const
|
|
|
|
{
|
2013-07-18 04:24:33 +00:00
|
|
|
pcre_context_static<128> pc;
|
2014-02-01 14:41:11 +00:00
|
|
|
pcre_input pi(line.get_data(), 0, line.length());
|
2013-06-29 13:22:24 +00:00
|
|
|
struct line_range lr;
|
|
|
|
pcre_context::capture_t *cap;
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
if (this->jlf_json) {
|
|
|
|
values = this->jlf_line_values;
|
|
|
|
sa = this->jlf_line_attrs;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
pattern &pat = *this->elf_pattern_order[this->lf_fmt_lock];
|
|
|
|
|
|
|
|
if (!pat.p_pcre->match(pc, pi)) {
|
2013-06-29 13:22:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-02-09 15:11:58 +00:00
|
|
|
cap = pc[this->lf_timestamp_field_index];
|
2013-06-29 13:22:24 +00:00
|
|
|
lr.lr_start = cap->c_begin;
|
|
|
|
lr.lr_end = cap->c_end;
|
2014-01-25 17:29:35 +00:00
|
|
|
sa.push_back(string_attr(lr, &logline::L_TIMESTAMP));
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2014-02-09 15:11:58 +00:00
|
|
|
cap = pc[this->elf_body_field_index];
|
2013-06-29 13:22:24 +00:00
|
|
|
if (cap != NULL && cap->c_begin != -1) {
|
|
|
|
lr.lr_start = cap->c_begin;
|
|
|
|
lr.lr_end = cap->c_end;
|
|
|
|
}
|
|
|
|
else {
|
2014-02-01 14:41:11 +00:00
|
|
|
lr.lr_start = line.length();
|
|
|
|
lr.lr_end = line.length();
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
2014-01-25 17:29:35 +00:00
|
|
|
sa.push_back(string_attr(lr, &textview_curses::SA_BODY));
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
view_colors &vc = view_colors::singleton();
|
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
for (size_t lpc = 0; lpc < pat.p_value_by_index.size(); lpc++) {
|
|
|
|
const value_def &vd = pat.p_value_by_index[lpc];
|
2013-07-23 12:55:08 +00:00
|
|
|
const struct scaling_factor *scaling = NULL;
|
2014-03-02 16:55:00 +00:00
|
|
|
pcre_context::capture_t *cap = pc[vd.vd_index];
|
2014-02-01 14:41:11 +00:00
|
|
|
shared_buffer_ref field;
|
2013-07-23 12:55:08 +00:00
|
|
|
|
|
|
|
if (vd.vd_unit_field_index >= 0) {
|
|
|
|
pcre_context::iterator unit_cap = pc[vd.vd_unit_field_index];
|
|
|
|
|
|
|
|
if (unit_cap != NULL && unit_cap->c_begin != -1) {
|
|
|
|
std::string unit_val = pi.get_substr(unit_cap);
|
|
|
|
std::map<string, scaling_factor>::const_iterator unit_iter;
|
|
|
|
|
|
|
|
unit_iter = vd.vd_unit_scaling.find(unit_val);
|
|
|
|
if (unit_iter != vd.vd_unit_scaling.end()) {
|
|
|
|
const struct scaling_factor &sf = unit_iter->second;
|
|
|
|
|
|
|
|
scaling = &sf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2014-03-02 16:55:00 +00:00
|
|
|
field.subset(line, cap->c_begin, cap->length());
|
2014-02-01 14:41:11 +00:00
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
values.push_back(logline_value(vd.vd_name,
|
|
|
|
vd.vd_kind,
|
2014-02-01 14:41:11 +00:00
|
|
|
field,
|
2013-07-23 12:55:08 +00:00
|
|
|
vd.vd_identifier,
|
2013-09-10 13:20:37 +00:00
|
|
|
scaling,
|
2013-10-11 13:22:29 +00:00
|
|
|
vd.vd_column,
|
2014-03-02 16:55:00 +00:00
|
|
|
cap->c_begin,
|
|
|
|
cap->c_end));
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
if (pc[vd.vd_index]->c_begin != -1 && vd.vd_identifier) {
|
|
|
|
lr.lr_start = pc[vd.vd_index]->c_begin;
|
|
|
|
lr.lr_end = pc[vd.vd_index]->c_end;
|
2014-01-25 17:29:35 +00:00
|
|
|
sa.push_back(string_attr(lr, &view_curses::VC_STYLE,
|
|
|
|
vc.attrs_for_ident(pi.get_substr_start(pc[vd.vd_index]), lr.length())));
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
static int read_json_field(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
|
|
|
vector<external_log_format::json_format_element> &line_format =
|
|
|
|
jlu->jlu_format->jlf_line_format;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2014-06-18 04:29:42 +00:00
|
|
|
struct exttm tm_out;
|
2013-09-10 13:20:37 +00:00
|
|
|
struct timeval tv_out;
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
if (jlu->jlu_format->lf_timestamp_field == field_name) {
|
2014-10-20 05:16:40 +00:00
|
|
|
jlu->jlu_format->lf_date_time.scan((const char *)str, len, NULL, &tm_out, tv_out);
|
2013-09-10 13:20:37 +00:00
|
|
|
jlu->jlu_base_line->set_time(tv_out);
|
|
|
|
}
|
2014-10-28 14:02:27 +00:00
|
|
|
else if (jlu->jlu_format->elf_level_field == field_name) {
|
|
|
|
jlu->jlu_base_line->set_level(logline::abbrev2level((const char *)str, len));
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (find_if(line_format.begin(), line_format.end(),
|
|
|
|
json_field_cmp(external_log_format::JLF_VARIABLE,
|
|
|
|
field_name)) == line_format.end()) {
|
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
for (size_t lpc = 0; lpc < len; lpc++) {
|
|
|
|
if (str[lpc] == '\n') {
|
|
|
|
jlu->jlu_sub_line_count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int rewrite_json_field(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!ypc->is_level(1)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const intern_string_t body_name = intern_string::lookup("body", -1);
|
2013-09-10 13:20:37 +00:00
|
|
|
json_log_userdata *jlu = (json_log_userdata *)ypc->ypc_userdata;
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t field_name = ypc->get_path_fragment_i(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
if (jlu->jlu_format->lf_timestamp_field == field_name) {
|
2013-09-10 13:20:37 +00:00
|
|
|
char time_buf[64];
|
|
|
|
|
2014-02-23 18:23:17 +00:00
|
|
|
sql_strftime(time_buf, sizeof(time_buf),
|
|
|
|
jlu->jlu_line->get_timeval(), 'T');
|
2014-02-01 14:41:11 +00:00
|
|
|
tmp_shared_buffer tsb(time_buf);
|
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(field_name, tsb.tsb_ref));
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
2014-02-01 14:41:11 +00:00
|
|
|
else {
|
|
|
|
tmp_shared_buffer tsb((const char *)str, len);
|
|
|
|
|
|
|
|
if (field_name == jlu->jlu_format->elf_body_field) {
|
2014-10-28 14:02:27 +00:00
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(body_name, tsb.tsb_ref));
|
2014-02-01 14:41:11 +00:00
|
|
|
}
|
|
|
|
jlu->jlu_format->jlf_line_values.push_back(logline_value(field_name, tsb.tsb_ref));
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
void external_log_format::get_subline(const logline &ll, shared_buffer_ref &sbr)
|
2013-09-10 13:20:37 +00:00
|
|
|
{
|
|
|
|
if (!this->jlf_json) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->jlf_cached_offset != ll.get_offset()) {
|
|
|
|
auto_mem<yajl_handle_t> handle(yajl_free);
|
2013-09-14 13:36:31 +00:00
|
|
|
yajlpp_parse_context &ypc = *(this->jlf_parse_context);
|
2013-09-10 13:20:37 +00:00
|
|
|
view_colors &vc = view_colors::singleton();
|
|
|
|
json_log_userdata jlu;
|
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
this->jlf_share_manager.invalidate_refs();
|
2013-09-10 13:20:37 +00:00
|
|
|
this->jlf_cached_line.clear();
|
|
|
|
this->jlf_line_values.clear();
|
|
|
|
this->jlf_line_offsets.clear();
|
|
|
|
this->jlf_line_attrs.clear();
|
2013-09-14 13:36:31 +00:00
|
|
|
|
|
|
|
handle = yajl_alloc(&this->jlf_parse_context->ypc_callbacks,
|
|
|
|
NULL,
|
|
|
|
this->jlf_parse_context.get());
|
2014-10-28 14:02:27 +00:00
|
|
|
yajl_config(handle, yajl_dont_validate_strings, 0);
|
|
|
|
ypc.set_static_handler(json_log_rewrite_handlers[0]);
|
2013-09-14 13:36:31 +00:00
|
|
|
ypc.ypc_userdata = &jlu;
|
|
|
|
ypc.ypc_ignore_unused = true;
|
2013-09-10 13:20:37 +00:00
|
|
|
ypc.ypc_alt_callbacks.yajl_start_array = json_array_start;
|
|
|
|
ypc.ypc_alt_callbacks.yajl_end_array = json_array_end;
|
|
|
|
ypc.ypc_alt_callbacks.yajl_start_map = json_array_start;
|
|
|
|
ypc.ypc_alt_callbacks.yajl_end_map = json_array_end;
|
2013-09-14 13:36:31 +00:00
|
|
|
jlu.jlu_format = this;
|
|
|
|
jlu.jlu_line = ≪
|
|
|
|
jlu.jlu_handle = handle;
|
2014-02-01 14:41:11 +00:00
|
|
|
jlu.jlu_line_value = sbr.get_data();
|
2013-09-14 13:36:31 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
yajl_status parse_status = yajl_parse(handle.in(),
|
|
|
|
(const unsigned char *)sbr.get_data(), sbr.length());
|
2013-09-14 13:36:31 +00:00
|
|
|
if (parse_status == yajl_status_ok &&
|
2013-09-10 13:20:37 +00:00
|
|
|
yajl_complete_parse(handle.in()) == yajl_status_ok) {
|
|
|
|
std::vector<logline_value>::iterator lv_iter;
|
|
|
|
std::vector<json_format_element>::iterator iter;
|
|
|
|
bool used_values[this->jlf_line_values.size()];
|
|
|
|
struct line_range lr;
|
|
|
|
|
|
|
|
memset(used_values, 0, sizeof(used_values));
|
|
|
|
|
|
|
|
for (lv_iter = this->jlf_line_values.begin();
|
|
|
|
lv_iter != this->jlf_line_values.end();
|
|
|
|
++lv_iter) {
|
2014-10-28 14:02:27 +00:00
|
|
|
map<const intern_string_t, external_log_format::value_def>::iterator vd_iter;
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
vd_iter = this->elf_value_defs.find(lv_iter->lv_name);
|
|
|
|
if (vd_iter != this->elf_value_defs.end()) {
|
|
|
|
lv_iter->lv_identifier = vd_iter->second.vd_identifier;
|
|
|
|
lv_iter->lv_column = vd_iter->second.vd_column;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (iter = this->jlf_line_format.begin();
|
|
|
|
iter != this->jlf_line_format.end();
|
|
|
|
++iter) {
|
2014-10-28 14:02:27 +00:00
|
|
|
static const intern_string_t ts_field = intern_string::lookup("__timestamp__", -1);
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
switch (iter->jfe_type) {
|
|
|
|
case JLF_CONSTANT:
|
2014-10-28 14:02:27 +00:00
|
|
|
this->json_append_to_cache(iter->jfe_default_value.c_str(),
|
|
|
|
iter->jfe_default_value.size());
|
2013-09-10 13:20:37 +00:00
|
|
|
break;
|
|
|
|
case JLF_VARIABLE:
|
|
|
|
lv_iter = find_if(this->jlf_line_values.begin(),
|
|
|
|
this->jlf_line_values.end(),
|
|
|
|
logline_value_cmp(&iter->jfe_value));
|
|
|
|
if (lv_iter != this->jlf_line_values.end()) {
|
|
|
|
string str = lv_iter->to_string();
|
|
|
|
size_t nl_pos = str.find('\n');
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
lr.lr_start = this->jlf_cached_line.size();
|
|
|
|
this->json_append_to_cache(
|
|
|
|
str.c_str(), str.size());
|
2013-09-10 13:20:37 +00:00
|
|
|
if (nl_pos == string::npos)
|
2014-10-28 14:02:27 +00:00
|
|
|
lr.lr_end = this->jlf_cached_line.size();
|
2013-09-10 13:20:37 +00:00
|
|
|
else
|
|
|
|
lr.lr_end = lr.lr_start + nl_pos;
|
2014-01-25 17:29:35 +00:00
|
|
|
if (lv_iter->lv_name == this->lf_timestamp_field) {
|
|
|
|
this->jlf_line_attrs.push_back(
|
|
|
|
string_attr(lr, &logline::L_TIMESTAMP));
|
|
|
|
}
|
|
|
|
else if (lv_iter->lv_name == this->elf_body_field) {
|
|
|
|
this->jlf_line_attrs.push_back(
|
|
|
|
string_attr(lr, &textview_curses::SA_BODY));
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
else if (lv_iter->lv_identifier) {
|
2014-01-25 17:29:35 +00:00
|
|
|
this->jlf_line_attrs.push_back(
|
|
|
|
string_attr(lr, &view_curses::VC_STYLE,
|
|
|
|
vc.attrs_for_ident(str.c_str(), lr.length())));
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
2013-10-11 13:22:29 +00:00
|
|
|
lv_iter->lv_origin = lr;
|
2013-09-10 13:20:37 +00:00
|
|
|
used_values[distance(this->jlf_line_values.begin(),
|
|
|
|
lv_iter)] = true;
|
|
|
|
}
|
2014-10-28 14:02:27 +00:00
|
|
|
else if (iter->jfe_value == ts_field) {
|
2014-03-11 10:49:52 +00:00
|
|
|
struct line_range lr;
|
2014-10-28 14:02:27 +00:00
|
|
|
ssize_t ts_len;
|
2014-03-11 10:49:52 +00:00
|
|
|
char ts[64];
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
ts_len = sql_strftime(ts, sizeof(ts), ll.get_timeval(), 'T');
|
|
|
|
lr.lr_start = this->jlf_cached_line.size();
|
|
|
|
this->json_append_to_cache(ts, ts_len);
|
|
|
|
lr.lr_end = this->jlf_cached_line.size();
|
2014-03-11 10:49:52 +00:00
|
|
|
this->jlf_line_attrs.push_back(
|
|
|
|
string_attr(lr, &logline::L_TIMESTAMP));
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
else {
|
2014-10-28 14:02:27 +00:00
|
|
|
this->json_append_to_cache(
|
|
|
|
iter->jfe_default_value.c_str(),
|
|
|
|
iter->jfe_default_value.size());
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-10-28 14:02:27 +00:00
|
|
|
this->json_append_to_cache("\n", 1);
|
2013-09-10 13:20:37 +00:00
|
|
|
for (size_t lpc = 0; lpc < this->jlf_line_values.size(); lpc++) {
|
2014-10-28 14:02:27 +00:00
|
|
|
static const intern_string_t body_name = intern_string::lookup("body", -1);
|
2013-10-11 13:22:29 +00:00
|
|
|
logline_value &lv = this->jlf_line_values[lpc];
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
if (used_values[lpc] ||
|
2014-03-11 10:49:52 +00:00
|
|
|
lv.lv_name == this->lf_timestamp_field ||
|
2014-10-28 14:02:27 +00:00
|
|
|
lv.lv_name == body_name ||
|
2013-10-11 13:22:29 +00:00
|
|
|
lv.lv_name == this->elf_level_field) {
|
2013-09-10 13:20:37 +00:00
|
|
|
continue;
|
2013-10-11 13:22:29 +00:00
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
const std::string str = lv.to_string();
|
|
|
|
size_t curr_pos = 0, nl_pos, line_len = -1;
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
lv.lv_origin.lr_start = this->jlf_cached_line.size();
|
2013-09-10 13:20:37 +00:00
|
|
|
do {
|
|
|
|
nl_pos = str.find('\n', curr_pos);
|
|
|
|
if (nl_pos != std::string::npos) {
|
|
|
|
line_len = nl_pos - curr_pos;
|
|
|
|
}
|
2014-10-28 14:02:27 +00:00
|
|
|
else {
|
|
|
|
line_len = str.size();
|
|
|
|
}
|
|
|
|
this->json_append_to_cache(" ", 2);
|
|
|
|
this->json_append_to_cache(lv.lv_name.get(),
|
|
|
|
lv.lv_name.size());
|
|
|
|
this->json_append_to_cache(": ", 2);
|
|
|
|
this->json_append_to_cache(
|
|
|
|
&str.c_str()[curr_pos], line_len);
|
|
|
|
this->json_append_to_cache("\n", 1);
|
2013-09-10 13:20:37 +00:00
|
|
|
curr_pos = nl_pos + 1;
|
|
|
|
line_len = -1;
|
|
|
|
} while (nl_pos != std::string::npos &&
|
|
|
|
nl_pos < str.size());
|
2014-10-28 14:02:27 +00:00
|
|
|
lv.lv_origin.lr_end = this->jlf_cached_line.size();
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->jlf_line_offsets.push_back(0);
|
|
|
|
for (size_t lpc = 0; lpc < this->jlf_cached_line.size(); lpc++) {
|
|
|
|
if (this->jlf_cached_line[lpc] == '\n') {
|
|
|
|
this->jlf_line_offsets.push_back(lpc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this->jlf_line_offsets.push_back(this->jlf_cached_line.size());
|
|
|
|
}
|
|
|
|
|
|
|
|
this->jlf_cached_offset = ll.get_offset();
|
|
|
|
}
|
|
|
|
|
2014-07-30 23:27:50 +00:00
|
|
|
off_t this_off = 0, next_off = 0;
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2014-07-30 23:27:50 +00:00
|
|
|
if (!this->jlf_line_offsets.empty()) {
|
|
|
|
this_off = this->jlf_line_offsets[ll.get_sub_offset()];
|
|
|
|
if (this->jlf_cached_line[this_off] == '\n') {
|
|
|
|
this_off += 1;
|
|
|
|
}
|
|
|
|
next_off = this->jlf_line_offsets[ll.get_sub_offset() + 1];
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
sbr.share(this->jlf_share_manager,
|
2014-10-28 14:02:27 +00:00
|
|
|
&this->jlf_cached_line[0] + this_off,
|
2014-02-01 14:41:11 +00:00
|
|
|
next_off - this_off);
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
void external_log_format::build(std::vector<std::string> &errors)
|
2013-06-29 13:22:24 +00:00
|
|
|
{
|
2013-09-10 13:20:37 +00:00
|
|
|
try {
|
|
|
|
this->elf_filename_pcre = new pcrepp(this->elf_file_pattern.c_str());
|
|
|
|
}
|
|
|
|
catch (const pcrepp::error &e) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name + ".file-pattern:" +
|
|
|
|
e.what());
|
|
|
|
}
|
2013-08-07 13:31:34 +00:00
|
|
|
for (std::map<string, pattern>::iterator iter = this->elf_patterns.begin();
|
2013-06-29 18:00:34 +00:00
|
|
|
iter != this->elf_patterns.end();
|
2013-06-29 13:22:24 +00:00
|
|
|
++iter) {
|
2013-06-30 04:19:03 +00:00
|
|
|
try {
|
2013-08-07 13:31:34 +00:00
|
|
|
iter->second.p_pcre = new pcrepp(iter->second.p_string.c_str());
|
2013-06-30 04:19:03 +00:00
|
|
|
}
|
|
|
|
catch (const pcrepp::error &e) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name + ".regex[]" +
|
|
|
|
":" +
|
|
|
|
e.what());
|
|
|
|
continue;
|
|
|
|
}
|
2013-08-07 13:31:34 +00:00
|
|
|
for (pcre_named_capture::iterator name_iter = iter->second.p_pcre->named_begin();
|
|
|
|
name_iter != iter->second.p_pcre->named_end();
|
2013-06-29 18:00:34 +00:00
|
|
|
++name_iter) {
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, value_def>::iterator value_iter;
|
|
|
|
const intern_string_t name = intern_string::lookup(name_iter->pnc_name, -1);
|
2013-06-29 18:00:34 +00:00
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
value_iter = this->elf_value_defs.find(name);
|
2013-06-29 18:00:34 +00:00
|
|
|
if (value_iter != this->elf_value_defs.end()) {
|
2013-09-10 13:20:37 +00:00
|
|
|
value_def &vd = value_iter->second;
|
|
|
|
|
|
|
|
vd.vd_index = name_iter->index();
|
2014-10-28 14:02:27 +00:00
|
|
|
if (!vd.vd_unit_field.empty()) {
|
|
|
|
vd.vd_unit_field_index = iter->second.p_pcre->name_index(vd.vd_unit_field.get());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
vd.vd_unit_field_index = -1;
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
if (vd.vd_column == -1) {
|
|
|
|
vd.vd_column = this->elf_column_count++;
|
|
|
|
}
|
|
|
|
iter->second.p_value_by_index.push_back(vd);
|
2013-06-29 18:00:34 +00:00
|
|
|
}
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
stable_sort(iter->second.p_value_by_index.begin(),
|
|
|
|
iter->second.p_value_by_index.end());
|
|
|
|
|
|
|
|
this->elf_pattern_order.push_back(&iter->second);
|
2013-06-29 18:00:34 +00:00
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
if (this->jlf_json) {
|
|
|
|
if (!this->elf_patterns.empty()) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
": JSON logs cannot have regexes");
|
|
|
|
}
|
2013-09-14 13:36:31 +00:00
|
|
|
if (this->jlf_json) {
|
|
|
|
this->jlf_parse_context.reset(new yajlpp_parse_context(this->elf_name));
|
|
|
|
}
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (this->elf_patterns.empty()) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
": no regexes specified for format");
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
for (std::map<logline::level_t, level_pattern>::iterator iter = this->elf_level_patterns.begin();
|
|
|
|
iter != this->elf_level_patterns.end();
|
|
|
|
++iter) {
|
2013-06-30 04:19:03 +00:00
|
|
|
try {
|
|
|
|
iter->second.lp_pcre = new pcrepp(iter->second.lp_regex.c_str());
|
|
|
|
}
|
|
|
|
catch (const pcrepp::error &e) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name + ".level:" + e.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
for (std::map<const intern_string_t, value_def>::iterator iter = this->elf_value_defs.begin();
|
2013-09-10 13:20:37 +00:00
|
|
|
iter != this->elf_value_defs.end();
|
|
|
|
++iter) {
|
2013-10-11 13:22:29 +00:00
|
|
|
std::vector<std::string>::iterator act_iter;
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
if (iter->second.vd_column == -1) {
|
|
|
|
iter->second.vd_column = this->elf_column_count++;
|
|
|
|
}
|
2013-10-11 13:22:29 +00:00
|
|
|
|
|
|
|
for (act_iter = iter->second.vd_action_list.begin();
|
|
|
|
act_iter != iter->second.vd_action_list.end();
|
|
|
|
++act_iter) {
|
|
|
|
if (this->lf_action_defs.find(*act_iter) ==
|
|
|
|
this->lf_action_defs.end()) {
|
|
|
|
errors.push_back("error:" +
|
2014-10-28 14:02:27 +00:00
|
|
|
this->elf_name + ":" + iter->first.get() +
|
2013-10-11 13:22:29 +00:00
|
|
|
": cannot find action -- " + (*act_iter));
|
|
|
|
}
|
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!this->jlf_json && this->elf_samples.empty()) {
|
2013-07-31 04:21:28 +00:00
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":no sample logs provided, all formats must have samples");
|
|
|
|
}
|
|
|
|
|
2013-06-30 04:19:03 +00:00
|
|
|
for (std::vector<sample>::iterator iter = this->elf_samples.begin();
|
|
|
|
iter != this->elf_samples.end();
|
|
|
|
++iter) {
|
2013-07-18 04:24:33 +00:00
|
|
|
pcre_context_static<128> pc;
|
2013-06-30 04:19:03 +00:00
|
|
|
pcre_input pi(iter->s_line);
|
|
|
|
bool found = false;
|
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
for (std::vector<pattern *>::iterator pat_iter = this->elf_pattern_order.begin();
|
2014-03-22 15:02:48 +00:00
|
|
|
pat_iter != this->elf_pattern_order.end() && !found;
|
2013-06-30 04:19:03 +00:00
|
|
|
++pat_iter) {
|
2013-08-07 13:31:34 +00:00
|
|
|
pattern &pat = *(*pat_iter);
|
|
|
|
|
|
|
|
if (!pat.p_pcre)
|
2013-07-13 14:36:48 +00:00
|
|
|
continue;
|
2013-06-30 04:19:03 +00:00
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
if (pat.p_pcre->name_index(this->lf_timestamp_field.to_string()) < 0) {
|
2014-04-07 05:11:04 +00:00
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":timestamp field '" +
|
2014-10-28 14:02:27 +00:00
|
|
|
this->lf_timestamp_field.get() +
|
2014-04-07 05:11:04 +00:00
|
|
|
"' not found in pattern -- " +
|
|
|
|
pat.p_string);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
if (pat.p_pcre->match(pc, pi)) {
|
2014-03-22 15:02:48 +00:00
|
|
|
const char *ts = pi.get_substr_start(
|
2014-10-28 14:02:27 +00:00
|
|
|
pc[this->lf_timestamp_field.get()]);
|
|
|
|
ssize_t ts_len = pc[this->lf_timestamp_field.get()]->length();
|
2014-03-22 15:02:48 +00:00
|
|
|
date_time_scanner dts;
|
|
|
|
struct timeval tv;
|
2014-06-18 04:29:42 +00:00
|
|
|
struct exttm tm;
|
2014-03-22 15:02:48 +00:00
|
|
|
|
2014-04-07 05:11:04 +00:00
|
|
|
found = true;
|
2014-10-20 05:16:40 +00:00
|
|
|
if (ts_len == -1 || dts.scan(ts, ts_len, NULL, &tm, tv) == NULL) {
|
2014-04-07 05:11:04 +00:00
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":invalid sample -- " +
|
|
|
|
iter->s_line);
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
2014-06-18 04:29:42 +00:00
|
|
|
":unrecognized timestamp format -- " + ts);
|
|
|
|
|
|
|
|
for (int lpc = 0; PTIMEC_FORMATS[lpc].pf_fmt != NULL; lpc++) {
|
|
|
|
off_t off = 0;
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
PTIMEC_FORMATS[lpc].pf_func(&tm, ts, off, ts_len);
|
2014-06-18 04:29:42 +00:00
|
|
|
errors.push_back(" format: " + string(PTIMEC_FORMATS[lpc].pf_fmt) +
|
|
|
|
"; matched: " + string(ts, off));
|
|
|
|
}
|
2014-03-22 15:02:48 +00:00
|
|
|
}
|
2013-06-30 04:19:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":invalid sample -- " +
|
|
|
|
iter->s_line);
|
2013-07-28 18:03:31 +00:00
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
for (std::vector<pattern *>::iterator pat_iter = this->elf_pattern_order.begin();
|
|
|
|
pat_iter != this->elf_pattern_order.end();
|
2013-07-28 18:03:31 +00:00
|
|
|
++pat_iter) {
|
2013-08-07 13:31:34 +00:00
|
|
|
pattern &pat = *(*pat_iter);
|
|
|
|
|
|
|
|
if (!pat.p_pcre)
|
2013-07-28 18:03:31 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
std::string line_partial = iter->s_line;
|
|
|
|
|
|
|
|
while (!line_partial.empty()) {
|
|
|
|
pcre_input pi_partial(line_partial);
|
|
|
|
|
2013-08-07 13:31:34 +00:00
|
|
|
if (pat.p_pcre->match(pc, pi_partial, PCRE_PARTIAL)) {
|
2013-07-28 18:03:31 +00:00
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":partial sample matched -- " +
|
|
|
|
line_partial);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
line_partial = line_partial.substr(0, line_partial.size() - 1);
|
|
|
|
}
|
|
|
|
if (line_partial.empty()) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":no partial match found");
|
|
|
|
}
|
|
|
|
}
|
2013-06-30 04:19:03 +00:00
|
|
|
}
|
2013-06-29 18:00:34 +00:00
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class external_log_table : public log_vtab_impl {
|
|
|
|
public:
|
|
|
|
external_log_table(const external_log_format &elf) :
|
|
|
|
log_vtab_impl(elf.get_name()), elt_format(elf) {
|
|
|
|
};
|
|
|
|
|
|
|
|
void get_columns(vector<vtab_column> &cols) {
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, external_log_format::value_def>::const_iterator iter;
|
2013-07-23 12:55:08 +00:00
|
|
|
const external_log_format &elf = this->elt_format;
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
cols.resize(elf.elf_value_defs.size());
|
|
|
|
for (iter = elf.elf_value_defs.begin();
|
|
|
|
iter != elf.elf_value_defs.end();
|
2013-06-29 13:22:24 +00:00
|
|
|
++iter) {
|
2013-09-10 13:20:37 +00:00
|
|
|
const external_log_format::value_def &vd = iter->second;
|
2013-06-29 13:22:24 +00:00
|
|
|
int type;
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
switch (vd.vd_kind) {
|
|
|
|
case logline_value::VALUE_NULL:
|
2013-06-29 13:22:24 +00:00
|
|
|
case logline_value::VALUE_TEXT:
|
2014-05-05 13:44:58 +00:00
|
|
|
case logline_value::VALUE_JSON:
|
2014-06-18 04:29:42 +00:00
|
|
|
case logline_value::VALUE_QUOTED:
|
2013-06-29 13:22:24 +00:00
|
|
|
type = SQLITE3_TEXT;
|
|
|
|
break;
|
|
|
|
case logline_value::VALUE_FLOAT:
|
|
|
|
type = SQLITE_FLOAT;
|
|
|
|
break;
|
2013-09-10 13:20:37 +00:00
|
|
|
case logline_value::VALUE_BOOLEAN:
|
2013-06-29 13:22:24 +00:00
|
|
|
case logline_value::VALUE_INTEGER:
|
|
|
|
type = SQLITE_INTEGER;
|
|
|
|
break;
|
|
|
|
case logline_value::VALUE_UNKNOWN:
|
2014-01-18 14:46:51 +00:00
|
|
|
case logline_value::VALUE__MAX:
|
2014-03-06 14:58:49 +00:00
|
|
|
ensure(0);
|
2013-06-29 13:22:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2014-10-28 14:02:27 +00:00
|
|
|
cols[vd.vd_column].vc_name = vd.vd_name.get();
|
2013-09-10 13:20:37 +00:00
|
|
|
cols[vd.vd_column].vc_type = type;
|
|
|
|
cols[vd.vd_column].vc_collator = vd.vd_collate.c_str();
|
2013-06-29 13:22:24 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-07-13 22:38:12 +00:00
|
|
|
void get_foreign_keys(std::vector<std::string> &keys_inout)
|
|
|
|
{
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, external_log_format::value_def>::const_iterator iter;
|
2013-07-13 22:38:12 +00:00
|
|
|
|
|
|
|
log_vtab_impl::get_foreign_keys(keys_inout);
|
|
|
|
|
|
|
|
for (iter = this->elt_format.elf_value_defs.begin();
|
|
|
|
iter != this->elt_format.elf_value_defs.end();
|
|
|
|
++iter) {
|
|
|
|
if (iter->second.vd_foreign_key) {
|
2014-10-28 14:02:27 +00:00
|
|
|
keys_inout.push_back(iter->first.to_string());
|
2013-07-13 22:38:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
const external_log_format &elt_format;
|
|
|
|
};
|
|
|
|
|
|
|
|
log_vtab_impl *external_log_format::get_vtab_impl(void) const
|
|
|
|
{
|
|
|
|
return new external_log_table(*this);
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
/* XXX */
|
2009-09-14 01:07:32 +00:00
|
|
|
#include "log_format_impls.cc"
|