Add logging
This commit is contained in:
parent
f1c2dc7f63
commit
3bf47f3a5c
11
Makefile
11
Makefile
|
@ -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)
|
||||
|
|
27
config.cpp
27
config.cpp
|
@ -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) + ')');
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue