Compare commits

...

2 Commits

Author SHA1 Message Date
blankie 55210a7e30
Reflow logcat_entry.cpp 2023-03-30 21:32:31 +07:00
blankie d1afe12773
Use `struct tm` to store time 2023-03-30 21:24:01 +07:00
7 changed files with 125 additions and 99 deletions

View File

@ -6,9 +6,10 @@
std::vector<LogEntry> log_entries; std::vector<LogEntry> log_entries;
LogEntry::LogEntry(time_t time_, std::string message_) : time(time_), message(std::move(message_)) { LogEntry::LogEntry(time_t time, std::string message_) : message(std::move(message_)) {
size_t pos; size_t pos;
localtime_r(&time, &this->time);
while ((pos = this->message.find('\n')) != std::string::npos) { while ((pos = this->message.find('\n')) != std::string::npos) {
this->message.replace(pos, 1, 1, ' '); this->message.replace(pos, 1, 1, ' ');
} }
@ -16,15 +17,14 @@ LogEntry::LogEntry(time_t time_, std::string message_) : time(time_), message(st
std::string to_string(const LogEntry& entry) { std::string to_string(const LogEntry& entry) {
struct tm tm;
char time_as_str[128] = {0}; char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&entry.time, &tm)); strftime(time_as_str, 127 * sizeof(char), "%c", &entry.time);
return std::string(1, '[') + time_as_str + "] " + entry.message; return std::string(1, '[') + time_as_str + "] " + entry.message;
} }
void print_log(const LogEntry& entry) { void print_log(const LogEntry& entry) {
char time_as_str[128] = {0}; char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime(&entry.time)); strftime(time_as_str, 127 * sizeof(char), "%c", &entry.time);
fprintf(stderr, "[%s] %s\n", time_as_str, entry.message.c_str()); fprintf(stderr, "[%s] %s\n", time_as_str, entry.message.c_str());
} }

5
log.h
View File

@ -1,14 +1,15 @@
#pragma once #pragma once
#include <ctime>
#include <string> #include <string>
#include <vector> #include <vector>
struct LogEntry { struct LogEntry {
time_t time; struct tm time;
std::string message; std::string message;
LogEntry() = default; LogEntry() = default;
LogEntry(time_t time_, std::string message_); LogEntry(time_t time, std::string message_);
}; };
extern std::vector<LogEntry> log_entries; extern std::vector<LogEntry> log_entries;

View File

