mirror of
https://github.com/tstack/lnav.git
synced 2024-09-11 13:05:51 +03:00
[base] refactor duration2str
This commit is contained in:
parent
d15c1103cf
commit
d31aa845f5
@ -108,7 +108,6 @@ of log lines fed into `lnav` via `journalctl`'s `-b` option.
|
||||
## Contributing
|
||||
|
||||
- [Become a Sponsor on GitHub](https://github.com/sponsors/tstack)
|
||||
- [Make a one-time donation on Ko-fi](https://ko-fi.com/tstack)
|
||||
|
||||
### Building From Source
|
||||
|
||||
|
@ -45,7 +45,7 @@ point point::from_tv(const timeval &tv)
|
||||
return point(tv);
|
||||
}
|
||||
|
||||
std::string point::as_time_ago()
|
||||
std::string point::as_time_ago() const
|
||||
{
|
||||
struct timeval current_time = this->p_recent_point
|
||||
.value_or(current_timeval());
|
||||
@ -89,7 +89,7 @@ std::string point::as_time_ago()
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
std::string point::as_precise_time_ago()
|
||||
std::string point::as_precise_time_ago() const
|
||||
{
|
||||
struct timeval now, diff;
|
||||
|
||||
@ -121,5 +121,77 @@ std::string point::as_precise_time_ago()
|
||||
}
|
||||
}
|
||||
|
||||
duration duration::from_tv(const struct timeval &tv)
|
||||
{
|
||||
return duration{tv};
|
||||
}
|
||||
|
||||
std::string duration::to_string() const
|
||||
{
|
||||
/* 24h22m33s111 */
|
||||
|
||||
static const struct rel_interval {
|
||||
uint64_t length;
|
||||
const char *format;
|
||||
const char *symbol;
|
||||
} intervals[] = {
|
||||
{ 1000, "%03lld%s", "" },
|
||||
{ 60, "%lld%s", "s" },
|
||||
{ 60, "%lld%s", "m" },
|
||||
{ 24, "%lld%s", "h" },
|
||||
{ 0, "%lld%s", "d" },
|
||||
};
|
||||
|
||||
auto *curr_interval = intervals;
|
||||
auto usecs = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::seconds(this->d_timeval.tv_sec)) +
|
||||
std::chrono::microseconds(this->d_timeval.tv_usec);
|
||||
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(usecs);
|
||||
std::string retval;
|
||||
bool neg = false;
|
||||
|
||||
if (millis < 0s) {
|
||||
neg = true;
|
||||
millis = -millis;
|
||||
}
|
||||
|
||||
uint64_t remaining;
|
||||
if (millis >= 10min) {
|
||||
remaining = std::chrono::duration_cast<std::chrono::seconds>(millis)
|
||||
.count();
|
||||
curr_interval += 1;
|
||||
} else {
|
||||
remaining = millis.count();
|
||||
}
|
||||
|
||||
for (; curr_interval != std::end(intervals); curr_interval++) {
|
||||
uint64_t amount;
|
||||
char segment[32];
|
||||
|
||||
if (curr_interval->length) {
|
||||
amount = remaining % curr_interval->length;
|
||||
remaining = remaining / curr_interval->length;
|
||||
}
|
||||
else {
|
||||
amount = remaining;
|
||||
remaining = 0;
|
||||
}
|
||||
|
||||
if (!amount && !remaining) {
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(segment, sizeof(segment), curr_interval->format, amount,
|
||||
curr_interval->symbol);
|
||||
retval.insert(0, segment);
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
retval.insert(0, "-");
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string as_time_ago();
|
||||
std::string as_time_ago() const;
|
||||
|
||||
std::string as_precise_time_ago();
|
||||
std::string as_precise_time_ago() const;
|
||||
|
||||
private:
|
||||
explicit point(const struct timeval &tv) : p_past_point{tv.tv_sec,
|
||||
@ -69,6 +69,17 @@ private:
|
||||
bool p_convert_to_local{false};
|
||||
};
|
||||
|
||||
class duration {
|
||||
public:
|
||||
static duration from_tv(const struct timeval& tv);
|
||||
|
||||
std::string to_string() const;
|
||||
private:
|
||||
explicit duration(const struct timeval& tv) : d_timeval(tv) {}
|
||||
|
||||
struct timeval d_timeval;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,3 +100,29 @@ TEST_CASE("time ago")
|
||||
.with_recent_point({1612000000, 0})
|
||||
.as_time_ago() == "23 days ago");
|
||||
}
|
||||
|
||||
TEST_CASE("duration to_string") {
|
||||
std::string val;
|
||||
|
||||
val = humanize::time::duration::from_tv({25 * 60 * 60, 123000})
|
||||
.to_string();
|
||||
CHECK(val == "1d1h0m0s");
|
||||
val = humanize::time::duration::from_tv({10, 123000})
|
||||
.to_string();
|
||||
CHECK(val == "10s123");
|
||||
val = humanize::time::duration::from_tv({10, 0})
|
||||
.to_string();
|
||||
CHECK(val == "10s000");
|
||||
val = humanize::time::duration::from_tv({0, 100000})
|
||||
.to_string();
|
||||
CHECK(val == "100");
|
||||
val = humanize::time::duration::from_tv({0, 0})
|
||||
.to_string();
|
||||
CHECK(val == "");
|
||||
val = humanize::time::duration::from_tv({0, -10000})
|
||||
.to_string();
|
||||
CHECK(val == "-010");
|
||||
val = humanize::time::duration::from_tv({-10, 0})
|
||||
.to_string();
|
||||
CHECK(val == "-10s000");
|
||||
}
|
||||
|
@ -117,6 +117,15 @@ bool operator!=(const struct timeval &left, const struct timeval &right) {
|
||||
left.tv_usec != right.tv_usec;
|
||||
}
|
||||
|
||||
inline
|
||||
struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
|
||||
{
|
||||
struct timeval diff;
|
||||
|
||||
timersub(&lhs, &rhs, &diff);
|
||||
return diff;
|
||||
}
|
||||
|
||||
typedef int64_t mstime_t;
|
||||
|
||||
inline mstime_t getmstime() {
|
||||
|
@ -80,9 +80,9 @@ void field_overlay_source::build_summary_lines(const listview_curses &lv)
|
||||
humanize::time::point::from_tv(last_line->get_timeval())
|
||||
.with_convert_to_local(true)
|
||||
.as_precise_time_ago() + ANSI_NORM;
|
||||
duration2str(last_line->get_time_in_millis() -
|
||||
first_line->get_time_in_millis(),
|
||||
time_span);
|
||||
time_span = humanize::time::duration::from_tv(
|
||||
last_line->get_timeval() - first_line->get_timeval())
|
||||
.to_string();
|
||||
|
||||
time_t local_now = convert_log_time_to_local(now);
|
||||
time_t five_minutes_ago = local_now - (5 * 60 * 60);
|
||||
@ -325,7 +325,8 @@ void field_overlay_source::build_field_lines(const listview_curses &lv)
|
||||
timersub(&curr_tv, &actual_tv, &diff_tv);
|
||||
time_str.append("; Diff: ");
|
||||
time_lr.lr_start = time_str.length();
|
||||
str2reltime(diff_tv, time_str);
|
||||
time_str.append(humanize::time::duration::from_tv(diff_tv)
|
||||
.to_string());
|
||||
time_lr.lr_end = time_str.length();
|
||||
time_line.with_attr(string_attr(
|
||||
time_lr,
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <algorithm>
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include "base/humanize.time.hh"
|
||||
#include "base/string_util.hh"
|
||||
#include "k_merge_tree.h"
|
||||
#include "lnav_util.hh"
|
||||
@ -303,9 +304,8 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
|
||||
}
|
||||
|
||||
if (this->lss_flags & F_TIME_OFFSET) {
|
||||
int64_t curr_millis, diff;
|
||||
|
||||
curr_millis = this->lss_token_line->get_time_in_millis();
|
||||
auto curr_tv = this->lss_token_line->get_timeval();
|
||||
struct timeval diff_tv;
|
||||
|
||||
vis_line_t prev_mark =
|
||||
tc.get_bookmarks()[&textview_curses::BM_USER].prev(vis_line_t(row));
|
||||
@ -314,24 +314,19 @@ void logfile_sub_source::text_value_for_line(textview_curses &tc,
|
||||
if (prev_mark == -1 && next_mark != -1) {
|
||||
auto next_line = this->find_line(this->at(next_mark));
|
||||
|
||||
diff = curr_millis - next_line->get_time_in_millis();
|
||||
diff_tv = curr_tv - next_line->get_timeval();
|
||||
} else {
|
||||
if (prev_mark == -1) {
|
||||
if (prev_mark == -1_vl) {
|
||||
prev_mark = 0_vl;
|
||||
}
|
||||
|
||||
auto first_line = this->find_line(this->at(prev_mark));
|
||||
auto start_millis = first_line->get_time_in_millis();
|
||||
diff = curr_millis - start_millis;
|
||||
auto start_tv = first_line->get_timeval();
|
||||
diff_tv = curr_tv - start_tv;
|
||||
}
|
||||
|
||||
value_out = "|" + value_out;
|
||||
string relstr;
|
||||
size_t rel_length = duration2str(diff, relstr);
|
||||
value_out.insert(0, relstr);
|
||||
if (rel_length < 12) {
|
||||
value_out.insert(0, 12 - rel_length, ' ');
|
||||
}
|
||||
auto relstr = humanize::time::duration::from_tv(diff_tv).to_string();
|
||||
value_out = fmt::format(FMT_STRING("{: >12}|{}"), relstr, value_out);
|
||||
}
|
||||
this->lss_in_value_for_line = false;
|
||||
}
|
||||
|
@ -820,61 +820,3 @@ nonstd::optional<exttm> relative_time::window_start(
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
size_t duration2str(int64_t millis, std::string &value_out)
|
||||
{
|
||||
/* 24h22m33s111 */
|
||||
|
||||
static struct rel_interval {
|
||||
long long length;
|
||||
const char *format;
|
||||
const char *symbol;
|
||||
} intervals[] = {
|
||||
{ 1000, "%03lld%s", "" },
|
||||
{ 60, "%lld%s", "s" },
|
||||
{ 60, "%lld%s", "m" },
|
||||
{ 24, "%lld%s", "h" },
|
||||
{ 0, "%lld%s", "d" },
|
||||
};
|
||||
|
||||
struct rel_interval *curr_interval = intervals;
|
||||
size_t retval = 0;
|
||||
|
||||
if (millis < 0) {
|
||||
value_out.append(1, '-');
|
||||
millis = -millis;
|
||||
retval += 1;
|
||||
}
|
||||
|
||||
size_t in_len = value_out.length();
|
||||
|
||||
if (millis >= (10 * 60 * 1000)) {
|
||||
millis /= 1000;
|
||||
curr_interval += 1;
|
||||
}
|
||||
|
||||
for (; curr_interval != end(intervals); curr_interval++) {
|
||||
long long amount;
|
||||
char segment[32];
|
||||
|
||||
if (curr_interval->length) {
|
||||
amount = millis % curr_interval->length;
|
||||
millis = millis / curr_interval->length;
|
||||
}
|
||||
else {
|
||||
amount = millis;
|
||||
millis = 0;
|
||||
}
|
||||
|
||||
if (!amount && !millis) {
|
||||
break;
|
||||
}
|
||||
|
||||
snprintf(segment, sizeof(segment), curr_interval->format, amount,
|
||||
curr_interval->symbol);
|
||||
retval += strlen(segment);
|
||||
value_out.insert(in_len, segment);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -270,11 +270,4 @@ public:
|
||||
int rt_absolute_field_end;
|
||||
};
|
||||
|
||||
size_t duration2str(int64_t millis, std::string &value_out);
|
||||
|
||||
inline
|
||||
size_t str2reltime(const struct timeval &tv, std::string &value_out) {
|
||||
return duration2str(tv.tv_sec * 1000 + tv.tv_usec / 1000, value_out);
|
||||
};
|
||||
|
||||
#endif //LNAV_RELATIVE_TIME_HH
|
||||
|
@ -61,31 +61,6 @@ TEST_CASE("overwritten-logfile") {
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("duration2str") {
|
||||
string val;
|
||||
|
||||
duration2str(25 * 60 * 60 * 1000 + 123, val);
|
||||
CHECK(val == "1d1h0m0s");
|
||||
val.clear();
|
||||
duration2str(10 * 1000 + 123, val);
|
||||
CHECK(val == "10s123");
|
||||
val.clear();
|
||||
duration2str(10 * 1000, val);
|
||||
CHECK(val == "10s000");
|
||||
val.clear();
|
||||
duration2str(100, val);
|
||||
CHECK(val == "100");
|
||||
val.clear();
|
||||
duration2str(0, val);
|
||||
CHECK(val == "");
|
||||
val.clear();
|
||||
duration2str(-10, val);
|
||||
CHECK(val == "-010");
|
||||
val.clear();
|
||||
duration2str(-10 * 1000, val);
|
||||
CHECK(val == "-10s000");
|
||||
}
|
||||
|
||||
TEST_CASE("byte_array") {
|
||||
using my_array_t = byte_array<8>;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user