一个简单的日志类的开发
前段时间,由于工作需要,需开发一个新的日志类,要求将服务端所处理的有关同一个请求的所有日志全部记录在一个json中,以方便日志收集与查询、分析。像以前那样处理到某一步打印一条日志的方式便不再可行了。
一个请求由于中间有好多处理过程,而且不尽相同,要求将这些处理产生的日志都打印在一起,最先想到的自然就是设计一个新的日志类,里边有一个buffer,在收到请求时创建一个该类的对象,然后所有的请求日志都通过该类写入buffer,而实际写入日志文件则是在该类的析构函数中进行,也就达到了一次性写入的目的。
//请求日志记录类,每条请求添加一条日志记录的对象 class RequestLogger { public: enum LogLevel { TRACE = 0, DEBUG, INFO, WARN, ERROR, NUM_LOG_LEVELS }; ~RequestLogger() { Json::FastWriter writer; std::string &&s = writer.write(m_value); LoggerWriter::getLoggerWriter().write(s); } RequestLogger& operator <<(std::string s) { if(s.size() != 0) m_buf.append(s); return *this; } RequestLogger& operator <<(int i) { try { std::string tmp = boost::lexical_cast<std::string>(i); return *this << tmp; }catch(boost::bad_lexical_cast& e) { return *this; } } void addLog(LogLevel level, const char* filename, const int line) { Json::Value tmp; const char* slash = strrchr(filename, '/'); if(!slash) slash = filename; else slash++; tmp["file"] = slash; tmp["line"] = line; struct timeval tv; gettimeofday(&tv, NULL); int64_t seconds = tv.tv_sec + 8*3600; // UTC + 8.0 char buf[32] = {0}; struct tm tm_time; gmtime_r(&seconds,&tm_time); snprintf(buf, sizeof(buf), "%4d-%02d-%02d %02d:%02d:%02d.%06d", tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, tv.tv_usec); tmp["time"] = std::string(buf); tmp["content"] = m_buf; switch(level) { case TRACE: tmp["level"] = "TRACE"; break; case DEBUG: tmp["level"] = "DEBUG"; break; case INFO: tmp["level"] = "INFO"; break; case WARN: tmp["level"] = "WARN"; break; case ERROR: tmp["level"] = "ERROR"; break; } m_value["processlog"].append(tmp); m_buf = ""; } private: std::string m_buf; Json::Value m_value; };
通过重载operator << 操作符,对日志写入进行了方便对日志进行写入,然后,再定义addLog函数,将buf中的内容转换到json变量中,最后在析构时调用LoggerWriter单例类去写入日志文件。为方便使用,定义以下宏来使用。
#define REQUEST_TRACE(logger_ptr, logstream) ((*logger_ptr) << logstream).addLog(RequestLogger::LogLevel::TRACE, __FILE__, __LINE__); #define REQUEST_DEBUG(logger_ptr, logstream) ((*logger_ptr) << logstream).addLog(RequestLogger::LogLevel::DEBUG, __FILE__, __LINE__); #define REQUEST_INFO(logger_ptr, logstream) ((*logger_ptr) << logstream).addLog(RequestLogger::LogLevel::INFO, __FILE__, __LINE__); #define REQUEST_WARN(logger_ptr, logstream) ((*logger_ptr) << logstream).addLog(RequestLogger::LogLevel::WARN, __FILE__, __LINE__); #define REQUEST_ERROR(logger_ptr, logstream) ((*logger_ptr) << logstream).addLog(RequestLogger::LogLevel::ERROR, __FILE__, __LINE__);
记录日志使用如下:
std::shared_ptr<RequestLogger> ptr_logger(new RequestLogger()); REQUEST_INFO(ptr_logger, "基本预处理后: " << tmp_query);
还是蛮方便的。