liunx伺服器-日誌模組設計
阿新 • • 發佈:2021-01-18
技術標籤: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