mirror of
https://github.com/tstack/lnav
synced 2024-11-01 21:40:34 +00:00
parent
4d091988a0
commit
41854cf637
5
NEWS
5
NEWS
@ -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
|
||||
|
@ -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 "-".
|
||||
|
||||
|
@ -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" \
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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");
|
||||
|
283
src/ptimec.hh
283
src/ptimec.hh
@ -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[];
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -7,6 +7,8 @@
|
||||
"line-format" : [
|
||||
{ "field" : "ts" },
|
||||
" ",
|
||||
{ "timestamp-format" : "abc %S def" },
|
||||
" ",
|
||||
{ "field" : "lvl" },
|
||||
" ",
|
||||
{ "field" : "msg" }
|
||||
|
@ -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;
|
||||
|
@ -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' \
|
||||
|
Loading…
Reference in New Issue
Block a user