mirror of
https://github.com/tstack/lnav.git
synced 2024-09-11 13:05:51 +03:00
[date-time-scanner] fix generating with a user-defined format
Fixes #967
This commit is contained in:
parent
531c35158c
commit
d82140de52
2
NEWS
2
NEWS
@ -7,6 +7,8 @@ lnav v0.10.2:
|
||||
* Added a 'language' column to the lnav_view_filters table that
|
||||
specifies the language of the 'pattern' column, either 'regex'
|
||||
or 'sql'.
|
||||
* Timestamps that do not have a day or month are rewritten to a
|
||||
full timestamp like YYYY-MM-DD HH:MM:SS.
|
||||
|
||||
Fixes:
|
||||
* Toggling enabled/disabled filters when there is a SQL expression
|
||||
|
@ -35,11 +35,29 @@
|
||||
#include "ptimec.hh"
|
||||
|
||||
size_t
|
||||
date_time_scanner::ftime(char* dst, size_t len, const exttm& tm) const
|
||||
date_time_scanner::ftime(char* dst,
|
||||
size_t len,
|
||||
const char* const time_fmt[],
|
||||
const exttm& tm) const
|
||||
{
|
||||
off_t off = 0;
|
||||
|
||||
PTIMEC_FORMATS[this->dts_fmt_lock].pf_ffunc(dst, off, len, tm);
|
||||
if (time_fmt == nullptr) {
|
||||
PTIMEC_FORMATS[this->dts_fmt_lock].pf_ffunc(dst, off, len, tm);
|
||||
if (tm.et_flags & ETF_MILLIS_SET) {
|
||||
dst[off++] = '.';
|
||||
ftime_L(dst, off, len, tm);
|
||||
} else if (tm.et_flags & ETF_MICROS_SET) {
|
||||
dst[off++] = '.';
|
||||
ftime_f(dst, off, len, tm);
|
||||
} else if (tm.et_flags & ETF_NANOS_SET) {
|
||||
dst[off++] = '.';
|
||||
ftime_N(dst, off, len, tm);
|
||||
}
|
||||
dst[off] = '\0';
|
||||
} else {
|
||||
off = ftime_fmt(dst, len, time_fmt[this->dts_fmt_lock], tm);
|
||||
}
|
||||
|
||||
return (size_t) off;
|
||||
}
|
||||
@ -196,13 +214,29 @@ date_time_scanner::scan(const char* time_dest,
|
||||
if (retval[0] == '.' || retval[0] == ',') {
|
||||
off_t off = (retval - time_dest) + 1;
|
||||
|
||||
if (ptime_f(tm_out, time_dest, off, time_len)) {
|
||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||
if (ptime_N(tm_out, time_dest, off, time_len)) {
|
||||
tv_out.tv_usec
|
||||
= std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::nanoseconds{tm_out->et_nsec})
|
||||
.count();
|
||||
this->dts_fmt_len += 10;
|
||||
tm_out->et_flags |= ETF_NANOS_SET;
|
||||
retval += 10;
|
||||
} else if (ptime_f(tm_out, time_dest, off, time_len)) {
|
||||
tv_out.tv_usec
|
||||
= std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::nanoseconds{tm_out->et_nsec})
|
||||
.count();
|
||||
this->dts_fmt_len += 7;
|
||||
tm_out->et_flags |= ETF_MICROS_SET;
|
||||
retval += 7;
|
||||
} else if (ptime_L(tm_out, time_dest, off, time_len)) {
|
||||
tv_out.tv_usec = tm_out->et_nsec / 1000;
|
||||
tv_out.tv_usec
|
||||
= std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::nanoseconds{tm_out->et_nsec})
|
||||
.count();
|
||||
this->dts_fmt_len += 4;
|
||||
tm_out->et_flags |= ETF_MILLIS_SET;
|
||||
retval += 4;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,10 @@ struct date_time_scanner {
|
||||
struct timeval& tv_out,
|
||||
bool convert_local = true);
|
||||
|
||||
size_t ftime(char* dst, size_t len, const struct exttm& tm) const;
|
||||
size_t ftime(char* dst,
|
||||
size_t len,
|
||||
const char* const time_fmt[],
|
||||
const struct exttm& tm) const;
|
||||
|
||||
bool convert_to_timeval(const char* time_src,
|
||||
ssize_t time_len,
|
||||
|
@ -75,6 +75,9 @@ enum exttm_bits_t {
|
||||
ETB_DAY_SET,
|
||||
ETB_MACHINE_ORIENTED,
|
||||
ETB_EPOCH_TIME,
|
||||
ETB_MILLIS_SET,
|
||||
ETB_MICROS_SET,
|
||||
ETB_NANOS_SET,
|
||||
};
|
||||
|
||||
enum exttm_flags_t {
|
||||
@ -83,6 +86,9 @@ enum exttm_flags_t {
|
||||
ETF_DAY_SET = (1UL << ETB_DAY_SET),
|
||||
ETF_MACHINE_ORIENTED = (1UL << ETB_MACHINE_ORIENTED),
|
||||
ETF_EPOCH_TIME = (1UL << ETB_EPOCH_TIME),
|
||||
ETF_MILLIS_SET = (1UL << ETB_MILLIS_SET),
|
||||
ETF_MICROS_SET = (1UL << ETB_MICROS_SET),
|
||||
ETF_NANOS_SET = (1UL << ETB_NANOS_SET),
|
||||
};
|
||||
|
||||
struct exttm {
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include "command_executor.hh"
|
||||
#include "config.h"
|
||||
#include "k_merge_tree.h"
|
||||
#include "lnav_util.hh"
|
||||
#include "log_accel.hh"
|
||||
#include "relative_time.hh"
|
||||
#include "sql_util.hh"
|
||||
@ -119,7 +118,7 @@ logfile_sub_source::find(const char* fn, content_line_t& line_base)
|
||||
iter++)
|
||||
{
|
||||
auto& ld = *(*iter);
|
||||
auto lf = ld.get_file_ptr();
|
||||
auto* lf = ld.get_file_ptr();
|
||||
|
||||
if (lf == nullptr) {
|
||||
continue;
|
||||
@ -233,7 +232,9 @@ logfile_sub_source::text_value_for_line(textview_curses& tc,
|
||||
}
|
||||
|
||||
if ((this->lss_token_file->is_time_adjusted()
|
||||
|| format->lf_timestamp_flags & ETF_MACHINE_ORIENTED)
|
||||
|| format->lf_timestamp_flags & ETF_MACHINE_ORIENTED
|
||||
|| !(format->lf_timestamp_flags & ETF_DAY_SET)
|
||||
|| !(format->lf_timestamp_flags & ETF_MONTH_SET))
|
||||
&& format->lf_date_time.dts_fmt_lock != -1)
|
||||
{
|
||||
auto time_attr
|
||||
@ -246,7 +247,10 @@ logfile_sub_source::text_value_for_line(textview_curses& tc,
|
||||
const char* fmt;
|
||||
ssize_t len;
|
||||
|
||||
if (format->lf_timestamp_flags & ETF_MACHINE_ORIENTED) {
|
||||
if (format->lf_timestamp_flags & ETF_MACHINE_ORIENTED
|
||||
|| !(format->lf_timestamp_flags & ETF_DAY_SET)
|
||||
|| !(format->lf_timestamp_flags & ETF_MONTH_SET))
|
||||
{
|
||||
format->lf_date_time.convert_to_timeval(
|
||||
&this->lss_token_value.c_str()[time_range.lr_start],
|
||||
time_range.length(),
|
||||
@ -254,14 +258,23 @@ logfile_sub_source::text_value_for_line(textview_curses& tc,
|
||||
adjusted_time);
|
||||
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;
|
||||
adjusted_tm.et_nsec
|
||||
= std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::microseconds{adjusted_time.tv_usec})
|
||||
.count();
|
||||
len = ftime_fmt(buffer, sizeof(buffer), fmt, adjusted_tm);
|
||||
} else {
|
||||
adjusted_time = this->lss_token_line->get_timeval();
|
||||
gmtime_r(&adjusted_time.tv_sec, &adjusted_tm.et_tm);
|
||||
adjusted_tm.et_nsec = adjusted_time.tv_usec * 1000;
|
||||
adjusted_tm.et_nsec
|
||||
= std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::microseconds{adjusted_time.tv_usec})
|
||||
.count();
|
||||
len = format->lf_date_time.ftime(
|
||||
buffer, sizeof(buffer), adjusted_tm);
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
format->get_timestamp_formats(),
|
||||
adjusted_tm);
|
||||
}
|
||||
|
||||
value_out.replace(
|
||||
@ -585,7 +598,6 @@ logfile_sub_source::text_attrs_for_line(textview_curses& lv,
|
||||
auto sql_filter_opt = this->get_sql_filter();
|
||||
if (sql_filter_opt) {
|
||||
auto* sf = (sql_filter*) sql_filter_opt.value().get();
|
||||
log_debug("eval sql %p %p", &this->tss_filters, sf);
|
||||
auto eval_res = this->eval_sql_filter(sf->sf_filter_stmt.in(),
|
||||
this->lss_token_file_data,
|
||||
this->lss_token_line);
|
||||
|
@ -39,6 +39,7 @@ static const char* GOOD_TIMES[] = {
|
||||
"May 01 00:00:01",
|
||||
"May 10 12:00:01",
|
||||
"2014-02-11 16:12:34",
|
||||
"2014-02-11 16:12:34.123",
|
||||
"05/18/2018 12:00:53 PM",
|
||||
"05/18/2018 12:00:53 AM",
|
||||
};
|
||||
@ -70,7 +71,7 @@ main(int argc, char* argv[])
|
||||
char ts[64];
|
||||
|
||||
gmtime_r(&tv.tv_sec, &tm.et_tm);
|
||||
dts.ftime(ts, sizeof(ts), tm);
|
||||
dts.ftime(ts, sizeof(ts), nullptr, tm);
|
||||
printf("orig %s\n", good_time);
|
||||
printf("loop %s\n", ts);
|
||||
assert(strcmp(ts, good_time) == 0);
|
||||
@ -85,7 +86,7 @@ main(int argc, char* argv[])
|
||||
auto rc = dts.scan(OLD_TIME, strlen(OLD_TIME), nullptr, &tm, tv);
|
||||
assert(rc != nullptr);
|
||||
char ts[64];
|
||||
dts.ftime(ts, sizeof(ts), tm);
|
||||
dts.ftime(ts, sizeof(ts), nullptr, tm);
|
||||
assert(strcmp(ts, "05/18/1980 12:00:53 AM") == 0);
|
||||
}
|
||||
|
||||
@ -145,6 +146,24 @@ main(int argc, char* argv[])
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char* ts = "22:46:03.471";
|
||||
const char* fmt[] = {
|
||||
"%H:%M:%S.%L",
|
||||
nullptr,
|
||||
};
|
||||
char buf[64];
|
||||
date_time_scanner dts;
|
||||
struct exttm tm;
|
||||
struct timeval tv;
|
||||
|
||||
const auto* ts_end = dts.scan(ts, strlen(ts), fmt, &tm, tv);
|
||||
assert(ts_end - ts == 12);
|
||||
auto rc = dts.ftime(buf, sizeof(buf), fmt, tm);
|
||||
assert(rc == 12);
|
||||
assert(strcmp(ts, buf) == 0);
|
||||
}
|
||||
|
||||
{
|
||||
const char* epoch_str = "ts 1428721664 ]";
|
||||
struct exttm tm;
|
||||
|
@ -325,6 +325,15 @@ Apr 06 10:30:11 2014 -- 474
|
||||
Apr 06 11:01:11 2014 -- 475
|
||||
EOF
|
||||
|
||||
run_test ${lnav_test} -n ${srcdir}/logfile_tcf.1
|
||||
|
||||
check_output "timestamps with no dates are not rewritten?" <<EOF
|
||||
TCF 2014-04-06 11:59:47.191000: Server-Properties: {"Name":"TCF Protocol Logger","OSName":"Linux 3.2.0-60-generic","UserName":"xavier","AgentID":"1fde3dd1-d4be-4f79-8090-6f8d212f03bf","TransportName":"TCP","Proxy":"","ValueAdd":"1","Port":"1534"}
|
||||
TCF 2014-04-06 11:30:11.474000: 0: ---> C 2 RunControl getChildren null <eom>
|
||||
TCF 2014-04-06 11:01:11.475000: 0: <--- R 2 ["P1"] <eom>
|
||||
EOF
|
||||
|
||||
|
||||
# The TCSH format converts to local time, so we need to specify a TZ
|
||||
export TZ="UTC"
|
||||
run_test ./drive_logfile -t -f tcsh_history ${srcdir}/logfile_tcsh_history.0
|
||||
|
Loading…
Reference in New Issue
Block a user