Add logging

This commit is contained in:
blankie 2023-01-05 17:27:14 +07:00
parent f1c2dc7f63
commit 3bf47f3a5c
Signed by: blankie
GPG Key ID: CC15FC822C7F61F5
6 changed files with 162 additions and 39 deletions

View File

@ -12,19 +12,20 @@
#
#CXX = g++
#CXX = clang++
CXX = clang++
EXE = logmeow
IMGUI_DIR = imgui
SOURCES = main.cpp config.cpp event_loop.cpp
SOURCES = main.cpp log.cpp config.cpp event_loop.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/misc/cpp/imgui_stdlib.cpp $(IMGUI_DIR)/backends/imgui_impl_sdl.cpp $(IMGUI_DIR)/backends/imgui_impl_opengl3.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
LINUX_GL_LIBS = -lGL
CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/misc/cpp -I$(IMGUI_DIR)/backends
CXXFLAGS += -g -Wall -Wformat
CXXFLAGS = -std=c++14 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/misc/cpp -I$(IMGUI_DIR)/backends
# https://t.me/NightShadowsHangout/670691
CXXFLAGS += -g -Werror -Wall -Wextra -Wshadow -Wpedantic -Wno-gnu-anonymous-struct -fno-rtti -fPIC -Wconversion -Wno-unused-parameter -Wimplicit-fallthrough
LIBS =
##---------------------------------------------------------------------
@ -85,7 +86,7 @@ endif
$(CXX) $(CXXFLAGS) -c -o $@ $<
$(EXE): $(OBJS)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
$(CXX) -o $@ $^ $(CXXFLAGS) -fuse-ld=lld $(LIBS)
clean:
rm -f $(EXE) $(OBJS)

View File

