1. 程式人生 > 其它 >liunx伺服器-日誌模組設計

liunx伺服器-日誌模組設計

技術標籤:Liunx程式開發

文章目錄


前言

日誌是一個程式最核心的一個模組,此日誌程式模仿log4j日誌,日誌具有5個級別,
DEBUG 指出細粒度資訊事件對除錯應用程式是非常有幫助的。
INFO 表明 訊息在粗粒度級別上突出強調應用程式的執行過程。
WARN 表明會出現潛在錯誤的情形。
ERROR 指出雖然發生錯誤事件,但仍然不影響系統的繼續執行。
FATAL 指出每個嚴重的錯誤事件將會導致應用程式的退出。
在這裡插入圖片描述
分別對應 系統時間 協程id 執行緒id 日誌級別 使用者名稱 檔案 行號 內容


一、日誌是什麼?

執行日誌是程式最核心的模組之一,許多應用程式需要記錄它們的活動。系統程式經常需要向控制檯或日誌檔案寫訊息。這些訊息可能指示錯誤、警告或是與系統狀態有關的一般資訊,便於快速排查問題。

二、程式碼實現

1.日誌級別

//日誌級別
	class LogLevel {
	public:
		enum Level {
			UNKNOW = 0,
			DEBUG = 1,
			INFO = 2,
			WARN = 3,
			ERROR = 4,
			FATAL = 5
		};

		static const char * ToString(LogLevel::Level level)
; };

2.日誌事件

//日誌事件
	class LogEvent {
	public:
		typedef std::shared_ptr<LogEvent> ptr;

		LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level ,const char * file, int32_t line, \
			uint32_t elapse, uint32_t thread_id, uint32_t fiber_id, uint64_t time);

		const char * getFile
() const { return m_file; } //獲得檔案 int32_t getLine() const { return m_line; } //獲得行號 uint32_t getElapse() const { return m_elapase; }//程式啟動到現在運行了多長時間 uint32_t getTheadId() const { return m_threadId; }//執行緒id uint32_t getFiberId() const { return m_fiberId; } //協程id uint64_t getTime() const { return m_time; } //獲得時間 std::string getContent() const { return m_ss.str(); } //獲得檔案內容 std::stringstream & getSS() { return m_ss; } // std::shared_ptr<Logger> getLogger() const { return m_logger; } LogLevel::Level getLevel() const { return m_level; } private: const char * m_file = nullptr; //檔名 int32_t m_line = 0; //行號 uint32_t m_elapase = 0; //程式啟動到現在的毫秒數 uint32_t m_threadId = 0; //執行緒id uint32_t m_fiberId = 0; //協程id uint64_t m_time; //時間戳 std::stringstream m_ss; //檔案內容 std::shared_ptr<Logger> m_logger; //日誌器 LogLevel::Level m_level; //日誌級別 };

3.日誌包裝器

//日誌包裝器
	class LogEventWrap
	{
	public:
		LogEventWrap(LogEvent::ptr e);

		std::stringstream & getSS();

		~LogEventWrap();

	private:
		LogEvent::ptr m_event;
	};

4.日誌格式器

//日誌格式器
	class LogFormatter {
	public:
		typedef std::shared_ptr<LogFormatter> ptr;

		LogFormatter(const std::string & pattern);

		std::string format(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event);

	public:
		class FormatItem {
		public:
			typedef std::shared_ptr<FormatItem> ptr;
			FormatItem(const std::string & fmt = "") {};
			virtual ~FormatItem() {}
			virtual void format(std::ostream & os, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;
		};

		void init();
	private:
		std::string m_pattern;
		std::vector<FormatItem::ptr> m_items;
	};

5.日誌輸出地

//日誌輸出地
	class LogAppender {
	public:
		typedef std::shared_ptr<LogAppender> ptr;

		virtual ~LogAppender() {};

		virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;  /* 純虛擬函式 父類不做實現 */

		//%d{%Y-%m-%d %H:%M:%S}%T%t%T%F%T[%p]%T[%c]%T%f:%l%T%m%n
		//時間 執行緒id 協成id 日誌級別 使用者名稱 檔名 行號 檔案內容 回車符
		void setFormatter(LogFormatter::ptr val) { m_formatter = val; } //設定輸出格式
		LogFormatter::ptr getFormatter() const { return m_formatter; }

	protected:
		LogLevel::Level m_level;
		LogFormatter::ptr m_formatter;
	};

6.日誌器

//日誌器  
	class Logger : public std::enable_shared_from_this<Logger>{
	public:
		typedef std::shared_ptr<Logger> ptr;

		Logger(const std::string & name = "root");

		void log(LogLevel::Level level, LogEvent::ptr event);

		/* 五種日誌級別 */
		void debug(LogEvent::ptr event);
		void info(LogEvent::ptr event);
		void warn(LogEvent::ptr event);
		void error(LogEvent::ptr event);
		void fatal(LogEvent::ptr event);

		/* 新增和刪除Appender */
		void addAppender(LogAppender::ptr event);
		void delAppender(LogAppender::ptr event);

		/* 獲得level和設定level */
		LogLevel::Level getLevel() const { return m_level; }
		void setLevel(LogLevel::Level val) { m_level = val; }

		std::string getName() const { return m_name; }
	private:
		std::string m_name;							//日誌名字
		LogLevel::Level m_level;					//日誌級別
		std::list<LogAppender::ptr> m_appenders;	//Appender集合
		LogFormatter::ptr m_formatter;				//初始化formatter
	};

7.輸出到控制檯

//輸出到控制檯
	class StdoutLogAppender : public LogAppender {
	public:
		typedef std::shared_ptr<StdoutLogAppender> ptr;
		void log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override;  /* 父類繼承過載實現 */
	};

8.輸出到檔案

//輸出到檔案
	class FileLogAppender : public LogAppender {
	public:
		typedef std::shared_ptr<FileLogAppender> ptr;

		FileLogAppender(const std::string & filename);

		void log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override;  /* 父類繼承過載實現 */

		bool reopen();
	private:
		std::string m_filename;
		std::ofstream m_filestream; //寫檔案
	};

三、測試程式碼

sylar::Logger::ptr logger(new sylar::Logger);

	logger->addAppender(sylar::LogAppender::ptr(new sylar::StdoutLogAppender));
	SYLAR_LOG_DEBUG(logger) << "zcy";
	SYLAR_LOG_INFO(logger) << "zcy";
	SYLAR_LOG_WARN(logger) << "zcy";
	SYLAR_LOG_ERROR(logger) << "zcy";
	SYLAR_LOG_FATAL(logger) << "zcy";
#define SYLAR_LOG_LEVEL(logger,level) \
	if(logger->getLevel() <= level) \
		zcy::LogEventWrap(zcy::LogEvent::ptr(new zcy::LogEvent(logger,level,\
			__FILE__, __LINE__, 0, 1, 2, time(0)))).getSS()

#define SYLAR_LOG_DEBUG(logger) SYLAR_LOG_LEVEL(logger, zcy::LogLevel::DEBUG)
#define SYLAR_LOG_INFO(logger) SYLAR_LOG_LEVEL(logger, zcy::LogLevel::INFO)
#define SYLAR_LOG_WARN(logger) SYLAR_LOG_LEVEL(logger, zcy::LogLevel::WARN)
#define SYLAR_LOG_ERROR(logger) SYLAR_LOG_LEVEL(logger,zcy::LogLevel::ERROR)
#define SYLAR_LOG_FATAL(logger) SYLAR_LOG_LEVEL(logger,zcy::LogLevel::FATAL)

在這裡插入圖片描述
完整程式碼連結
提取碼: a3b3