@ -7,9 +7,24 @@
#include "logcat_entry.h" #include "logcat_entry.h"
#include "pcre2_wrapper.h" #include "pcre2_wrapper.h"
static const Pcre2Regex LogcatEntryRegex("^\\s*(\\d+)(?:\\.\\d+)?(?:\\s+([\\w\\d._-]+))?\\s+(\\d+)\\s+(\\d+)\\s+([A-Z])\\s+(.+?)\\s*:\\s(.*)$"); static const Pcre2Regex LogcatEntryRegex(
"^ *(\\d+)(?:\\.\\d+)?" // time
"(?: +([\\w\\d._-]+))?" // optional user
" +(\\d+)" // pid
" +(\\d+)" // tid
" +([A-Z])" // priority
" +(.+?) *: (.*)$" // tag and message
);
static const Pcre2Regex BufferRegex("^--------- (?:beginning of|switch to) (\\w+)$"); static const Pcre2Regex BufferRegex("^--------- (?:beginning of|switch to) (\\w+)$");
static std::string leftpad(const std::string& str, size_t characters);
static inline char to_char(Priority priority);
static inline std::string rightpad(const std::string& str, size_t characters);
static inline Priority priority_from(char c);
static inline long to_long(const char* str, const char* expected_end);
static unsigned long long to_ull(const char* str, const char* expected_end);
const char* to_string(Priority priority) { const char* to_string(Priority priority) {
switch (priority) { switch (priority) {
case Priority::Verbose: return "Verbose"; case Priority::Verbose: return "Verbose";
@ -44,34 +59,9 @@ const char* to_string_lower(Buffer buffer) {
} }
} }
static std::string leftpad(const std::string& str, size_t characters) {
return str.size() >= characters
? str
: std::string(characters - str.size(), ' ') + str;
}
static inline char to_char(Priority priority) {
switch (priority) {
case Priority::Verbose: return 'V';
case Priority::Debug: return 'D';
case Priority::Info: return 'I';
case Priority::Warn: return 'W';
case Priority::Error: return 'E';
case Priority::Fatal: return 'F';
case Priority::Unknown: return 'U';
}
}
static inline std::string rightpad(const std::string& str, size_t characters) {
return str.size() >= characters
? str
: str + std::string(characters - str.size(), ' ');
}
std::string to_string(const LogcatEntry& logcat_entry) { std::string to_string(const LogcatEntry& logcat_entry) {
char logcat_style_time_as_str[32] = {0}; char logcat_style_time_as_str[32] = {0};
struct tm tm; strftime(logcat_style_time_as_str, 31 * sizeof(char), "%Y-%m-%d %H:%M:%S", &logcat_entry.time);
strftime(logcat_style_time_as_str, 31 * sizeof(char), "%Y-%m-%d %H:%M:%S", localtime_r(&logcat_entry.time, &tm));
return std::string(logcat_style_time_as_str) return std::string(logcat_style_time_as_str)
+ ' ' + leftpad(logcat_entry.user.value_or(" "), 5) + ' ' + leftpad(logcat_entry.user.value_or(" "), 5)
@ -82,45 +72,6 @@ std::string to_string(const LogcatEntry& logcat_entry) {
+ ": " + logcat_entry.message; + ": " + logcat_entry.message;
} }
static inline Priority priority_from(char c) {
switch (c) {
case 'V': return Priority::Verbose;
case 'D': return Priority::Debug;
case 'I': return Priority::Info;
case 'W': return Priority::Warn;
case 'E': return Priority::Error;
case 'F': return Priority::Fatal;
default: return Priority::Unknown;
}
}
static inline long to_long(const char* str, const char* expected_end) {
char* endptr;
errno = 0;
long res = strtol(str, &endptr, 10);
if (endptr != expected_end) {
throw std::invalid_argument(std::string(str) + " has trailing text");
} else if (res == LONG_MAX && errno == ERANGE) {
throw std::overflow_error(std::string(str) + " is too big");
} else if (res == LONG_MIN && errno == ERANGE) {
throw std::underflow_error(std::string(str) + " is too small");
}
return res;
}
static unsigned long long to_unsigned_long_long(const char* str, const char* expected_end) {
char* endptr;
errno = 0;
unsigned long long res = strtoull(str, &endptr, 10);
if (endptr != expected_end) {
throw std::invalid_argument(std::string(str) + " has trailing text");
} else if (res == ULLONG_MAX && errno == ERANGE) {
throw std::overflow_error(std::string(str) + " is too big");
}
return res;
}
std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buffer buffer) { std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buffer buffer) {
regmatch_t matches[8]; regmatch_t matches[8];
@ -134,21 +85,26 @@ std::optional<LogcatEntry> try_parse_logcat_entry(char* buf, size_t length, Buff
return std::nullopt; return std::nullopt;
} }
std::optional<std::string> user; auto group_exists = [](const regmatch_t& match) { return match.rm_so > -1 && match.rm_eo > -1; };
if (matches[2].rm_so > -1 && matches[2].rm_eo > -1) { auto group_long = [&](const regmatch_t& match) { return to_long(&buf[match.rm_so], &buf[match.rm_eo]); };
user = std::string(&buf[matches[2].rm_so], static_cast<size_t>(matches[2].rm_eo - matches[2].rm_so)); auto group_ull = [&](const regmatch_t& match) { return to_ull(&buf[match.rm_so], &buf[match.rm_eo]); };
} auto group_string = [&](const regmatch_t& match) { return std::string(&buf[match.rm_so], static_cast<size_t>(match.rm_eo - match.rm_so)); };
auto group_priority = [&](const regmatch_t& match) { return priority_from(buf[match.rm_so]); };
// if pcre2 gives us negative offsets then i'll die // if pcre2 gives us negative offsets then i'll die
LogcatEntry logcat_entry = { LogcatEntry logcat_entry = {
.buffer = buffer, .buffer = buffer,
.time = to_long(&buf[matches[1].rm_so], &buf[matches[1].rm_eo]), // time to be set at the end
.user = std::move(user), .user = group_exists(matches[2]) ? std::optional(group_string(matches[2])) : std::nullopt,
.pid = to_unsigned_long_long(&buf[matches[3].rm_so], &buf[matches[3].rm_eo]), .pid = group_ull(matches[3]),
.tid = to_unsigned_long_long(&buf[matches[4].rm_so], &buf[matches[4].rm_eo]), .tid = group_ull(matches[4]),
.priority = priority_from(buf[matches[5].rm_so]), .priority = group_priority(matches[5]),
.tag = std::string(&buf[matches[6].rm_so], static_cast<size_t>(matches[6].rm_eo - matches[6].rm_so)), .tag = group_string(matches[6]),
.message = std::string(&buf[matches[7].rm_so], static_cast<size_t>(matches[7].rm_eo - matches[7].rm_so)), .message = group_string(matches[7]),
}; };
time_t time = group_long(matches[1]);
localtime_r(&time, &logcat_entry.time);
return std::move(logcat_entry); return std::move(logcat_entry);
} }
@ -238,3 +194,69 @@ void to_json(nlohmann::json& j, const Priority& priority) {
case Priority::Fatal: j = "FATAL"; break; case Priority::Fatal: j = "FATAL"; break;
} }
} }
static std::string leftpad(const std::string& str, size_t characters) {
return str.size() >= characters
? str
: std::string(characters - str.size(), ' ') + str;
}
static inline char to_char(Priority priority) {
switch (priority) {
case Priority::Verbose: return 'V';
case Priority::Debug: return 'D';
case Priority::Info: return 'I';
case Priority::Warn: return 'W';
case Priority::Error: return 'E';
case Priority::Fatal: return 'F';
case Priority::Unknown: return 'U';
}
}
static inline std::string rightpad(const std::string& str, size_t characters) {
return str.size() >= characters
? str
: str + std::string(characters - str.size(), ' ');
}
static inline Priority priority_from(char c) {
switch (c) {
case 'V': return Priority::Verbose;
case 'D': return Priority::Debug;
case 'I': return Priority::Info;
case 'W': return Priority::Warn;
case 'E': return Priority::Error;
case 'F': return Priority::Fatal;
default: return Priority::Unknown;
}
}
static inline long to_long(const char* str, const char* expected_end) {
char* endptr;
errno = 0;
long res = strtol(str, &endptr, 10);
if (endptr != expected_end) {
throw std::invalid_argument(std::string(str) + " has trailing text");
} else if (res == LONG_MAX && errno == ERANGE) {
throw std::overflow_error(std::string(str) + " is too big");
} else if (res == LONG_MIN && errno == ERANGE) {
throw std::underflow_error(std::string(str) + " is too small");
}
return res;
}
static unsigned long long to_ull(const char* str, const char* expected_end) {
char* endptr;
errno = 0;
unsigned long long res = strtoull(str, &endptr, 10);
if (endptr != expected_end) {
throw std::invalid_argument(std::string(str) + " has trailing text");
} else if (res == ULLONG_MAX && errno == ERANGE) {
throw std::overflow_error(std::string(str) + " is too big");
}
return res;
}

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <ctime>
#include <string> #include <string>
#include <optional> #include <optional>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -27,7 +28,7 @@ enum class Priority {
struct LogcatEntry { struct LogcatEntry {
Buffer buffer; Buffer buffer;
time_t time; struct tm time;
std::optional<std::string> user; std::optional<std::string> user;
size_t pid; size_t pid;
size_t tid; size_t tid;

View File

@ -52,27 +52,33 @@ void debug_window(LogcatThread& logcat_thread, LogcatEntries& logcat_entries) {
ImGui::Separator(); ImGui::Separator();
if (ImGui::Button("Add test entry (w/ user)")) { if (ImGui::Button("Add test entry (w/ user)")) {
logcat_entries.push_back({ LogcatEntry entry = {
.buffer = Buffer::Main, .buffer = Buffer::Main,
.time = time(nullptr), // time to be set later
.user = "blankie", .user = "blankie",
.pid = 69, .pid = 69,
.tid = 420, .tid = 420,
.priority = Priority::Error, .priority = Priority::Error,
.tag = "blanket, inc.", .tag = "blanket, inc.",
.message = "Failed to make blanket", .message = "Failed to make blanket",
}); };
time_t entry_time = time(nullptr);
localtime_r(&entry_time, &entry.time);
logcat_entries.push_back(std::move(entry));
} }
if (ImGui::Button("Add test entry (w/o user)")) { if (ImGui::Button("Add test entry (w/o user)")) {
logcat_entries.push_back({ LogcatEntry entry = {
.buffer = Buffer::Crash, .buffer = Buffer::Crash,
.time = time(nullptr), // time to be set later
.pid = 420, .pid = 420,
.tid = 69, .tid = 69,
.priority = Priority::Fatal, .priority = Priority::Fatal,
.tag = "blanket, inc.", .tag = "blanket, inc.",
.message = "Failed to invent blankets", .message = "Failed to invent blankets",
}); };
time_t entry_time = time(nullptr);
localtime_r(&entry_time, &entry.time);
logcat_entries.push_back(std::move(entry));
} }
ImGui::End(); ImGui::End();

View File

@ -6,9 +6,8 @@
#include "logs.h" #include "logs.h"
static inline void render_table_item_context_menu(const LogEntry& log_entry) { static inline void render_table_item_context_menu(const LogEntry& log_entry) {
struct tm tm;
char time_as_str[128] = {0}; char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&log_entry.time, &tm)); strftime(time_as_str, 127 * sizeof(char), "%c", &log_entry.time);
ImGui::TextDisabled("[%s] %s", time_as_str, log_entry.message.c_str()); ImGui::TextDisabled("[%s] %s", time_as_str, log_entry.message.c_str());
ImGui::Separator(); ImGui::Separator();
@ -32,9 +31,8 @@ static inline void render_table_item(const LogEntry& log_entry, size_t log_entry
ImGui::TableNextRow(); ImGui::TableNextRow();
if (ImGui::TableSetColumnIndex(0)) { if (ImGui::TableSetColumnIndex(0)) {
struct tm tm;
char time_as_str[128] = {0}; char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&log_entry.time, &tm)); strftime(time_as_str, 127 * sizeof(char), "%c", &log_entry.time);
ImGui::TextUnformatted(time_as_str); ImGui::TextUnformatted(time_as_str);
table_item_popup(); table_item_popup();

View File

@ -19,9 +19,8 @@ static inline void render_table_item_context_menu(const LogcatEntry& logcat_entr
if (ImGui::Selectable("Copy")) ImGui::SetClipboardText(text.c_str()); if (ImGui::Selectable("Copy")) ImGui::SetClipboardText(text.c_str());
if (ImGui::Selectable("Copy Time")) { if (ImGui::Selectable("Copy Time")) {
struct tm tm;
char time_as_str[128] = {0}; char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&logcat_entry.time, &tm)); strftime(time_as_str, 127 * sizeof(char), "%c", &logcat_entry.time);
ImGui::SetClipboardText(time_as_str); ImGui::SetClipboardText(time_as_str);
} }
if (ImGui::Selectable("Copy User", false, logcat_entry.user ? 0 : ImGuiSelectableFlags_Disabled)) { if (ImGui::Selectable("Copy User", false, logcat_entry.user ? 0 : ImGuiSelectableFlags_Disabled)) {
@ -48,9 +47,8 @@ static inline void render_table_item(const LogcatEntry& logcat_entry, size_t log
ImGui::TableNextRow(); ImGui::TableNextRow();
if (ImGui::TableSetColumnIndex(0)) { if (ImGui::TableSetColumnIndex(0)) {
struct tm tm;
char time_as_str[128] = {0}; char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime_r(&logcat_entry.time, &tm)); strftime(time_as_str, 127 * sizeof(char), "%c", &logcat_entry.time);
ImGui::TextUnformatted(time_as_str); ImGui::TextUnformatted(time_as_str);
table_item_popup(); table_item_popup();