forked from skyfireitdiy/sflib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsf_logger.h
217 lines (175 loc) · 6.04 KB
/
sf_logger.h
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
/**
* @version 1.0.0
* @author skyfire
* @mail [email protected]
* @see http://github.com/skyfireitdiy/sflib
* @file sf_logger.h
* sflib第一版本发布
* 版本号1.0.0
* 发布日期:2018-10-22
*/
/*
* sf_logger日志打印
*/
#pragma once
#include <fstream>
#include <iostream>
#include <sstream>
#include <mutex>
#include <map>
#include <ctime>
#include <iomanip>
#include <functional>
#include <thread>
#include <condition_variable>
#include <deque>
#include <atomic>
#include <unordered_map>
#include <climits>
#include <shared_mutex>
#include <thread>
#ifdef QT_CORE_LIB
#include <QString>
#endif
// 独立使用
#ifdef SF_LOGGER_STANDALONE
namespace skyfire{
class sf_empty_class{};
}
#define SF_SINGLE_TON(ClassName) \
ClassName(const ClassName&) = delete; \
ClassName(ClassName&&) = delete; \
ClassName& operator=(const ClassName&) = delete; \
static ClassName* get_instance() \
{ \
static std::mutex init_mutex; \
static ClassName* instance__{ nullptr }; \
if(instance__==nullptr){ \
std::lock_guard<std::mutex> lck(init_mutex); \
if (instance__ == nullptr) \
{ \
instance__ = new ClassName; \
} \
} \
return instance__; \
} \
#else
#include "sf_random.hpp"
#include "sf_single_instance.hpp"
#include "sf_empty_class.hpp"
#endif
namespace skyfire
{
/**
* @brief 日志等级
*/
enum SF_LOG_LEVEL
{
SF_DEBUG_LEVEL = 0,
SF_INFO_LEVEL = 1,
SF_WARN_LEVEL = 2,
SF_ERROR_LEVEL = 3,
SF_FATAL_LEVEL = 4
};
/**
* @brief 日志信息
*/
struct sf_logger_info_t__
{
SF_LOG_LEVEL level; // 日志等级
std::string time; // 时间
int line; // 行号
std::string file; // 文件名称
std::thread::id thread_id; // 线程号
std::string func; // 函数名称
std::string msg; // 消息
};
/**
* @brief 默认日志格式
*/
constexpr char sf_default_log_format[] = "[{level}][{time}][{thread}][{file} ({line}) {func}] --> {msg}\n";
/**
* 日志类
* @tparam _Base 基类(默认为empty_class)
*/
template<typename _Base = sf_empty_class>
class sf_logger__ : public _Base
{
public:
SF_SINGLE_TON(sf_logger__)
/**
* 添加指定等级的回调函数
* @param level 等级
* @param func 函数
* @return id号(可用于移除回调)
*/
int add_level_func(SF_LOG_LEVEL level, std::function<void(const sf_logger_info_t__ &)> func);
/**
* 添加指定等级日志输出流
* @param level 等级
* @param os 输出流
* @param format 格式化字符串
* @return id号(可用于移除回调)
*/
int add_level_stream(SF_LOG_LEVEL level, std::ostream *os, std::string format = sf_default_log_format);
/**
* 添加指定等级日志输出文件
* @param level 等级
* @param filename 文件名
* @param format 格式化字符串
* @return id号(可用于移除回调)
*/
int add_level_file(SF_LOG_LEVEL level, const std::string &filename, std::string format = sf_default_log_format);
/**
* 根据id删除过滤器
* @param key id
*/
void remove_filter(int key);
template<typename T>
void logout(SF_LOG_LEVEL level, const std::string &file, int line, const std::string &func, const T &dt);
template<typename...T>
void logout(SF_LOG_LEVEL level, const std::string &file, int line, const std::string &func, const T &...dt);
void stop_logger();
void empty_func__(){}
std::string format(std::string format_str, const sf_logger_info_t__& log_info);
private:
std::deque<sf_logger_info_t__> log_deque__;
std::mutex cond_mu__;
std::condition_variable cond__;
std::mutex deque_mu__;
std::map<int, std::unordered_map<int ,std::function<void(const sf_logger_info_t__ &)>>> logger_func_set__;
std::atomic<bool> run__ {true};
std::recursive_mutex func_set_mutex__;
bool check_key_can_use__(int key);
int make_random_logger_id__();
std::map<SF_LOG_LEVEL, std::string> logger_level_str__{
{SF_DEBUG_LEVEL, "DEBUG"},
{SF_INFO_LEVEL, "INFO "},
{SF_WARN_LEVEL, "WARN "},
{SF_ERROR_LEVEL, "ERROR"},
{SF_FATAL_LEVEL, "FATAL"},
};
sf_logger__();
template<typename T, typename...U>
void logout__(std::ostringstream &oss, sf_logger_info_t__ &log_info, const T &tmp, const U &...tmp2);
#ifdef QT_CORE_LIB
template<typename...U>
void logout__(std::ostringstream &oss, sf_logger_info_t__ &log_info, const QString &tmp, const U &...tmp2);
//template<>
void logout__(std::ostringstream &oss, sf_logger_info_t__ &log_info, const QString &tmp);
#endif
template<typename T>
void logout__(std::ostringstream &oss, sf_logger_info_t__ &log_info, const T &tmp);
static std::string make_time_str__();
};
using sf_logger = sf_logger__<>;
#ifdef SF_DEBUG
#define sf_debug(...) skyfire::g_logger->logout(skyfire::SF_DEBUG_LEVEL,__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__)
#else
#define sf_debug(...) skyfire::g_logger->empty_func__()
#endif
#define sf_info(...) skyfire::g_logger->logout(skyfire::SF_INFO_LEVEL,__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__)
#define sf_warn(...) skyfire::g_logger->logout(skyfire::SF_WARN_LEVEL,__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__)
#define sf_error(...) skyfire::g_logger->logout(skyfire::SF_ERROR_LEVEL,__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__)
#define sf_fatal(...) skyfire::g_logger->logout(skyfire::SF_FATAL_LEVEL,__FILE__,__LINE__,__FUNCTION__,__VA_ARGS__)
}