[json-log] custom date formats

Fixes #341
This commit is contained in:
Timothy Stack 2016-08-18 22:15:35 -07:00
parent 4d091988a0
commit 41854cf637
17 changed files with 492 additions and 79 deletions

5
NEWS
View File

@ -1,4 +1,9 @@
lnav v0.8.2:
Features:
* The timestamp format for JSON log files can be specified with the
"timestamp-format" option in the "line-format" array.
lnav v0.8.1:
Features:
* Added a spectrogram command and view that displays the values of a

View File

@ -74,6 +74,8 @@ fields:
:field: The name of the message field that should be inserted at this
point in the message.
:timestamp-format: The timestamp format to use when displaying the time
for this log message. (v0.8.2+)
:default-value: The default value to use if the field could not be found
in the current log message. The built-in default is "-".

View File

@ -33,7 +33,7 @@ init-sql.c: bin2c
$(BIN2C_V)./bin2c -z -c $(srcdir)/init.sql $@
%.c: $(srcdir)/%.lnav bin2c
$(BIN2C_V)./bin2c -z -c $(srcdir)/$< $@
$(BIN2C_V)./bin2c -z -c $< $@
TIME_FORMATS = \
"@%@" \
@ -52,6 +52,8 @@ TIME_FORMATS = \
"%d/%b/%Y:%H:%M:%S +0000" \
"%d/%b/%Y:%H:%M:%S %z" \
"%b %d %H:%M:%S" \
"%b %d %k:%M:%S" \
"%b %d %l:%M:%S" \
"%b %e, %Y %l:%M:%S %p" \
"%m/%d/%y %H:%M:%S" \
"%m/%d/%Y %I:%M:%S:%L %p %Z" \

View File

