2012-09-22 23:15:15 +00:00
|
|
|
/**
|
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.
|
|
|
|
*
|
2012-09-22 23:15:15 +00:00
|
|
|
* @file log_format.hh
|
|
|
|
*/
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
#ifndef __log_format_hh
|
|
|
|
#define __log_format_hh
|
|
|
|
|
|
|
|
#include <time.h>
|
2013-06-30 23:43:08 +00:00
|
|
|
#include <sys/time.h>
|
2012-07-13 16:26:47 +00:00
|
|
|
#include <stdint.h>
|
2013-06-01 04:13:26 +00:00
|
|
|
#define __STDC_FORMAT_MACROS
|
|
|
|
#include <inttypes.h>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
#include <set>
|
2015-04-05 14:12:20 +00:00
|
|
|
#include <list>
|
2009-09-14 01:07:32 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2009-10-14 19:42:58 +00:00
|
|
|
#include <memory>
|
2013-09-10 13:20:37 +00:00
|
|
|
#include <sstream>
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
#include "pcrepp.hh"
|
2013-09-14 13:36:31 +00:00
|
|
|
#include "yajlpp.hh"
|
2014-03-06 14:58:49 +00:00
|
|
|
#include "lnav_log.hh"
|
2013-06-30 23:43:08 +00:00
|
|
|
#include "lnav_util.hh"
|
2013-06-12 13:59:48 +00:00
|
|
|
#include "byte_array.hh"
|
2013-05-24 14:55:56 +00:00
|
|
|
#include "view_curses.hh"
|
2014-10-28 14:02:27 +00:00
|
|
|
#include "intern_string.hh"
|
2014-02-01 14:41:11 +00:00
|
|
|
#include "shared_buffer.hh"
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2015-07-19 09:40:02 +00:00
|
|
|
class log_format;
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
/**
|
|
|
|
* Metadata for a single line in a log file.
|
|
|
|
*/
|
|
|
|
class logline {
|
|
|
|
public:
|
2014-01-25 17:29:35 +00:00
|
|
|
static string_attr_type L_PREFIX;
|
|
|
|
static string_attr_type L_TIMESTAMP;
|
|
|
|
static string_attr_type L_FILE;
|
|
|
|
static string_attr_type L_PARTITION;
|
2015-07-18 03:39:06 +00:00
|
|
|
static string_attr_type L_MODULE;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The logging level identifiers for a line(s).
|
|
|
|
*/
|
|
|
|
typedef enum {
|
2013-05-28 04:35:00 +00:00
|
|
|
LEVEL_UNKNOWN,
|
|
|
|
LEVEL_TRACE,
|
2015-04-11 02:50:05 +00:00
|
|
|
LEVEL_DEBUG5,
|
|
|
|
LEVEL_DEBUG4,
|
|
|
|
LEVEL_DEBUG3,
|
|
|
|
LEVEL_DEBUG2,
|
2013-05-28 04:35:00 +00:00
|
|
|
LEVEL_DEBUG,
|
|
|
|
LEVEL_INFO,
|
2015-04-11 02:50:05 +00:00
|
|
|
LEVEL_STATS,
|
2013-05-28 04:35:00 +00:00
|
|
|
LEVEL_WARNING,
|
|
|
|
LEVEL_ERROR,
|
|
|
|
LEVEL_CRITICAL,
|
|
|
|
LEVEL_FATAL,
|
|
|
|
|
|
|
|
LEVEL__MAX,
|
|
|
|
|
2014-03-02 07:40:12 +00:00
|
|
|
LEVEL_MARK = 0x40, /*< Bookmarked line. */
|
2013-05-28 04:35:00 +00:00
|
|
|
LEVEL_CONTINUED = 0x80, /*< Continuation of multiline entry. */
|
|
|
|
|
|
|
|
/** Mask of flags for the level field. */
|
2014-03-02 07:40:12 +00:00
|
|
|
LEVEL__FLAGS = (LEVEL_MARK | LEVEL_CONTINUED)
|
2009-09-14 01:07:32 +00:00
|
|
|
} level_t;
|
|
|
|
|
2014-03-16 09:46:17 +00:00
|
|
|
static const char *level_names[LEVEL__MAX + 1];
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
static level_t string2level(const char *levelstr, ssize_t len = -1, bool exact = false);
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
static level_t abbrev2level(const char *levelstr, ssize_t len = -1);
|
2014-02-18 17:06:50 +00:00
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
static int levelcmp(const char *l1, ssize_t l1_len,
|
|
|
|
const char *l2, ssize_t l2_len);
|
2014-02-18 17:06:50 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
/**
|
|
|
|
* Construct a logline object with the given values.
|
|
|
|
*
|
|
|
|
* @param off The offset of the line in the file.
|
|
|
|
* @param t The timestamp for the line.
|
|
|
|
* @param millis The millisecond timestamp for the line.
|
|
|
|
* @param l The logging level.
|
|
|
|
*/
|
|
|
|
logline(off_t off,
|
2013-05-28 04:35:00 +00:00
|
|
|
time_t t,
|
|
|
|
uint16_t millis,
|
2015-07-18 03:39:06 +00:00
|
|
|
level_t l,
|
|
|
|
uint8_t mod = 0)
|
2013-05-28 04:35:00 +00:00
|
|
|
: ll_offset(off),
|
|
|
|
ll_time(t),
|
|
|
|
ll_millis(millis),
|
2014-10-31 18:11:56 +00:00
|
|
|
ll_sub_offset(0),
|
2015-07-18 03:39:06 +00:00
|
|
|
ll_level(l),
|
|
|
|
ll_module_id(mod)
|
2013-06-16 01:07:50 +00:00
|
|
|
{
|
2013-06-12 13:59:48 +00:00
|
|
|
memset(this->ll_schema, 0, sizeof(this->ll_schema));
|
|
|
|
};
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-30 23:43:08 +00:00
|
|
|
logline(off_t off,
|
|
|
|
const struct timeval &tv,
|
|
|
|
level_t l,
|
2015-07-18 03:39:06 +00:00
|
|
|
uint8_t mod = 0)
|
2013-06-30 23:43:08 +00:00
|
|
|
: ll_offset(off),
|
2014-10-31 18:11:56 +00:00
|
|
|
ll_sub_offset(0),
|
2015-07-18 03:39:06 +00:00
|
|
|
ll_level(l),
|
|
|
|
ll_module_id(mod)
|
2013-06-30 23:43:08 +00:00
|
|
|
{
|
|
|
|
this->set_time(tv);
|
|
|
|
memset(this->ll_schema, 0, sizeof(this->ll_schema));
|
|
|
|
};
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
/** @return The offset of the line in the file. */
|
|
|
|
off_t get_offset() const { return this->ll_offset; };
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
uint16_t get_sub_offset() const { return this->ll_sub_offset; };
|
|
|
|
|
|
|
|
void set_sub_offset(uint16_t suboff) { this->ll_sub_offset = suboff; };
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
/** @return The timestamp for the line. */
|
|
|
|
time_t get_time() const { return this->ll_time; };
|
|
|
|
|
|
|
|
void set_time(time_t t) { this->ll_time = t; };
|
|
|
|
|
|
|
|
/** @return The millisecond timestamp for the line. */
|
|
|
|
uint16_t get_millis() const { return this->ll_millis; };
|
|
|
|
|
2013-06-30 23:43:08 +00:00
|
|
|
void set_millis(uint16_t m) { this->ll_millis = m; };
|
|
|
|
|
2014-03-16 22:07:08 +00:00
|
|
|
uint64_t get_time_in_millis() const {
|
|
|
|
return (this->ll_time * 1000ULL + (uint64_t) this->ll_millis);
|
|
|
|
};
|
|
|
|
|
2013-06-30 23:43:08 +00:00
|
|
|
struct timeval get_timeval() const {
|
|
|
|
struct timeval retval = { this->ll_time, this->ll_millis * 1000 };
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
|
|
|
void set_time(const struct timeval &tv) {
|
|
|
|
this->ll_time = tv.tv_sec;
|
|
|
|
this->ll_millis = tv.tv_usec / 1000;
|
|
|
|
};
|
2013-04-23 16:25:18 +00:00
|
|
|
|
2014-03-02 07:40:12 +00:00
|
|
|
void set_mark(bool val) {
|
|
|
|
if (val) {
|
|
|
|
this->ll_level |= LEVEL_MARK;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this->ll_level &= ~LEVEL_MARK;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool is_marked(void) const { return this->ll_level & LEVEL_MARK; };
|
2009-09-14 01:07:32 +00:00
|
|
|
|
|
|
|
/** @param l The logging level. */
|
|
|
|
void set_level(level_t l) { this->ll_level = l; };
|
|
|
|
|
|
|
|
/** @return The logging level. */
|
|
|
|
level_t get_level() const { return (level_t)(this->ll_level & 0xff); };
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
level_t get_msg_level() const {
|
|
|
|
return (level_t)(this->ll_level & ~LEVEL__FLAGS);
|
|
|
|
};
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
const char *get_level_name() const
|
|
|
|
{
|
2015-04-11 02:50:05 +00:00
|
|
|
return level_names[this->ll_level & ~LEVEL__FLAGS];
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2013-07-31 04:21:28 +00:00
|
|
|
bool is_continued(void) const {
|
|
|
|
return this->get_level() & LEVEL_CONTINUED;
|
|
|
|
};
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
uint8_t get_module_id(void) const {
|
|
|
|
return this->ll_module_id;
|
|
|
|
};
|
|
|
|
|
2013-06-12 13:59:48 +00:00
|
|
|
/**
|
|
|
|
* @return True if there is a schema value set for this log line.
|
|
|
|
*/
|
2013-06-16 01:07:50 +00:00
|
|
|
bool has_schema(void) const
|
|
|
|
{
|
2013-07-23 12:55:08 +00:00
|
|
|
return (this->ll_schema[0] != 0 ||
|
2015-07-18 03:39:06 +00:00
|
|
|
this->ll_schema[1] != 0);
|
2013-06-12 13:59:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the "schema" for this log line. The schema ID is used to match log
|
|
|
|
* lines that have a similar format when generating the logline table. The
|
|
|
|
* schema is set lazily so that startup is faster.
|
2013-06-16 01:07:50 +00:00
|
|
|
*
|
2013-06-12 13:59:48 +00:00
|
|
|
* @param ba The SHA-1 hash of the constant parts of this log line.
|
|
|
|
*/
|
2014-02-04 17:26:25 +00:00
|
|
|
void set_schema(const byte_array<2, uint64_t> &ba)
|
2013-06-16 01:07:50 +00:00
|
|
|
{
|
2013-06-12 13:59:48 +00:00
|
|
|
memcpy(this->ll_schema, ba.in(), sizeof(this->ll_schema));
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Perform a partial match of the given schema against this log line.
|
|
|
|
* Storing the full schema is not practical, so we just keep the first four
|
|
|
|
* bytes.
|
2013-06-16 01:07:50 +00:00
|
|
|
*
|
2013-06-12 13:59:48 +00:00
|
|
|
* @param ba The SHA-1 hash of the constant parts of a log line.
|
|
|
|
* @return True if the first four bytes of the given schema match the
|
|
|
|
* schema stored in this log line.
|
|
|
|
*/
|
2014-02-04 17:26:25 +00:00
|
|
|
bool match_schema(const byte_array<2, uint64_t> &ba) const
|
2013-06-16 01:07:50 +00:00
|
|
|
{
|
2013-06-12 13:59:48 +00:00
|
|
|
return memcmp(this->ll_schema, ba.in(), sizeof(this->ll_schema)) == 0;
|
|
|
|
}
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
/**
|
|
|
|
* Compare loglines based on their timestamp.
|
|
|
|
*/
|
|
|
|
bool operator<(const logline &rhs) const
|
|
|
|
{
|
2013-05-28 04:35:00 +00:00
|
|
|
return this->ll_time < rhs.ll_time ||
|
|
|
|
(this->ll_time == rhs.ll_time &&
|
|
|
|
this->ll_millis < rhs.ll_millis);
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2013-04-17 16:27:12 +00:00
|
|
|
bool operator<(const time_t &rhs) const { return this->ll_time < rhs; };
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-07-14 04:31:59 +00:00
|
|
|
bool operator<(const struct timeval &rhs) const {
|
|
|
|
return ((this->ll_time < rhs.tv_sec) ||
|
|
|
|
(this->ll_millis < (rhs.tv_usec / 1000)));
|
|
|
|
};
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
private:
|
2013-05-28 04:35:00 +00:00
|
|
|
off_t ll_offset;
|
|
|
|
time_t ll_time;
|
|
|
|
uint16_t ll_millis;
|
2013-09-10 13:20:37 +00:00
|
|
|
uint16_t ll_sub_offset;
|
2014-10-31 18:11:56 +00:00
|
|
|
uint8_t ll_level;
|
2015-07-18 03:39:06 +00:00
|
|
|
uint8_t ll_module_id;
|
|
|
|
char ll_schema[2];
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2013-07-23 12:55:08 +00:00
|
|
|
enum scale_op_t {
|
|
|
|
SO_IDENTITY,
|
|
|
|
SO_MULTIPLY,
|
|
|
|
SO_DIVIDE
|
|
|
|
};
|
|
|
|
|
|
|
|
struct scaling_factor {
|
|
|
|
scaling_factor() : sf_op(SO_IDENTITY), sf_value(1) { };
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void scale(T &val) const {
|
|
|
|
switch (this->sf_op) {
|
|
|
|
case SO_IDENTITY:
|
|
|
|
break;
|
|
|
|
case SO_DIVIDE:
|
|
|
|
val = val / (T)this->sf_value;
|
|
|
|
break;
|
|
|
|
case SO_MULTIPLY:
|
|
|
|
val = val * (T)this->sf_value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scale_op_t sf_op;
|
|
|
|
double sf_value;
|
|
|
|
};
|
|
|
|
|
2013-05-24 14:55:56 +00:00
|
|
|
class logline_value {
|
|
|
|
public:
|
2013-05-28 04:35:00 +00:00
|
|
|
enum kind_t {
|
2013-06-29 13:22:24 +00:00
|
|
|
VALUE_UNKNOWN = -1,
|
2013-09-10 13:20:37 +00:00
|
|
|
VALUE_NULL,
|
2013-05-28 04:35:00 +00:00
|
|
|
VALUE_TEXT,
|
|
|
|
VALUE_INTEGER,
|
|
|
|
VALUE_FLOAT,
|
2013-09-10 13:20:37 +00:00
|
|
|
VALUE_BOOLEAN,
|
2014-05-05 13:44:58 +00:00
|
|
|
VALUE_JSON,
|
2014-06-18 04:29:42 +00:00
|
|
|
VALUE_QUOTED,
|
2014-01-18 14:46:51 +00:00
|
|
|
|
|
|
|
VALUE__MAX
|
2013-05-28 04:35:00 +00:00
|
|
|
};
|
|
|
|
|
2014-01-18 14:46:51 +00:00
|
|
|
static const char *value_names[VALUE__MAX];
|
2013-06-29 13:22:24 +00:00
|
|
|
static kind_t string2kind(const char *kindstr);
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
logline_value(const intern_string_t name)
|
2015-07-19 09:40:02 +00:00
|
|
|
: lv_name(name), lv_kind(VALUE_NULL), lv_identifier(), lv_column(-1),
|
|
|
|
lv_from_module(false), lv_format(NULL) { };
|
2014-10-28 14:02:27 +00:00
|
|
|
logline_value(const intern_string_t name, bool b)
|
2013-09-10 13:20:37 +00:00
|
|
|
: lv_name(name),
|
|
|
|
lv_kind(VALUE_BOOLEAN),
|
2015-06-03 13:36:58 +00:00
|
|
|
lv_value((int64_t)(b ? 1 : 0)),
|
2013-09-10 13:20:37 +00:00
|
|
|
lv_identifier(),
|
2015-07-19 09:40:02 +00:00
|
|
|
lv_column(-1),
|
|
|
|
lv_from_module(false), lv_format(NULL) { };
|
2014-10-28 14:02:27 +00:00
|
|
|
logline_value(const intern_string_t name, int64_t i)
|
2015-07-19 09:40:02 +00:00
|
|
|
: lv_name(name), lv_kind(VALUE_INTEGER), lv_value(i), lv_identifier(), lv_column(-1),
|
|
|
|
lv_from_module(false), lv_format(NULL) { };
|
2014-10-28 14:02:27 +00:00
|
|
|
logline_value(const intern_string_t name, double i)
|
2015-07-19 09:40:02 +00:00
|
|
|
: lv_name(name), lv_kind(VALUE_FLOAT), lv_value(i), lv_identifier(), lv_column(-1),
|
|
|
|
lv_from_module(false), lv_format(NULL) { };
|
2015-06-03 13:36:58 +00:00
|
|
|
logline_value(const intern_string_t name, shared_buffer_ref &sbr, int column = -1)
|
2014-02-01 14:41:11 +00:00
|
|
|
: lv_name(name), lv_kind(VALUE_TEXT), lv_sbr(sbr),
|
2015-07-19 09:40:02 +00:00
|
|
|
lv_identifier(), lv_column(column),
|
|
|
|
lv_from_module(false), lv_format(NULL) {
|
2015-06-03 13:36:58 +00:00
|
|
|
};
|
|
|
|
logline_value(const intern_string_t name, const intern_string_t val, int column = -1)
|
|
|
|
: lv_name(name), lv_kind(VALUE_TEXT), lv_intern_string(val), lv_identifier(),
|
2015-07-19 09:40:02 +00:00
|
|
|
lv_column(column), lv_from_module(false), lv_format(NULL) {
|
2015-06-03 13:36:58 +00:00
|
|
|
|
2014-01-25 20:13:41 +00:00
|
|
|
};
|
2014-10-28 14:02:27 +00:00
|
|
|
logline_value(const intern_string_t name, kind_t kind, shared_buffer_ref &sbr,
|
2013-09-10 13:20:37 +00:00
|
|
|
bool ident=false, const scaling_factor *scaling=NULL,
|
2015-07-19 09:40:02 +00:00
|
|
|
int col=-1, int start=-1, int end=-1, bool from_module=false,
|
|
|
|
const log_format *format=NULL)
|
2014-02-01 14:41:11 +00:00
|
|
|
: lv_name(name), lv_kind(kind),
|
2014-01-25 20:13:41 +00:00
|
|
|
lv_identifier(ident), lv_column(col),
|
2015-07-19 09:40:02 +00:00
|
|
|
lv_origin(start, end),
|
|
|
|
lv_from_module(from_module),
|
|
|
|
lv_format(format)
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
2014-02-01 14:41:11 +00:00
|
|
|
if (sbr.get_data() == NULL) {
|
2014-01-25 20:13:41 +00:00
|
|
|
this->lv_kind = kind = VALUE_NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
switch (kind) {
|
2014-05-05 13:44:58 +00:00
|
|
|
case VALUE_JSON:
|
2013-05-28 04:35:00 +00:00
|
|
|
case VALUE_TEXT:
|
2014-06-18 04:29:42 +00:00
|
|
|
case VALUE_QUOTED:
|
2014-02-01 14:41:11 +00:00
|
|
|
this->lv_sbr = sbr;
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
case VALUE_NULL:
|
|
|
|
break;
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
case VALUE_INTEGER:
|
2015-06-03 13:36:58 +00:00
|
|
|
strtonum(this->lv_value.i, sbr.get_data(), sbr.length());
|
2013-07-23 12:55:08 +00:00
|
|
|
if (scaling != NULL) {
|
2015-06-03 13:36:58 +00:00
|
|
|
scaling->scale(this->lv_value.i);
|
2013-07-23 12:55:08 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
case VALUE_FLOAT: {
|
|
|
|
char scan_value[sbr.length() + 1];
|
|
|
|
|
|
|
|
memcpy(scan_value, sbr.get_data(), sbr.length());
|
|
|
|
scan_value[sbr.length()] = '\0';
|
2015-06-03 13:36:58 +00:00
|
|
|
this->lv_value.d = strtod(scan_value, NULL);
|
2013-07-23 12:55:08 +00:00
|
|
|
if (scaling != NULL) {
|
2015-06-03 13:36:58 +00:00
|
|
|
scaling->scale(this->lv_value.d);
|
2013-07-23 12:55:08 +00:00
|
|
|
}
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2014-02-01 14:41:11 +00:00
|
|
|
}
|
2013-06-29 13:22:24 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
case VALUE_BOOLEAN:
|
2014-02-01 14:41:11 +00:00
|
|
|
if (strncmp(sbr.get_data(), "true", sbr.length()) == 0 ||
|
|
|
|
strncmp(sbr.get_data(), "yes", sbr.length()) == 0) {
|
2015-06-03 13:36:58 +00:00
|
|
|
this->lv_value.i = 1;
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-06-03 13:36:58 +00:00
|
|
|
this->lv_value.i = 0;
|
2013-09-10 13:20:37 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
case VALUE_UNKNOWN:
|
2014-01-18 14:46:51 +00:00
|
|
|
case VALUE__MAX:
|
2014-03-06 14:58:49 +00:00
|
|
|
ensure(0);
|
2014-02-01 14:41:11 +00:00
|
|
|
break;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
const std::string to_string() const
|
2013-05-28 04:35:00 +00:00
|
|
|
{
|
|
|
|
char buffer[128];
|
|
|
|
|
|
|
|
switch (this->lv_kind) {
|
2013-09-10 13:20:37 +00:00
|
|
|
case VALUE_NULL:
|
|
|
|
return "null";
|
|
|
|
|
2014-05-05 13:44:58 +00:00
|
|
|
case VALUE_JSON:
|
2013-05-28 04:35:00 +00:00
|
|
|
case VALUE_TEXT:
|
2015-06-03 13:36:58 +00:00
|
|
|
if (this->lv_sbr.empty()) {
|
|
|
|
return this->lv_intern_string.to_string();
|
|
|
|
}
|
2014-02-01 14:41:11 +00:00
|
|
|
return std::string(this->lv_sbr.get_data(), this->lv_sbr.length());
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2014-06-18 04:29:42 +00:00
|
|
|
case VALUE_QUOTED:
|
|
|
|
if (this->lv_sbr.length() == 0) {
|
|
|
|
return "";
|
|
|
|
} else {
|
|
|
|
switch (this->lv_sbr.get_data()[0]) {
|
|
|
|
case '\'':
|
|
|
|
case '"': {
|
|
|
|
char unquoted_str[this->lv_sbr.length()];
|
|
|
|
size_t unquoted_len;
|
|
|
|
|
|
|
|
unquoted_len = unquote(unquoted_str, this->lv_sbr.get_data(),
|
|
|
|
this->lv_sbr.length());
|
|
|
|
return std::string(unquoted_str, unquoted_len);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return std::string(this->lv_sbr.get_data(), this->lv_sbr.length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
case VALUE_INTEGER:
|
2015-06-03 13:36:58 +00:00
|
|
|
snprintf(buffer, sizeof(buffer), "%" PRId64, this->lv_value.i);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VALUE_FLOAT:
|
2015-06-03 13:36:58 +00:00
|
|
|
snprintf(buffer, sizeof(buffer), "%lf", this->lv_value.d);
|
2013-05-28 04:35:00 +00:00
|
|
|
break;
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
case VALUE_BOOLEAN:
|
2015-06-03 13:36:58 +00:00
|
|
|
if (this->lv_value.i) {
|
2013-09-10 13:20:37 +00:00
|
|
|
return "true";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return "false";
|
|
|
|
}
|
|
|
|
break;
|
2013-06-29 13:22:24 +00:00
|
|
|
case VALUE_UNKNOWN:
|
2014-01-18 14:46:51 +00:00
|
|
|
case VALUE__MAX:
|
2014-03-06 14:58:49 +00:00
|
|
|
ensure(0);
|
2013-09-10 13:20:37 +00:00
|
|
|
break;
|
2013-05-28 04:35:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return std::string(buffer);
|
|
|
|
};
|
|
|
|
|
2015-06-03 13:36:58 +00:00
|
|
|
const char *text_value() const {
|
|
|
|
if (this->lv_sbr.empty()) {
|
2015-07-19 09:40:02 +00:00
|
|
|
if (this->lv_intern_string.empty()) {
|
|
|
|
return "";
|
|
|
|
}
|
2015-06-03 13:36:58 +00:00
|
|
|
return this->lv_intern_string.get();
|
|
|
|
}
|
|
|
|
return this->lv_sbr.get_data();
|
|
|
|
};
|
|
|
|
|
|
|
|
const size_t text_length() const {
|
|
|
|
if (this->lv_sbr.empty()) {
|
|
|
|
return this->lv_intern_string.size();
|
|
|
|
}
|
|
|
|
return this->lv_sbr.length();
|
|
|
|
}
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
intern_string_t lv_name;
|
2013-05-28 04:35:00 +00:00
|
|
|
kind_t lv_kind;
|
|
|
|
union value_u {
|
|
|
|
int64_t i;
|
|
|
|
double d;
|
|
|
|
|
|
|
|
value_u() : i(0) { };
|
|
|
|
value_u(int64_t i) : i(i) { };
|
|
|
|
value_u(double d) : d(d) { };
|
2015-06-03 13:36:58 +00:00
|
|
|
} lv_value;
|
2014-02-01 14:41:11 +00:00
|
|
|
shared_buffer_ref lv_sbr;
|
2015-06-03 13:36:58 +00:00
|
|
|
intern_string_t lv_intern_string;
|
2013-06-29 13:22:24 +00:00
|
|
|
bool lv_identifier;
|
2013-09-10 13:20:37 +00:00
|
|
|
int lv_column;
|
2013-10-11 13:22:29 +00:00
|
|
|
struct line_range lv_origin;
|
2015-07-19 09:40:02 +00:00
|
|
|
bool lv_from_module;
|
|
|
|
const log_format *lv_format;
|
2013-09-10 13:20:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct logline_value_cmp {
|
2014-10-28 14:02:27 +00:00
|
|
|
logline_value_cmp(const intern_string_t *name = NULL, int col = -1)
|
2013-09-10 13:20:37 +00:00
|
|
|
: lvc_name(name), lvc_column(col) {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
bool operator()(const logline_value &lv) {
|
|
|
|
bool retval = true;
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
if (this->lvc_name != NULL) {
|
2013-09-10 13:20:37 +00:00
|
|
|
retval = retval && ((*this->lvc_name) == lv.lv_name);
|
2014-10-28 14:02:27 +00:00
|
|
|
}
|
|
|
|
if (this->lvc_column != -1) {
|
2013-09-10 13:20:37 +00:00
|
|
|
retval = retval && (this->lvc_column == lv.lv_column);
|
2014-10-28 14:02:27 +00:00
|
|
|
}
|
2013-09-10 13:20:37 +00:00
|
|
|
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
const intern_string_t *lvc_name;
|
2013-09-10 13:20:37 +00:00
|
|
|
int lvc_column;
|
2013-05-24 14:55:56 +00:00
|
|
|
};
|
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
class log_vtab_impl;
|
|
|
|
|
2012-09-22 23:15:15 +00:00
|
|
|
/**
|
|
|
|
* Base class for implementations of log format parsers.
|
|
|
|
*/
|
2009-09-14 01:07:32 +00:00
|
|
|
class log_format {
|
|
|
|
public:
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2012-09-22 23:15:15 +00:00
|
|
|
/**
|
|
|
|
* @return The collection of builtin log formats.
|
|
|
|
*/
|
2009-09-14 01:07:32 +00:00
|
|
|
static std::vector<log_format *> &get_root_formats(void);
|
|
|
|
|
2012-09-22 23:15:15 +00:00
|
|
|
/**
|
|
|
|
* Template used to register log formats during initialization.
|
|
|
|
*/
|
2013-05-28 04:35:00 +00:00
|
|
|
template<class T>
|
|
|
|
class register_root_format {
|
|
|
|
public:
|
|
|
|
register_root_format()
|
|
|
|
{
|
|
|
|
static T format;
|
2012-04-20 23:59:19 +00:00
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
log_format::lf_root_formats.push_back(&format);
|
|
|
|
};
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
static log_format *find_root_format(const char *name) {
|
|
|
|
std::vector<log_format *> &fmts = get_root_formats();
|
|
|
|
for (std::vector<log_format *>::iterator iter = fmts.begin();
|
|
|
|
iter != fmts.end();
|
|
|
|
++iter) {
|
|
|
|
log_format *lf = *iter;
|
|
|
|
if (lf->get_name() == name) {
|
|
|
|
return lf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
struct action_def {
|
|
|
|
std::string ad_name;
|
|
|
|
std::string ad_label;
|
|
|
|
std::vector<std::string> ad_cmdline;
|
|
|
|
bool ad_capture_output;
|
|
|
|
|
|
|
|
action_def() : ad_capture_output(false) { };
|
|
|
|
|
|
|
|
bool operator<(const action_def &rhs) const {
|
|
|
|
return this->ad_name < rhs.ad_name;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
log_format() : lf_mod_index(0),
|
|
|
|
lf_fmt_lock(-1),
|
2014-10-28 14:02:27 +00:00
|
|
|
lf_timestamp_field(intern_string::lookup("timestamp", -1)) {
|
2013-06-18 13:12:36 +00:00
|
|
|
};
|
2015-07-11 23:32:48 +00:00
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
virtual ~log_format() { };
|
|
|
|
|
2013-05-28 04:35:00 +00:00
|
|
|
virtual void clear(void)
|
|
|
|
{
|
|
|
|
this->lf_fmt_lock = -1;
|
2013-06-30 23:43:08 +00:00
|
|
|
this->lf_date_time.clear();
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2012-09-22 23:15:15 +00:00
|
|
|
/**
|
|
|
|
* Get the name of this log format.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2012-09-22 23:15:15 +00:00
|
|
|
* @return The log format name.
|
|
|
|
*/
|
2015-06-03 13:36:58 +00:00
|
|
|
virtual intern_string_t get_name(void) const = 0;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
virtual bool match_name(const std::string &filename) { return true; };
|
|
|
|
|
2012-09-22 23:15:15 +00:00
|
|
|
/**
|
|
|
|
* Scan a log line to see if it matches this log format.
|
|
|
|
*
|
|
|
|
* @param dst The vector of loglines that the formatter should append to
|
|
|
|
* if it detected a match.
|
|
|
|
* @param offset The offset in the file where this line is located.
|
|
|
|
* @param prefix The contents of the line.
|
|
|
|
* @param len The length of the prefix string.
|
|
|
|
*/
|
2013-05-28 04:35:00 +00:00
|
|
|
virtual bool scan(std::vector<logline> &dst,
|
|
|
|
off_t offset,
|
2014-10-20 05:16:40 +00:00
|
|
|
shared_buffer_ref &sbr) = 0;
|
2012-09-22 23:15:15 +00:00
|
|
|
|
2015-07-20 13:33:52 +00:00
|
|
|
virtual bool scan_for_partial(shared_buffer_ref &sbr, size_t &len_out) {
|
2015-07-11 23:32:48 +00:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2013-04-23 16:25:18 +00:00
|
|
|
/**
|
|
|
|
* Remove redundant data from the log line string.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-04-23 16:25:18 +00:00
|
|
|
* XXX We should probably also add some attributes to the line here, so we
|
|
|
|
* can highlight things like the date.
|
2013-05-28 04:35:00 +00:00
|
|
|
*
|
2013-04-23 16:25:18 +00:00
|
|
|
* @param line The log line to edit.
|
|
|
|
*/
|
2012-09-22 23:15:15 +00:00
|
|
|
virtual void scrub(std::string &line) { };
|
2013-05-24 14:55:56 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
virtual void annotate(shared_buffer_ref &sbr,
|
2013-05-24 14:55:56 +00:00
|
|
|
string_attrs_t &sa,
|
2015-07-19 09:40:02 +00:00
|
|
|
std::vector<logline_value> &values,
|
|
|
|
bool annotate_module = true) const
|
2013-05-24 14:55:56 +00:00
|
|
|
{ };
|
2013-05-28 04:35:00 +00:00
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
virtual std::auto_ptr<log_format> specialized(int fmt_lock = -1) = 0;
|
2009-09-14 01:07:32 +00:00
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
virtual log_vtab_impl *get_vtab_impl(void) const {
|
|
|
|
return NULL;
|
|
|
|
};
|
|
|
|
|
2015-03-19 05:57:30 +00:00
|
|
|
virtual void get_subline(const logline &ll, shared_buffer_ref &sbr, bool full_message = false) {
|
2013-09-10 13:20:37 +00:00
|
|
|
};
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
virtual const std::vector<std::string> *get_actions(const logline_value &lv) const {
|
|
|
|
return NULL;
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual const std::set<std::string> get_source_path() const {
|
|
|
|
std::set<std::string> retval;
|
|
|
|
|
|
|
|
retval.insert("default");
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
2015-04-11 05:55:57 +00:00
|
|
|
const char * const *get_timestamp_formats() const {
|
|
|
|
if (this->lf_timestamp_format.empty()) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return &this->lf_timestamp_format[0];
|
|
|
|
};
|
|
|
|
|
2014-03-16 05:33:56 +00:00
|
|
|
void check_for_new_year(std::vector<logline> &dst,
|
2014-04-07 05:11:04 +00:00
|
|
|
const struct timeval &log_tv);
|
2014-03-16 05:33:56 +00:00
|
|
|
|
2015-07-11 04:39:03 +00:00
|
|
|
virtual std::string get_pattern_name() const {
|
|
|
|
char name[32];
|
|
|
|
snprintf(name, sizeof(name), "builtin (%d)", this->lf_fmt_lock);
|
|
|
|
return name;
|
|
|
|
};
|
|
|
|
|
|
|
|
virtual std::string get_pattern_regex() const {
|
|
|
|
return "";
|
|
|
|
};
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
uint8_t lf_mod_index;
|
2013-06-30 23:43:08 +00:00
|
|
|
date_time_scanner lf_date_time;
|
|
|
|
int lf_fmt_lock;
|
2014-10-28 14:02:27 +00:00
|
|
|
intern_string_t lf_timestamp_field;
|
2015-04-11 05:55:57 +00:00
|
|
|
std::vector<const char *> lf_timestamp_format;
|
2013-10-11 13:22:29 +00:00
|
|
|
std::map<std::string, action_def> lf_action_defs;
|
2009-09-14 01:07:32 +00:00
|
|
|
protected:
|
|
|
|
static std::vector<log_format *> lf_root_formats;
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
struct pcre_format {
|
2015-07-11 04:39:03 +00:00
|
|
|
pcre_format(const char *regex) : name(regex), pcre(regex) {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
pcre_format() : name(NULL), pcre("") { };
|
|
|
|
|
2014-10-20 05:16:40 +00:00
|
|
|
const char *name;
|
|
|
|
pcrepp pcre;
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool next_format(pcre_format *fmt, int &index, int &locked_index);
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
const char *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,
|
2015-03-21 18:56:12 +00:00
|
|
|
struct timeval *tv_out,
|
2013-06-26 01:45:07 +00:00
|
|
|
...);
|
2009-09-14 01:07:32 +00:00
|
|
|
};
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
class module_format;
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
class external_log_format : public log_format {
|
|
|
|
|
|
|
|
public:
|
|
|
|
struct sample {
|
|
|
|
std::string s_line;
|
|
|
|
logline::level_t s_level;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct value_def {
|
2013-06-29 13:22:24 +00:00
|
|
|
value_def() :
|
|
|
|
vd_index(-1),
|
|
|
|
vd_kind(logline_value::VALUE_UNKNOWN),
|
2013-07-23 12:55:08 +00:00
|
|
|
vd_identifier(false),
|
|
|
|
vd_foreign_key(false),
|
2013-09-10 13:20:37 +00:00
|
|
|
vd_unit_field_index(-1),
|
2013-10-11 13:22:29 +00:00
|
|
|
vd_column(-1),
|
|
|
|
vd_hidden(false) {
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
intern_string_t vd_name;
|
2013-06-29 13:22:24 +00:00
|
|
|
int vd_index;
|
2013-06-26 01:45:07 +00:00
|
|
|
logline_value::kind_t vd_kind;
|
2013-06-29 13:22:24 +00:00
|
|
|
std::string vd_collate;
|
|
|
|
bool vd_identifier;
|
2013-07-13 22:38:12 +00:00
|
|
|
bool vd_foreign_key;
|
2014-10-28 14:02:27 +00:00
|
|
|
intern_string_t vd_unit_field;
|
2013-07-23 12:55:08 +00:00
|
|
|
int vd_unit_field_index;
|
|
|
|
std::map<std::string, scaling_factor> vd_unit_scaling;
|
2013-09-10 13:20:37 +00:00
|
|
|
int vd_column;
|
2013-10-11 13:22:29 +00:00
|
|
|
bool vd_hidden;
|
|
|
|
std::vector<std::string> vd_action_list;
|
2013-06-29 13:22:24 +00:00
|
|
|
|
|
|
|
bool operator<(const value_def &rhs) const {
|
|
|
|
return this->vd_index < rhs.vd_index;
|
|
|
|
};
|
2013-06-26 01:45:07 +00:00
|
|
|
};
|
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
struct pattern {
|
2015-07-18 03:39:06 +00:00
|
|
|
pattern() : p_pcre(NULL),
|
|
|
|
p_timestamp_field_index(-1),
|
|
|
|
p_level_field_index(-1),
|
|
|
|
p_module_field_index(-1),
|
|
|
|
p_body_field_index(-1),
|
|
|
|
p_timestamp_end(-1),
|
|
|
|
p_module_format(false) {
|
|
|
|
|
|
|
|
};
|
2013-06-29 18:00:34 +00:00
|
|
|
|
2015-07-11 04:39:03 +00:00
|
|
|
std::string p_config_path;
|
2013-06-29 18:00:34 +00:00
|
|
|
std::string p_string;
|
|
|
|
pcrepp *p_pcre;
|
|
|
|
std::vector<value_def> p_value_by_index;
|
2015-07-18 03:39:06 +00:00
|
|
|
int p_timestamp_field_index;
|
|
|
|
int p_level_field_index;
|
|
|
|
int p_module_field_index;
|
|
|
|
int p_body_field_index;
|
2015-07-11 23:32:48 +00:00
|
|
|
int p_timestamp_end;
|
2015-07-18 03:39:06 +00:00
|
|
|
bool p_module_format;
|
2013-06-29 18:00:34 +00:00
|
|
|
};
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
struct level_pattern {
|
2013-07-13 14:36:48 +00:00
|
|
|
level_pattern() : lp_pcre(NULL) { };
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
std::string lp_regex;
|
|
|
|
pcrepp *lp_pcre;
|
|
|
|
};
|
|
|
|
|
2015-06-03 13:36:58 +00:00
|
|
|
external_log_format(const intern_string_t name)
|
2013-09-10 13:20:37 +00:00
|
|
|
: elf_file_pattern(".*"),
|
2013-09-11 03:27:14 +00:00
|
|
|
elf_filename_pcre(NULL),
|
2013-09-10 13:20:37 +00:00
|
|
|
elf_column_count(0),
|
2014-03-11 10:49:52 +00:00
|
|
|
elf_timestamp_divisor(1.0),
|
2014-10-28 14:02:27 +00:00
|
|
|
elf_body_field(intern_string::lookup("body", -1)),
|
2015-07-11 23:32:48 +00:00
|
|
|
elf_multiline(true),
|
2015-07-18 03:39:06 +00:00
|
|
|
elf_container(false),
|
|
|
|
elf_has_module_format(false),
|
2013-09-11 03:27:14 +00:00
|
|
|
jlf_json(false),
|
2015-07-07 03:53:42 +00:00
|
|
|
jlf_hide_extra(false),
|
2013-09-10 13:20:37 +00:00
|
|
|
jlf_cached_offset(-1),
|
2014-10-29 13:42:45 +00:00
|
|
|
jlf_yajl_handle(yajl_free),
|
2013-09-10 13:20:37 +00:00
|
|
|
elf_name(name) {
|
|
|
|
this->jlf_line_offsets.reserve(128);
|
|
|
|
};
|
2013-06-26 01:45:07 +00:00
|
|
|
|
2015-06-03 13:36:58 +00:00
|
|
|
intern_string_t get_name(void) const {
|
2013-06-26 01:45:07 +00:00
|
|
|
return this->elf_name;
|
|
|
|
};
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
bool match_name(const std::string &filename) {
|
|
|
|
pcre_context_static<10> pc;
|
|
|
|
pcre_input pi(filename);
|
|
|
|
|
|
|
|
return this->elf_filename_pcre->match(pc, pi);
|
|
|
|
};
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
bool scan(std::vector<logline> &dst,
|
|
|
|
off_t offset,
|
2014-10-20 05:16:40 +00:00
|
|
|
shared_buffer_ref &sbr);
|
2015-07-11 23:32:48 +00:00
|
|
|
|
2015-07-20 13:33:52 +00:00
|
|
|
bool scan_for_partial(shared_buffer_ref &sbr, size_t &len_out);
|
2015-07-11 23:32:48 +00:00
|
|
|
|
2014-02-01 14:41:11 +00:00
|
|
|
void annotate(shared_buffer_ref &line,
|
2013-06-26 01:45:07 +00:00
|
|
|
string_attrs_t &sa,
|
2015-07-19 09:40:02 +00:00
|
|
|
std::vector<logline_value> &values,
|
|
|
|
bool annotate_module = true) const;
|
2013-06-26 01:45:07 +00:00
|
|
|
|
2013-06-29 18:00:34 +00:00
|
|
|
void build(std::vector<std::string> &errors);
|
2013-06-26 01:45:07 +00:00
|
|
|
|
2015-04-05 14:12:20 +00:00
|
|
|
bool match_samples(const std::vector<sample> &samples) const;
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
std::auto_ptr<log_format> specialized(int fmt_lock) {
|
2014-02-09 15:11:58 +00:00
|
|
|
external_log_format *elf = new external_log_format(*this);
|
|
|
|
std::auto_ptr<log_format> retval((log_format *)elf);
|
2013-06-26 01:45:07 +00:00
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
if (fmt_lock != -1) {
|
|
|
|
elf->lf_fmt_lock = fmt_lock;
|
|
|
|
}
|
|
|
|
|
2013-09-14 13:36:31 +00:00
|
|
|
if (this->jlf_json) {
|
2015-06-03 13:36:58 +00:00
|
|
|
this->jlf_parse_context.reset(new yajlpp_parse_context(this->elf_name.to_string()));
|
2014-10-29 13:42:45 +00:00
|
|
|
this->jlf_yajl_handle.reset(yajl_alloc(
|
|
|
|
&this->jlf_parse_context->ypc_callbacks,
|
|
|
|
NULL,
|
|
|
|
this->jlf_parse_context.get()));
|
|
|
|
yajl_config(this->jlf_yajl_handle.in(), yajl_dont_validate_strings, 1);
|
2014-10-31 20:16:35 +00:00
|
|
|
this->jlf_cached_line.reserve(16 * 1024);
|
2013-09-14 13:36:31 +00:00
|
|
|
}
|
|
|
|
|
2013-06-26 01:45:07 +00:00
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
2015-03-19 05:57:30 +00:00
|
|
|
void get_subline(const logline &ll, shared_buffer_ref &sbr, bool full_message);
|
2013-09-10 13:20:37 +00:00
|
|
|
|
2013-06-29 13:22:24 +00:00
|
|
|
log_vtab_impl *get_vtab_impl(void) const;
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
const std::vector<std::string> *get_actions(const logline_value &lv) const {
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, value_def>::const_iterator iter;
|
2013-10-11 13:22:29 +00:00
|
|
|
const std::vector<std::string> *retval = NULL;
|
|
|
|
|
|
|
|
iter = this->elf_value_defs.find(lv.lv_name);
|
|
|
|
if (iter != this->elf_value_defs.end()) {
|
|
|
|
retval = &iter->second.vd_action_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
};
|
|
|
|
|
|
|
|
const std::set<std::string> get_source_path() const {
|
|
|
|
return this->elf_source_path;
|
|
|
|
};
|
|
|
|
|
2015-04-25 19:15:51 +00:00
|
|
|
bool has_value_def(const intern_string_t &ist) const {
|
2015-04-26 11:57:36 +00:00
|
|
|
return (ist == this->lf_timestamp_field ||
|
|
|
|
ist == this->elf_level_field ||
|
|
|
|
ist == this->elf_body_field ||
|
|
|
|
this->elf_value_defs.find(ist) != this->elf_value_defs.end());
|
2015-04-25 19:15:51 +00:00
|
|
|
}
|
|
|
|
|
2015-07-11 04:39:03 +00:00
|
|
|
std::string get_pattern_name() const {
|
|
|
|
if (this->jlf_json) {
|
|
|
|
return "json";
|
|
|
|
}
|
|
|
|
return this->elf_pattern_order[this->lf_fmt_lock]->p_config_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string get_pattern_regex() const {
|
|
|
|
if (this->jlf_json) {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return this->elf_pattern_order[this->lf_fmt_lock]->p_string;
|
|
|
|
}
|
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
typedef std::map<intern_string_t, module_format> mod_map_t;
|
|
|
|
static mod_map_t MODULE_FORMATS;
|
|
|
|
static std::vector<external_log_format *> GRAPH_ORDERED_FORMATS;
|
|
|
|
|
2013-10-11 13:22:29 +00:00
|
|
|
std::set<std::string> elf_source_path;
|
2015-06-03 13:36:58 +00:00
|
|
|
std::list<intern_string_t> elf_collision;
|
2013-09-10 13:20:37 +00:00
|
|
|
std::string elf_file_pattern;
|
|
|
|
pcrepp *elf_filename_pcre;
|
2013-08-07 13:31:34 +00:00
|
|
|
std::map<std::string, pattern> elf_patterns;
|
|
|
|
std::vector<pattern *> elf_pattern_order;
|
2013-06-26 01:45:07 +00:00
|
|
|
std::vector<sample> elf_samples;
|
2014-10-28 14:02:27 +00:00
|
|
|
std::map<const intern_string_t, value_def> elf_value_defs;
|
2013-09-10 13:20:37 +00:00
|
|
|
int elf_column_count;
|
2014-03-11 10:49:52 +00:00
|
|
|
double elf_timestamp_divisor;
|
2014-10-28 14:02:27 +00:00
|
|
|
intern_string_t elf_level_field;
|
|
|
|
intern_string_t elf_body_field;
|
2015-07-18 03:39:06 +00:00
|
|
|
intern_string_t elf_module_id_field;
|
2013-06-26 01:45:07 +00:00
|
|
|
std::map<logline::level_t, level_pattern> elf_level_patterns;
|
2015-07-11 23:32:48 +00:00
|
|
|
bool elf_multiline;
|
2015-07-18 03:39:06 +00:00
|
|
|
bool elf_container;
|
|
|
|
bool elf_has_module_format;
|
2013-06-26 01:45:07 +00:00
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
enum json_log_field {
|
|
|
|
JLF_CONSTANT,
|
2014-03-11 10:49:52 +00:00
|
|
|
JLF_VARIABLE
|
2013-09-10 13:20:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct json_format_element {
|
|
|
|
json_format_element()
|
|
|
|
: jfe_type(JLF_CONSTANT), jfe_default_value("-"), jfe_min_width(0)
|
|
|
|
{ };
|
|
|
|
|
|
|
|
json_log_field jfe_type;
|
2014-10-28 14:02:27 +00:00
|
|
|
intern_string_t jfe_value;
|
2013-09-10 13:20:37 +00:00
|
|
|
std::string jfe_default_value;
|
|
|
|
int jfe_min_width;
|
|
|
|
};
|
|
|
|
|
2014-10-28 14:02:27 +00:00
|
|
|
void json_append_to_cache(const char *value, size_t len) {
|
|
|
|
size_t old_size = this->jlf_cached_line.size();
|
|
|
|
this->jlf_cached_line.resize(old_size + len);
|
|
|
|
memcpy(&this->jlf_cached_line[old_size], value, len);
|
|
|
|
};
|
|
|
|
|
2013-09-10 13:20:37 +00:00
|
|
|
bool jlf_json;
|
2015-07-07 03:53:42 +00:00
|
|
|
bool jlf_hide_extra;
|
2013-09-10 13:20:37 +00:00
|
|
|
std::vector<json_format_element> jlf_line_format;
|
|
|
|
std::vector<logline_value> jlf_line_values;
|
|
|
|
|
|
|
|
off_t jlf_cached_offset;
|
|
|
|
std::vector<off_t> jlf_line_offsets;
|
2014-02-01 14:41:11 +00:00
|
|
|
shared_buffer jlf_share_manager;
|
2014-10-28 14:02:27 +00:00
|
|
|
std::vector<char> jlf_cached_line;
|
2013-09-10 13:20:37 +00:00
|
|
|
string_attrs_t jlf_line_attrs;
|
2013-09-14 13:36:31 +00:00
|
|
|
std::auto_ptr<yajlpp_parse_context> jlf_parse_context;
|
2014-10-29 13:42:45 +00:00
|
|
|
auto_mem<yajl_handle_t> jlf_yajl_handle;
|
2013-06-26 01:45:07 +00:00
|
|
|
private:
|
2015-06-03 13:36:58 +00:00
|
|
|
const intern_string_t elf_name;
|
2013-06-26 01:45:07 +00:00
|
|
|
|
2015-07-18 03:39:06 +00:00
|
|
|
static uint8_t module_scan(const pcre_input &pi,
|
|
|
|
pcre_context::capture_t *body_cap,
|
|
|
|
const intern_string_t &mod_name);
|
|
|
|
};
|
|
|
|
|
|
|
|
class module_format {
|
|
|
|
|
|
|
|
public:
|
|
|
|
module_format() : mf_mod_format(NULL) {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
external_log_format *mf_mod_format;
|
2013-06-26 01:45:07 +00:00
|
|
|
};
|
|
|
|
|
2009-09-14 01:07:32 +00:00
|
|
|
#endif
|