[gantt] tweak the style of dates in the chart headers

This commit is contained in:
Tim Stack 2023-08-08 08:12:47 -07:00
parent 116ff24da3
commit 9306ddbf13
14 changed files with 228 additions and 68 deletions

View File

@ -200,18 +200,22 @@
"type": "string"
},
"opid": {
"description": "Definitions related to operations found in logs",
"title": "/<format_name>/opid",
"type": "object",
"properties": {
"description": {
"description": "Define how to construct a description of an operation",
"title": "/<format_name>/opid/description",
"type": "object",
"patternProperties": {
"([\\w\\.\\-]+)": {
"description": "A type of description for this operation",
"title": "/<format_name>/opid/description/<opid_descriptor>",
"type": "object",
"properties": {
"format": {
"description": "Defines the elements of this operation description",
"title": "/<format_name>/opid/description/<opid_descriptor>/format",
"type": "array",
"items": {
@ -219,18 +223,27 @@
"properties": {
"field": {
"title": "/<format_name>/opid/description/<opid_descriptor>/format/field",
"description": "The field to include in the operation description",
"type": "string"
},
"extractor": {
"title": "/<format_name>/opid/description/<opid_descriptor>/format/extractor",
"description": "The regex used to extract content for the operation description",
"type": "string"
},
"prefix": {
"title": "/<format_name>/opid/description/<opid_descriptor>/format/prefix",
"description": "A string to prepend to this field in the description",
"type": "string"
},
"suffix": {
"title": "/<format_name>/opid/description/<opid_descriptor>/format/suffix",
"description": "A string to append to this field in the description",
"type": "string"
},
"joiner": {
"title": "/<format_name>/opid/description/<opid_descriptor>/format/joiner",
"description": "A string to insert between instances of this field when the field is found more than once",
"type": "string"
}
},

View File

@ -201,12 +201,15 @@ struct string_fragment {
return memcmp(this->data(), sf.data(), sf.length()) == 0;
}
int operator<(const string_fragment& rhs) const
bool operator<(const string_fragment& rhs) const
{
return strncmp(this->data(),
rhs.data(),
std::min(this->length(), rhs.length()))
< 0;
auto rc = strncmp(
this->data(), rhs.data(), std::min(this->length(), rhs.length()));
if (rc < 0 || (rc == 0 && this->length() < rhs.length())) {
return true;
}
return false;
}
bool iequal(const string_fragment& sf) const

View File

@ -43,6 +43,15 @@ TEST_CASE("string_fragment::startswith")
CHECK_FALSE(sf.startswith("abc"));
}
TEST_CASE("string_fragment::lt")
{
auto sf1 = string_fragment::from_const("abc");
auto sf2 = string_fragment::from_const("abcdef");
CHECK(sf1 < sf2);
CHECK_FALSE(sf2 < sf1);
}
TEST_CASE("split_lines")
{
std::string in1 = "Hello, World!";

View File

@ -58,8 +58,24 @@
"vum": {
"format": [
{
"field": "sub",
"extractor": "^(com\\..*)$"
"field": "body",
"extractor": "RequireAdminUserAuthz::Invoke Method is (.*)",
"suffix": "("
},
{
"prefix": "",
"field": "body",
"extractor": "PrivCheck: Resource:((?!com)[^,]+)"
},
{
"prefix": ") - ",
"field": "body",
"extractor": "PrivCheck: Resource:(?:com[^,]+), User:([^,]+)"
},
{
"prefix": "",
"field": "body",
"extractor": "()Invoking method com\\..*"
}
]
},
@ -76,6 +92,21 @@
}
]
},
"vpxd-lro": {
"format": [
{
"field": "body",
"extractor": "\\[VpxLRO\\] -- BEGIN (?:[^ ]+) -- (?:[^ ]*) -- ([^ ]+)"
}
]
},
"vpxd-item": {
"format": [
{
"field": "item"
}
]
},
"vsan": {
"format": [
{
@ -102,7 +133,8 @@
},
"src": {
"kind": "string",
"identifier": true
"identifier": true,
"hidden": true
},
"comp": {
"kind": "string",

View File

@ -31,6 +31,8 @@
#include "gantt_source.hh"
#include <time.h>
#include "base/humanize.hh"
#include "base/humanize.time.hh"
#include "base/math_util.hh"
@ -55,6 +57,60 @@ static const std::vector<std::chrono::seconds> TIME_SPANS = {
static constexpr size_t MAX_OPID_WIDTH = 60;
size_t
abbrev_ftime(char* datebuf,
size_t db_size,
const struct tm& lb_tm,
const struct tm& dt)
{
char lb_fmt[32] = " ";
bool same = true;
if (lb_tm.tm_year == dt.tm_year) {
strcat(lb_fmt, " ");
} else {
same = false;
strcat(lb_fmt, "%Y");
}
if (same && lb_tm.tm_mon == dt.tm_mon) {
strcat(lb_fmt, " ");
} else {
if (!same) {
strcat(lb_fmt, "-");
}
same = false;
strcat(lb_fmt, "%m");
}
if (same && lb_tm.tm_mday == dt.tm_mday) {
strcat(lb_fmt, " ");
} else {
if (!same) {
strcat(lb_fmt, "-");
}
same = false;
strcat(lb_fmt, "%d");
}
if (same && lb_tm.tm_hour == dt.tm_hour) {
strcat(lb_fmt, " ");
} else {
if (!same) {
strcat(lb_fmt, "T");
}
same = false;
strcat(lb_fmt, "%H");
}
if (same && lb_tm.tm_min == dt.tm_min) {
strcat(lb_fmt, " ");
} else {
if (!same) {
strcat(lb_fmt, ":");
}
same = false;
strcat(lb_fmt, "%M");
}
return strftime(datebuf, db_size, lb_fmt, &dt);
}
gantt_header_overlay::gantt_header_overlay(std::shared_ptr<gantt_source> src)
: gho_src(src)
{
@ -79,21 +135,39 @@ gantt_header_overlay::list_static_overlay(const listview_curses& lv,
return false;
}
auto lb = this->gho_src->gs_lower_bound;
struct tm lb_tm;
auto ub = this->gho_src->gs_upper_bound;
struct tm ub_tm;
auto bounds = this->gho_src->get_time_bounds_for(lv.get_selection());
if (bounds.first.tv_sec < lb.tv_sec) {
lb.tv_sec = bounds.first.tv_sec;
}
if (ub.tv_sec < bounds.second.tv_sec) {
ub.tv_sec = bounds.second.tv_sec;
}
secs2tm(lb.tv_sec, &lb_tm);
secs2tm(ub.tv_sec, &ub_tm);
struct tm sel_lb_tm;
secs2tm(bounds.first.tv_sec, &sel_lb_tm);
struct tm sel_ub_tm;
secs2tm(bounds.second.tv_sec, &sel_ub_tm);
auto width = lv.get_dimensions().second - 1;
char datebuf[64];
if (y == 0) {
auto lb = this->gho_src->gs_lower_bound;
auto ub = this->gho_src->gs_upper_bound;
double span = ub.tv_sec - lb.tv_sec;
double per_ch = span / (double) width;
sql_strftime(datebuf, sizeof(datebuf), lb, 'T');
value_out.appendf(FMT_STRING(" {}"), datebuf);
strftime(datebuf, sizeof(datebuf), " %Y-%m-%dT%H:%M", &lb_tm);
value_out.append(datebuf);
auto upper_size = sql_strftime(datebuf, sizeof(datebuf), ub, 'T');
auto upper_size
= strftime(datebuf, sizeof(datebuf), "%Y-%m-%dT%H:%M", &ub_tm);
value_out.append(width - value_out.length() - upper_size - 1, ' ')
.append(datebuf);
@ -118,12 +192,12 @@ gantt_header_overlay::list_static_overlay(const listview_curses& lv,
lr, VC_ROLE.value(role_t::VCR_CURSOR_LINE));
value_out.with_attr_for_all(VC_ROLE.value(role_t::VCR_STATUS_INFO));
} else if (y == 1) {
sql_strftime(datebuf, sizeof(datebuf), bounds.first, 'T');
value_out.appendf(FMT_STRING(" {}"), datebuf);
abbrev_ftime(datebuf, sizeof(datebuf), lb_tm, sel_lb_tm);
value_out.appendf(FMT_STRING(" {}"), datebuf);
auto upper_size
= sql_strftime(datebuf, sizeof(datebuf), bounds.second, 'T');
value_out.append(width - value_out.length() - upper_size - 5, ' ')
= abbrev_ftime(datebuf, sizeof(datebuf), ub_tm, sel_ub_tm);
value_out.append(width - value_out.length() - upper_size - 1, ' ')
.append(datebuf);
value_out.with_attr_for_all(VC_ROLE.value(role_t::VCR_CURSOR_LINE));
} else {
@ -319,6 +393,8 @@ gantt_source::rebuild_indexes()
this->gs_opid_width = 0;
this->gs_total_width = 0;
this->gs_filtered_count = 0;
this->gs_opid_map.clear();
this->gs_allocator.reset();
this->gs_preview_source.clear();
this->gs_preview_status_source.get_description().clear();
@ -352,7 +428,7 @@ gantt_source::rebuild_indexes()
auto active_iter = active_opids.find(pair.first);
if (active_iter == active_opids.end()) {
auto active_emp_res = active_opids.emplace(
iter->first, opid_row{pair.first, pair.second});
iter->first, opid_row{iter->first, pair.second});
active_iter = active_emp_res.first;
} else {
active_iter->second.or_value |= pair.second;
@ -363,7 +439,10 @@ gantt_source::rebuild_indexes()
auto desc_def_iter
= format->lf_opid_description_def->find(desc_id);
if (desc_def_iter != format->lf_opid_description_def->end()) {
if (desc_def_iter == format->lf_opid_description_def->end()) {
log_error("cannot find description: %s",
iter->first.data());
} else {
auto& format_descs
= iter->second.odd_format_to_desc[format->get_name()];
format_descs[desc_id]
@ -377,6 +456,8 @@ gantt_source::rebuild_indexes()
curr_desc_m[desc_pair.first] = desc_pair.second;
}
}
} else {
ensure(pair.second.otr_description.empty());
}
}
}
@ -414,6 +495,7 @@ gantt_source::rebuild_indexes()
= this->gs_opid_map[pair.second.or_name]
.odd_format_to_desc[desc.first];
require(!format_desc_defs.empty());
for (auto& desc_format_pairs : desc.second) {
const auto& desc_def_v
= *format_desc_defs.find(desc_format_pairs.first)->second;

View File

@ -1438,6 +1438,7 @@ looper()
= std::make_unique<spectro_status_source>();
lnav_data.ld_status[LNS_SPECTRO].set_data_source(
lnav_data.ld_spectro_status_source.get());
lnav_data.ld_status[LNS_GANTT].set_enabled(false);
lnav_data.ld_status[LNS_GANTT].set_data_source(
&lnav_data.ld_gantt_status_source);

View File

@ -897,43 +897,44 @@ external_log_format::scan(logfile& lf,
desc_def_index++)
{
const auto& desc_def = desc_def_v[desc_def_index];
auto found_desc = false;
auto found_desc = desc_v.begin();
for (const auto& desc_pair : desc_v) {
if (desc_pair.first == desc_def_index) {
found_desc = true;
for (; found_desc != desc_v.end(); ++found_desc) {
if (found_desc->first == desc_def_index) {
break;
}
}
if (!found_desc) {
auto desc_cap_iter
= this->lf_desc_captures.find(
desc_def.od_field.pp_value);
if (desc_cap_iter
== this->lf_desc_captures.end())
{
continue;
}
if (desc_def.od_extractor.pp_value) {
static thread_local auto desc_md = lnav::
pcre2pp::match_data::unitialized();
auto desc_cap_iter = this->lf_desc_captures.find(
desc_def.od_field.pp_value);
if (desc_cap_iter == this->lf_desc_captures.end()) {
continue;
}
nonstd::optional<std::string> desc_str;
if (desc_def.od_extractor.pp_value) {
static thread_local auto desc_md
= lnav::pcre2pp::match_data::unitialized();
auto match_res
= desc_def.od_extractor.pp_value
->capture_from(
desc_cap_iter->second)
.into(desc_md)
.matches(PCRE2_NO_UTF_CHECK)
.ignore_error();
if (match_res) {
desc_v.emplace_back(
desc_def_index,
desc_md.to_string());
}
auto match_res
= desc_def.od_extractor.pp_value
->capture_from(desc_cap_iter->second)
.into(desc_md)
.matches(PCRE2_NO_UTF_CHECK)
.ignore_error();
if (match_res) {
desc_str = desc_md.to_string();
}
} else {
desc_str = desc_cap_iter->second.to_string();
}
if (desc_str) {
if (found_desc == desc_v.end()) {
desc_v.emplace_back(desc_def_index,
desc_str.value());
} else {
desc_v.emplace_back(
desc_def_index,
desc_cap_iter->second.to_string());
found_desc->second.append(
desc_def.od_joiner);
found_desc->second.append(desc_str.value());
}
}
}

View File

@ -546,6 +546,7 @@ public:
factory_container<lnav::pcre2pp::code> od_extractor;
std::string od_prefix{" "};
std::string od_suffix;
std::string od_joiner{", "};
};
struct opid_descriptors {

View File

@ -846,30 +846,46 @@ static const struct json_path_container converter_handlers = {
};
static const struct json_path_container opid_descriptor_handlers = {
yajlpp::property_handler("field").for_field(
&log_format::opid_descriptor::od_field),
yajlpp::property_handler("field")
.with_synopsis("<name>")
.with_description("The field to include in the operation description")
.for_field(&log_format::opid_descriptor::od_field),
yajlpp::property_handler("extractor")
.with_synopsis("<regex>")
.with_description(
"The regex used to extract content for the operation description")
.for_field(&log_format::opid_descriptor::od_extractor),
yajlpp::property_handler("prefix").for_field(
&log_format::opid_descriptor::od_prefix),
yajlpp::property_handler("suffix").for_field(
&log_format::opid_descriptor::od_suffix),
yajlpp::property_handler("prefix")
.with_description(
"A string to prepend to this field in the description")
.for_field(&log_format::opid_descriptor::od_prefix),
yajlpp::property_handler("suffix")
.with_description("A string to append to this field in the description")
.for_field(&log_format::opid_descriptor::od_suffix),
yajlpp::property_handler("joiner")
.with_description("A string to insert between instances of this field "
"when the field is found more than once")
.for_field(&log_format::opid_descriptor::od_joiner),
};
static const struct json_path_container opid_description_format_handlers = {
yajlpp::property_handler("format#")
.with_description("Defines the elements of this operation description")
.for_field(&log_format::opid_descriptors::od_descriptors)
.with_children(opid_descriptor_handlers),
};
static const struct json_path_container opid_description_handlers = {
yajlpp::pattern_property_handler(R"((?<opid_descriptor>[\w\.\-]+))")
.with_description("A type of description for this operation")
.for_field(&log_format::lf_opid_description_def)
.with_children(opid_description_format_handlers),
};
static const struct json_path_container opid_handlers = {
yajlpp::property_handler("description")
.with_description(
"Define how to construct a description of an operation")
.with_children(opid_description_handlers),
};
@ -956,7 +972,9 @@ const struct json_path_container format_handlers = {
.with_description(
"The name of the operation-id field in the log message pattern")
.for_field(&external_log_format::elf_opid_field),
yajlpp::property_handler("opid").with_children(opid_handlers),
yajlpp::property_handler("opid")
.with_description("Definitions related to operations found in logs")
.with_children(opid_handlers),
yajlpp::property_handler("ordered-by-time")
.with_synopsis("<bool>")
.with_description(

View File

@ -1,5 +1,5 @@
2011-11-03T00:19:26.452 2011-11-03T00:21:13.204
2011-11-03T00:17:00.000 2011-11-03T00:22:00.000
2011-11-03T00:17 2011-11-03T00:22
 Duration | ✘▲ | Operation
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76

View File

@ -1,5 +1,5 @@
2011-11-03T00:19:26.452 2011-11-03T00:21:13.204
2011-11-03T00:17:00.000 2011-11-03T00:22:00.000
2011-11-03T00:17 2011-11-03T00:22
 Duration | ✘▲ | Operation
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76

View File

@ -1,5 +1,5 @@
2011-11-03T00:19:26.452 2011-11-03T00:21:13.204
2011-11-03T00:17:00.000 2011-11-03T00:22:00.000
2011-11-03T00:17 2011-11-03T00:22
 Duration | ✘▲ | Operation
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76

View File

@ -1,4 +1,4 @@
2011-11-03T00:19:26.452 2011-11-03T00:21:13.204
2011-11-03T00:17:00.000 2011-11-03T00:22:00.000
2011-11-03T00:17 2011-11-03T00:22
 Duration | ✘▲ | Operation
     CdysLK1XpcrXOpVDuh 192.168.2.76

View File

@ -1,5 +1,5 @@
2011-11-03T00:19:26.452 2011-11-03T00:21:13.204
2011-11-03T00:17:00.000 2011-11-03T00:22:00.000
2011-11-03T00:17 2011-11-03T00:22
 Duration | ✘▲ | Operation
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76