@ -614,7 +614,7 @@ const char *date_time_scanner::scan(const char *time_dest,
this->dts_fmt_len += 7;
retval += 7;
}
else if (ptime_F(tm_out, time_dest, off, time_len)) {
else if (ptime_L(tm_out, time_dest, off, time_len)) {
tv_out.tv_usec = tm_out->et_nsec / 1000;
this->dts_fmt_len += 4;
retval += 4;

View File

@ -335,6 +335,14 @@ struct date_time_scanner {
struct timeval &tv_out,
bool convert_local = true);
size_t ftime(char *dst, size_t len, const struct exttm &tm) {
off_t off = 0;
PTIMEC_FORMATS[this->dts_fmt_lock].pf_ffunc(dst, off, len, tm);
return (size_t) off;
};
bool convert_to_timeval(const char *time_src,
ssize_t time_len,
struct timeval &tv_out) {

View File

@ -1170,12 +1170,23 @@ void external_log_format::get_subline(const logline &ll, shared_buffer_ref &sbr,
used_values[distance(this->jlf_line_values.begin(),
lv_iter)] = true;
}
else if (iter->jfe_value == ts_field) {
else if (iter->jfe_value == ts_field ||
!iter->jfe_ts_format.empty()) {
struct line_range lr;
ssize_t ts_len;
char ts[64];
ts_len = sql_strftime(ts, sizeof(ts), ll.get_timeval(), 'T');
if (iter->jfe_ts_format.empty()) {
ts_len = sql_strftime(ts, sizeof(ts),
ll.get_timeval(), 'T');
} else {
struct exttm et;
ll.to_exttm(et);
ts_len = ftime_fmt(ts, sizeof(ts),
iter->jfe_ts_format.c_str(),
et);
}
lr.lr_start = this->jlf_cached_line.size();
this->json_append_to_cache(ts, ts_len);
lr.lr_end = this->jlf_cached_line.size();

View File

@ -1049,6 +1049,7 @@ public:
intern_string_t jfe_value;
std::string jfe_default_value;
int jfe_min_width;
std::string jfe_ts_format;
};
void json_append_to_cache(const char *value, size_t len) {

View File

@ -106,6 +106,26 @@ static external_log_format::pattern *pattern_provider(yajlpp_parse_context &ypc,
return &pat;
}
static external_log_format::json_format_element &
ensure_json_format_element(external_log_format *elf, int index)
{
elf->jlf_line_format.resize(index + 1);
return elf->jlf_line_format[index];
}
static external_log_format::json_format_element *line_format_provider(
yajlpp_parse_context &ypc, void *root)
{
external_log_format *elf = ensure_format(&ypc);
int index = ypc.ypc_array_index.back();
external_log_format::json_format_element &jfe = ensure_json_format_element(elf, index);
jfe.jfe_type = external_log_format::JLF_VARIABLE;
return &jfe;
}
static int read_format_bool(yajlpp_parse_context *ypc, int val)
{
external_log_format *elf = ensure_format(ypc);
@ -358,14 +378,6 @@ static int read_sample_line(yajlpp_parse_context *ypc, const unsigned char *str,
return 1;
}
static external_log_format::json_format_element &
ensure_json_format_element(external_log_format *elf, int index)
{
elf->jlf_line_format.resize(index + 1);
return elf->jlf_line_format[index];
}
static int read_json_constant(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
{
external_log_format *elf = ensure_format(ypc);
@ -382,38 +394,6 @@ static int read_json_constant(yajlpp_parse_context *ypc, const unsigned char *st
return 1;
}
static int read_json_variable(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
{
external_log_format *elf = ensure_format(ypc);
string val = string((const char *)str, len);
int index = ypc->ypc_array_index.back();
external_log_format::json_format_element &jfe = ensure_json_format_element(elf, index);
string field_name = ypc->get_path_fragment(3);
jfe.jfe_type = external_log_format::JLF_VARIABLE;
if (field_name == "field") {
jfe.jfe_value = intern_string::lookup(val);
}
else if (field_name == "default-value") {
jfe.jfe_default_value = val;
}
return 1;
}
static int read_json_variable_num(yajlpp_parse_context *ypc, long long val)
{
external_log_format *elf = ensure_format(ypc);
int index = ypc->ypc_array_index.back();
external_log_format::json_format_element &jfe = ensure_json_format_element(elf, index);
string field_name = ypc->get_path_fragment(2);
jfe.jfe_type = external_log_format::JLF_VARIABLE;
jfe.jfe_min_width = val;
return 1;
}
static int create_search_table(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
{
external_log_format *elf = ensure_format(ypc);
@ -443,6 +423,27 @@ static struct json_path_handler pattern_handlers[] = {
json_path_handler()
};
static struct json_path_handler line_format_handlers[] = {
json_path_handler("field")
.with_synopsis("<field-name>")
.with_description("The name of the field to substitute at this position")
.with_min_length(1)
.for_field(&nullobj<external_log_format::json_format_element>()->jfe_value),
json_path_handler("default-value")
.with_synopsis("<string>")
.with_description("The default value for this position if the field is null")
.for_field(&nullobj<external_log_format::json_format_element>()->jfe_default_value),
json_path_handler("timestamp-format")
.with_synopsis("<string>")
.with_min_length(1)
.with_description("The strftime(3) format for this field")
.for_field(&nullobj<external_log_format::json_format_element>()->jfe_ts_format),
json_path_handler()
};
static struct json_path_handler format_handlers[] = {
json_path_handler("/\\w+/regex/[^/]+/")
.with_obj_provider(pattern_provider)
@ -470,8 +471,10 @@ static struct json_path_handler format_handlers[] = {
json_path_handler("/\\w+/action/[^/]+/capture-output", read_action_bool),
json_path_handler("/\\w+/action/[^/]+/cmd#", read_action_cmd),
json_path_handler("/\\w+/sample#/line", read_sample_line),
json_path_handler("/\\w+/line-format#/(field|default-value)", read_json_variable),
json_path_handler("/\\w+/line-format#/min-width", read_json_variable_num),
json_path_handler("/\\w+/line-format#/")
.with_obj_provider(line_format_provider)
.with_children(line_format_handlers),
json_path_handler("/\\w+/line-format#", read_json_constant),
json_path_handler("/\\w+/search-table/.+/pattern", create_search_table)

View File

@ -146,7 +146,7 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
this->lss_token_attrs, &logline::L_TIMESTAMP);
if (time_range.is_valid()) {
struct timeval adjusted_time;
struct tm adjusted_tm;
struct exttm adjusted_tm;
char buffer[128];
const char *fmt;
@ -155,35 +155,20 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
&this->lss_token_value.c_str()[time_range.lr_start],
time_range.length(),
adjusted_time);
fmt = "%Y-%m-%d %H:%M:%S.";
fmt = "%Y-%m-%d %H:%M:%S.%f";
gmtime_r(&adjusted_time.tv_sec, &adjusted_tm.et_tm);
adjusted_tm.et_nsec = adjusted_time.tv_usec * 1000;
ftime_fmt(buffer, sizeof(buffer), fmt, adjusted_tm);
}
else {
fmt = PTIMEC_FORMAT_STR[format->lf_date_time.dts_fmt_lock];
adjusted_time = this->lss_token_line->get_timeval();
}
strftime(buffer, sizeof(buffer),
fmt,
gmtime_r(&adjusted_time.tv_sec, &adjusted_tm));
if (format->lf_timestamp_flags & ETF_MACHINE_ORIENTED) {
size_t buffer_len = strlen(buffer);
snprintf(&buffer[buffer_len], sizeof(buffer) - buffer_len,
"%06d",
adjusted_time.tv_usec);
gmtime_r(&adjusted_time.tv_sec, &adjusted_tm.et_tm);
adjusted_tm.et_nsec = adjusted_time.tv_usec * 1000;
format->lf_date_time.ftime(buffer, sizeof(buffer), adjusted_tm);
}
const char *last = value_out.c_str();
ssize_t len = strlen(buffer);
if ((last[time_range.lr_start + len] == '.' ||
last[time_range.lr_start + len] == ',') &&
len + 4 <= time_range.length()) {
len = snprintf(&buffer[len], sizeof(buffer) - len,
".%03d",
this->lss_token_line->get_millis());
}
if (len > time_range.length()) {
ssize_t padding = len - time_range.length();

View File

@ -96,10 +96,36 @@ int main(int argc, char *argv[])
printf(" return true;\n");
printf("}\n\n");
}
for (int lpc = 1; lpc < argc; lpc++) {
const char *arg = argv[lpc];
printf("void ftime_f%d(char *dst, off_t &off_inout, size_t len, const struct exttm &tm) {\n",
lpc);
for (int index = 0; arg[index]; arg++) {
if (arg[index] == '%') {
switch (arg[index + 1]) {
case '@':
printf(" ftime_at(dst, off_inout, len, tm);\n");
arg += 1;
break;
default:
printf(" ftime_%c(dst, off_inout, len, tm);\n",
arg[index + 1]);
arg += 1;
break;
}
} else {
printf(" ftime_char(dst, off_inout, len, '%s');\n",
escape_char(arg[index]));
}
}
printf(" dst[off_inout] = '\\0';\n");
printf("}\n\n");
}
printf("struct ptime_fmt PTIMEC_FORMATS[] = {\n");
for (int lpc = 1; lpc < argc; lpc++) {
printf(" { \"%s\", ptime_f%d },\n", argv[lpc], lpc);
printf(" { \"%s\", ptime_f%d, ftime_f%d },\n", argv[lpc], lpc, lpc);
}
printf("\n");
printf(" { NULL, NULL }\n");

View File

@ -35,12 +35,16 @@
// XXX
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <cstdlib>
struct tm *secs2tm(time_t *tim_p, struct tm *res);
time_t tm2sec(const struct tm *t);
enum exttm_bits_t {
ETB_YEAR_SET,
@ -74,6 +78,13 @@ struct exttm {
\
off_inout += amount;
#define PTIME_APPEND(ch) \
if ((off_inout + 2) >= len) { \
return; \
} \
dst[off_inout] = ch; \
off_inout += 1;
#define ABR_TO_INT(a, b, c) \
((a << 24) | (b << 16) | (c << 8))
@ -157,6 +168,87 @@ inline bool ptime_b(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return ptime_b_slow(dst, str, off_inout, len);
}
inline void ftime_a(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
}
inline void ftime_Z(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
}
inline void ftime_b(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
switch (tm.et_tm.tm_mon) {
case 0:
PTIME_APPEND('J');
PTIME_APPEND('a');
PTIME_APPEND('n');
break;
case 1:
PTIME_APPEND('F');
PTIME_APPEND('e');
PTIME_APPEND('b');
break;
case 2:
PTIME_APPEND('M');
PTIME_APPEND('a');
PTIME_APPEND('r');
break;
case 3:
PTIME_APPEND('A');
PTIME_APPEND('p');
PTIME_APPEND('r');
break;
case 4:
PTIME_APPEND('M');
PTIME_APPEND('a');
PTIME_APPEND('y');
break;
case 5:
PTIME_APPEND('J');
PTIME_APPEND('u');
PTIME_APPEND('n');
break;
case 6:
PTIME_APPEND('J');
PTIME_APPEND('u');
PTIME_APPEND('l');
break;
case 7:
PTIME_APPEND('A');
PTIME_APPEND('u');
PTIME_APPEND('g');
break;
case 8:
PTIME_APPEND('S');
PTIME_APPEND('e');
PTIME_APPEND('p');
break;
case 9:
PTIME_APPEND('O');
PTIME_APPEND('c');
PTIME_APPEND('t');
break;
case 10:
PTIME_APPEND('N');
PTIME_APPEND('o');
PTIME_APPEND('v');
break;
case 11:
PTIME_APPEND('D');
PTIME_APPEND('e');
PTIME_APPEND('c');
break;
default:
PTIME_APPEND('X');
PTIME_APPEND('X');
PTIME_APPEND('X');
break;
}
}
inline bool ptime_S(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -169,6 +261,12 @@ inline bool ptime_S(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (dst->et_tm.tm_sec >= 0 && dst->et_tm.tm_sec <= 59);
}
inline void ftime_S(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
PTIME_APPEND('0' + ((tm.et_tm.tm_sec / 10) % 10));
PTIME_APPEND('0' + ((tm.et_tm.tm_sec / 1) % 10));
}
inline bool ptime_s(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
time_t epoch = 0;
@ -185,6 +283,14 @@ inline bool ptime_s(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (epoch > 0);
}
inline void ftime_s(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
time_t t = tm2sec(&tm.et_tm);
snprintf(&dst[off_inout], len - off_inout, "%ld", t);
off_inout = strlen(dst);
}
inline bool ptime_L(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
int ms = 0;
@ -209,6 +315,15 @@ inline bool ptime_L(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return false;
}
inline void ftime_L(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
int millis = tm.et_nsec / 1000000;
PTIME_APPEND('0' + ((millis / 100) % 10));
PTIME_APPEND('0' + ((millis / 10) % 10));
PTIME_APPEND('0' + ((millis / 1) % 10));
}
inline bool ptime_M(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -221,6 +336,12 @@ inline bool ptime_M(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (dst->et_tm.tm_min >= 0 && dst->et_tm.tm_min <= 59);
}
inline void ftime_M(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
PTIME_APPEND('0' + ((tm.et_tm.tm_min / 10) % 10));
PTIME_APPEND('0' + ((tm.et_tm.tm_min / 1) % 10));
}
inline bool ptime_H(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -233,6 +354,12 @@ inline bool ptime_H(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23);
}
inline void ftime_H(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 10) % 10));
PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 1) % 10));
}
inline bool ptime_i(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
uint64_t epoch_ms = 0;
@ -252,6 +379,15 @@ inline bool ptime_i(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (epoch_ms > 0);
}
inline void ftime_i(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
uint64_t t = tm2sec(&tm.et_tm);
t += tm.et_nsec / 1000000;
snprintf(&dst[off_inout], len - off_inout, "%lld", t);
off_inout = strlen(dst);
}
inline bool ptime_I(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -264,6 +400,21 @@ inline bool ptime_I(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (dst->et_tm.tm_hour >= 1 && dst->et_tm.tm_hour <= 12);
}
inline void ftime_I(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
int hour = tm.et_tm.tm_hour;
if (hour > 12) {
hour -= 12;
if (hour == 0) {
hour = 12;
}
}
PTIME_APPEND('0' + ((hour / 10) % 10));
PTIME_APPEND('0' + ((hour / 1) % 10));
}
inline bool ptime_d(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -286,6 +437,12 @@ inline bool ptime_d(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return false;
}
inline void ftime_d(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 10) % 10));
PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 1) % 10));
}
inline bool ptime_e(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
dst->et_tm.tm_mday = 0;
@ -310,6 +467,17 @@ inline bool ptime_e(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return false;
}
inline void ftime_e(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
if (tm.et_tm.tm_mday < 10) {
PTIME_APPEND(' ');
}
else {
PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 10) % 10));
}
PTIME_APPEND('0' + ((tm.et_tm.tm_mday / 1) % 10));
}
inline bool ptime_m(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
dst->et_tm.tm_mon = 0;
@ -336,6 +504,12 @@ inline bool ptime_m(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return false;
}
inline void ftime_m(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
PTIME_APPEND('0' + (((tm.et_tm.tm_mon + 1) / 10) % 10));
PTIME_APPEND('0' + (((tm.et_tm.tm_mon + 1) / 1) % 10));
}
inline bool ptime_k(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
dst->et_tm.tm_hour = 0;
@ -356,6 +530,17 @@ inline bool ptime_k(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (dst->et_tm.tm_hour >= 0 && dst->et_tm.tm_hour <= 23);
}
inline void ftime_k(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
if (tm.et_tm.tm_hour < 10) {
PTIME_APPEND(' ');
}
else {
PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 10) % 10));
}
PTIME_APPEND('0' + ((tm.et_tm.tm_hour / 1) % 10));
}
inline bool ptime_l(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
dst->et_tm.tm_hour = 0;
@ -376,6 +561,26 @@ inline bool ptime_l(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return (dst->et_tm.tm_hour >= 1 && dst->et_tm.tm_hour <= 12);
}
inline void ftime_l(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
int hour = tm.et_tm.tm_hour;
if (hour > 12) {
hour -= 12;
if (hour == 0) {
hour = 12;
}
}
if (hour < 10) {
PTIME_APPEND(' ');
}
else {
PTIME_APPEND('0' + ((hour / 10) % 10));
}
PTIME_APPEND('0' + ((hour / 1) % 10));
}
inline bool ptime_p(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -397,6 +602,17 @@ inline bool ptime_p(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return true;
}
inline void ftime_p(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
if (tm.et_tm.tm_hour < 12) {
PTIME_APPEND('A');
}
else {
PTIME_APPEND('P');
}
PTIME_APPEND('M');
}
inline bool ptime_Y(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(4, {
@ -412,6 +628,16 @@ inline bool ptime_Y(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return true;
}
inline void ftime_Y(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
int year = tm.et_tm.tm_year + 1900;
PTIME_APPEND('0' + ((year / 1000) % 10));
PTIME_APPEND('0' + ((year / 100) % 10));
PTIME_APPEND('0' + ((year / 10) % 10));
PTIME_APPEND('0' + ((year / 1) % 10));
}
inline bool ptime_y(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(2, {
@ -431,6 +657,14 @@ inline bool ptime_y(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return false;
}
inline void ftime_y(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
int year = tm.et_tm.tm_year + 1900;
PTIME_APPEND('0' + ((year / 10) % 10));
PTIME_APPEND('0' + ((year / 1) % 10));
}
inline bool ptime_z(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(5, {
@ -463,6 +697,26 @@ inline bool ptime_z(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return true;
}
inline void ftime_z(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
long gmtoff = std::abs(tm.et_gmtoff) / 60;
if (tm.et_gmtoff < 0) {
PTIME_APPEND('-');
}
else {
PTIME_APPEND('+');
}
long mins = gmtoff % 60;
long hours = gmtoff / 60;
PTIME_APPEND('0' + ((hours / 10) % 10));
PTIME_APPEND('0' + ((hours / 1) % 10));
PTIME_APPEND('0' + ((mins / 10) % 10));
PTIME_APPEND('0' + ((mins / 1) % 10));
}
inline bool ptime_f(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
{
PTIME_CONSUME(6, {
@ -483,16 +737,16 @@ inline bool ptime_f(struct exttm *dst, const char *str, off_t &off_inout, ssize_
return true;
}
inline bool ptime_F(struct exttm *dst, const char *str, off_t &off_inout, ssize_t len)
inline void ftime_f(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
PTIME_CONSUME(3, {
dst->et_nsec = (
(str[off_inout + 0] - '0') * 100 +
(str[off_inout + 1] - '0') * 10 +
(str[off_inout + 2] - '0') * 1) * 1000 * 1000;
});
uint32_t micros = tm.et_nsec / 1000;
return true;
PTIME_APPEND('0' + ((micros / 100000) % 10));
PTIME_APPEND('0' + ((micros / 10000) % 10));
PTIME_APPEND('0' + ((micros / 1000) % 10));
PTIME_APPEND('0' + ((micros / 100) % 10));
PTIME_APPEND('0' + ((micros / 10) % 10));
PTIME_APPEND('0' + ((micros / 1) % 10));
}
inline bool ptime_char(char val, const char *str, off_t &off_inout, ssize_t len)
@ -506,6 +760,11 @@ inline bool ptime_char(char val, const char *str, off_t &off_inout, ssize_t len)
return true;
}
inline void ftime_char(char *dst, off_t &off_inout, ssize_t len, char ch)
{
PTIME_APPEND(ch);
}
template<typename T>
inline bool ptime_hex_to_quad(T &value_inout, const char quad)
{
@ -561,13 +820,21 @@ inline bool ptime_at(struct exttm *dst, const char *str, off_t &off_inout, ssize
return true;
}
inline void ftime_at(char *dst, off_t &off_inout, ssize_t len, const struct exttm &tm)
{
}
typedef bool (*ptime_func)(struct exttm *dst, const char *str, off_t &off, ssize_t len);
typedef void (*ftime_func)(char *dst, off_t &off_inout, size_t len, const struct exttm &tm);
bool ptime_fmt(const char *fmt, struct exttm *dst, const char *str, off_t &off, ssize_t len);
size_t ftime_fmt(char *dst, size_t len, const char *fmt, const struct exttm &tm);
struct ptime_fmt {
const char *pf_fmt;
ptime_func pf_func;
ftime_func pf_ffunc;
};
extern struct ptime_fmt PTIMEC_FORMATS[];

View File

@ -102,3 +102,46 @@ bool ptime_fmt(const char *fmt, struct exttm *dst, const char *str, off_t &off,
return true;
}
#define FTIME_FMT_CASE(ch, c) \
case ch: \
ftime_ ## c(dst, off_inout, len, tm); \
lpc += 1; \
break
size_t ftime_fmt(char *dst, size_t len, const char *fmt, const struct exttm &tm)
{
off_t off_inout = 0;
for (ssize_t lpc = 0; fmt[lpc]; lpc++) {
if (fmt[lpc] == '%') {
switch (fmt[lpc + 1]) {
case '%':
ftime_char(dst, off_inout, len, '%');
break;
FTIME_FMT_CASE('b', b);
FTIME_FMT_CASE('S', S);
FTIME_FMT_CASE('s', s);
FTIME_FMT_CASE('L', L);
FTIME_FMT_CASE('M', M);
FTIME_FMT_CASE('H', H);
FTIME_FMT_CASE('i', i);
FTIME_FMT_CASE('I', I);
FTIME_FMT_CASE('d', d);
FTIME_FMT_CASE('e', e);
FTIME_FMT_CASE('k', k);
FTIME_FMT_CASE('l', l);
FTIME_FMT_CASE('m', m);
FTIME_FMT_CASE('p', p);
FTIME_FMT_CASE('Y', Y);
FTIME_FMT_CASE('y', y);
FTIME_FMT_CASE('z', z);
}
}
else {
ftime_char(dst, off_inout, len, fmt[lpc]);
}
}
return (size_t) off_inout;
}

View File

@ -59,6 +59,16 @@ int yajlpp_static_string(yajlpp_parse_context *ypc, const unsigned char *str, si
return 1;
}
int yajlpp_static_intern_string(yajlpp_parse_context *ypc, const unsigned char *str, size_t len)
{
char *root_ptr = resolve_root(ypc);
intern_string_t *field_ptr = (intern_string_t *) root_ptr;
(*field_ptr) = intern_string::lookup((const char *) str, len);
return 1;
}
yajl_gen_status yajlpp_static_gen_string(yajlpp_gen_context &ygc,
const json_path_handler_base &jph,
yajl_gen handle)

View File

@ -122,6 +122,7 @@ struct json_path_handler_base {
};
int yajlpp_static_string(yajlpp_parse_context *, const unsigned char *, size_t);
int yajlpp_static_intern_string(yajlpp_parse_context *, const unsigned char *, size_t);
yajl_gen_status yajlpp_static_gen_string(yajlpp_gen_context &ygc,
const json_path_handler_base &,
yajl_gen);
@ -235,6 +236,14 @@ struct json_path_handler : public json_path_handler_base {
return *this;
};
json_path_handler &for_field(intern_string_t *field) {
this->add_cb(yajlpp_static_intern_string);
this->jph_simple_offset = field;
this->jph_gen_callback = yajlpp_static_gen_string;
this->jph_validator = yajlpp_validator_for_string;
return *this;
};
json_path_handler &for_field(long long *field) {
this->add_cb(yajlpp_static_number);
this->jph_simple_offset = field;

View File

@ -7,6 +7,8 @@
"line-format" : [
{ "field" : "ts" },
" ",
{ "timestamp-format" : "abc %S def" },
" ",
{ "field" : "lvl" },
" ",
{ "field" : "msg" }

View File

@ -35,6 +35,14 @@
#include "lnav_util.hh"
#include "../src/lnav_util.hh"
static const char *GOOD_TIMES[] = {
"May 01 00:00:01",
"May 10 12:00:01",
"2014-02-11 16:12:34",
NULL
};
static const char *BAD_TIMES[] = {
"1-2-3 1:2:3",
@ -49,6 +57,25 @@ static const char *BAD_TIMES[] = {
int main(int argc, char *argv[])
{
setenv("TZ", "UTC", 1);
for (int lpc = 0; GOOD_TIMES[lpc]; lpc++) {
date_time_scanner dts;
struct timeval tv;
struct exttm tm;
const char *rc;
rc = dts.scan(GOOD_TIMES[lpc], strlen(GOOD_TIMES[lpc]), NULL, &tm, tv);
printf("ret %s %p\n", GOOD_TIMES[lpc], rc);
assert(rc != NULL);
char ts[64];
dts.ftime(ts, sizeof(ts), tm);
printf("orig %s\n", GOOD_TIMES[lpc]);
printf("loop %s\n", ts);
assert(strcmp(ts, GOOD_TIMES[lpc]) == 0);
}
{
date_time_scanner dts;
struct timeval tv;

View File

@ -48,6 +48,18 @@ log_line,log_part,log_time,log_idle_msecs,log_level,log_mark,user
13,<NULL>,2013-09-06 22:01:49.124,0,fatal,0,<NULL>
EOF
run_test ${lnav_test} -n \
-I ${test_dir} \
${test_dir}/logfile_json2.json
check_output "timestamp-format not working" <<EOF
2013-09-06T20:00:49.124 abc 49 def 0 Starting up service
2013-09-06T22:00:49.124 abc 49 def 0 Shutting down service
user: steve@example.com
2013-09-06T22:01:49.124 abc 49 def 10 looking bad
EOF
run_test ${lnav_test} -n -d /tmp/lnav.err \
-I ${test_dir} \
-c ';select * from json_log2' \