pqlog.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. #include "pqlog.h"
  2. #include <QTime>
  3. #include <QEvent>
  4. #include <QThread>
  5. #include <QCoreApplication>
  6. #include <iostream>
  7. #include <QDir>
  8. #include <QDate>
  9. #include <memory>
  10. #include <QDebug>
  11. #include <QDateTime>
  12. #include "core/pqapppath.h"
  13. namespace PQ {
  14. static const char * LevelName[6] = {"Test","Debug","Info","Warning","Critical","Fatal"};
  15. void customMessageHandler(QtMsgType type, const QMessageLogContext &context,const QString & msg)
  16. {
  17. auto log = PQLogManger::this_()->qDebugLog();
  18. if(log == nullptr) return;
  19. switch (type) {
  20. //调试信息提示
  21. case QtDebugMsg:
  22. if (log->checkLevel(DebugMsg)) {
  23. LogMessage(log,context.file,context.line,DebugMsg).stream() << msg ;
  24. }
  25. break;
  26. //一般的warning提示
  27. case QtWarningMsg:
  28. if (log->checkLevel(WarningMsg)) {
  29. LogMessage(log,context.file,context.line,WarningMsg).stream() << msg ;
  30. }
  31. break;
  32. //严重错误提示
  33. case QtCriticalMsg:
  34. if (log->checkLevel(CriticalMsg)) {
  35. LogMessage(log,context.file,context.line,CriticalMsg).stream() << msg ;
  36. }
  37. break;
  38. //致命错误提示
  39. case QtFatalMsg:
  40. if (log->checkLevel(FatalMsg)) {
  41. LogMessage(log,context.file,context.line,FatalMsg).stream() << msg ;
  42. }
  43. break;
  44. case QtInfoMsg :
  45. if (log->checkLevel(InfoMsg)) {
  46. LogMessage(log,context.file,context.line,InfoMsg).stream() << msg ;
  47. }
  48. break;
  49. }
  50. }
  51. PQLogManger::PQLogManger()
  52. {
  53. _thread.start();
  54. auto nm = QCoreApplication::applicationName();
  55. _baseLog.reset(new PQLog(nm,STD_OUT));
  56. _baseLog->moveToThread(&_thread);
  57. _qtLog.reset(new PQLog("qtdebug",STD_OUT));
  58. _qtLog->moveToThread(&_thread);
  59. _logs.insert(nm,_baseLog);
  60. _logs.insert("qtdebug",_qtLog);
  61. connect(this,&PQLogManger::updateSavePath,_baseLog.data(),&PQLog::restLog,Qt::QueuedConnection);
  62. connect(this,&PQLogManger::updateSavePath,_qtLog.data(),&PQLog::restLog,Qt::QueuedConnection);
  63. setSaveFilePath(AppPath::this_()->logDir().absolutePath());
  64. }
  65. PQLogManger * PQLogManger::this_()
  66. {
  67. static PQLogManger logManger;
  68. return &logManger;
  69. }
  70. PQLogManger::~PQLogManger()
  71. {
  72. _thread.quit();
  73. _thread.wait(1000);
  74. if(_thread.isRunning()){
  75. _thread.terminate();
  76. }
  77. }
  78. bool PQLogManger::setSaveFilePath(const QString & path)
  79. {
  80. QDir dir(path);
  81. if(dir.exists() || dir.mkpath(dir.absolutePath())) {
  82. QFileInfo info(path);
  83. if(info.isWritable()){
  84. path_ = dir.absolutePath();
  85. emit updateSavePath();
  86. }
  87. }
  88. return false;
  89. }
  90. PQLog * PQLogManger::enbleQtMessage()
  91. {
  92. qInstallMessageHandler(customMessageHandler);
  93. return _qtLog.data();
  94. }
  95. PQLog * PQLogManger::getLog(const QString & name)
  96. {
  97. _locker.lockForRead();
  98. auto log = _logs.value(name);
  99. _locker.unlock();
  100. if(log.isNull()){
  101. _locker.lockForWrite();
  102. log = _logs.value(name);
  103. if(log.isNull()){
  104. log.reset(new PQLog(name));
  105. log->moveToThread(&_thread);
  106. connect(this,&PQLogManger::updateSavePath,log.data(),&PQLog::restLog,Qt::QueuedConnection);
  107. _logs.insert(name,log);
  108. }
  109. _locker.unlock();
  110. }
  111. return log.data();
  112. }
  113. class LogEvent : public QEvent
  114. {
  115. public:
  116. LogEvent(QString && str,LogLevel lv): QEvent(eventType),level(lv),str_(str) {}
  117. ~LogEvent() {}
  118. const QString & getString() const {return str_;}
  119. static QEvent::Type eventType;
  120. LogLevel level;
  121. private:
  122. QString str_;
  123. };
  124. QEvent::Type LogEvent::eventType = static_cast<QEvent::Type>(QEvent::registerEventType());
  125. class UpEventOutStatus : public QEvent
  126. {
  127. public:
  128. UpEventOutStatus(OutState state): QEvent(eventType),state(state) {}
  129. ~UpEventOutStatus() {}
  130. static QEvent::Type eventType;
  131. OutState state;
  132. };
  133. QEvent::Type UpEventOutStatus::eventType = static_cast<QEvent::Type>(QEvent::registerEventType());
  134. LogMessage::LogMessage(PQLog * log,const char * file, int line,LogLevel level) : log(log), ts(&str_),level_(level)
  135. {
  136. if(log == nullptr || level < log->level) return;
  137. if(log->writeTime){
  138. ts << "[" << QTime::currentTime().toString("hh:mm:ss.zzz") << "]:";
  139. }
  140. if(log->writeFileInfo) {
  141. ts << "[@ " << file << " : " << line << "]:";
  142. }
  143. if(log->writeLevel){
  144. ts << "[" << LevelName[level] << "]:";
  145. }
  146. }
  147. LogMessage::LogMessage(PQLog * log,LogLevel level): log(log), ts(&str_),level_(level)
  148. {
  149. if(log == nullptr || level < log->level) return;
  150. if(log->writeTime){
  151. ts << "[" << QTime::currentTime().toString("hh:mm:ss.zzz") << "]:";
  152. }
  153. if(log->writeFileInfo) {
  154. ts << "[@ ]:";
  155. }
  156. if(log->writeLevel){
  157. ts << "[" << LevelName[level] << "]:";
  158. }
  159. }
  160. LogMessage::~LogMessage()
  161. {
  162. if (log != nullptr && level_ >= log->level ) {
  163. if(log->writeEndLine)
  164. ts << "\r\n";
  165. ts.setDevice(nullptr);
  166. QCoreApplication::postEvent(log,new LogEvent(std::move(str_),level_));
  167. if (level_ == FatalMsg) {
  168. QCoreApplication::exit(-1);
  169. }
  170. }
  171. }
  172. PQLog::PQLog(const QString & name, OutState state)
  173. : QObject(nullptr),state_(state),file_(nullptr),_name(name)
  174. {
  175. level = TestMsg;
  176. writeTime = true;
  177. writeFileInfo = true;
  178. writeLevel = true;
  179. writeEndLine = true;
  180. fileCreateType = DayOne;
  181. ts_.setDevice(nullptr);
  182. _fileCreateId = -1;
  183. }
  184. PQLog::~PQLog()
  185. {
  186. releaseLogFile();
  187. }
  188. void PQLog::setOutState(OutState outState)
  189. {
  190. QCoreApplication::postEvent(this,new UpEventOutStatus(outState));
  191. }
  192. void PQLog::restLog()
  193. {
  194. if(state_ == File){
  195. releaseLogFile();
  196. }
  197. }
  198. void PQLog::releaseLogFile()
  199. {
  200. ts_.setDevice(nullptr);
  201. if(file_){
  202. file_->close();
  203. delete file_;
  204. file_ = nullptr;
  205. }
  206. }
  207. void PQLog::customEvent(QEvent * event)
  208. {
  209. if(event->type() == UpEventOutStatus::eventType){
  210. UpEventOutStatus * ev = static_cast<UpEventOutStatus *>(event);
  211. if(state_ != ev->state) {
  212. state_ = ev->state;
  213. releaseLogFile();
  214. }
  215. } else if (event->type() == LogEvent::eventType) {
  216. LogEvent * ev = static_cast<LogEvent *>(event);
  217. if(ev->level >= level) {
  218. switch (state_) {
  219. case STD_OUT :{
  220. std::cout << ev->getString().toStdString();
  221. return;
  222. }
  223. break;
  224. case STD_ERROR:{
  225. std::cerr << ev->getString().toStdString();
  226. return;
  227. }
  228. break;
  229. case File : {
  230. if(file_){
  231. int id = _fileCreateId;
  232. switch (fileCreateType) {
  233. case DayOne: {
  234. id = QDate::currentDate().day();
  235. }
  236. break;
  237. case HourOne:
  238. id = QTime::currentTime().hour();
  239. break;
  240. case MonthOne:
  241. id = QDate::currentDate().month();
  242. break;
  243. default:
  244. id = _fileCreateId;
  245. break;
  246. }
  247. if(id != _fileCreateId)
  248. releaseLogFile();
  249. }
  250. if(file_ == nullptr){
  251. QString fname = PQLogManger::this_()->getSaveFilePath() + "/" + _name;
  252. switch (fileCreateType) {
  253. case OneStartOne:{
  254. auto pid = QCoreApplication::applicationPid();
  255. fname += "_";
  256. fname += QDateTime::currentDateTime().toString("yyyy-MM-dd.hh-mm-ss.zzz");
  257. fname += "_";
  258. fname += QString::number(pid);
  259. _fileCreateId = 0;
  260. }
  261. case DayOne: {
  262. auto dt = QDate::currentDate();
  263. fname += "_";
  264. fname += dt.toString("yyyy-MM-dd");
  265. _fileCreateId = dt.day();
  266. }
  267. break;
  268. case HourOne:{
  269. auto dt = QDateTime::currentDateTime();
  270. fname += "_";
  271. fname += dt.toString("yyyy-MM-dd.hh");
  272. _fileCreateId = dt.time().hour();
  273. }
  274. break;
  275. case MonthOne:{
  276. auto dt = QDate::currentDate();
  277. fname += "_";
  278. fname += dt.toString("yyyy-MM");
  279. _fileCreateId = dt.month();
  280. }
  281. break;
  282. default:
  283. break;
  284. }
  285. fname += ".logs";
  286. file_ = new QFile(fname,this);
  287. file_->open(QFile::Append);
  288. ts_.setDevice(file_);
  289. }
  290. }
  291. break;
  292. default:
  293. break;
  294. }
  295. if (ts_.device() != nullptr) {
  296. ts_ << ev->getString();
  297. ts_.flush();
  298. }
  299. }
  300. }
  301. event->accept();
  302. }
  303. }//namespace PQLog