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"
|
2013-06-29 13:22:24 +00:00
|
|
|
#include "log_vtab_impl.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
|
|
|
|
*/
|
|
|
|
|
|
|
|
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-16 01:07:50 +00:00
|
|
|
|
2013-06-04 13:53:25 +00:00
|
|
|
int (*cmpfunc)(const char *, const char *);
|
|
|
|
|
2013-06-16 01:07:50 +00:00
|
|
|
if (exact) {
|
2013-06-04 13:53:25 +00:00
|
|
|
cmpfunc = strcasecmp;
|
2013-06-16 01:07:50 +00:00
|
|
|
}
|
|
|
|
else{
|
2013-06-04 13:53:25 +00:00
|
|
|
cmpfunc = strcasestr_i;
|
2013-06-16 01:07:50 +00:00
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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-06-29 18:00:34 +00:00
|
|
|
static bool next_format(const std::vector<external_log_format::pattern> &patterns,
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
const char *log_format::log_scanf(const char *line,
|
|
|
|
const char *fmt[],
|
|
|
|
int expected_matches,
|
|
|
|
const char *time_fmt[],
|
|
|
|
char *time_dest,
|
|
|
|
struct tm *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;
|
2009-09-14 01:07:32 +00:00
|
|
|
va_list args;
|
|
|
|
|
|
|
|
while (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
|
|
|
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 {
|
2013-06-30 23:43:08 +00:00
|
|
|
retval = this->lf_date_time.scan(time_dest, time_fmt, 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;
|
|
|
|
break;
|
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;
|
|
|
|
}
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
bool external_log_format::scan(std::vector<logline> &dst,
|
|
|
|
off_t offset,
|
|
|
|
char *prefix,
|
|
|
|
int len)
|
|
|
|
{
|
|
|
|
pcre_input pi(prefix, 0, len);
|
|
|
|
pcre_context_static<30> pc;
|
|
|
|
bool retval = false;
|
2013-06-29 18:00:34 +00:00
|
|
|
int curr_fmt = -1;
|
|
|
|
|
|
|
|
while (next_format(this->elf_patterns, curr_fmt, this->lf_fmt_lock)) {
|
|
|
|
if (!this->elf_patterns[curr_fmt].p_pcre->match(pc, pi)) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
pcre_context::capture_t *ts = pc["timestamp"];
|
|
|
|
pcre_context::capture_t *level_cap = pc[this->elf_level_field];
|
|
|
|
const char *ts_str = pi.get_substr_start(ts);
|
|
|
|
const char *last;
|
2013-06-29 18:00:34 +00:00
|
|
|
struct tm 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,
|
|
|
|
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) {
|
|
|
|
pcre_context_static<30> pc_level;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
if (!dst.empty() &&
|
2013-06-30 23:43:08 +00:00
|
|
|
((dst.back().get_time() - log_tv.tv_sec) > (24 * 60 * 60))) {
|
2013-06-29 18:00:34 +00:00
|
|
|
vector<logline>::iterator iter;
|
|
|
|
|
|
|
|
for (iter = dst.begin(); iter != dst.end(); iter++) {
|
|
|
|
time_t ot = iter->get_time();
|
|
|
|
struct tm *otm;
|
|
|
|
|
|
|
|
otm = gmtime(&ot);
|
|
|
|
otm->tm_year -= 1;
|
|
|
|
iter->set_time(tm2sec(otm));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void external_log_format::annotate(const std::string &line,
|
|
|
|
string_attrs_t &sa,
|
|
|
|
std::vector<logline_value> &values) const
|
|
|
|
{
|
|
|
|
pcre_context_static<30> pc;
|
|
|
|
pcre_input pi(line);
|
|
|
|
struct line_range lr;
|
|
|
|
pcre_context::capture_t *cap;
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
if (!this->elf_patterns[this->lf_fmt_lock].p_pcre->match(pc, pi)) {
|
2013-06-29 13:22:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cap = pc["timestamp"];
|
|
|
|
lr.lr_start = cap->c_begin;
|
|
|
|
lr.lr_end = cap->c_end;
|
|
|
|
sa[lr].insert(make_string_attr("timestamp", 0));
|
|
|
|
|
|
|
|
cap = pc["body"];
|
|
|
|
if (cap != NULL && cap->c_begin != -1) {
|
|
|
|
lr.lr_start = cap->c_begin;
|
|
|
|
lr.lr_end = cap->c_end;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
lr.lr_start = line.size();
|
|
|
|
lr.lr_end = line.size();
|
|
|
|
}
|
|
|
|
sa[lr].insert(make_string_attr("body", 0));
|
|
|
|
|
|
|
|
view_colors &vc = view_colors::singleton();
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
for (size_t lpc = 0; lpc < this->elf_patterns[this->lf_fmt_lock].p_value_by_index.size(); lpc++) {
|
|
|
|
const value_def &vd = this->elf_patterns[this->lf_fmt_lock].p_value_by_index[lpc];
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
values.push_back(logline_value(vd.vd_name,
|
|
|
|
vd.vd_kind,
|
|
|
|
pi.get_substr(pc[vd.vd_index]),
|
|
|
|
vd.vd_identifier));
|
|
|
|
|
|
|
|
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;
|
|
|
|
sa[lr].insert(make_string_attr("style", vc.attrs_for_ident(pi.get_substr_start(pc[vd.vd_index]), lr.length())));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-06-29 18:00:34 +00:00
|
|
|
for (std::vector<pattern>::iterator iter = this->elf_patterns.begin();
|
|
|
|
iter != this->elf_patterns.end();
|
2013-06-29 13:22:24 +00:00
|
|
|
++iter) {
|
2013-06-30 04:19:03 +00:00
|
|
|
try {
|
|
|
|
iter->p_pcre = new pcrepp(iter->p_string.c_str());
|
|
|
|
}
|
|
|
|
catch (const pcrepp::error &e) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name + ".regex[]" +
|
|
|
|
":" +
|
|
|
|
e.what());
|
|
|
|
continue;
|
|
|
|
}
|
2013-06-29 18:00:34 +00:00
|
|
|
for (pcre_named_capture::iterator name_iter = iter->p_pcre->named_begin();
|
|
|
|
name_iter != iter->p_pcre->named_end();
|
|
|
|
++name_iter) {
|
|
|
|
std::map<std::string, value_def>::iterator value_iter;
|
|
|
|
|
|
|
|
value_iter = this->elf_value_defs.find(std::string(name_iter->pnc_name));
|
|
|
|
if (value_iter != this->elf_value_defs.end()) {
|
|
|
|
value_iter->second.vd_index = name_iter->index();
|
|
|
|
iter->p_value_by_index.push_back(value_iter->second);
|
|
|
|
}
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
stable_sort(iter->p_value_by_index.begin(),
|
|
|
|
iter->p_value_by_index.end());
|
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
if (this->elf_patterns.empty()) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
": 'regex' field is empty");
|
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());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (std::vector<sample>::iterator iter = this->elf_samples.begin();
|
|
|
|
iter != this->elf_samples.end();
|
|
|
|
++iter) {
|
|
|
|
pcre_context_static<30> pc;
|
|
|
|
pcre_input pi(iter->s_line);
|
|
|
|
bool found = false;
|
|
|
|
|
|
|
|
for (std::vector<pattern>::iterator pat_iter = this->elf_patterns.begin();
|
|
|
|
pat_iter != this->elf_patterns.end();
|
|
|
|
++pat_iter) {
|
2013-07-13 14:36:48 +00:00
|
|
|
if (!pat_iter->p_pcre)
|
|
|
|
continue;
|
2013-06-30 04:19:03 +00:00
|
|
|
|
|
|
|
if (pat_iter->p_pcre->match(pc, pi)) {
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
errors.push_back("error:" +
|
|
|
|
this->elf_name +
|
|
|
|
":invalid sample -- " +
|
|
|
|
iter->s_line);
|
|
|
|
}
|
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) {
|
|
|
|
std::vector<external_log_format::value_def>::const_iterator iter;
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
for (iter = this->elt_format.elf_patterns[0].p_value_by_index.begin();
|
|
|
|
iter != this->elt_format.elf_patterns[0].p_value_by_index.end();
|
2013-06-29 13:22:24 +00:00
|
|
|
++iter) {
|
|
|
|
int type;
|
|
|
|
|
|
|
|
switch (iter->vd_kind) {
|
|
|
|
case logline_value::VALUE_TEXT:
|
|
|
|
type = SQLITE3_TEXT;
|
|
|
|
break;
|
|
|
|
case logline_value::VALUE_FLOAT:
|
|
|
|
type = SQLITE_FLOAT;
|
|
|
|
break;
|
|
|
|
case logline_value::VALUE_INTEGER:
|
|
|
|
type = SQLITE_INTEGER;
|
|
|
|
break;
|
|
|
|
case logline_value::VALUE_UNKNOWN:
|
|
|
|
assert(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cols.push_back(vtab_column(iter->vd_name.c_str(),
|
|
|
|
type,
|
|
|
|
iter->vd_collate.c_str()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-07-13 22:38:12 +00:00
|
|
|
void get_foreign_keys(std::vector<std::string> &keys_inout)
|
|
|
|
{
|
|
|
|
std::map<std::string, external_log_format::value_def>::const_iterator iter;
|
|
|
|
|
|
|
|
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) {
|
|
|
|
keys_inout.push_back(iter->first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
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"
|