wtlog日志库整体设计

wtlog日志库由前后端两部分组成,前端Logger是日志信息的入口,负责将原始的日志信息格式化成相应的日志格式,然后传递给日志接收端Sinker,后端的日志接收端负责将接收到的日志按照预定的方式写入到目标位置,比如磁盘文件或是终端等。
日志的传递通过Carrier类进行封装,一条日志在进入Logger后,直到写入目标位置前都会封装在某个Carrier中。

Logger

Logger应该由一个日志工厂统一进行创建和管理,避免直接向外暴露创建接口,在外部提供接口函数来屏蔽和简化创建过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class Logger {
public:
Logger() = default;

virtual ~Logger();

public:
void attachSinker(std::shared_ptr<sinks::Sinker> sinker);

void detachSinker(std::shared_ptr<sinks::Sinker> sinker);

void setCarrier(std::shared_ptr<details::Carrier> carrier);

void setTimePrecision(wtlog::utils::Clock::Unit precision);

void setLevel(const LogLevel level);

LogLevel level() const;

virtual void log(std::string_view raw_msg);

protected:
void send2Backend();

std::string enrich(std::string_view raw_msg);
};

class LogGenerator {
private:
LogGenerator() = default;

LogGenerator(const LogGenerator&) = delete;

LogGenerator(LogGenerator&&) noexcept = delete;

~LogGenerator() = default;

public:
static LogGenerator& instance();

template<typename Logger, typename... Args, typename = std::enable_if_t<std::is_constructible_v<Logger, Args...>>>
std::shared_ptr<Logger> create(Args&&... args) {
return m_loggers.emplace_back(std::make_shared<Logger>(std::forward<Args>(args)...));
}

template<typename... Args>
void log(const LogLevel level, std::string_view fmt, Args&&... args) {
// auto format_args = ;
auto message = std::vformat(fmt, std::make_format_args(std::forward<Args&>(args)...));
for(auto& logger : m_loggers) {
if(logger->level() <= level) {
logger->log(message);
}
}
}

private:
inline static std::vector<std::shared_ptr<Logger>> m_loggers{};
};

Sinker

后端负责接收处理好的日志信息,并将其写入目标位置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Sinker {
public:
virtual ~Sinker() = default;

virtual void collect(Pointer<details::Carrier> carrier) {
m_carrier = carrier;
flush();
};

virtual void flush() = 0;

protected:
Pointer<details::Carrier> m_carrier{ nullptr };
};

Logger通过一个中介者来与相关联的后端接收器传递日志:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class SinkSplitter {
protected:
SinkSplitter() = default;

SinkSplitter(const SinkSplitter&) = delete;

SinkSplitter(SinkSplitter&&) = delete;

public:
~SinkSplitter() = default;

public:
static Pointer<SinkSplitter> instance();

ui64_t registerSink(Pointer<Sinker> sinker);

ui64_t unregisterSink(Pointer<Sinker> sinker);

void distribute(Pointer<details::Carrier> carrier, const std::vector<ui64_t>& sinks_no);

private:
std::unordered_map<ui64_t, std::shared_ptr<Sinker>> m_sinks{};
};

Logger中提供对应的方法将接收器进行注册绑定,然后需要发送日志时,调用分流器的distribute()方法将日志转发给相应的若干接收器。

Carrier

Carrier是负责传递日志的中间媒介,负责日志信息的缓存和读取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Carrier {
public:
enum class Status : char {
valid,
ready
};

public:
virtual ~Carrier() = default;

public:
virtual Status state() const = 0;

virtual std::string_view content() = 0;

virtual ui64_t store(std::string_view msg) = 0;

virtual Pointer<Carrier> transfer() = 0;

virtual bool empty() = 0;
};