#include "pqlog.h" #include #include #include #include #include #include #include #include #include #include #include "core/pqapppath.h" namespace PQ { static const char * LevelName[6] = {"Test","Debug","Info","Warning","Critical","Fatal"}; void customMessageHandler(QtMsgType type, const QMessageLogContext &context,const QString & msg) { auto log = PQLogManger::this_()->qDebugLog(); if(log == nullptr) return; switch (type) { //调试信息提示 case QtDebugMsg: if (log->checkLevel(DebugMsg)) { LogMessage(log,context.file,context.line,DebugMsg).stream() << msg ; } break; //一般的warning提示 case QtWarningMsg: if (log->checkLevel(WarningMsg)) { LogMessage(log,context.file,context.line,WarningMsg).stream() << msg ; } break; //严重错误提示 case QtCriticalMsg: if (log->checkLevel(CriticalMsg)) { LogMessage(log,context.file,context.line,CriticalMsg).stream() << msg ; } break; //致命错误提示 case QtFatalMsg: if (log->checkLevel(FatalMsg)) { LogMessage(log,context.file,context.line,FatalMsg).stream() << msg ; } break; case QtInfoMsg : if (log->checkLevel(InfoMsg)) { LogMessage(log,context.file,context.line,InfoMsg).stream() << msg ; } break; } } PQLogManger::PQLogManger() { _thread.start(); auto nm = QCoreApplication::applicationName(); _baseLog.reset(new PQLog(nm,STD_OUT)); _baseLog->moveToThread(&_thread); _qtLog.reset(new PQLog("qtdebug",STD_OUT)); _qtLog->moveToThread(&_thread); _logs.insert(nm,_baseLog); _logs.insert("qtdebug",_qtLog); connect(this,&PQLogManger::updateSavePath,_baseLog.data(),&PQLog::restLog,Qt::QueuedConnection); connect(this,&PQLogManger::updateSavePath,_qtLog.data(),&PQLog::restLog,Qt::QueuedConnection); setSaveFilePath(AppPath::this_()->logDir().absolutePath()); } PQLogManger * PQLogManger::this_() { static PQLogManger logManger; return &logManger; } PQLogManger::~PQLogManger() { _thread.quit(); _thread.wait(1000); if(_thread.isRunning()){ _thread.terminate(); } } bool PQLogManger::setSaveFilePath(const QString & path) { QDir dir(path); if(dir.exists() || dir.mkpath(dir.absolutePath())) { QFileInfo info(path); if(info.isWritable()){ path_ = dir.absolutePath(); emit updateSavePath(); } } return false; } PQLog * PQLogManger::enbleQtMessage() { qInstallMessageHandler(customMessageHandler); return _qtLog.data(); } PQLog * PQLogManger::getLog(const QString & name) { _locker.lockForRead(); auto log = _logs.value(name); _locker.unlock(); if(log.isNull()){ _locker.lockForWrite(); log = _logs.value(name); if(log.isNull()){ log.reset(new PQLog(name)); log->moveToThread(&_thread); connect(this,&PQLogManger::updateSavePath,log.data(),&PQLog::restLog,Qt::QueuedConnection); _logs.insert(name,log); } _locker.unlock(); } return log.data(); } class LogEvent : public QEvent { public: LogEvent(QString && str,LogLevel lv): QEvent(eventType),level(lv),str_(str) {} ~LogEvent() {} const QString & getString() const {return str_;} static QEvent::Type eventType; LogLevel level; private: QString str_; }; QEvent::Type LogEvent::eventType = static_cast(QEvent::registerEventType()); class UpEventOutStatus : public QEvent { public: UpEventOutStatus(OutState state): QEvent(eventType),state(state) {} ~UpEventOutStatus() {} static QEvent::Type eventType; OutState state; }; QEvent::Type UpEventOutStatus::eventType = static_cast(QEvent::registerEventType()); LogMessage::LogMessage(PQLog * log,const char * file, int line,LogLevel level) : log(log), ts(&str_),level_(level) { if(log == nullptr || level < log->level) return; if(log->writeTime){ ts << "[" << QTime::currentTime().toString("hh:mm:ss.zzz") << "]:"; } if(log->writeFileInfo) { ts << "[@ " << file << " : " << line << "]:"; } if(log->writeLevel){ ts << "[" << LevelName[level] << "]:"; } } LogMessage::LogMessage(PQLog * log,LogLevel level): log(log), ts(&str_),level_(level) { if(log == nullptr || level < log->level) return; if(log->writeTime){ ts << "[" << QTime::currentTime().toString("hh:mm:ss.zzz") << "]:"; } if(log->writeFileInfo) { ts << "[@ ]:"; } if(log->writeLevel){ ts << "[" << LevelName[level] << "]:"; } } LogMessage::~LogMessage() { if (log != nullptr && level_ >= log->level ) { if(log->writeEndLine) ts << "\r\n"; ts.setDevice(nullptr); QCoreApplication::postEvent(log,new LogEvent(std::move(str_),level_)); if (level_ == FatalMsg) { QCoreApplication::exit(-1); } } } PQLog::PQLog(const QString & name, OutState state) : QObject(nullptr),state_(state),file_(nullptr),_name(name) { level = TestMsg; writeTime = true; writeFileInfo = true; writeLevel = true; writeEndLine = true; fileCreateType = DayOne; ts_.setDevice(nullptr); _fileCreateId = -1; } PQLog::~PQLog() { releaseLogFile(); } void PQLog::setOutState(OutState outState) { QCoreApplication::postEvent(this,new UpEventOutStatus(outState)); } void PQLog::restLog() { if(state_ == File){ releaseLogFile(); } } void PQLog::releaseLogFile() { ts_.setDevice(nullptr); if(file_){ file_->close(); delete file_; file_ = nullptr; } } void PQLog::customEvent(QEvent * event) { if(event->type() == UpEventOutStatus::eventType){ UpEventOutStatus * ev = static_cast(event); if(state_ != ev->state) { state_ = ev->state; releaseLogFile(); } } else if (event->type() == LogEvent::eventType) { LogEvent * ev = static_cast(event); if(ev->level >= level) { switch (state_) { case STD_OUT :{ std::cout << ev->getString().toStdString(); return; } break; case STD_ERROR:{ std::cerr << ev->getString().toStdString(); return; } break; case File : { if(file_){ int id = _fileCreateId; switch (fileCreateType) { case DayOne: { id = QDate::currentDate().day(); } break; case HourOne: id = QTime::currentTime().hour(); break; case MonthOne: id = QDate::currentDate().month(); break; default: id = _fileCreateId; break; } if(id != _fileCreateId) releaseLogFile(); } if(file_ == nullptr){ QString fname = PQLogManger::this_()->getSaveFilePath() + "/" + _name; switch (fileCreateType) { case OneStartOne:{ auto pid = QCoreApplication::applicationPid(); fname += "_"; fname += QDateTime::currentDateTime().toString("yyyy-MM-dd.hh-mm-ss.zzz"); fname += "_"; fname += QString::number(pid); _fileCreateId = 0; } case DayOne: { auto dt = QDate::currentDate(); fname += "_"; fname += dt.toString("yyyy-MM-dd"); _fileCreateId = dt.day(); } break; case HourOne:{ auto dt = QDateTime::currentDateTime(); fname += "_"; fname += dt.toString("yyyy-MM-dd.hh"); _fileCreateId = dt.time().hour(); } break; case MonthOne:{ auto dt = QDate::currentDate(); fname += "_"; fname += dt.toString("yyyy-MM"); _fileCreateId = dt.month(); } break; default: break; } fname += ".logs"; file_ = new QFile(fname,this); file_->open(QFile::Append); ts_.setDevice(file_); } } break; default: break; } if (ts_.device() != nullptr) { ts_ << ev->getString(); ts_.flush(); } } } event->accept(); } }//namespace PQLog