Write log files incrementally so that they actually exist for crashes

This commit is contained in:
Thomas Goyne 2013-01-22 09:20:32 -08:00
parent 101721863a
commit c6005be4a1
4 changed files with 35 additions and 47 deletions

View file

@ -26,6 +26,8 @@
#include "libaegisub/util.h" #include "libaegisub/util.h"
#include <algorithm> #include <algorithm>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/range/algorithm.hpp> #include <boost/range/algorithm.hpp>
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
@ -90,43 +92,37 @@ Message::~Message() {
msg.freeze(false); msg.freeze(false);
} }
JsonEmitter::JsonEmitter(agi::fs::path const& directory, const agi::log::LogSink *log_sink) JsonEmitter::JsonEmitter(fs::path const& directory)
: time_start(util::time_log()) : fp(new boost::filesystem::ofstream(unique_path(directory/util::strftime("%Y-%m-%d-%H-%M-%S-%%%%%%%%.json"))))
, directory(directory)
, log_sink(log_sink)
{ {
WriteTime("open");
} }
JsonEmitter::~JsonEmitter() { JsonEmitter::~JsonEmitter() {
json::Object root; WriteTime("close");
json::Array &array = root["log"]; }
auto time_close = util::time_log(); void JsonEmitter::log(SinkMessage *sm) {
json::Object entry;
entry["sec"] = (int64_t)sm->tv.tv_sec;
entry["usec"] = (int64_t)sm->tv.tv_usec;
entry["severity"] = sm->severity;
entry["section"] = sm->section;
entry["file"] = sm->file;
entry["func"] = sm->func;
entry["line"] = sm->line;
entry["message"] = sm->message;
json::Writer::Write(entry, *fp);
fp->flush();
}
Sink const& sink = *log_sink->GetSink(); void JsonEmitter::WriteTime(const char *key) {
for (unsigned int i=0; i < sink.size(); i++) { auto time = util::time_log();
json::Object entry; json::Object obj;
entry["sec"] = (int64_t)sink[i]->tv.tv_sec; json::Array &timeval = obj[key];
entry["usec"] = (int64_t)sink[i]->tv.tv_usec; timeval.push_back((int64_t)time.tv_sec);
entry["severity"] = sink[i]->severity; timeval.push_back((int64_t)time.tv_usec);
entry["section"] = sink[i]->section; json::Writer::Write(obj, *fp);
entry["file"] = sink[i]->file;
entry["func"] = sink[i]->func;
entry["line"] = sink[i]->line;
entry["message"] = sink[i]->message;
array.push_back(std::move(entry));
}
json::Array &timeval_open = root["timeval"]["open"];
timeval_open.push_back((int64_t)time_start.tv_sec);
timeval_open.push_back((int64_t)time_start.tv_usec);
json::Array &timeval_close = root["timeval"]["close"];
timeval_close.push_back((int64_t)time_close.tv_sec);
timeval_close.push_back((int64_t)time_close.tv_usec);
json::Writer::Write(root, io::Save(directory/(std::to_string(time_start.tv_sec) + ".json")).Get());
} }
} // namespace log } // namespace log

View file

@ -19,11 +19,9 @@
#include <libaegisub/fs_fwd.h> #include <libaegisub/fs_fwd.h>
#include <libaegisub/time.h> #include <libaegisub/time.h>
#include <boost/filesystem/path.hpp>
#include <cstdint>
#include <cstdio>
#include <ctime> #include <ctime>
#include <deque> #include <deque>
#include <iosfwd>
#include <memory> #include <memory>
#include <vector> #include <vector>
@ -133,26 +131,20 @@ public:
virtual void log(SinkMessage *sm)=0; virtual void log(SinkMessage *sm)=0;
}; };
/// A simple emitter which writes the log to a file in json format when it's destroyed /// A simple emitter which writes the log to a file in json format
class JsonEmitter : public Emitter { class JsonEmitter : public Emitter {
/// Init time std::unique_ptr<std::ostream> fp;
timeval time_start;
/// Directory to write the log file in void WriteTime(const char *key);
const agi::fs::path directory;
/// Parent sink to get messages from
const agi::log::LogSink *log_sink;
public: public:
/// Constructor /// Constructor
/// @param directory Directory to write the log file in /// @param directory Directory to write the log file in
/// @param log_sink Parent sink to get messages from JsonEmitter(fs::path const& directory);
JsonEmitter(agi::fs::path const& directory, const agi::log::LogSink *log_sink);
/// Destructor /// Destructor
~JsonEmitter(); ~JsonEmitter();
/// No-op log function as everything is done in the destructor void log(SinkMessage *);
void log(SinkMessage *) { }
}; };
/// Generates a message and submits it to the log sink. /// Generates a message and submits it to the log sink.

View file

@ -180,7 +180,7 @@ bool AegisubApp::OnInit() {
StartupLog("Create log writer"); StartupLog("Create log writer");
auto path_log = StandardPaths::DecodePath("?user/log/"); auto path_log = StandardPaths::DecodePath("?user/log/");
agi::fs::CreateDirectory(path_log); agi::fs::CreateDirectory(path_log);
agi::log::log->Subscribe(new agi::log::JsonEmitter(path_log, agi::log::log)); agi::log::log->Subscribe(new agi::log::JsonEmitter(path_log));
CleanCache(path_log, "*.json", 10, 100); CleanCache(path_log, "*.json", 10, 100);
StartupLog("Load user configuration"); StartupLog("Load user configuration");

View file

@ -23,7 +23,7 @@ int main(int argc, char **argv) {
int retval; 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)); agi::log::log->Subscribe(new agi::log::JsonEmitter("./"));
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
retval = RUN_ALL_TESTS(); retval = RUN_ALL_TESTS();