diff --git a/aegisub/libaegisub/common/log.cpp b/aegisub/libaegisub/common/log.cpp index afb970449..f4bb1c4f9 100644 --- a/aegisub/libaegisub/common/log.cpp +++ b/aegisub/libaegisub/common/log.cpp @@ -64,49 +64,17 @@ SinkMessage::~SinkMessage() { delete message; } - -LogSink::LogSink(const std::string& dir_log): dir_log(dir_log) { - util::time_log(time_start); -} - /// @todo The log files need to be trimmed after N amount. LogSink::~LogSink() { - json::Object root; - json::Array &array = root["log"]; + // The destructor for emitters may try to log messages, so disable all the + // emitters before destructing any + std::vector emitters_temp; + swap(emitters_temp, emitters); + util::delete_clear(emitters_temp); - agi_timeval time_close; - util::time_log(time_close); - - for (unsigned int i=0; i < sink.size(); i++) { - json::Object entry; - entry["sec"] = sink[i]->tv.tv_sec; - entry["usec"] = sink[i]->tv.tv_usec; - entry["severity"] = sink[i]->severity, - entry["section"] = sink[i]->section; - entry["file"] = sink[i]->file; - entry["func"] = sink[i]->func; - entry["line"] = sink[i]->line; - entry["message"] = std::string(sink[i]->message, sink[i]->len); - - array.push_back(entry); - } - - json::Array &timeval_open = root["timeval"]["open"]; - timeval_open.push_back(time_start.tv_sec); - timeval_open.push_back(time_start.tv_usec); - - json::Array &timeval_close = root["timeval"]["close"]; - timeval_close.push_back(time_close.tv_sec); - timeval_close.push_back(time_close.tv_usec); - - std::stringstream str; - str << dir_log << time_start.tv_sec << ".json"; - json::Writer::Write(root, io::Save(str.str()).Get()); - - agi::util::delete_clear(sink); + util::delete_clear(sink); } - void LogSink::log(SinkMessage *sm) { sink.push_back(sm); @@ -147,5 +115,47 @@ Message::~Message() { agi::log::log->log(sm); } +JsonEmitter::JsonEmitter(std::string const& directory, const agi::log::LogSink *log_sink) +: directory(directory) +, log_sink(log_sink) +{ + util::time_log(time_start); +} + +JsonEmitter::~JsonEmitter() { + json::Object root; + json::Array &array = root["log"]; + + agi_timeval time_close; + util::time_log(time_close); + + Sink const& sink = *log_sink->GetSink(); + for (unsigned int i=0; i < sink.size(); i++) { + json::Object entry; + entry["sec"] = sink[i]->tv.tv_sec; + entry["usec"] = sink[i]->tv.tv_usec; + entry["severity"] = sink[i]->severity; + entry["section"] = sink[i]->section; + entry["file"] = sink[i]->file; + entry["func"] = sink[i]->func; + entry["line"] = sink[i]->line; + entry["message"] = std::string(sink[i]->message, sink[i]->len); + + array.push_back(entry); + } + + json::Array &timeval_open = root["timeval"]["open"]; + timeval_open.push_back(time_start.tv_sec); + timeval_open.push_back(time_start.tv_usec); + + json::Array &timeval_close = root["timeval"]["close"]; + timeval_close.push_back(time_close.tv_sec); + timeval_close.push_back(time_close.tv_usec); + + std::stringstream str; + str << directory << time_start.tv_sec << ".json"; + json::Writer::Write(root, io::Save(str.str()).Get()); +} + } // namespace log } // namespace agi diff --git a/aegisub/libaegisub/include/libaegisub/log.h b/aegisub/libaegisub/include/libaegisub/log.h index 1068963a2..a495045ae 100644 --- a/aegisub/libaegisub/include/libaegisub/log.h +++ b/aegisub/libaegisub/include/libaegisub/log.h @@ -110,17 +110,7 @@ class LogSink { /// List of pointers to emitters std::vector emitters; - /// Init time for log writing purposes. - agi_timeval time_start; - - /// Directory to place logfiles. - const std::string dir_log; - public: - /// Constructor - /// @param dir_log Directory to place log files. - LogSink(const std::string &dir_log); - /// Destructor ~LogSink(); @@ -139,7 +129,7 @@ public: /// @brief @get the complete (current) log. /// @return Const pointer to internal sink. - const Sink* GetSink() { return &sink; } + const Sink* GetSink() const { return &sink; } }; /// An emitter to produce human readable output for a log sink. @@ -152,6 +142,28 @@ public: virtual void log(SinkMessage *sm)=0; }; +/// A simple emitter which writes the log to a file in json format when it's destroyed +class JsonEmitter : public Emitter { + /// Init time + agi_timeval time_start; + + /// Directory to write the log file in + std::string directory; + + /// Parent sink to get messages from + const agi::log::LogSink *log_sink; +public: + /// Constructor + /// @param directory Directory to write the log file in + /// @param log_sink Parent sink to get messages from + JsonEmitter(std::string const& directory, const agi::log::LogSink *log_sink); + /// Destructor + ~JsonEmitter(); + + /// No-op log function as everything is done in the destructor + void log(SinkMessage *) { } +}; + /// Generates a message and submits it to the log sink. class Message { const int len; diff --git a/aegisub/reporter/main.cpp b/aegisub/reporter/main.cpp index f75e55699..5c1990399 100644 --- a/aegisub/reporter/main.cpp +++ b/aegisub/reporter/main.cpp @@ -43,7 +43,7 @@ bool Reporter::OnInit() { const std::string path_log(util::config_path() + "log/"); wxFileName::Mkdir(path_log, 0777, wxPATH_MKDIR_FULL); - agi::log::log = new agi::log::LogSink(path_log); + agi::log::log = new agi::log::LogSink; // if ( !wxApp::OnInit() ) // return false; diff --git a/aegisub/src/main.cpp b/aegisub/src/main.cpp index 17f0baf4a..d1042ae9d 100644 --- a/aegisub/src/main.cpp +++ b/aegisub/src/main.cpp @@ -144,7 +144,8 @@ bool AegisubApp::OnInit() { // logging. wxString path_log = StandardPaths::DecodePath("?user/log/"); wxFileName::Mkdir(path_log, 0777, wxPATH_MKDIR_FULL); - agi::log::log = new agi::log::LogSink(STD_STR(path_log)); + agi::log::log = new agi::log::LogSink; + agi::log::log->Subscribe(new agi::log::JsonEmitter(STD_STR(path_log), agi::log::log)); #ifdef _DEBUG agi::log::log->Subscribe(new agi::log::EmitSTDOUT()); diff --git a/aegisub/tests/main.cpp b/aegisub/tests/main.cpp index d021c0b3b..b96aeb15b 100644 --- a/aegisub/tests/main.cpp +++ b/aegisub/tests/main.cpp @@ -24,7 +24,8 @@ int main(int argc, char **argv) { int retval; - agi::log::log = new agi::log::LogSink("./"); + agi::log::log = new agi::log::LogSink; + agi::log::log->Subscribe(new agi::log::JsonEmitter("./", agi::log::log)); ::testing::InitGoogleTest(&argc, argv); retval = RUN_ALL_TESTS();