[gantt] support for sub-ids

pull/1161/merge
Tim Stack 10 months ago
parent 917270e293
commit 1c857feed7

@ -84,6 +84,8 @@ Bug Fixes:
configuration can be viewed by passing the `-W` flag.
Interface changes:
* The breadcrumb bar hotkey is moving to backtick `` ` ``
instead of `ENTER`.
* The DB view now uses the "alt-text" theme style to draw
alternating rows instead of being hard-coded to bold. The
alternation is also now done in groups of two rows instead

@ -204,6 +204,11 @@
"title": "/<format_name>/opid",
"type": "object",
"properties": {
"subid": {
"title": "/<format_name>/opid/subid",
"description": "The field that holds the ID for a sub-operation",
"type": "string"
},
"description": {
"description": "Define how to construct a description of an operation",
"title": "/<format_name>/opid/description",
@ -255,6 +260,58 @@
}
},
"additionalProperties": false
},
"sub-description": {
"description": "Define how to construct a description of a sub-operation",
"title": "/<format_name>/opid/sub-description",
"type": "object",
"patternProperties": {
"([\\w\\.\\-]+)": {
"description": "A type of description for this sub-operation",
"title": "/<format_name>/opid/sub-description/<subid_descriptor>",
"type": "object",
"properties": {
"format": {
"description": "Defines the elements of this operation description",
"title": "/<format_name>/opid/sub-description/<subid_descriptor>/format",
"type": "array",
"items": {
"type": "object",
"properties": {
"field": {
"title": "/<format_name>/opid/sub-description/<subid_descriptor>/format/field",
"description": "The field to include in the operation description",
"type": "string"
},
"extractor": {
"title": "/<format_name>/opid/sub-description/<subid_descriptor>/format/extractor",
"description": "The regex used to extract content for the operation description",
"type": "string"
},
"prefix": {
"title": "/<format_name>/opid/sub-description/<subid_descriptor>/format/prefix",
"description": "A string to prepend to this field in the description",
"type": "string"
},
"suffix": {
"title": "/<format_name>/opid/sub-description/<subid_descriptor>/format/suffix",
"description": "A string to append to this field in the description",
"type": "string"
},
"joiner": {
"title": "/<format_name>/opid/sub-description/<subid_descriptor>/format/joiner",
"description": "A string to insert between instances of this field when the field is found more than once",
"type": "string"
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}
},
"additionalProperties": false

@ -54,6 +54,7 @@ add_library(
lnav.console.into.hh
log_level_enum.hh
lrucache.hpp
map_util.hh
math_util.hh
network.tcp.hh
paths.hh

@ -52,6 +52,7 @@ noinst_HEADERS = \
lnav.gzip.hh \
log_level_enum.hh \
lrucache.hpp \
map_util.hh \
math_util.hh \
network.tcp.hh \
opt_util.hh \

@ -33,6 +33,7 @@
#include "config.h"
#include "fmt/format.h"
#include "math_util.hh"
#include "time_util.hh"
namespace humanize {
@ -161,18 +162,21 @@ duration::to_string() const
millis = -millis;
}
uint64_t remaining;
uint64_t remaining = millis.count();
uint64_t scale = 1;
if (this->d_msecs_resolution > 0) {
remaining = roundup(remaining, this->d_msecs_resolution);
}
if (millis >= 10min) {
remaining
= std::chrono::duration_cast<std::chrono::seconds>(millis).count();
remaining /= curr_interval->length;
scale *= curr_interval->length;
curr_interval += 1;
} else {
remaining = millis.count();
}
for (; curr_interval != std::end(intervals); curr_interval++) {
uint64_t amount;
char segment[32];
auto skip = scale < this->d_msecs_resolution;
if (curr_interval->length) {
amount = remaining % curr_interval->length;
@ -181,11 +185,16 @@ duration::to_string() const
amount = remaining;
remaining = 0;
}
scale *= curr_interval->length;
if (!amount && !remaining) {
if (amount == 0 && remaining == 0) {
break;
}
if (skip) {
continue;
}
snprintf(segment,
sizeof(segment),
curr_interval->format,

@ -74,12 +74,22 @@ class duration {
public:
static duration from_tv(const struct timeval& tv);
template<class Rep, class Period>
duration& with_resolution(const std::chrono::duration<Rep, Period>& res)
{
this->d_msecs_resolution
= std::chrono::duration_cast<std::chrono::milliseconds>(res)
.count();
return *this;
}
std::string to_string() const;
private:
explicit duration(const struct timeval& tv) : d_timeval(tv) {}
struct timeval d_timeval;
uint64_t d_msecs_resolution{1};
};
} // namespace time

@ -201,6 +201,11 @@ struct string_fragment {
return memcmp(this->data(), sf.data(), sf.length()) == 0;
}
bool operator!=(const string_fragment& rhs) const
{
return !(*this == rhs);
}
bool operator<(const string_fragment& rhs) const
{
auto rc = strncmp(

@ -0,0 +1,74 @@
/**
* Copyright (c) 2023, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * 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.
*
* 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.
*/
#ifndef lnav_map_util_hh
#define lnav_map_util_hh
#include <functional>
#include <map>
#include <type_traits>
#include <vector>
#include "optional.hpp"
namespace lnav {
namespace map {
template<typename C>
nonstd::optional<
std::reference_wrapper<std::conditional_t<std::is_const<C>::value,
const typename C::mapped_type,
typename C::mapped_type>>>
find(C& container, typename C::key_type& key)
{
auto iter = container.find(key);
if (iter != container.end()) {
return nonstd::make_optional(std::ref(iter->second));
}
return nonstd::nullopt;
}
template<typename K, typename V, typename M = std::map<K, V>>
M
from_vec(const std::vector<std::pair<K, V>>& container)
{
M retval;
for (const auto& elem : container) {
retval[elem.first] = elem.second;
}
return retval;
}
} // namespace map
} // namespace lnav
#endif

@ -33,6 +33,7 @@
#include <sys/types.h>
#undef rounddown
#undef roundup
/**
* Round down a number based on a given granularity.
@ -47,6 +48,17 @@ rounddown(Size size, Step step)
return size - (size % step);
}
template<typename Size, typename Step>
inline auto
roundup(Size size, Step step)
{
auto retval = size + (step - 1);
retval -= (retval % step);
return retval;
}
inline int
rounddown_offset(size_t size, int step, int offset)
{

@ -249,3 +249,38 @@ exttm::to_timeval() const
return retval;
}
time_range&
time_range::operator|=(const time_range& rhs)
{
if (rhs.tr_begin < this->tr_begin) {
this->tr_begin = rhs.tr_begin;
}
if (this->tr_end < rhs.tr_end) {
this->tr_end = rhs.tr_end;
}
return *this;
}
void
time_range::extend_to(const timeval& tv)
{
if (tv < this->tr_begin) {
// logs aren't always in time-order
this->tr_begin = tv;
} else if (this->tr_end < tv) {
this->tr_end = tv;
}
}
std::chrono::milliseconds
time_range::duration() const
{
auto diff = this->tr_end - this->tr_begin;
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::seconds(diff.tv_sec))
+ std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::microseconds(diff.tv_usec));
}

@ -180,6 +180,12 @@ operator-(const struct timeval& lhs, const struct timeval& rhs)
typedef int64_t mstime_t;
inline mstime_t
to_mstime(const timeval& tv)
{
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
}
inline mstime_t
getmstime()
{
@ -187,7 +193,7 @@ getmstime()
gettimeofday(&tv, nullptr);
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL;
return to_mstime(tv);
}
inline struct timeval
@ -222,4 +228,18 @@ hour_num(time_t ti)
return ti / (60 * 60);
}
struct time_range {
struct timeval tr_begin;
struct timeval tr_end;
bool operator<(const time_range& rhs) const
{
return this->tr_begin < rhs.tr_begin;
}
time_range& operator|=(const time_range& rhs);
void extend_to(const timeval& tv);
std::chrono::milliseconds duration() const;
};
#endif

@ -25,6 +25,7 @@
},
"opid-field": "opid",
"opid": {
"subid": "log_syslog_tag",
"description": {
"settingsd": {
"format": [

@ -54,6 +54,17 @@
},
"opid-field": "opid",
"opid": {
"subid": "tid",
"sub-description": {
"vum": {
"format": [
{
"field": "sub",
"extractor": "^(?!VumVapi::Utils).*$"
}
]
}
},
"description": {
"vum": {
"format": [
@ -65,7 +76,7 @@
{
"prefix": "",
"field": "body",
"extractor": "PrivCheck: Resource:((?!com)[^,]+)"
"extractor": "PrivCheck: Resource:((?!com)[^,]+)|Entity Priv Result:()"
},
{
"prefix": ") - ",

@ -48,6 +48,8 @@ static const std::vector<std::chrono::seconds> TIME_SPANS = {
5min,
15min,
1h,
2h,
4h,
8h,
24h,
7 * 24h,
@ -141,11 +143,11 @@ gantt_header_overlay::list_static_overlay(const listview_curses& lv,
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 (bounds.first < lb) {
lb = bounds.first;
}
if (ub.tv_sec < bounds.second.tv_sec) {
ub.tv_sec = bounds.second.tv_sec;
if (ub < bounds.second) {
ub = bounds.second;
}
secs2tm(lb.tv_sec, &lb_tm);
@ -166,10 +168,17 @@ gantt_header_overlay::list_static_overlay(const listview_curses& lv,
strftime(datebuf, sizeof(datebuf), " %Y-%m-%dT%H:%M", &lb_tm);
value_out.append(datebuf);
auto duration_str = humanize::time::duration::from_tv(ub - lb)
.with_resolution(1min)
.to_string();
auto duration_pos = width / 2 - duration_str.size() / 2;
value_out.pad_to(duration_pos).append(duration_str);
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);
= strftime(datebuf, sizeof(datebuf), "%Y-%m-%dT%H:%M ", &ub_tm);
auto upper_pos = width - upper_size;
value_out.pad_to(upper_pos).append(datebuf);
auto lr = line_range{};
if (lb.tv_sec < bounds.first.tv_sec) {
@ -195,10 +204,17 @@ gantt_header_overlay::list_static_overlay(const listview_curses& lv,
abbrev_ftime(datebuf, sizeof(datebuf), lb_tm, sel_lb_tm);
value_out.appendf(FMT_STRING(" {}"), datebuf);
auto duration_str
= humanize::time::duration::from_tv(bounds.second - bounds.first)
.with_resolution(1min)
.to_string();
auto duration_pos = width / 2 - duration_str.size() / 2;
value_out.pad_to(duration_pos).append(duration_str);
auto upper_size
= abbrev_ftime(datebuf, sizeof(datebuf), ub_tm, sel_ub_tm);
value_out.append(width - value_out.length() - upper_size - 1, ' ')
.append(datebuf);
auto upper_pos = width - upper_size - 1;
value_out.pad_to(upper_pos).append(datebuf);
value_out.with_attr_for_all(VC_ROLE.value(role_t::VCR_CURSOR_LINE));
} else {
value_out.append(" Duration "_h1)
@ -218,6 +234,92 @@ gantt_header_overlay::list_static_overlay(const listview_curses& lv,
return true;
}
void
gantt_header_overlay::list_value_for_overlay(
const listview_curses& lv,
vis_line_t line,
std::vector<attr_line_t>& value_out)
{
if (lv.get_selection() != line) {
return;
}
if (line >= this->gho_src->gs_time_order.size()) {
return;
}
const auto& row = this->gho_src->gs_time_order[line];
if (row.or_value.otr_sub_ops.size() <= 1) {
return;
}
auto width = lv.get_dimensions().second;
if (width < 37) {
return;
}
width -= 37;
double span = row.or_value.otr_range.duration().count();
double per_ch = span / (double) width;
for (const auto& sub : row.or_value.otr_sub_ops) {
value_out.resize(value_out.size() + 1);
auto& al = value_out.back();
auto& attrs = al.get_attrs();
auto total_msgs = sub.ostr_level_stats.lls_total_count;
auto duration = sub.ostr_range.tr_end - sub.ostr_range.tr_begin;
auto duration_str = fmt::format(
FMT_STRING(" {: >13}"),
humanize::time::duration::from_tv(duration).to_string());
al.pad_to(14)
.append(duration_str, VC_ROLE.value(role_t::VCR_OFFSET_TIME))
.append(" ")
.append(lnav::roles::error(humanize::sparkline(
sub.ostr_level_stats.lls_error_count, total_msgs)))
.append(lnav::roles::warning(humanize::sparkline(
sub.ostr_level_stats.lls_warning_count, total_msgs)))
.append(" ")
.append(lnav::roles::identifier(sub.ostr_subid.to_string()))
.append(" ")
.append(sub.ostr_description);
al.with_attr_for_all(VC_ROLE.value(role_t::VCR_COMMENT));
auto start_diff = (double) to_mstime(sub.ostr_range.tr_begin
- row.or_value.otr_range.tr_begin);
auto end_diff = (double) to_mstime(sub.ostr_range.tr_end
- row.or_value.otr_range.tr_begin);
auto lr = line_range{
(int) (32 + (start_diff / per_ch)),
(int) (32 + (end_diff / per_ch)),
line_range::unit::codepoint,
};
if (lr.lr_start == lr.lr_end) {
lr.lr_end += 1;
}
auto block_attrs = text_attrs{};
block_attrs.ta_attrs = A_REVERSE;
attrs.emplace_back(lr, VC_STYLE.value(block_attrs));
}
if (!value_out.empty()) {
text_attrs ta_under;
ta_under.ta_attrs = A_UNDERLINE;
value_out.back().get_attrs().emplace_back(line_range{0, -1},
VC_STYLE.value(ta_under));
}
}
nonstd::optional<attr_line_t>
gantt_header_overlay::list_header_for_overlay(const listview_curses& lv,
vis_line_t line)
{
return attr_line_t("\u258C Sub-operations:");
}
gantt_source::gantt_source(textview_curses& log_view,
logfile_sub_source& lss,
@ -239,24 +341,27 @@ gantt_source::get_time_bounds_for(int line)
const auto& sel_row = this->gs_time_order[line];
const auto& high_row = this->gs_time_order[std::min(
line + CONTEXT_LINES, (int) this->gs_time_order.size() - 1)];
auto high_tv_sec = std::max(sel_row.or_value.otr_end.tv_sec,
high_row.or_value.otr_begin.tv_sec);
auto high_tv_sec = std::max(sel_row.or_value.otr_range.tr_end.tv_sec,
high_row.or_value.otr_range.tr_begin.tv_sec);
auto duration
= std::chrono::seconds{high_tv_sec - low_row.or_value.otr_begin.tv_sec};
auto duration = std::chrono::seconds{
high_tv_sec - low_row.or_value.otr_range.tr_begin.tv_sec};
auto span_iter
= std::upper_bound(TIME_SPANS.begin(), TIME_SPANS.end(), duration);
if (span_iter == TIME_SPANS.end()) {
--span_iter;
}
auto span_secs = span_iter->count() - 60;
auto round_to = (*span_iter) == 5min
? 60
: ((*span_iter) == 15min ? 60 * 15 : 60 * 60);
auto span_secs = span_iter->count() - round_to;
struct timeval lower_tv = {
rounddown(low_row.or_value.otr_begin.tv_sec, 60),
rounddown(low_row.or_value.otr_range.tr_begin.tv_sec, round_to),
0,
};
lower_tv.tv_sec -= span_secs / 2;
struct timeval upper_tv = {
static_cast<time_t>(roundup_size(high_tv_sec, 60)),
static_cast<time_t>(roundup(high_tv_sec, round_to)),
0,
};
upper_tv.tv_sec += span_secs / 2;
@ -278,24 +383,24 @@ gantt_source::text_value_for_line(textview_curses& tc,
{
if (line < this->gs_time_order.size()) {
const auto& row = this->gs_time_order[line];
auto duration = row.or_value.otr_end - row.or_value.otr_begin;
auto duration
= row.or_value.otr_range.tr_end - row.or_value.otr_range.tr_begin;
auto duration_str = fmt::format(
FMT_STRING(" {: >13}"),
humanize::time::duration::from_tv(duration).to_string());
this->gs_rendered_line.clear();
auto total_msgs = row.or_value.get_total_msgs();
auto total_msgs = row.or_value.otr_level_stats.lls_total_count;
auto truncated_name = row.or_name.to_string();
truncate_to(truncated_name, MAX_OPID_WIDTH);
this->gs_rendered_line
.append(duration_str, VC_ROLE.value(role_t::VCR_OFFSET_TIME))
.append(" ")
.append(lnav::roles::error(humanize::sparkline(
row.or_value.get_error_count(), total_msgs)))
row.or_value.otr_level_stats.lls_error_count, total_msgs)))
.append(lnav::roles::warning(humanize::sparkline(
row.or_value.otr_level_counts[log_level_t::LEVEL_WARNING],
total_msgs)))
row.or_value.otr_level_stats.lls_warning_count, total_msgs)))
.append(" ")
.append(lnav::roles::identifier(truncated_name))
.append(this->gs_opid_width
@ -320,11 +425,11 @@ gantt_source::text_attrs_for_line(textview_curses& tc,
value_out = this->gs_rendered_line.get_attrs();
auto lr = line_range{};
auto lr = line_range{-1, -1, line_range::unit::codepoint};
auto sel_bounds = this->get_time_bounds_for(tc.get_selection());
if (row.or_value.otr_begin <= sel_bounds.second
&& sel_bounds.first <= row.or_value.otr_end)
if (row.or_value.otr_range.tr_begin <= sel_bounds.second
&& sel_bounds.first <= row.or_value.otr_range.tr_end)
{
static const int INDENT = 22;
@ -336,20 +441,20 @@ gantt_source::text_attrs_for_line(textview_curses& tc,
= sel_bounds.second.tv_sec - sel_bounds.first.tv_sec;
double per_ch = span / (double) width;
if (row.or_value.otr_begin <= sel_bounds.first) {
if (row.or_value.otr_range.tr_begin <= sel_bounds.first) {
lr.lr_start = INDENT;
} else {
auto start_diff = row.or_value.otr_begin.tv_sec
auto start_diff = row.or_value.otr_range.tr_begin.tv_sec
- sel_bounds.first.tv_sec;
lr.lr_start = INDENT + start_diff / per_ch;
}
if (sel_bounds.second < row.or_value.otr_end) {
if (sel_bounds.second < row.or_value.otr_range.tr_end) {
lr.lr_end = -1;
} else {
auto end_diff
= row.or_value.otr_end.tv_sec - sel_bounds.first.tv_sec;
auto end_diff = row.or_value.otr_range.tr_end.tv_sec
- sel_bounds.first.tv_sec;
lr.lr_end = INDENT + end_diff / per_ch;
if (lr.lr_start == lr.lr_end) {
@ -394,6 +499,7 @@ gantt_source::rebuild_indexes()
this->gs_total_width = 0;
this->gs_filtered_count = 0;
this->gs_opid_map.clear();
this->gs_subid_map.clear();
this->gs_allocator.reset();
this->gs_preview_source.clear();
this->gs_preview_status_source.get_description().clear();
@ -413,10 +519,11 @@ gantt_source::rebuild_indexes()
}
auto format = ld->get_file_ptr()->get_format();
safe::ReadAccess<logfile::safe_opid_map> r_opid_map(
safe::ReadAccess<logfile::safe_opid_state> r_opid_map(
ld->get_file_ptr()->get_opids());
for (const auto& pair : *r_opid_map) {
for (const auto& pair : r_opid_map->los_opid_ranges) {
auto& otr = pair.second;
auto iter = this->gs_opid_map.find(pair.first);
if (iter == this->gs_opid_map.end()) {
auto opid = pair.first.to_owned(this->gs_allocator);
@ -428,14 +535,27 @@ 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{iter->first, pair.second});
iter->first, opid_row{iter->first, otr});
active_iter = active_emp_res.first;
} else {
active_iter->second.or_value |= pair.second;
active_iter->second.or_value |= otr;
}
if (pair.second.otr_description_id) {
auto desc_id = pair.second.otr_description_id.value();
for (auto& sub : active_iter->second.or_value.otr_sub_ops) {
auto subid_iter = this->gs_subid_map.find(sub.ostr_subid);
if (subid_iter == this->gs_subid_map.end()) {
subid_iter = this->gs_subid_map
.emplace(sub.ostr_subid.to_owned(
this->gs_allocator),
true)
.first;
}
sub.ostr_subid = subid_iter->first;
}
if (otr.otr_description.lod_id) {
auto desc_id = otr.otr_description.lod_id.value();
auto desc_def_iter
= format->lf_opid_description_def->find(desc_id);
@ -445,19 +565,18 @@ gantt_source::rebuild_indexes()
} else {
auto& format_descs
= iter->second.odd_format_to_desc[format->get_name()];
format_descs[desc_id]
= desc_def_iter->second.od_descriptors;
format_descs[desc_id] = desc_def_iter->second;
auto& all_descs = active_iter->second.or_descriptions;
auto& curr_desc_m = all_descs[format->get_name()][desc_id];
auto& new_desc_v = pair.second.otr_description;
const auto& new_desc_v = otr.otr_description.lod_elements;
for (const auto& desc_pair : new_desc_v) {
curr_desc_m[desc_pair.first] = desc_pair.second;
}
}
} else {
ensure(pair.second.otr_description.empty());
ensure(otr.otr_description.lod_elements.empty());
}
}
}
@ -465,16 +584,17 @@ gantt_source::rebuild_indexes()
std::multimap<struct timeval, opid_row> time_order_map;
for (const auto& pair : active_opids) {
if (this->gs_lower_bound.tv_sec == 0
|| pair.second.or_value.otr_begin < this->gs_lower_bound)
|| pair.second.or_value.otr_range.tr_begin < this->gs_lower_bound)
{
this->gs_lower_bound = pair.second.or_value.otr_begin;
this->gs_lower_bound = pair.second.or_value.otr_range.tr_begin;
}
if (this->gs_upper_bound.tv_sec == 0
|| this->gs_upper_bound < pair.second.or_value.otr_end)
|| this->gs_upper_bound < pair.second.or_value.otr_range.tr_end)
{
this->gs_upper_bound = pair.second.or_value.otr_end;
this->gs_upper_bound = pair.second.or_value.otr_range.tr_end;
}
time_order_map.emplace(pair.second.or_value.otr_begin, pair.second);
time_order_map.emplace(pair.second.or_value.otr_range.tr_begin,
pair.second);
}
this->gs_time_order.clear();
size_t filtered_in_count = 0;
@ -497,13 +617,9 @@ gantt_source::rebuild_indexes()
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;
for (size_t lpc = 0; lpc < desc_def_v.size(); lpc++) {
full_desc.append(desc_def_v[lpc].od_prefix);
full_desc.append(desc_format_pairs.second[lpc]);
full_desc.append(desc_def_v[lpc].od_suffix);
}
const auto& desc_def
= format_desc_defs.find(desc_format_pairs.first)->second;
full_desc = desc_def.to_string(desc_format_pairs.second);
}
}
@ -538,10 +654,14 @@ gantt_source::rebuild_indexes()
}
}
if (min_log_time_opt && otr.otr_end < min_log_time_opt.value()) {
if (min_log_time_opt
&& otr.otr_range.tr_end < min_log_time_opt.value())
{
filtered_out = true;
}
if (max_log_time_opt && max_log_time_opt.value() < otr.otr_begin) {
if (max_log_time_opt
&& max_log_time_opt.value() < otr.otr_range.tr_begin)
{
filtered_out = true;
}
@ -557,12 +677,9 @@ gantt_source::rebuild_indexes()
if (full_desc.size() > max_desc_width) {
max_desc_width = full_desc.size();
}
if (pair.second.or_value.get_error_count() > 0) {
if (pair.second.or_value.otr_level_stats.lls_error_count > 0) {
bm_errs.insert_once(vis_line_t(this->gs_time_order.size()));
} else if (pair.second.or_value
.otr_level_counts[log_level_t::LEVEL_WARNING]
> 0)
{
} else if (pair.second.or_value.otr_level_stats.lls_warning_count > 0) {
bm_warns.insert_once(vis_line_t(this->gs_time_order.size()));
}
this->gs_time_order.emplace_back(std::move(pair.second));
@ -570,7 +687,7 @@ gantt_source::rebuild_indexes()
this->gs_opid_width = std::min(this->gs_opid_width, MAX_OPID_WIDTH);
this->gs_total_width
= std::max<size_t>(22 + this->gs_opid_width + max_desc_width,
1 + 23 + 10 + 23 + 1 /* header */);
1 + 16 + 5 + 8 + 5 + 16 + 1 /* header */);
this->tss_view->set_needs_update();
}
@ -578,12 +695,13 @@ gantt_source::rebuild_indexes()
nonstd::optional<vis_line_t>
gantt_source::row_for_time(struct timeval time_bucket)
{
auto iter = std::lower_bound(this->gs_time_order.begin(),
this->gs_time_order.end(),
time_bucket,
[](const opid_row& lhs, const timeval& rhs) {
return lhs.or_value.otr_begin < rhs;
});
auto iter
= std::lower_bound(this->gs_time_order.begin(),
this->gs_time_order.end(),
time_bucket,
[](const opid_row& lhs, const timeval& rhs) {
return lhs.or_value.otr_range.tr_begin < rhs;
});
if (iter == this->gs_time_order.end()) {
return nonstd::nullopt;
}
@ -598,7 +716,7 @@ gantt_source::time_for_row(vis_line_t row)
return nonstd::nullopt;
}
return this->gs_time_order[row].or_value.otr_begin;
return this->gs_time_order[row].or_value.otr_range.tr_begin;
}
size_t
@ -620,9 +738,8 @@ gantt_source::text_selection_changed(textview_curses& tc)
}
const auto& row = this->gs_time_order[sel];
auto low_vl = this->gs_lss.row_for_time(row.or_value.otr_begin);
auto high_tv = row.or_value.otr_end;
auto low_vl = this->gs_lss.row_for_time(row.or_value.otr_range.tr_begin);
auto high_tv = row.or_value.otr_range.tr_end;
high_tv.tv_sec += 1;
auto high_vl = this->gs_lss.row_for_time(high_tv).value_or(
this->gs_lss.text_line_count());
@ -671,7 +788,7 @@ gantt_source::text_selection_changed(textview_curses& tc)
this->gs_preview_source.replace_with(preview_content);
this->gs_preview_status_source.get_description().set_value(
" OPID %.*s", row.or_name.length(), row.or_name.data());
auto err_count = row.or_value.get_error_count();
auto err_count = row.or_value.otr_level_stats.lls_error_count;
if (err_count == 0) {
this->gs_preview_status_source
.statusview_value_for_field(gantt_status_source::TSF_ERRORS)
@ -687,7 +804,8 @@ gantt_source::text_selection_changed(textview_curses& tc)
}
this->gs_preview_status_source
.statusview_value_for_field(gantt_status_source::TSF_TOTAL)
.set_value("%'d messages ", row.or_value.get_total_msgs());
.set_value("%'d messages ",
row.or_value.otr_level_stats.lls_total_count);
}
void
@ -747,7 +865,7 @@ gantt_source::text_crumbs_for_line(int line,
const auto& row = this->gs_time_order[line];
char ts[64];
sql_strftime(ts, sizeof(ts), row.or_value.otr_begin, 'T');
sql_strftime(ts, sizeof(ts), row.or_value.otr_range.tr_begin, 'T');
crumbs.emplace_back(
std::string(ts),

@ -85,10 +85,8 @@ public:
ArenaAlloc::Alloc<char> gs_allocator{64 * 1024};
struct opid_description_defs {
std::map<
intern_string_t,
std::map<intern_string_t,
std::shared_ptr<std::vector<log_format::opid_descriptor>>>>
std::map<intern_string_t,
std::map<intern_string_t, log_format::opid_descriptors>>
odd_format_to_desc;
};
@ -98,7 +96,14 @@ public:
frag_hasher,
std::equal_to<string_fragment>>;
using gantt_subid_map
= robin_hood::unordered_map<string_fragment,
bool,
frag_hasher,
std::equal_to<string_fragment>>;
gantt_opid_map gs_opid_map;
gantt_subid_map gs_subid_map;
struct opid_row {
string_fragment or_name;
@ -129,6 +134,13 @@ public:
int bottom,
attr_line_t& value_out) override;
nonstd::optional<attr_line_t> list_header_for_overlay(
const listview_curses& lv, vis_line_t line) override;
void list_value_for_overlay(const listview_curses& lv,
vis_line_t line,
std::vector<attr_line_t>& value_out) override;
private:
std::shared_ptr<gantt_source> gho_src;
};

@ -69,9 +69,9 @@ INSERT INTO http_status_codes VALUES (511, 'Network Authentication Required');
CREATE TABLE lnav_example_log
(
log_line INTEGER PRIMARY KEY,
log_part TEXT collate naturalnocase,
log_time datetime,
log_actual_time datetime hidden,
log_part TEXT COLLATE naturalnocase,
log_time DATETIME,
log_actual_time DATETIME hidden,
log_idle_msecs int,
log_level TEXT collate loglevel,
log_mark boolean,
@ -94,17 +94,17 @@ FROM lnav_views
WHERE name = (SELECT name FROM lnav_view_stack ORDER BY rowid DESC LIMIT 1);
INSERT INTO lnav_example_log
VALUES (0, null, '2017-02-03T04:05:06.100', '2017-02-03T04:05:06.100', 0,
'info', 0, null, null, null, 'hw', 2, 1486094706000, '/tmp/log',
VALUES (0, NULL, '2017-02-03T04:05:06.100', '2017-02-03T04:05:06.100', 0,
'info', 0, NULL, NULL, NULL, 'hw', 2, 1486094706000, '/tmp/log',
'2017-02-03T04:05:06.100 hw(2): Hello, World!', 'Hello, World!'),
(1, null, '2017-02-03T04:05:06.200', '2017-02-03T04:05:06.200', 100,
'error', 0, null, null, null, 'gw', 4, 1486094706000, '/tmp/log',
(1, NULL, '2017-02-03T04:05:06.200', '2017-02-03T04:05:06.200', 100,
'error', 0, NULL, NULL, NULL, 'gw', 4, 1486094706000, '/tmp/log',
'2017-02-03T04:05:06.200 gw(4): Goodbye, World!', 'Goodbye, World!'),
(2, 'new', '2017-02-03T04:25:06.200', '2017-02-03T04:25:06.200', 1200000,
'warn', 0, null, null, null, 'gw', 1, 1486095906000, '/tmp/log',
'warn', 0, NULL, NULL, NULL, 'gw', 1, 1486095906000, '/tmp/log',
'2017-02-03T04:25:06.200 gw(1): Goodbye, World!', 'Goodbye, World!'),
(3, 'new', '2017-02-03T04:55:06.200', '2017-02-03T04:55:06.200', 1800000,
'debug', 0, null, null, null, 'gw', 10, 1486097706000, '/tmp/log',
'debug', 0, NULL, NULL, NULL, 'gw', 10, 1486097706000, '/tmp/log',
'2017-02-03T04:55:06.200 gw(10): Goodbye, World!', 'Goodbye, World!');
CREATE TABLE lnav_user_notifications
@ -128,8 +128,8 @@ CREATE TABLE lnav_user_notifications
);
INSERT INTO lnav_user_notifications (id, priority, expiration, message)
VALUES ('org.lnav.breadcrumb.focus', -1, datetime('now', '+1 minute'),
'Press ENTER to focus on the breadcrumb bar');
VALUES ('org.lnav.breadcrumb.focus', -1, DATETIME('now', '+1 minute'),
'Press <span class="-lnav_status-styles_hotkey">`</span> to focus on the breadcrumb bar');
CREATE TABLE lnav_views_echo AS
SELECT name, top, "left", height, inner_height, top_time, search