@ -6,6 +6,7 @@
#include <memory>
#include <system_error>
#include "log.h"
#include "config.h"
static FILE* fopen_or_raise(const char* path, const char* mode, bool ignore_enoent) {
@ -13,14 +14,15 @@ static FILE* fopen_or_raise(const char* path, const char* mode, bool ignore_enoe
if (file || (ignore_enoent && errno == ENOENT)) {
return file;
}
throw std::system_error(errno, std::generic_category(), "fopen()");
throw std::system_error(errno, std::generic_category(), std::string("fopen(") + quote(path) + ')');
}
static void fclose_and_log(FILE* file) {
if (!fclose(file)) {
return;
}
// TODO log() when logging exists
std::system_error e = std::system_error(errno, std::generic_category(), "fclose()");
log("Failed to close a file", std::move(e));
}
static bool write(const std::string& ptr, FILE* file) {
@ -52,21 +54,23 @@ std::string get_config_file_path() {
// tries to create a directory with an empty string if it's just "/" but who cares
void create_config_folders_if_necessary() {
std::string path = get_config_folder();
std::string full_path = get_config_folder();
std::string path;
size_t pos = 0;
while (pos != std::string::npos) {
pos = path.find('/', pos);
pos = full_path.find('/', pos);
if (pos != std::string::npos) {
pos++;
}
if (!mkdir(path.substr(0, pos).c_str(), 0600)) {
path = full_path.substr(0, pos);
if (!mkdir(path.c_str(), 0600)) {
continue;
}
if (errno == EEXIST) {
continue;
}
throw std::system_error(errno, std::generic_category(), "mkdir()");
throw std::system_error(errno, std::generic_category(), std::string("mkdir(") + quote(path) + ')');
}
}
@ -87,7 +91,7 @@ static inline Config load_config(FILE* file) {
if (errsv == ENOMEM) {
throw std::bad_alloc();
} else if (errsv != 0) {
throw std::system_error(errsv, std::generic_category(), "reading config line");
throw std::system_error(errsv, std::generic_category(), "getline()");
} else {
break;
}
@ -129,13 +133,13 @@ static inline void write_config(FILE* file, const Config& config) {
"# # a comment, only available at the start of a line\n"
"# (an empty line, no whitespace)\n"
"# key=value pairs, no spaces around the delimiter, and no unknown keys\n\n", file)) {
throw std::runtime_error("failed to write info comment");
throw std::runtime_error("Failed to write info comment");
}
if (!write("logcat_command=", file)) {
throw std::runtime_error("failed to write logcat command key");
throw std::runtime_error("Failed to write logcat command key");
}
if (!write(config.logcat_command, file)) {
throw std::runtime_error("failed to write logcat command value");
throw std::runtime_error("Failed to write logcat command value");
}
}
@ -150,5 +154,6 @@ void write_config(const Config& config) {
if (!rename(tmp_config_file_path.c_str(), config_file_path.c_str())) {
return;
}
throw std::system_error(errno, std::generic_category(), "rename()");
throw std::system_error(errno, std::generic_category(),
std::string("rename(") + quote(tmp_config_file_path) + ", " + quote(config_file_path) + ')');
}

View File

@ -1,31 +1,57 @@
#include <imgui.h>
#include <imgui_stdlib.h>
#include "log.h"
#include "config.h"
static inline void write_config_and_update_structures(const Config& config) {
try {
write_config(config);
} catch (const std::exception& e) {
// TODO log() when logging exists
throw;
log("Failed to write config", e);
return;
}
}
static inline void settings_window(Config& config, float* config_write_timer, bool* show_settings_window) {
if (!ImGui::Begin("Settings", show_settings_window)) {
ImGui::End();
return;
}
// TODO actually have process control
ImGui::Text("Logcat command is only modifiable when logcat is stopped");
ImGui::Text("Logcat command only takes effect when logcat is not running");
if (ImGui::InputTextWithHint("Logcat command", "adb logcat -Dv 'threadtime UTC epoch usec'", &config.logcat_command)) {
*config_write_timer = *config_write_timer > 0.0f ? *config_write_timer : 5.0f;
}
ImGui::End();
}
static inline void main_window(Config& active_config, bool* show_settings_window, bool* exit_requested_rev) {
static inline void logs_window(bool* show_logs_window) {
if (!ImGui::Begin("LogMeow Logs", show_logs_window)) {
ImGui::End();
return;
}
if (ImGui::Button("Clear")) {
log_entries.clear();
}
ImGui::SameLine();
if (ImGui::Button("Copy")) {
ImGui::SetClipboardText(log_entries.c_str());
}
// copied from imgui/imgui_demo.cpp: [SECTION] Example App: Debug Console / ShowExampleAppConsole()
ImGui::Separator();
if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, 0), false, ImGuiWindowFlags_HorizontalScrollbar)) {
ImGui::TextUnformatted(log_entries.data(), &log_entries[log_entries.size()]);
}
ImGui::EndChild();
ImGui::End();
}
static inline void main_window(Config& active_config, bool* show_settings_window, bool* show_logs_window, bool* exit_requested_rev) {
if (!ImGui::Begin("LogMeow", exit_requested_rev)) {
ImGui::End();
return;
@ -33,6 +59,31 @@ static inline void main_window(Config& active_config, bool* show_settings_window
if (ImGui::Button("Settings")) {
*show_settings_window = true;
}
ImGui::SameLine();
if (ImGui::Button("Logs")) {
*show_logs_window = true;
}
ImGui::End();
}
static inline void debug_window() {
static bool show_demo_window = false;
static size_t add_log_entry_presses = 1;
if (show_demo_window) {
ImGui::ShowDemoWindow(&show_demo_window);
}
if (!ImGui::Begin("LogMeow Debug")) {
ImGui::End();
return;
}
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Checkbox("Show Dear ImGui Demo Window", &show_demo_window);
ImGui::Separator();
if (ImGui::Button("Add Log Entry")) {
std::exception e;
log(std::string("Add log entry button pressed ") + std::to_string(add_log_entry_presses++) + " time(s)", e);
}
ImGui::End();
}
@ -53,25 +104,13 @@ static inline void exit_modal_if_necessary(bool* run_event_loop) {
ImGui::EndPopup();
}
static inline void debug_window() {
static bool show_demo_window = false;
if (show_demo_window) {
ImGui::ShowDemoWindow(&show_demo_window);
}
if (!ImGui::Begin("LogMeow Debug")) {
ImGui::End();
return;
}
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Checkbox("Show Dear ImGui Demo Window", &show_demo_window);
ImGui::End();
}
void event_loop(Config& config, float* config_write_timer, bool* run_event_loop) {
static bool show_settings_window = false;
static bool show_logs_window = false;
static bool exit_requested_rev = true;
debug_window();
if (show_settings_window) {
settings_window(config, config_write_timer, &show_settings_window);
}
@ -82,11 +121,14 @@ void event_loop(Config& config, float* config_write_timer, bool* run_event_loop)
}
}
if (show_logs_window) {
logs_window(&show_logs_window);
}
if (!exit_requested_rev) {
ImGui::OpenPopup("Exit?");
exit_requested_rev = true;
}
exit_modal_if_necessary(run_event_loop);
main_window(config, &show_settings_window, &exit_requested_rev);
debug_window();
main_window(config, &show_settings_window, &show_logs_window, &exit_requested_rev);
}

63
log.cpp Normal file
View File

@ -0,0 +1,63 @@
#include <ctime>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <iostream>
#include <exception>
#include <system_error>
#include "log.h"
static time_t current_time() {
static bool no_time_warned = false;
struct timespec tp;
if (!clock_gettime(CLOCK_REALTIME, &tp)) {
return tp.tv_sec;
}
if (no_time_warned) {
return 0;
}
no_time_warned = true;
std::system_error e = std::system_error(errno, std::generic_category(), "clock_gettime()");
log("Failed to get current time", std::move(e));
return 0;
}
std::string log_entries;
void log(std::string entry, time_t time) {
size_t last_newline_pos = 0, newline_pos;
std::string line;
char time_as_str[128] = {0};
strftime(time_as_str, 127 * sizeof(char), "%c", localtime(&time));
do {
newline_pos = entry.find('\n', last_newline_pos);
line = '[';
line += time_as_str;
line += "] ";
line += entry.substr(last_newline_pos, newline_pos);
printf("%s\n", line.c_str());
if (!log_entries.empty()) {
log_entries += '\n';
}
log_entries += std::move(line);
last_newline_pos = newline_pos + 1;
} while (last_newline_pos);
}
void log(std::string action, const std::exception& e) {
log(action + ": " + e.what(), current_time());
}
std::string quote(const std::string& str) {
std::stringstream ss;
ss << std::quoted(str);
return ss.str();
}

10
log.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <string>
#include <vector>
#include <exception>
extern std::string log_entries;
void log(std::string action, const std::exception& e);
std::string quote(const std::string& str);

View File

@ -1,4 +1,5 @@
#include <cstdio>
#include <locale.h>
#include <sys/stat.h>
#include <imgui.h>
@ -14,8 +15,9 @@
#include "config.h"
#include "event_loop.h"
int main(int, char**)
{
int main(int, char**) {
setlocale(LC_ALL, "");
Config config;
try {
config = load_config();