PILog works
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
#include "pilog.h"
|
#include "pilog.h"
|
||||||
|
|
||||||
#include "pidir.h"
|
#include "pidir.h"
|
||||||
|
#include "piliterals_string.h"
|
||||||
#include "piliterals_time.h"
|
#include "piliterals_time.h"
|
||||||
#include "pitime.h"
|
#include "pitime.h"
|
||||||
|
|
||||||
@@ -71,12 +72,16 @@
|
|||||||
|
|
||||||
|
|
||||||
PILog::PILog(): PIThread(), log_ts(&log_file) {
|
PILog::PILog(): PIThread(), log_ts(&log_file) {
|
||||||
split_time = 8_h;
|
setName("PILog");
|
||||||
|
split_time = 8_h;
|
||||||
|
timestamp_format = "yyyy-MM-dd hh:mm:ss.zzz";
|
||||||
|
setLineFormat("t - c: m");
|
||||||
|
CONNECTU(PICout::Notifier::object(), finished, this, coutDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PILog::~PILog() {
|
PILog::~PILog() {
|
||||||
stopAndWait();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -89,16 +94,91 @@ void PILog::setDir(const PIString & d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PILog::enqueue(const PIString & msg) {
|
void PILog::setLineFormat(const PIString & f) {
|
||||||
|
line_format = f;
|
||||||
|
line_format_p = line_format;
|
||||||
|
line_format_p.replace("t", "${t}").replace("c", "${c}").replace("m", "${m}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PICout PILog::debug(PIObject * context) {
|
||||||
|
return makePICout(context, Category::Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PICout PILog::warning(PIObject * context) {
|
||||||
|
return makePICout(context, Category::Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PICout PILog::error(PIObject * context) {
|
||||||
|
return makePICout(context, Category::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PILog::stop() {
|
||||||
|
while (true) {
|
||||||
|
log_mutex.lock();
|
||||||
|
bool done = queue.isEmpty();
|
||||||
|
log_mutex.unlock();
|
||||||
|
if (done) break;
|
||||||
|
piMinSleep();
|
||||||
|
}
|
||||||
|
PIThread::stopAndWait();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PILog::coutDone(int id, PIString * buffer) {
|
||||||
|
cout_mutex.lock();
|
||||||
|
if (!cout_cat_by_id.contains(id)) {
|
||||||
|
cout_mutex.unlock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto cat = cout_cat_by_id.take(id, PILog::Category::Debug);
|
||||||
|
cout_mutex.unlock();
|
||||||
|
if (!buffer) return;
|
||||||
|
enqueue(*buffer, cat);
|
||||||
|
delete buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PICout PILog::makePICout(PIObject * context, Category cat) {
|
||||||
|
cout_mutex.lock();
|
||||||
|
int id = ++cout_id;
|
||||||
|
auto buffer = new PIString();
|
||||||
|
cout_cat_by_id[id] = cat;
|
||||||
|
cout_mutex.unlock();
|
||||||
|
if (context) {
|
||||||
|
*buffer = "["_a + context->className();
|
||||||
|
if (context->name().isNotEmpty()) *buffer += " \"" + context->name() + "\"";
|
||||||
|
*buffer += "] ";
|
||||||
|
}
|
||||||
|
return PICout::withExternalBuffer(buffer, id, PICoutManipulators::AddSpaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PILog::enqueue(const PIString & msg, Category cat) {
|
||||||
if (log_file.isClosed()) return;
|
if (log_file.isClosed()) return;
|
||||||
auto cur_dt = PIDateTime::fromSystemTime(PISystemTime::current());
|
auto t = PIDateTime::fromSystemTime(PISystemTime::current());
|
||||||
PIMutexLocker ml(log_mutex);
|
PIMutexLocker ml(log_mutex);
|
||||||
queue.enqueue(cur_dt.toString("hh:mm:ss.zzz") + " - " + msg);
|
queue.enqueue({cat, t, msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PIString PILog::entryToString(const Entry & e) const {
|
||||||
|
static PIStringList categories{"debug", "warn ", "error"};
|
||||||
|
PIString t = e.time.toString(timestamp_format);
|
||||||
|
PIString ret = line_format_p;
|
||||||
|
ret.replace("${t}", t).replace("${c}", categories[static_cast<int>(e.cat)]).replace("${m}", e.msg);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PILog::newFile() {
|
void PILog::newFile() {
|
||||||
log_file.open(log_dir + "/" + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss__p" + PIString::fromNumber(++part_number) + ".txt"),
|
PIString aname = app_name;
|
||||||
|
if (aname.isNotEmpty()) aname += "__";
|
||||||
|
log_file.open(log_dir + "/" + aname + PIDateTime::current().toString("yyyy_MM_dd__hh_mm_ss") + ".log." +
|
||||||
|
PIString::fromNumber(++part_number),
|
||||||
PIIODevice::ReadWrite);
|
PIIODevice::ReadWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,6 +203,8 @@ void PILog::run() {
|
|||||||
}
|
}
|
||||||
auto qi = queue.dequeue();
|
auto qi = queue.dequeue();
|
||||||
log_mutex.unlock();
|
log_mutex.unlock();
|
||||||
log_ts << qi << "\n";
|
auto str = entryToString(qi);
|
||||||
|
log_ts << str << "\n";
|
||||||
|
piCout << str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,26 +41,78 @@ public:
|
|||||||
PILog();
|
PILog();
|
||||||
~PILog();
|
~PILog();
|
||||||
|
|
||||||
|
//! \~english Returns prefix for filename.
|
||||||
|
PIString applicationName() const { return app_name; }
|
||||||
|
|
||||||
|
//! \~english Set prefix for filename. Should be set \b before \a setDir()!
|
||||||
|
void setApplicationName(const PIString & n) { app_name = n; }
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Returns directory for log files.
|
||||||
PIString dir() const { return log_dir; }
|
PIString dir() const { return log_dir; }
|
||||||
|
|
||||||
|
//! \~english Set directory for log files. Should be set \b after \a setApplicationName()!
|
||||||
void setDir(const PIString & d);
|
void setDir(const PIString & d);
|
||||||
|
|
||||||
PISystemTime splitTime() const { return split_time; }
|
|
||||||
void setSplitTime(PISystemTime st) { split_time = st; }
|
|
||||||
|
|
||||||
void enqueue(const PIString & msg);
|
//! \~english Returns lifetime for file.
|
||||||
|
PISystemTime fileSplitTime() const { return split_time; }
|
||||||
|
|
||||||
|
//! \~english Set lifetime for file. Each "st" interval new file will be created.
|
||||||
|
void setFileSplitTime(PISystemTime st) { split_time = st; }
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Returns timestamp format for line.
|
||||||
|
PIString timestampFormat() const { return timestamp_format; }
|
||||||
|
|
||||||
|
//! \~english Set timestamp format for line. Default is "yyyy-MM-dd hh:mm:ss.zzz".
|
||||||
|
void setTimestampFormat(const PIString & f) { timestamp_format = f; }
|
||||||
|
|
||||||
|
|
||||||
|
//! \~english Returns line format.
|
||||||
|
PIString lineFormat() const { return line_format; }
|
||||||
|
|
||||||
|
//! \~english Set line format. "t" is timestamp, "c" is category and "m" is message. Default is "t - c: m".
|
||||||
|
void setLineFormat(const PIString & f);
|
||||||
|
|
||||||
|
PICout debug(PIObject * context = nullptr);
|
||||||
|
PICout warning(PIObject * context = nullptr);
|
||||||
|
PICout error(PIObject * context = nullptr);
|
||||||
|
|
||||||
|
//! \~english Write all queued lines and stop. Also called in destructor.
|
||||||
|
void stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class Category {
|
||||||
|
Debug,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
EVENT_HANDLER2(void, coutDone, int, id, PIString *, buff);
|
||||||
|
|
||||||
|
PICout makePICout(PIObject * context, Category cat);
|
||||||
|
void enqueue(const PIString & msg, Category cat = Category::Debug);
|
||||||
|
|
||||||
|
struct Entry {
|
||||||
|
Category cat;
|
||||||
|
PIDateTime time;
|
||||||
|
PIString msg;
|
||||||
|
};
|
||||||
|
|
||||||
|
PIString entryToString(const Entry & e) const;
|
||||||
void newFile();
|
void newFile();
|
||||||
void run() override;
|
void run() override;
|
||||||
|
|
||||||
PIMutex log_mutex;
|
PIMutex log_mutex, cout_mutex;
|
||||||
PIFile log_file;
|
PIFile log_file;
|
||||||
PIIOTextStream log_ts;
|
PIIOTextStream log_ts;
|
||||||
PITimeMeasurer split_tm;
|
PITimeMeasurer split_tm;
|
||||||
PISystemTime split_time;
|
PISystemTime split_time;
|
||||||
PIString log_dir;
|
PIString log_dir, timestamp_format, line_format, line_format_p, app_name;
|
||||||
PIQueue<PIString> queue;
|
PIQueue<Entry> queue;
|
||||||
int part_number = -1;
|
PIMap<int, Category> cout_cat_by_id;
|
||||||
|
int part_number = -1, cout_id = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
20
main.cpp
20
main.cpp
@@ -5,6 +5,7 @@
|
|||||||
#include "piintrospection_server.h"
|
#include "piintrospection_server.h"
|
||||||
#include "piiostream.h"
|
#include "piiostream.h"
|
||||||
#include "pijson.h"
|
#include "pijson.h"
|
||||||
|
#include "pilog.h"
|
||||||
#include "pimathbase.h"
|
#include "pimathbase.h"
|
||||||
#include "pip.h"
|
#include "pip.h"
|
||||||
#include "pivaluetree_conversions.h"
|
#include "pivaluetree_conversions.h"
|
||||||
@@ -67,6 +68,25 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[]) {
|
int main(int argc, char * argv[]) {
|
||||||
|
PILog log;
|
||||||
|
log.setApplicationName("test");
|
||||||
|
log.setDir("logs");
|
||||||
|
// log.setTimestampFormat("hh-mm-ss");
|
||||||
|
// log.setLineFormat("[c] m (t)");
|
||||||
|
log.start();
|
||||||
|
|
||||||
|
// log.enqueue("debug msg");
|
||||||
|
// log.enqueue("warn msg with ${c}", PILog::Category::Warning);
|
||||||
|
// log.enqueue("ERROR${m}${t}", PILog::Category::Error);
|
||||||
|
|
||||||
|
log.debug(&log) << "some msg";
|
||||||
|
piMSleep(50);
|
||||||
|
log.warning() << "another!";
|
||||||
|
piMSleep(50);
|
||||||
|
log.error() << "blahblahblag";
|
||||||
|
|
||||||
|
// log.stop();
|
||||||
|
return 0;
|
||||||
/*PIPeer p("123");
|
/*PIPeer p("123");
|
||||||
|
|
||||||
piCout << "start ...";
|
piCout << "start ...";
|
||||||
|
|||||||
Reference in New Issue
Block a user