@ -868,7 +868,9 @@ handle_key(int ch)
default: {
switch (lnav_data.ld_mode) {
case ln_mode_t::PAGING:
if (ch == KEY_ENTER || ch == '\n' || ch == '\r') {
if (ch == KEY_ENTER || ch == '\n' || ch == '\r'
|| ch == '`')
{
breadcrumb_view.focus();
lnav_data.ld_mode = ln_mode_t::BREADCRUMBS;
return true;

@ -36,6 +36,8 @@
#include "base/fs_util.hh"
#include "base/is_utf8.hh"
#include "base/map_util.hh"
#include "base/opt_util.hh"
#include "base/snippet_highlighters.hh"
#include "base/string_util.hh"
#include "command_executor.hh"
@ -70,48 +72,163 @@ external_log_format::mod_map_t external_log_format::MODULE_FORMATS;
std::vector<std::shared_ptr<external_log_format>>
external_log_format::GRAPH_ORDERED_FORMATS;
size_t
opid_time_range::get_total_msgs() const
log_level_stats&
log_level_stats::operator|=(const log_level_stats& rhs)
{
return std::accumulate(this->otr_level_counts.begin(),
this->otr_level_counts.end(),
size_t{0});
this->lls_error_count += rhs.lls_error_count;
this->lls_warning_count += rhs.lls_warning_count;
this->lls_total_count += rhs.lls_total_count;
return *this;
}
size_t
opid_time_range::get_error_count() const
log_op_description&
log_op_description::operator|=(const log_op_description& rhs)
{
size_t retval = 0;
for (const auto level : {
log_level_t::LEVEL_ERROR,
log_level_t::LEVEL_CRITICAL,
log_level_t::LEVEL_FATAL,
})
{
retval += this->otr_level_counts[level];
if (!this->lod_id && rhs.lod_id) {
this->lod_id = rhs.lod_id;
}
if (this->lod_elements.size() < rhs.lod_elements.size()) {
this->lod_elements = rhs.lod_elements;
}
return retval;
return *this;
}
opid_time_range&
opid_time_range::operator|=(const opid_time_range& rhs)
{
if (rhs.otr_begin < this->otr_begin) {
this->otr_begin = rhs.otr_begin;
this->otr_range |= rhs.otr_range;
this->otr_description |= rhs.otr_description;
this->otr_level_stats |= rhs.otr_level_stats;
for (const auto& rhs_sub : rhs.otr_sub_ops) {
bool found = false;
for (auto& sub : this->otr_sub_ops) {
if (sub.ostr_subid == rhs_sub.ostr_subid) {
sub.ostr_range |= rhs_sub.ostr_range;
found = true;
}
}
if (!found) {
this->otr_sub_ops.emplace_back(rhs_sub);
}
}
std::stable_sort(this->otr_sub_ops.begin(), this->otr_sub_ops.end());
return *this;
}
void
log_level_stats::update_msg_count(log_level_t lvl)
{
switch (lvl) {
case LEVEL_FATAL:
case LEVEL_CRITICAL:
case LEVEL_ERROR:
this->lls_error_count += 1;
break;
case LEVEL_WARNING:
this->lls_warning_count += 1;
break;
default:
break;
}
this->lls_total_count += 1;
}
void
opid_time_range::close_sub_ops(const string_fragment& subid)
{
for (auto& other_sub : this->otr_sub_ops) {
if (other_sub.ostr_subid == subid) {
other_sub.ostr_open = false;
}
}
}
opid_sub_time_range*
log_opid_state::sub_op_in_use(ArenaAlloc::Alloc<char>& alloc,
log_opid_map::iterator& op_iter,
const string_fragment& subid,
const timeval& tv,
log_level_t level)
{
const auto& opid = op_iter->first;
auto sub_iter = this->los_sub_in_use.find(subid);
if (sub_iter == this->los_sub_in_use.end()) {
auto emp_res
= this->los_sub_in_use.emplace(subid.to_owned(alloc), opid);
sub_iter = emp_res.first;
}
if (this->otr_end < rhs.otr_end) {
this->otr_end = rhs.otr_end;
auto retval = sub_iter->first;
if (sub_iter->second != opid) {
auto other_otr
= lnav::map::find(this->los_opid_ranges, sub_iter->second);
if (other_otr) {
other_otr->get().close_sub_ops(retval);
}
}
if (this->otr_description.size() < rhs.otr_description.size()) {
this->otr_description = rhs.otr_description;
sub_iter->second = opid;
auto& otr = op_iter->second;
auto sub_op_iter = otr.otr_sub_ops.rbegin();
for (; sub_op_iter != otr.otr_sub_ops.rend(); ++sub_op_iter) {
if (sub_op_iter->ostr_open && sub_op_iter->ostr_subid == retval) {
break;
}
}
for (size_t lpc = 0; lpc < this->otr_level_counts.size(); lpc++) {
this->otr_level_counts[lpc] += rhs.otr_level_counts[lpc];
if (sub_op_iter == otr.otr_sub_ops.rend()) {
otr.otr_sub_ops.emplace_back(opid_sub_time_range{
retval,
time_range{tv, tv},
});
otr.otr_sub_ops.back().ostr_level_stats.update_msg_count(level);
return &otr.otr_sub_ops.back();
} else {
sub_op_iter->ostr_range.extend_to(tv);
sub_op_iter->ostr_level_stats.update_msg_count(level);
return &(*sub_op_iter);
}
}
return *this;
nonstd::optional<std::string>
log_format::opid_descriptor::matches(const string_fragment& sf) const
{
if (this->od_extractor.pp_value) {
static thread_local auto desc_md
= lnav::pcre2pp::match_data::unitialized();
auto desc_match_res = this->od_extractor.pp_value->capture_from(sf)
.into(desc_md)
.matches(PCRE2_NO_UTF_CHECK)
.ignore_error();
if (desc_match_res) {
return desc_md.to_string();
}
return nonstd::nullopt;
}
return sf.to_string();
}
std::string
log_format::opid_descriptors::to_string(
const std::map<size_t, std::string>& lod) const
{
std::string retval;
for (size_t lpc = 0; lpc < this->od_descriptors->size(); lpc++) {
retval.append(this->od_descriptors->at(lpc).od_prefix);
lnav::map::find(lod, lpc) |
[&retval](const auto str) { retval.append(str); };
retval.append(this->od_descriptors->at(lpc).od_suffix);
}
return retval;
}
struct line_range
@ -303,6 +420,152 @@ log_format::get_root_formats()
return lf_root_formats;
}
void
external_log_format::update_op_description(
const std::map<intern_string_t, opid_descriptors>& desc_defs,
log_op_description& lod,
const pattern* fpat,
const lnav::pcre2pp::match_data& md)
{
nonstd::optional<std::string> desc_elem_str;
if (!lod.lod_id) {
for (const auto& desc_def_pair : desc_defs) {
if (lod.lod_id) {
break;
}
for (const auto& desc_def : *desc_def_pair.second.od_descriptors) {
auto desc_field_index_iter = fpat->p_value_name_to_index.find(
desc_def.od_field.pp_value);
if (desc_field_index_iter == fpat->p_value_name_to_index.end())
{
continue;
}
auto desc_cap_opt = md[desc_field_index_iter->second];
if (!desc_cap_opt) {
continue;
}
desc_elem_str = desc_def.matches(desc_cap_opt.value());
if (desc_elem_str) {
lod.lod_id = desc_def_pair.first;
}
}
}
}
if (lod.lod_id) {
const auto& desc_def_v
= *desc_defs.find(lod.lod_id.value())->second.od_descriptors;
auto& desc_v = lod.lod_elements;
if (desc_def_v.size() == desc_v.size()) {
return;
}
for (size_t desc_def_index = 0; desc_def_index < desc_def_v.size();
desc_def_index++)
{
const auto& desc_def = desc_def_v[desc_def_index];
auto found_desc = desc_v.begin();
for (; found_desc != desc_v.end(); ++found_desc) {
if (found_desc->first == desc_def_index) {
break;
}
}
auto desc_field_index_iter
= fpat->p_value_name_to_index.find(desc_def.od_field.pp_value);
if (desc_field_index_iter == fpat->p_value_name_to_index.end()) {
continue;
}
auto desc_cap_opt = md[desc_field_index_iter->second];
if (!desc_cap_opt) {
continue;
}
if (!desc_elem_str) {
desc_elem_str = desc_def.matches(desc_cap_opt.value());
}
if (desc_elem_str) {
if (found_desc == desc_v.end()) {
desc_v.emplace_back(desc_def_index, desc_elem_str.value());
} else if (!desc_elem_str->empty()) {
found_desc->second.append(desc_def.od_joiner);
found_desc->second.append(desc_elem_str.value());
}
}
desc_elem_str = nonstd::nullopt;
}
}
}
void
external_log_format::update_op_description(
const std::map<intern_string_t, opid_descriptors>& desc_defs,
log_op_description& lod)
{
nonstd::optional<std::string> desc_elem_str;
if (!lod.lod_id) {
for (const auto& desc_def_pair : desc_defs) {
if (lod.lod_id) {
break;
}
for (const auto& desc_def : *desc_def_pair.second.od_descriptors) {
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;
}
desc_elem_str = desc_def.matches(desc_cap_iter->second);
if (desc_elem_str) {
lod.lod_id = desc_def_pair.first;
}
}
}
}
if (lod.lod_id) {
const auto& desc_def_v
= *desc_defs.find(lod.lod_id.value())->second.od_descriptors;
auto& desc_v = lod.lod_elements;
if (desc_def_v.size() != desc_v.size()) {
for (size_t desc_def_index = 0; desc_def_index < desc_def_v.size();
desc_def_index++)
{
const auto& desc_def = desc_def_v[desc_def_index];
auto found_desc = desc_v.begin();
for (; found_desc != desc_v.end(); ++found_desc) {
if (found_desc->first == desc_def_index) {
break;
}
}
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_elem_str) {
desc_elem_str = desc_def.matches(desc_cap_iter->second);
}
if (desc_elem_str) {
if (found_desc == desc_v.end()) {
desc_v.emplace_back(desc_def_index,
desc_elem_str.value());
} else if (!desc_elem_str->empty()) {
found_desc->second.append(desc_def.od_joiner);
found_desc->second.append(desc_elem_str.value());
}
}
desc_elem_str = nonstd::nullopt;
}
}
}
}
static bool
next_format(
const std::vector<std::shared_ptr<external_log_format::pattern>>& patterns,
@ -507,6 +770,7 @@ struct json_log_userdata {
shared_buffer_ref& jlu_shared_buffer;
scan_batch_context* jlu_batch_context;
nonstd::optional<string_fragment> jlu_opid_frag;
nonstd::optional<std::string> jlu_subid;
};
static int read_json_field(yajlpp_parse_context* ypc,
@ -840,115 +1104,49 @@ external_log_format::scan(logfile& lf,
}
if (jlu.jlu_opid_frag) {
auto opid_iter = sbc.sbc_opids.find(jlu.jlu_opid_frag.value());
if (opid_iter == sbc.sbc_opids.end()) {
auto otr
= opid_time_range{ll.get_timeval(), ll.get_timeval()};
auto emplace_res
= sbc.sbc_opids.emplace(jlu.jlu_opid_frag.value(), otr);
auto opid_iter = sbc.sbc_opids.los_opid_ranges.find(
jlu.jlu_opid_frag.value());
if (opid_iter == sbc.sbc_opids.los_opid_ranges.end()) {
auto otr = opid_time_range{
time_range{ll.get_timeval(), ll.get_timeval()},
};
auto emplace_res = sbc.sbc_opids.los_opid_ranges.emplace(
jlu.jlu_opid_frag.value(), otr);
opid_iter = emplace_res.first;
} else {
opid_iter->second.otr_end = ll.get_timeval();
opid_iter->second.otr_range.extend_to(ll.get_timeval());
}
opid_iter->second.otr_level_counts[ll.get_msg_level()] += 1;
auto& otr = opid_iter->second;
if (!otr.otr_description_id) {
for (const auto& desc_def_pair :
*this->lf_opid_description_def)
{
if (otr.otr_description_id) {
break;
}
for (const auto& desc_def :
*desc_def_pair.second.od_descriptors)
{
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_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 (desc_match_res) {
otr.otr_description_id
= desc_def_pair.first;
}
} else {
otr.otr_description_id = desc_def_pair.first;
}
opid_iter->second.otr_level_stats.update_msg_count(
ll.get_msg_level());
if (jlu.jlu_subid) {
auto subid_frag
= string_fragment::from_str(jlu.jlu_subid.value());
auto* ostr
= sbc.sbc_opids.sub_op_in_use(sbc.sbc_allocator,
opid_iter,
subid_frag,
ll.get_timeval(),
ll.get_msg_level());
if (ostr != nullptr && ostr->ostr_description.empty()) {
log_op_description sub_desc;
this->update_op_description(
*this->lf_subid_description_def, sub_desc);
if (!sub_desc.lod_elements.empty()) {
auto& sub_desc_def
= this->lf_subid_description_def->at(
sub_desc.lod_id.value());
ostr->ostr_description = sub_desc_def.to_string(
lnav::map::from_vec(sub_desc.lod_elements));
}
}
}
if (otr.otr_description_id) {
const auto& desc_def_v
= *this->lf_opid_description_def
->find(
opid_iter->second.otr_description_id.value())
->second.od_descriptors;
auto& desc_v = opid_iter->second.otr_description;
if (desc_def_v.size() != desc_v.size()) {
for (size_t desc_def_index = 0;
desc_def_index < desc_def_v.size();
desc_def_index++)
{
const auto& desc_def = desc_def_v[desc_def_index];
auto found_desc = desc_v.begin();
for (; found_desc != desc_v.end(); ++found_desc) {
if (found_desc->first == desc_def_index) {
break;
}
}
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_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 {
found_desc->second.append(
desc_def.od_joiner);
found_desc->second.append(desc_str.value());
}
}
}
}
}
auto& otr = opid_iter->second;
this->update_op_description(*this->lf_opid_description_def,
otr.otr_description);
}
jlu.jlu_sub_line_count += this->jlf_line_format_init_count;
@ -1026,6 +1224,7 @@ external_log_format::scan(logfile& lf,
auto level_cap = md[fpat->p_level_field_index];
auto mod_cap = md[fpat->p_module_field_index];
auto opid_cap = md[fpat->p_opid_field_index];
auto subid_cap = md[fpat->p_subid_field_index];
auto body_cap = md[fpat->p_body_field_index];
const char* last;
struct exttm log_time_tm;
@ -1080,127 +1279,43 @@ external_log_format::scan(logfile& lf,
}
if (opid_cap && !opid_cap->empty()) {
auto opid_iter = sbc.sbc_opids.find(opid_cap.value());
auto opid_iter
= sbc.sbc_opids.los_opid_ranges.find(opid_cap.value());
if (opid_iter == sbc.sbc_opids.end()) {
if (opid_iter == sbc.sbc_opids.los_opid_ranges.end()) {
auto opid_copy = opid_cap->to_owned(sbc.sbc_allocator);
auto otr = opid_time_range{log_tv, log_tv};
auto emplace_res = sbc.sbc_opids.emplace(opid_copy, otr);
auto otr = opid_time_range{time_range{log_tv, log_tv}};
auto emplace_res
= sbc.sbc_opids.los_opid_ranges.emplace(opid_copy, otr);
opid_iter = emplace_res.first;
} else {
opid_iter->second.otr_end = log_tv;
opid_iter->second.otr_range.extend_to(log_tv);
}
opid_iter->second.otr_level_counts[level] += 1;
auto& otr = opid_iter->second;
if (!otr.otr_description_id) {
for (const auto& desc_def_pair : *this->lf_opid_description_def)
{
if (otr.otr_description_id) {
break;
}
for (const auto& desc_def :
*desc_def_pair.second.od_descriptors)
{
auto desc_field_index_iter
= fpat->p_value_name_to_index.find(
desc_def.od_field.pp_value);
if (desc_field_index_iter
!= fpat->p_value_name_to_index.end())
{
auto desc_cap_opt
= md[desc_field_index_iter->second];
if (desc_cap_opt) {
if (desc_def.od_extractor.pp_value) {
static thread_local auto desc_md = lnav::
pcre2pp::match_data::unitialized();
auto desc_match_res
= desc_def.od_extractor.pp_value
->capture_from(
desc_cap_opt.value())
.into(desc_md)
.matches(PCRE2_NO_UTF_CHECK)
.ignore_error();
if (desc_match_res) {
otr.otr_description_id
= desc_def_pair.first;
}
} else {
otr.otr_description_id
= desc_def_pair.first;
}
}
}
otr.otr_level_stats.update_msg_count(level);
if (subid_cap && !subid_cap->empty()) {
auto* ostr = sbc.sbc_opids.sub_op_in_use(sbc.sbc_allocator,
opid_iter,
subid_cap.value(),
log_tv,
level);
if (ostr != nullptr && ostr->ostr_description.empty()) {
log_op_description sub_desc;
this->update_op_description(
*this->lf_subid_description_def, sub_desc, fpat, md);
if (!sub_desc.lod_elements.empty()) {
auto& sub_desc_def = this->lf_subid_description_def->at(
sub_desc.lod_id.value());
ostr->ostr_description = sub_desc_def.to_string(
lnav::map::from_vec(sub_desc.lod_elements));
}
}
}
if (otr.otr_description_id) {
const auto& desc_def_v
= *this->lf_opid_description_def
->find(opid_iter->second.otr_description_id.value())
->second.od_descriptors;
auto& desc_v = opid_iter->second.otr_description;
if (desc_def_v.size() != desc_v.size()) {
for (size_t desc_def_index = 0;
desc_def_index < desc_def_v.size();
desc_def_index++)
{
const auto& desc_def = desc_def_v[desc_def_index];
auto found_desc = false;
for (const auto& desc_pair : desc_v) {
if (desc_pair.first == desc_def_index) {
found_desc = true;
break;
}
}
if (!found_desc) {
auto desc_field_index_iter
= fpat->p_value_name_to_index.find(
desc_def.od_field.pp_value);
if (desc_field_index_iter
!= fpat->p_value_name_to_index.end())
{
auto desc_cap_opt
= md[desc_field_index_iter->second];
if (desc_cap_opt) {
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_opt.value())
.into(desc_md)
.matches(PCRE2_NO_UTF_CHECK)
.ignore_error();
if (match_res) {
desc_v.emplace_back(
desc_def_index,
desc_md.to_string());
}
} else {
desc_v.emplace_back(
desc_def_index,
desc_cap_opt->to_string());
}
}
}
}
}
}
}
this->update_op_description(
*this->lf_opid_description_def, otr.otr_description, fpat, md);
opid = hash_str(opid_cap->data(), opid_cap->length());
}
@ -1644,13 +1759,16 @@ read_json_field(yajlpp_parse_context* ypc, const unsigned char* str, size_t len)
jlu->jlu_base_line->set_opid(opid);
auto& sbc = *jlu->jlu_batch_context;
auto opid_iter = sbc.sbc_opids.find(frag);
if (opid_iter == sbc.sbc_opids.end()) {
auto opid_iter = sbc.sbc_opids.los_opid_ranges.find(frag);
if (opid_iter == sbc.sbc_opids.los_opid_ranges.end()) {
jlu->jlu_opid_frag = frag.to_owned(sbc.sbc_allocator);
} else {
jlu->jlu_opid_frag = opid_iter->first;
}
}
if (jlu->jlu_format->elf_subid_field == field_name) {
jlu->jlu_subid = frag.to_string();
}
if (jlu->jlu_format->lf_desc_fields.contains(field_name)) {
auto frag_copy = frag.to_owned(jlu->jlu_format->lf_desc_allocator);
@ -2357,6 +2475,9 @@ external_log_format::build(std::vector<lnav::console::user_message>& errors)
if (name == this->elf_opid_field) {
pat.p_opid_field_index = named_cap.get_index();
}
if (name == this->elf_subid_field) {
pat.p_subid_field_index = named_cap.get_index();
}
if (name == this->elf_body_field) {
pat.p_body_field_index = named_cap.get_index();
}
@ -2646,6 +2767,25 @@ external_log_format::build(std::vector<lnav::console::user_message>& errors)
}
}
for (const auto& subid_desc_pair : *this->lf_subid_description_def) {
for (const auto& subid_desc : *subid_desc_pair.second.od_descriptors) {
auto iter = this->elf_value_defs.find(subid_desc.od_field.pp_value);
if (iter == this->elf_value_defs.end()) {
errors.emplace_back(
lnav::console::user_message::error(
attr_line_t("invalid subid description field ")
.append_quoted(lnav::roles::symbol(
subid_desc.od_field.pp_path.to_string())))
.with_reason(
attr_line_t("unknown value name ")
.append_quoted(subid_desc.od_field.pp_value))
.with_snippets(this->get_snippets()));
} else {
this->lf_desc_fields.insert(iter->first);
}
}
}
if (this->elf_type == elf_type_t::ELF_TYPE_TEXT
&& this->elf_samples.empty())
{

@ -547,16 +547,24 @@ public:
std::string od_prefix{" "};
std::string od_suffix;
std::string od_joiner{", "};
nonstd::optional<std::string> matches(const string_fragment& sf) const;
};
struct opid_descriptors {
std::shared_ptr<std::vector<opid_descriptor>> od_descriptors;
std::string to_string(const std::map<size_t, std::string>& lod) const;
};
std::shared_ptr<std::map<intern_string_t, opid_descriptors>>
lf_opid_description_def{
std::make_shared<std::map<intern_string_t, opid_descriptors>>()};
std::shared_ptr<std::map<intern_string_t, opid_descriptors>>
lf_subid_description_def{
std::make_shared<std::map<intern_string_t, opid_descriptors>>()};
ArenaAlloc::Alloc<char> lf_desc_allocator{2 * 1024};
using desc_field_set

@ -111,6 +111,7 @@ public:
int p_level_field_index{-1};
int p_module_field_index{-1};
int p_opid_field_index{-1};
int p_subid_field_index{-1};
int p_body_field_index{-1};
int p_timestamp_end{-1};
bool p_module_format{false};
@ -347,6 +348,7 @@ public:
intern_string_t elf_body_field;
intern_string_t elf_module_id_field;
intern_string_t elf_opid_field;
intern_string_t elf_subid_field;
std::map<log_level_t, level_pattern> elf_level_patterns;
std::vector<std::pair<int64_t, log_level_t>> elf_level_pairs;
bool elf_container{false};
@ -391,6 +393,16 @@ public:
elf_type_t elf_type{elf_type_t::ELF_TYPE_TEXT};
void update_op_description(
const std::map<intern_string_t, opid_descriptors>& desc_def,
log_op_description& lod,
const pattern* fpat,
const lnav::pcre2pp::match_data& md);
void update_op_description(
const std::map<intern_string_t, opid_descriptors>& desc_def,
log_op_description& lod);
void json_append_to_cache(const char* value, ssize_t len)
{
if (len <= 0) {

@ -47,15 +47,42 @@
class log_format;
struct log_level_stats {
uint32_t lls_error_count{0};
uint32_t lls_warning_count{0};
uint32_t lls_total_count{0};
log_level_stats& operator|=(const log_level_stats& rhs);
void update_msg_count(log_level_t lvl);
};
struct log_op_description {
nonstd::optional<intern_string_t> lod_id;
std::vector<std::pair<size_t, std::string>> lod_elements;
log_op_description& operator|=(const log_op_description& rhs);
};
struct opid_sub_time_range {
string_fragment ostr_subid;
time_range ostr_range;
bool ostr_open{true};
log_level_stats ostr_level_stats;
std::string ostr_description;
bool operator<(const opid_sub_time_range& rhs) const
{
return this->ostr_range < rhs.ostr_range;
}
};
struct opid_time_range {
struct timeval otr_begin;
struct timeval otr_end;
std::array<size_t, log_level_t::LEVEL__MAX> otr_level_counts;
nonstd::optional<intern_string_t> otr_description_id;
std::vector<std::pair<size_t, std::string>> otr_description;
time_range otr_range;
log_level_stats otr_level_stats;
log_op_description otr_description;
std::vector<opid_sub_time_range> otr_sub_ops;
size_t get_total_msgs() const;
size_t get_error_count() const;
void close_sub_ops(const string_fragment& subid);
opid_time_range& operator|=(const opid_time_range& rhs);
};
@ -65,9 +92,25 @@ using log_opid_map = robin_hood::unordered_map<string_fragment,
frag_hasher,
std::equal_to<string_fragment>>;
using sub_opid_map = robin_hood::unordered_map<string_fragment,
string_fragment,
frag_hasher,
std::equal_to<string_fragment>>;
struct log_opid_state {
log_opid_map los_opid_ranges;
sub_opid_map los_sub_in_use;
opid_sub_time_range* sub_op_in_use(ArenaAlloc::Alloc<char>& alloc,
log_opid_map::iterator& op_iter,
const string_fragment& subid,
const timeval& tv,
log_level_t level);
};
struct scan_batch_context {
ArenaAlloc::Alloc<char>& sbc_allocator;
log_opid_map sbc_opids;
log_opid_state sbc_opids;
std::string sbc_cached_level_strings[4];
log_level_t sbc_cached_level_values[4];
size_t sbc_cached_level_count{0};

@ -476,25 +476,27 @@ public:
}
if (opid_cap.is_valid()) {
auto opid_iter = sbc.sbc_opids.find(opid_cap);
auto opid_iter = sbc.sbc_opids.los_opid_ranges.find(opid_cap);
if (opid_iter == sbc.sbc_opids.end()) {
if (opid_iter == sbc.sbc_opids.los_opid_ranges.end()) {
auto opid_copy = opid_cap.to_owned(sbc.sbc_allocator);
auto otr = opid_time_range{tv, tv};
auto emplace_res = sbc.sbc_opids.emplace(opid_copy, otr);
auto otr = opid_time_range{time_range{tv, tv}};
auto emplace_res
= sbc.sbc_opids.los_opid_ranges.emplace(opid_copy, otr);
opid_iter = emplace_res.first;
} else {
opid_iter->second.otr_end = tv;
opid_iter->second.otr_range.extend_to(tv);
}
opid_iter->second.otr_level_counts[level] += 1;
opid_iter->second.otr_level_stats.update_msg_count(level);
auto& otr = opid_iter->second;
if (!otr.otr_description_id && host_cap.is_valid()
&& otr.otr_description.empty())
if (!otr.otr_description.lod_id && host_cap.is_valid()
&& otr.otr_description.lod_elements.empty())
{
otr.otr_description_id = get_opid_desc();
otr.otr_description.emplace_back(0, host_cap.to_string());
otr.otr_description.lod_id = get_opid_desc();
otr.otr_description.lod_elements.emplace_back(
0, host_cap.to_string());
}
}
dst.emplace_back(li.li_file_range.fr_offset, tv, level, 0, opid);

@ -882,11 +882,25 @@ static const struct json_path_container opid_description_handlers = {
.with_children(opid_description_format_handlers),
};
static const struct json_path_container subid_description_handlers = {
yajlpp::pattern_property_handler(R"((?<subid_descriptor>[\w\.\-]+))")
.with_description("A type of description for this sub-operation")
.for_field(&log_format::lf_subid_description_def)
.with_children(opid_description_format_handlers),
};
static const struct json_path_container opid_handlers = {
yajlpp::property_handler("subid")
.with_description("The field that holds the ID for a sub-operation")
.for_field(&external_log_format::elf_subid_field),
yajlpp::property_handler("description")
.with_description(
"Define how to construct a description of an operation")
.with_children(opid_description_handlers),
yajlpp::property_handler("sub-description")
.with_description(
"Define how to construct a description of a sub-operation")
.with_children(subid_description_handlers),
};
const struct json_path_container format_handlers = {

@ -1269,19 +1269,19 @@ log_cursor::string_constraint::matches(const std::string& sf) const
}
}
struct time_range {
nonstd::optional<timeval> tr_begin;
nonstd::optional<timeval> tr_end;
struct vtab_time_range {
nonstd::optional<timeval> vtr_begin;
nonstd::optional<timeval> vtr_end;
bool empty() const { return !this->tr_begin && !this->tr_end; }
bool empty() const { return !this->vtr_begin && !this->vtr_end; }
void add(const timeval& tv)
{
if (!this->tr_begin || tv < this->tr_begin) {
this->tr_begin = tv;
if (!this->vtr_begin || tv < this->vtr_begin) {
this->vtr_begin = tv;
}
if (!this->tr_end || this->tr_end < tv) {
this->tr_end = tv;
if (!this->vtr_end || this->vtr_end < tv) {
this->vtr_end = tv;
}
}
};
@ -1329,7 +1329,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
p_cur->log_cursor.lc_curr_line = 0_vl;
p_cur->log_cursor.lc_end_line = vis_line_t(vt->lss->text_line_count());
nonstd::optional<time_range> log_time_range;
nonstd::optional<vtab_time_range> log_time_range;
nonstd::optional<log_cursor::opid_hash> opid_val;
std::vector<log_cursor::string_constraint> log_path_constraints;
std::vector<log_cursor::string_constraint> log_unique_path_constraints;
@ -1382,23 +1382,23 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
case SQLITE_INDEX_CONSTRAINT_EQ:
case SQLITE_INDEX_CONSTRAINT_IS:
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
log_time_range->add(tv);
break;
case SQLITE_INDEX_CONSTRAINT_GT:
case SQLITE_INDEX_CONSTRAINT_GE:
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
log_time_range->tr_begin = tv;
log_time_range->vtr_begin = tv;
break;
case SQLITE_INDEX_CONSTRAINT_LT:
case SQLITE_INDEX_CONSTRAINT_LE:
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
log_time_range->tr_end = tv;
log_time_range->vtr_end = tv;
break;
}
}
@ -1426,23 +1426,23 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
case SQLITE_INDEX_CONSTRAINT_EQ:
case SQLITE_INDEX_CONSTRAINT_IS:
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
log_time_range->add(tv);
break;
case SQLITE_INDEX_CONSTRAINT_GT:
case SQLITE_INDEX_CONSTRAINT_GE:
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
log_time_range->tr_begin = tv;
log_time_range->vtr_begin = tv;
break;
case SQLITE_INDEX_CONSTRAINT_LT:
case SQLITE_INDEX_CONSTRAINT_LE:
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
log_time_range->tr_end = tv;
log_time_range->vtr_end = tv;
break;
}
break;
@ -1474,21 +1474,24 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
auto opid = from_sqlite<string_fragment>()(
argc, argv, lpc);
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
for (const auto& file_data : *vt->lss) {
if (file_data->get_file_ptr() == nullptr) {
continue;
}
safe::ReadAccess<logfile::safe_opid_map>
safe::ReadAccess<logfile::safe_opid_state>
r_opid_map(
file_data->get_file_ptr()->get_opids());
const auto& iter = r_opid_map->find(opid);
if (iter == r_opid_map->end()) {
const auto& iter
= r_opid_map->los_opid_ranges.find(opid);
if (iter == r_opid_map->los_opid_ranges.end()) {
continue;
}
log_time_range->add(iter->second.otr_begin);
log_time_range->add(iter->second.otr_end);
log_time_range->add(
iter->second.otr_range.tr_begin);
log_time_range->add(
iter->second.otr_range.tr_end);
}
opid_val = log_cursor::opid_hash{
@ -1508,7 +1511,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
auto found = false;
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
for (const auto& file_data : *vt->lss) {
auto* lf = file_data->get_file_ptr();
@ -1541,7 +1544,7 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
auto found = false;
if (!log_time_range) {
log_time_range = time_range{};
log_time_range = vtab_time_range{};
}
for (const auto& file_data : *vt->lss) {
auto* lf = file_data->get_file_ptr();
@ -1673,25 +1676,25 @@ vt_filter(sqlite3_vtab_cursor* p_vtc,
} else if (log_time_range->empty()) {
p_cur->log_cursor.lc_curr_line = p_cur->log_cursor.lc_end_line;
} else {
if (log_time_range->tr_begin) {
if (log_time_range->vtr_begin) {
auto vl_opt
= vt->lss->row_for_time(log_time_range->tr_begin.value());
= vt->lss->row_for_time(log_time_range->vtr_begin.value());
if (!vl_opt) {
p_cur->log_cursor.lc_curr_line = p_cur->log_cursor.lc_end_line;
} else {
p_cur->log_cursor.lc_curr_line = vl_opt.value();
}
}
if (log_time_range->tr_end) {
if (log_time_range->vtr_end) {
auto vl_max_opt
= vt->lss->row_for_time(log_time_range->tr_end.value());
= vt->lss->row_for_time(log_time_range->vtr_end.value());
if (vl_max_opt) {
p_cur->log_cursor.lc_end_line = vl_max_opt.value();
for (const auto& msg_info :
vt->lss->window_at(vl_max_opt.value(),
vis_line_t(vt->lss->text_line_count())))
{
if (log_time_range->tr_end.value()
if (log_time_range->vtr_end.value()
< msg_info.get_logline().get_timeval())
{
break;

@ -165,7 +165,7 @@ logfile::open(std::string filename, const logfile_open_options& loo, auto_fd fd)
logfile::logfile(std::string filename, const logfile_open_options& loo)
: lf_filename(std::move(filename)), lf_options(loo)
{
this->lf_opids.writeAccess()->reserve(64);
this->lf_opids.writeAccess()->los_opid_ranges.reserve(64);
}
logfile::~logfile() {}
@ -500,6 +500,14 @@ logfile::rebuild_index(nonstd::optional<ui_clock::time_point> deadline)
this->lf_partial_line = false;
this->lf_longest_line = 0;
this->lf_sort_needed = true;
{
safe::WriteAccess<logfile::safe_opid_state> writable_opid_map(
this->lf_opids);
writable_opid_map->los_opid_ranges.clear();
writable_opid_map->los_sub_in_use.clear();
}
this->lf_allocator.reset();
}
this->lf_zoned_to_local_state = dts_cfg.c_zoned_to_local;
@ -626,7 +634,7 @@ logfile::rebuild_index(nonstd::optional<ui_clock::time_point> deadline)
"loading file... %s:%d", this->lf_filename.c_str(), begin_size);
}
scan_batch_context sbc{this->lf_allocator};
sbc.sbc_opids.reserve(32);
sbc.sbc_opids.los_opid_ranges.reserve(32);
auto prev_range = file_range{off};
while (limit > 0) {
auto load_result = this->lf_line_buffer.load_next_line(prev_range);
@ -861,26 +869,25 @@ logfile::rebuild_index(nonstd::optional<ui_clock::time_point> deadline)
this->lf_stat = st;
{
safe::WriteAccess<logfile::safe_opid_map> writable_opid_map(
safe::WriteAccess<logfile::safe_opid_state> writable_opid_map(
this->lf_opids);
for (const auto& opid_pair : sbc.sbc_opids) {
auto opid_iter = writable_opid_map->find(opid_pair.first);
for (const auto& opid_pair : sbc.sbc_opids.los_opid_ranges) {
auto opid_iter
= writable_opid_map->los_opid_ranges.find(opid_pair.first);
if (opid_iter == writable_opid_map->end()) {
writable_opid_map->emplace(opid_pair);
if (opid_iter == writable_opid_map->los_opid_ranges.end()) {
writable_opid_map->los_opid_ranges.emplace(opid_pair);
} else {
if (opid_pair.second.otr_begin
< opid_iter->second.otr_begin)
{
opid_iter->second.otr_begin
= opid_pair.second.otr_begin;
}
if (opid_iter->second.otr_end < opid_pair.second.otr_end) {
opid_iter->second.otr_end = opid_pair.second.otr_end;
}
opid_iter->second |= opid_pair.second;
}
}
log_debug(
"%s: opid_map size: count=%zu; sizeof(otr)=%zu; alloc=%zu",
this->lf_filename.c_str(),
writable_opid_map->los_opid_ranges.size(),
sizeof(opid_time_range),
this->lf_allocator.getNumBytesAllocated());
}
if (sort_needed) {

@ -370,9 +370,9 @@ public:
note_map get_notes() const { return *this->lf_notes.readAccess(); }
using safe_opid_map = safe::Safe<log_opid_map>;
using safe_opid_state = safe::Safe<log_opid_state>;
safe_opid_map& get_opids() { return this->lf_opids; }
safe_opid_state& get_opids() { return this->lf_opids; }
void quiesce() { this->lf_line_buffer.quiesce(); }
@ -442,7 +442,7 @@ private:
text_format_t lf_text_format{text_format_t::TF_UNKNOWN};
uint32_t lf_out_of_time_order_count{0};
safe_notes lf_notes;
safe_opid_map lf_opids;
safe_opid_state lf_opids;
size_t lf_watch_count{0};
ArenaAlloc::Alloc<char> lf_allocator{64 * 1024};
nonstd::optional<time_t> lf_cached_base_time;

@ -2406,10 +2406,10 @@ logfile_sub_source::text_crumbs_for_line(int line,
if (file_data->get_file_ptr() == nullptr) {
continue;
}
safe::ReadAccess<logfile::safe_opid_map> r_opid_map(
safe::ReadAccess<logfile::safe_opid_state> r_opid_map(
file_data->get_file_ptr()->get_opids());
for (const auto& pair : *r_opid_map) {
for (const auto& pair : r_opid_map->los_opid_ranges) {
retval.emplace_back(pair.first.to_string());
}
}

@ -1,86 +1,86 @@
2011-11-03T00:17 2011-11-03T00:22
2011-11-03T00:17 5m 2011-11-03T00:22
5m
 Duration | ✘▲ | Operation
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76
     CdrfXZ1NOFPEawF218 192.168.2.76
     CJwUi9bdB9c1lLW44 192.168.2.76
     CJxSUgkInyKSHiju1 192.168.2.76
     CT0JIh479jXIGt0Po1 192.168.2.76
     C6Q4Vm14ZJIlZhsXqk 192.168.2.76
 1s070    CtgxRAqDLvrRUQdqe 192.168.2.76
     CdysLK1XpcrXOpVDuh 192.168.2.76
 200    C6nSoj1Qco9PGyslz6 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
     CdZUPH2DKOE7zzCLE3 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CsBgiE1WmGP4Yo749h 192.168.2.76
 657    CYfHyC28tAhkLYkXB7 192.168.2.76
     CtANmVrHYMtkWqPE5 192.168.2.76
 647    CSTH8n1O1nv0ztxNQd 192.168.2.76
     C4uDKU5tpeRU9Su19 192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd 192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO 192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl 192.168.2.76
 129    CKzjfhsJ8vrn2rrfg 192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae 192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
     C2vQ8sVgyADHjtEda 192.168.2.76
     CD69521bDXIAb4IkW 192.168.2.76
 6s648    CC3vUI3gFB04zLvWRa 192.168.2.76
 2s666    C7Krri4g9tZfHniGXh 192.168.2.76
     CmxyBl2c8XAMTuHEk4 192.168.2.76
 499    CSvs6v26bQqFylkk6l 192.168.2.76
     C4pHul1H3OeWYz7o7i 192.168.2.76
     C7Lcvr4vsTf6eYpBva 192.168.2.76
     CV8faD4L1sLL5kDwN9 192.168.2.76
     CxyAKs10ppnHFP6O8i 192.168.2.76
     C6MrHk2C7rLuJqhjsg 192.168.2.76
     CvfUrT2DgYXXoZw9Ah 192.168.2.76
     CBX0254QJoklXNbvv2 192.168.2.76
     C6Ym6jvMgikT0xTTc 192.168.2.76
     CRNn9f1zKNlzHSM5pa 192.168.2.76
     CJLgi92kpp2gLgGTE5 192.168.2.76
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76
     CdrfXZ1NOFPEawF218 192.168.2.76
     CJwUi9bdB9c1lLW44  192.168.2.76
     CJxSUgkInyKSHiju1  192.168.2.76
     CT0JIh479jXIGt0Po1 192.168.2.76
     C6Q4Vm14ZJIlZhsXqk 192.168.2.76
 1s070    CtgxRAqDLvrRUQdqe  192.168.2.76
     CdysLK1XpcrXOpVDuh 192.168.2.76
 200    C6nSoj1Qco9PGyslz6 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
     CdZUPH2DKOE7zzCLE3 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CsBgiE1WmGP4Yo749h 192.168.2.76
 657    CYfHyC28tAhkLYkXB7 192.168.2.76
     CtANmVrHYMtkWqPE5  192.168.2.76
 647    CSTH8n1O1nv0ztxNQd 192.168.2.76
     C4uDKU5tpeRU9Su19  192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd  192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO  192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl  192.168.2.76
 129    CKzjfhsJ8vrn2rrfg  192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae  192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
     C2vQ8sVgyADHjtEda 192.168.2.76
     CD69521bDXIAb4IkW 192.168.2.76
 6s648    CC3vUI3gFB04zLvWRa 192.168.2.76
 2s666    C7Krri4g9tZfHniGXh 192.168.2.76
     CmxyBl2c8XAMTuHEk4 192.168.2.76
 499    CSvs6v26bQqFylkk6l 192.168.2.76
     C4pHul1H3OeWYz7o7i 192.168.2.76
     C7Lcvr4vsTf6eYpBva 192.168.2.76
     CV8faD4L1sLL5kDwN9 192.168.2.76
     CxyAKs10ppnHFP6O8i 192.168.2.76
     C6MrHk2C7rLuJqhjsg 192.168.2.76
     CvfUrT2DgYXXoZw9Ah 192.168.2.76
     CBX0254QJoklXNbvv2 192.168.2.76
     C6Ym6jvMgikT0xTTc 192.168.2.76
     CRNn9f1zKNlzHSM5pa 192.168.2.76
     CJLgi92kpp2gLgGTE5 192.168.2.76

@ -1,85 +1,85 @@
2011-11-03T00:17 2011-11-03T00:22
2011-11-03T00:17 5m 2011-11-03T00:22
5m
 Duration | ✘▲ | Operation
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76
     CdrfXZ1NOFPEawF218 192.168.2.76
     CJwUi9bdB9c1lLW44 192.168.2.76
     CJxSUgkInyKSHiju1 192.168.2.76
     CT0JIh479jXIGt0Po1 192.168.2.76
     C6Q4Vm14ZJIlZhsXqk 192.168.2.76
 1s070    CtgxRAqDLvrRUQdqe 192.168.2.76
 200    C6nSoj1Qco9PGyslz6 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
     CdZUPH2DKOE7zzCLE3 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CsBgiE1WmGP4Yo749h 192.168.2.76
 657    CYfHyC28tAhkLYkXB7 192.168.2.76
     CtANmVrHYMtkWqPE5 192.168.2.76
 647    CSTH8n1O1nv0ztxNQd 192.168.2.76
     C4uDKU5tpeRU9Su19 192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd 192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO 192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl 192.168.2.76
 129    CKzjfhsJ8vrn2rrfg 192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae 192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
     C2vQ8sVgyADHjtEda 192.168.2.76
     CD69521bDXIAb4IkW 192.168.2.76
 6s648    CC3vUI3gFB04zLvWRa 192.168.2.76
 2s666    C7Krri4g9tZfHniGXh 192.168.2.76
     CmxyBl2c8XAMTuHEk4 192.168.2.76
 499    CSvs6v26bQqFylkk6l 192.168.2.76
     C4pHul1H3OeWYz7o7i 192.168.2.76
     C7Lcvr4vsTf6eYpBva 192.168.2.76
     CV8faD4L1sLL5kDwN9 192.168.2.76
     CxyAKs10ppnHFP6O8i 192.168.2.76
     C6MrHk2C7rLuJqhjsg 192.168.2.76
     CvfUrT2DgYXXoZw9Ah 192.168.2.76
     CBX0254QJoklXNbvv2 192.168.2.76
     C6Ym6jvMgikT0xTTc 192.168.2.76
     CRNn9f1zKNlzHSM5pa 192.168.2.76
     CJLgi92kpp2gLgGTE5 192.168.2.76
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76
     CdrfXZ1NOFPEawF218 192.168.2.76
     CJwUi9bdB9c1lLW44  192.168.2.76
     CJxSUgkInyKSHiju1  192.168.2.76
     CT0JIh479jXIGt0Po1 192.168.2.76
     C6Q4Vm14ZJIlZhsXqk 192.168.2.76
 1s070    CtgxRAqDLvrRUQdqe  192.168.2.76
 200    C6nSoj1Qco9PGyslz6 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
     CdZUPH2DKOE7zzCLE3 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CsBgiE1WmGP4Yo749h 192.168.2.76
 657    CYfHyC28tAhkLYkXB7 192.168.2.76
     CtANmVrHYMtkWqPE5  192.168.2.76
 647    CSTH8n1O1nv0ztxNQd 192.168.2.76
     C4uDKU5tpeRU9Su19  192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd  192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO  192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl  192.168.2.76
 129    CKzjfhsJ8vrn2rrfg  192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae  192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
     C2vQ8sVgyADHjtEda 192.168.2.76
     CD69521bDXIAb4IkW 192.168.2.76
 6s648    CC3vUI3gFB04zLvWRa 192.168.2.76
 2s666    C7Krri4g9tZfHniGXh 192.168.2.76
     CmxyBl2c8XAMTuHEk4 192.168.2.76
 499    CSvs6v26bQqFylkk6l 192.168.2.76
     C4pHul1H3OeWYz7o7i 192.168.2.76
     C7Lcvr4vsTf6eYpBva 192.168.2.76
     CV8faD4L1sLL5kDwN9 192.168.2.76
     CxyAKs10ppnHFP6O8i 192.168.2.76
     C6MrHk2C7rLuJqhjsg 192.168.2.76
     CvfUrT2DgYXXoZw9Ah 192.168.2.76
     CBX0254QJoklXNbvv2 192.168.2.76
     C6Ym6jvMgikT0xTTc 192.168.2.76
     CRNn9f1zKNlzHSM5pa 192.168.2.76
     CJLgi92kpp2gLgGTE5 192.168.2.76

@ -1,70 +1,70 @@
2011-11-03T00:17 2011-11-03T00:22
2011-11-03T00:17 5m 2011-11-03T00:22
5m
 Duration | ✘▲ | Operation
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd 192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO 192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl 192.168.2.76
 129    CKzjfhsJ8vrn2rrfg 192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae 192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
     C2vQ8sVgyADHjtEda 192.168.2.76
     CD69521bDXIAb4IkW 192.168.2.76
 6s648    CC3vUI3gFB04zLvWRa 192.168.2.76
 2s666    C7Krri4g9tZfHniGXh 192.168.2.76
     CmxyBl2c8XAMTuHEk4 192.168.2.76
 499    CSvs6v26bQqFylkk6l 192.168.2.76
     C4pHul1H3OeWYz7o7i 192.168.2.76
     C7Lcvr4vsTf6eYpBva 192.168.2.76
     CV8faD4L1sLL5kDwN9 192.168.2.76
     CxyAKs10ppnHFP6O8i 192.168.2.76
     C6MrHk2C7rLuJqhjsg 192.168.2.76
     CvfUrT2DgYXXoZw9Ah 192.168.2.76
     CBX0254QJoklXNbvv2 192.168.2.76
     C6Ym6jvMgikT0xTTc 192.168.2.76
     CRNn9f1zKNlzHSM5pa 192.168.2.76
     CJLgi92kpp2gLgGTE5 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd  192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO  192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl  192.168.2.76
 129    CKzjfhsJ8vrn2rrfg  192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae  192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
     C2vQ8sVgyADHjtEda 192.168.2.76
     CD69521bDXIAb4IkW 192.168.2.76
 6s648    CC3vUI3gFB04zLvWRa 192.168.2.76
 2s666    C7Krri4g9tZfHniGXh 192.168.2.76
     CmxyBl2c8XAMTuHEk4 192.168.2.76
 499    CSvs6v26bQqFylkk6l 192.168.2.76
     C4pHul1H3OeWYz7o7i 192.168.2.76
     C7Lcvr4vsTf6eYpBva 192.168.2.76
     CV8faD4L1sLL5kDwN9 192.168.2.76
     CxyAKs10ppnHFP6O8i 192.168.2.76
     C6MrHk2C7rLuJqhjsg 192.168.2.76
     CvfUrT2DgYXXoZw9Ah 192.168.2.76
     CBX0254QJoklXNbvv2 192.168.2.76
     C6Ym6jvMgikT0xTTc 192.168.2.76
     CRNn9f1zKNlzHSM5pa 192.168.2.76
     CJLgi92kpp2gLgGTE5 192.168.2.76

@ -1,4 +1,4 @@
2011-11-03T00:17 2011-11-03T00:22
2011-11-03T00:17 5m 2011-11-03T00:22
5m
 Duration | ✘▲ | Operation
     CdysLK1XpcrXOpVDuh 192.168.2.76
     CdysLK1XpcrXOpVDuh 192.168.2.76

@ -1,70 +1,70 @@
2011-11-03T00:17 2011-11-03T00:22
2011-11-03T00:17 5m 2011-11-03T00:22
5m
 Duration | ✘▲ | Operation
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76
     CdrfXZ1NOFPEawF218 192.168.2.76
     CJwUi9bdB9c1lLW44 192.168.2.76
     CJxSUgkInyKSHiju1 192.168.2.76
     CT0JIh479jXIGt0Po1 192.168.2.76
     C6Q4Vm14ZJIlZhsXqk 192.168.2.76
 1s070    CtgxRAqDLvrRUQdqe 192.168.2.76
     CdysLK1XpcrXOpVDuh 192.168.2.76
 200    C6nSoj1Qco9PGyslz6 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
     CdZUPH2DKOE7zzCLE3 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CsBgiE1WmGP4Yo749h 192.168.2.76
 657    CYfHyC28tAhkLYkXB7 192.168.2.76
     CtANmVrHYMtkWqPE5 192.168.2.76
 647    CSTH8n1O1nv0ztxNQd 192.168.2.76
     C4uDKU5tpeRU9Su19 192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd 192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO 192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl 192.168.2.76
 129    CKzjfhsJ8vrn2rrfg 192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae 192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76
 844    CwFs1P2UcUdlSxD2La 192.168.2.76
     CoX7zA3OJKGUOSCBY2 192.168.2.76
     CdrfXZ1NOFPEawF218 192.168.2.76
     CJwUi9bdB9c1lLW44  192.168.2.76
     CJxSUgkInyKSHiju1  192.168.2.76
     CT0JIh479jXIGt0Po1 192.168.2.76
     C6Q4Vm14ZJIlZhsXqk 192.168.2.76
 1s070    CtgxRAqDLvrRUQdqe  192.168.2.76
     CdysLK1XpcrXOpVDuh 192.168.2.76
 200    C6nSoj1Qco9PGyslz6 192.168.2.76
 23s044    CN5hnY3x51j6Hr1v4 192.168.2.76
     CdZUPH2DKOE7zzCLE3 192.168.2.76
 32s388    CmWpC33jXuKpXNLcie 192.168.2.76
     CsBgiE1WmGP4Yo749h 192.168.2.76
 657    CYfHyC28tAhkLYkXB7 192.168.2.76
     CtANmVrHYMtkWqPE5  192.168.2.76
 647    CSTH8n1O1nv0ztxNQd 192.168.2.76
     C4uDKU5tpeRU9Su19  192.168.2.76
     CEh6Ka2HInkNSH01L2 192.168.2.76
 4s840    CjPGiy13ncXKxU765j 192.168.2.76
 6s895    CPoz7NUpXISemlNSd  192.168.2.76
 6s837    Ct6ixh35y9AEr7J7o9 192.168.2.76
 6s889    CaEFHq2HVQ5iGJQiD9 192.168.2.76
 6s875    CjinlH2fzDtvzI9637 192.168.2.76
 6s884    Cedw7H3ddE2yLiLoXc 192.168.2.76
 6s917    CAUlC249svUfE6q0g3 192.168.2.76
     CIJIDL1ULo4HpT24Gl 192.168.2.76
 016    CLsqp41RLUd83arUQb 192.168.2.76
 166    CbCciH11995WKkobR1 192.168.2.76
 457    ClcvKE1dqsEFQu46m9 192.168.2.76
     CaP2LpLGvsmX7yJO  192.168.2.76
 043    CNbPns4mOMGgjI8Ele 192.168.2.76
 557    C185u7u9Q4qhJPhzl  192.168.2.76
 129    CKzjfhsJ8vrn2rrfg  192.168.2.76
 562    CiIjAe1n5MnPOVpQ9f 192.168.2.76
     CGv2Tp4Ngt8MmKmVRd 192.168.2.76
 7s071    C5DisEMFU77Wk9Kae  192.168.2.76
     Cs5yEZ3ELZTeuTOsP4 192.168.2.76
 4s667    Cu4gIx1BDNtGOl7Ht2 192.168.2.76
 1s288    CRgW2I2zo3SInm6iT8 192.168.2.76
     CWJhMU2cTLEnseTmCb 192.168.2.76
 042    CejI402rKGtdBXij4f 192.168.2.76
     C2KnU34GcVV6amo8va 192.168.2.76
     C5vx4911iSMAJuShFd 192.168.2.76
     CbUCgw1DrIGcXzONB7 192.168.2.76
 502    C96j2X1DixgLTj2Oi8 192.168.2.76
     CYYyja3FFNEnftw3K6 192.168.2.76
  █  CBHHuR1xFnm5C5CQBc 192.168.2.76
     CD1jfU3p9abEm77mzf 192.168.2.76
     C0K9DaoPFkfnzwlZa 192.168.2.76
 616    CbQAWi3GX2bCmX5L56 192.168.2.76
 298    Cd8s2R3OGDgkhnvSu9 192.168.2.76
 205    CBeaXe4Iyj1gXd2Iq 192.168.2.76
     CmWpSw3VtjiAceBCwf 192.168.2.76
 1m12s201    CbNCgO1MzloHRNeY4f 192.168.2.76
 315    CX1GjC4vn52UY1uDv6 192.168.2.76
     CaPClb1Bf0RrRGtyWi 192.168.2.76
 35s642    CibfNy1QQW4ImDWRq5 192.168.2.76
 1m11s547    CTRXSR3blXJE5ZE7Ij 192.168.2.76
 1m11s536    CnGze54kQWWpKqrrZ4 192.168.2.76
 12s337    C3TZMB4CrUwYfkGJy1 192.168.2.76
     CK957ERTz8lBycly4 192.168.2.76
 1s309    CO5QKYQkcSdxQFA35 192.168.2.76
     CurHpb1TGZOktTRNP1 192.168.2.76
     CuUKOQ1R3CqKBgeTdf 192.168.2.76
     C3xkHgJnzZszVSTpi 192.168.2.76
     CMrjgF2XLmRh9C9TR4 192.168.2.76

Loading…
Cancel
Save