#ifndef __SYLAR_LOG_H__
#define __SYLAR_LOG_H__
#include<iostream>
#include<string>
#include<stdint.h>//为了使用int32_t
#include<memory>//为了使用shared_ptr
#include<list>
#include<vector>
#include<sstream>
#include<fstream>//为了使用std::ofstream m_filestream;
namespace sylar//为了区分和别人的代码里有重名的一些内容
{
//每个日志在生成出来的时候,把它定义成LogEvent,这样的话,把它里面所要用的属性、字段等,都放里面。
//日志事件
class LogEvent
{
public:
//使用了C++11中的智能指针,方便内存管理
typedef std::shared_ptr<LogEvent> ptr;
LogEvent();
private:
const char *m_file = nullptr;//文件名 //nullptr:C++11内容
int32_t m_line = 0; //行号
uint32_t m_elapse = 0; //程序启动开始到现在的毫秒数
int m_threadId = 0; //线程号
uint32_t m_fiberId = 0; //协程号 //因为是协程库,所以还要有一个协程
uint64_t m_time; //时间戳
std::string m_content; //消息内容
};
//日志级别
class LogLevel
{
public:
//定义日志级别
//弹幕:日志级别完全可以用策略模式?为了以后的多种功能
enum Level
{
DEBUG = 1,
INFO = 2,
WARN = 3,
ERROR = 4,
FATAL = 5
};
};
//日志格式器
//目前只有一种Formatter,那么先只有一个Formatter
class LogFormatter
{
public:
typedef std::shared_ptr<LogFormatter> ptr;
//当pattern赋值的狮虎,我们会根据pattern的格式来解析出它里面的item的信息
LogFormatter(const std::string& pattern);
//格式示例:%t %thread_id %m%n
std::string format(LogEvent::ptr event);//把formatter的一个string提供给Appender输出
//创建一个日志解析的子模块,定义成一个FormatItem的抽象类,再定义它的子类用来实现
private:
class FormatItem
{
public:
typedef std::shared_ptr<FormatItem> ptr;
virtual ~FormatItem(){}
//使用ostream作为输出,不再使用std::string 来作为返回值,因为它会多个组合起来
//这样性能会更好一点
virtual void format(std::ostream os,LogEvent::ptr event) = 0;
};
void init();//init方法来做pattern的解析
//定义很多种具体的子类,每个子类负责输出一部分
private:
std::string m_pattern;//输出formatter结构
std::vector<FormatItem> m_items;
private:
};
//日志输出的地址
//可以输出到控制台、文件、网络等...
//这里实现文控制台(STD)、文件的....
//先定义一个基类,里面只有一个纯虚函数log,这样它的子类就必须实现这个方法
class LogAppender
{
public:
typedef std::shared_ptr<LogAppender> ptr;
//因为日志输出地址有很多,所以把它定义成一个虚类
//定义一个虚析构函数,让子类在继承的时候继承它,
//如果不写成虚析构函数,那么它的子类在释放的时候,可能会产生释放的问题
virtual ~LogAppender(){};
virtual void log(LogLevel::Level level, LogEvent::ptr event) = 0;
//设置formatter的方法
void setFormatter(LogFormatter::ptr val){ m_formatter = val; }
//获取formatter的方法
LogFormatter::ptr getFormatter()const{ return m_formatter; }
protected://由于是虚拟的基类,有可能要用到它的level,所以基类中的属性应该是个protected,这样的话,子类就可以使用到
LogLevel::Level m_level;//主要针对哪些日志来定义的级别
//Appender里面还有一个Formatter对象,这个formatter是定义要输出的格式
//可能有的输出格式要把线程、文件都输出出来,而有的不需要输出这些
//以及时间格式是如何定义的都可能不一样
//所以在这里定义一个LogFormatter
LogFormatter::ptr m_formatter;
};
//日志(输出)器
//只有满足了日志级别的日志才会被输出
class Logger
{
public:
typedef std::shared_ptr<Logger> ptr;//
//弹幕:成员函数能够直接初始化是C++11开始就支持的特性,
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);
//添加和删除日志级别
void addAppender(LogAppender::ptr appender); //添加Appender
void delAppender(LogAppender::ptr appender); //删除Appender
LogLevel::Level getLevel()const{ return m_level;} //获取日志级别
void setLevel(LogLevel::Level val){ m_level = val; }//设置日志级别
private:
std::string m_name; //日志名称
LogLevel::Level m_level; //日志级别,只有满足了日志级别的日志才会被输出
std::list<LogAppender::ptr> m_appenders; //Appender是输出到目的地的集合,这里用一个链来实现表
};
//输出到控制台(Std)的Appender
class StdoutLogAppender : public LogAppender
{
public:
//1.先定义出智能指针,后面很多时候,都是用智能指针来操作的
typedef std::shared_ptr<StdoutLogAppender> ptr;
//2.实现基类的抽象函数log
//从父类继承的函数的实现,可以用override来描述
void log(LogLevel::Level level, LogEvent::ptr event) override;
private:
};
//定义输出到文件的Appender
class FileLogAppender : public LogAppender
{
//1.先定义智能指针
typedef std::shared_ptr<FileLogAppender> ptr;
//2.实现基类的抽象函数log
//从父类继承的函数的实现,可以用override来描述
FileLogAppender(const std::string& filename);//FileLog跟StdLog不一样,因为它要输出到文件里,因此它需要一个文件名
void log(LogLevel::Level level, LogEvent::ptr event) override;
//重新打开文件,重新打开成功返回true
bool reopen();
private:
std::string m_filename;
std::ofstream m_filestream;//用流的方式去输出
};
}
#endif //__SYLAR_LOG_H__
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
#include"Log.h"
namespace sylar
{
Logger::Logger(const std::string &name = "root") : m_name(name)
{
}
void Logger::addAppender(LogAppender::ptr appender) //添加Appender
{
m_appenders.push_back(appender);//这里先不考虑线程安全,等后面线程库做出来之后再考虑
}
void Logger::delAppender(LogAppender::ptr appender) //删除Appender
{
//利用遍历的方式删除日志输出地址
for (auto it = m_appenders.begin();//auto 是C++11 的内容
it != m_appenders.end();++it)
{
if (*it == appender)
{
m_appenders.erase(it);
break;
}
}
}
void Logger::log(LogLevel::Level level, LogEvent::ptr & event)
{
if (level >= m_level)//就开始输出
{
//输出就是要输出到每个appender里去
//因此,就遍历每个appenders,然后再用appender把它输出出来
for (auto & i : m_appenders)
{
i->log(level, event);
}
}
else
{
}
}
//定义五种级别的日志
//下面的这几个方法,都是利用上面的Logger::log方法来实现的,只是为了便捷
//就像有的人喜欢用相应日志级别的函数输出,而不喜欢加 LogLevel
void Logger::debug(LogEvent::ptr event)
{
debug(LogLevel::DEBUG, event);
}
void Logger::info(LogEvent::ptr event)
{
debug(LogLevel::INFO event);
}
void Logger::warn(LogEvent::ptr event)
{
debug(LogLevel::WARN, event);
}
void Logger::error(LogEvent::ptr event)
{
debug(LogLevel::ERROR, event);
}
void fatal(LogEvent::ptr event)
{
debug(LogLevel::FATAL, event);
}
FileLogAppender::FileLogAppender(const std::string& filename)
:m_filename(filename)
{
}
void FileLogAppender::log(LogLevel::Level level, LogEvent::ptr event)
{
if (level >= m_level)
{
m_filestream << m_formatter.format(event);//把文件按照我们需要的方式输出出来
}
}
bool FileLogAppender::reopen()
{
if (m_filestream)//如果为true,就说明是已经打开的状态
{
m_filestream.close();//先关闭
}
m_filestream.open(m_filename);//再打开
return !!m_filestream;
}
void StdoutLogAppender::log(LogLevel::Level level, LogEvent::ptr event)
{
if (level >= m_level)
{
//初始化完成后,一定会有一个formatter
//使用formatter把日志序列化
if (level >= m_level)
{
std::cout << m_formatter.format(event);
}
}
}
LogFormatter::LogFormatter(const std::string &pattern)
:m_pattern(pattern)
{
}
std::string LogFormatter::format(LogEvent::ptr event)
{
std::stringstream ss;
for (auto& i :m_items)
{
i->format(ss, event);
}
return ss.str();
}
//两种格式:
//1.%xxx
//2.%xxx{xxx}
//3. %%
void LogFormatter::init()
{
std::vector<std::pair<std::string, int>> vec;
size_t last_pos = 0;
for (size_t i = 0; i < m_pattern.size();++i)
{
if (m_pattern[i] == '%')
{
if ((i + 1) < m_pattern.size())
{
}
}
}
}
}
标签:std,void,系统,event,LogEvent,日志,ptr
From: https://www.cnblogs.com/Epiephany/p/17107378.html