qlog.cpp 9.7 KB

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