仿muduo日志库:c++小巧日志库实现
- 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#pragma once #include <iostream> #include <chrono> #include <string.h> #include "log_stream.h" class Logger { public: /** * @brief 日志等级 */ enum LogLevel { TRACE, DEBUG, INFO, WARN, ERROR, FATAL, NUM_LOG_LEVELS, }; //compile time calculation of basename of source file /** * @brief 获取日志打印所在文件 */ class SourceFile { public: template<int N> inline SourceFile(const char(&arr)[N]) :m_data(arr), m_size(N - 1) { const char* slash = strrchr(m_data, '/'); // builtin function if (slash) { m_data = slash + 1; m_size -= static_cast<int>(m_data - arr); } } explicit SourceFile(const char* filename) : m_data(filename) { const char* slash = strrchr(filename, '/'); if (slash) { m_data = slash + 1; } m_size = static_cast<int>(strlen(m_data)); } const char* m_data; // 当前字符串 int m_size; // 当前字符串大小 }; /** * @brief Logger构造 * @param p_file:所在文件 * @param p_nline:所在行 */ Logger(SourceFile p_file, int p_nline); /** * @brief Logger构造 * @param p_file:所在文件 * @param p_nline:所在行 * @param p_enumLevel:日志等级 */ Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel); /** * @brief Logger构造 * @param p_file:所在文件 * @param p_nline:所在行 * @param p_enumLevel:日志等级 * @param p_func: 附带字符串 */ Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel, const char* p_func); /** * @brief Logger构造 * @param p_file:所在文件 * @param p_nline:所在行 * @param p_btoAbort: 布尔判断:传true:FATAL false:ERROR */ Logger(SourceFile p_file, int p_nline, bool p_btoAbort); ~Logger(); /** * @brief 设置日志等级 * @param p_enumLevel:日志等级 */ static void setLogLevel(LogLevel p_enumLevel); /** * @brief 获取日志等级 */ static LogLevel logLevel(); /** * @brief 获取输出字符串流 */ LogStream& stream() { return m_impl.m_stream; } typedef void (*outputFunc)(const char* msg, int len); typedef void (*flushFunc)(); /** * @brief 设置Output回调 */ static void setOutput(outputFunc); /** * @brief 设置flushFunc回调 */ static void setFlush(flushFunc); private: Logger(const Logger& lg); //no copyable Logger& operator=(const Logger& lg); class Impl { public: typedef Logger::LogLevel LogLevel; /** * @brief Impl构造 * @param p_enumLevel:日志等级 * @param p_nOldErrno: 错误码 * @param p_file:所在文件 * @param p_nline:所在行 */ Impl(LogLevel p_enumLevel, int p_nOldErrno, const SourceFile& p_file, int p_nline); /** * @brief 获取当前时间,精确到纳秒 */ void formatTime(); /** * @brief 结束符-换行 */ void finish(); std::chrono::system_clock::time_point m_time; // 时间参数 LogStream m_stream; // 字符串流 LogLevel m_level; // 日志等级 int m_line; // 行号 SourceFile m_fileBaseName; // 文件名 }; Impl m_impl; // }; #define log_trace if (Logger::logLevel() <= Logger::TRACE) Logger(__FILE__, __LINE__, Logger::TRACE, __func__).stream() #define log_info if (Logger::logLevel() <= Logger::INFO) Logger(__FILE__, __LINE__).stream() #define log_warn Logger(__FILE__, __LINE__, Logger::WARN).stream() #define log_debug Logger(__FILE__, __LINE__, Logger::DEBUG).stream() #define log_error Logger(__FILE__, __LINE__, Logger::ERROR).stream() #define log_fatal Logger(__FILE__, __LINE__, Logger::FATAL).stream() #define log_syserr Logger(__FILE__, __LINE__, false).stream() #define log_sysfatal Logger(__FILE__, __LINE__, true).stream()
- logger.cpp
复制代码
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//Logger #define _CRT_SECURE_NO_WARNINGS #include <time.h> #include <stdint.h> #include <stdlib.h> #include <assert.h> #include <stdio.h> #include <errno.h> #include <string.h> #include "logger.h" #include <ctime> #include <sstream> Logger::LogLevel g_logLevel = Logger::INFO; void Logger::setLogLevel(LogLevel p_enumLevel) { g_logLevel = p_enumLevel; } Logger::LogLevel Logger::logLevel() { return g_logLevel; } const char* LogLevelName[Logger::NUM_LOG_LEVELS] = { "[TRACE]", "[DEBUG]", "[INFO ]", "[WARN ]", "[ERROR]", "[FATAL]", }; // helper class for known string length at compile time class T { public: T(const char* str, unsigned len) :m_str(str), m_len(len) { assert(strlen(str) == m_len); } const char* m_str; const unsigned m_len; }; void defaultOutput(const char* msg, int len) { size_t n = fwrite(msg, 1, len, stdout); (void)n; } void defaultFlush() { fflush(stdout); } Logger::outputFunc g_output = defaultOutput; Logger::flushFunc g_flush = defaultFlush; void Logger::setOutput(outputFunc out) { g_output = out; } void Logger::setFlush(flushFunc flush) { g_flush = flush; } Logger::Logger(SourceFile p_file, int p_nline) : m_impl(INFO, 0, p_file, p_nline) { } Logger::Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel) : m_impl(p_enumLevel, 0, p_file, p_nline) { } Logger::Logger(SourceFile p_file, int p_nline, bool p_btoAbort) : m_impl(p_btoAbort ? FATAL : ERROR, errno, p_file, p_nline) { } Logger::Logger(SourceFile p_file, int p_nline, LogLevel p_enumLevel, const char* p_func) : m_impl(p_enumLevel, 0, p_file, p_nline) { m_impl.m_stream << '[' << p_func << "] "; } Logger::~Logger() { m_impl.finish(); const LogStream::Buffer& buf(stream().buffer()); g_output(buf.data(), buf.length()); // FATAL 致命bug日志,程序崩溃 if (m_impl.m_level == FATAL) { g_flush(); //abort(); } } Logger::Impl::Impl(LogLevel p_enumLevel, int p_nOldErrno, const SourceFile& p_file, int p_nline) : m_time(std::chrono::system_clock::now()), m_stream(), m_level(p_enumLevel), m_fileBaseName(p_file), m_line(p_nline) { formatTime(); m_stream << LogLevelName[p_enumLevel] << ' '; m_stream << '[' << m_fileBaseName.m_data << ':' << m_line << "] "; std::ostringstream oss; oss << std::this_thread::get_id(); m_stream << '[' << oss.str().c_str() << "] "; if (p_nOldErrno != 0) { m_stream /*<< strerror_tl(savedErrno)*/ << " (errno=" << p_nOldErrno << ") "; } } void Logger::Impl::finish() { m_stream << 'n'; } void Logger::Impl::formatTime() { auto tt = std::chrono::system_clock::to_time_t(m_time); struct tm* ptm = localtime(&tt); auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(m_time.time_since_epoch()) % 1000; auto cs = std::chrono::duration_cast<std::chrono::microseconds>(m_time.time_since_epoch()) % 1000000; auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(m_time.time_since_epoch()) % 1000000000; char date[128] = { 0 }; sprintf(date, "[%d-%02d-%02d %02d:%02d:%02d:%03ld:%03ld:%03ld] ", (int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday, (int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec, ms.count(), cs.count() % 1000, ns.count() % 1000); m_stream << date; }
- log_stream.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#pragma once #include <stdio.h> #include <string.h> #include <thread> const int kSmallBuffer = 4096; const int kLargeBuffer = 4096; template<int SIZE> class LogBuffer { public: LogBuffer() : m_cur(m_data) {} ~LogBuffer() {} /** * @brief 拼接字符串 * @param p_chBuf: 字符串 * @param p_nlen: 字符串长度 */ void append(const char* p_chBuf, size_t p_nlen) { // append partially if ((avail()) > p_nlen) { memcpy(m_cur, p_chBuf, p_nlen); m_cur += p_nlen; } } // write in m_data directly /** * @brief 获取当前字符串 */ char* current() { return m_cur; }; /** * @brief 判断当前追加字符串是否超过最大限制 */ int avail() const { return static_cast<int> (end() - m_cur); } /** * @brief 字符串偏移 * @param p_nlen: 偏移量 */ void add(size_t p_nlen) { m_cur += p_nlen; } /** * @brief 获取长度 */ int length() const { return m_cur - m_data; } /** * @brief 获取字符串 */ const char* data() const { return m_data; } private: /** * @brief 获取字符串最后位置节点 */ const char* end() const { return m_data + sizeof(m_data); } char m_data[SIZE]; // 输出日志的char数组 char* m_cur; // 传入字符串 }; class LogStream { public: LogStream(); ~LogStream(); using Buffer = LogBuffer<kSmallBuffer>; using self = LogStream; /** * @ 一系列重载 */ self& operator<<(bool v); self& operator<<(short); self& operator<<(unsigned short); self& operator<<(int); self& operator<<(unsigned int); self& operator<<(long); self& operator<<(unsigned long); self& operator<<(long long); self& operator<<(unsigned long long); self& operator<<(const void*); self& operator<<(float v); self& operator<<(double); self& operator<<(char v); self& operator<<(const char*); /** * @brief 往流缓存追加字符串 * @param p_chData:字符串 * @param p_nlen:字符串长度 */ void append(const char* p_chData, int p_nlen) { return m_buffer.append(p_chData, p_nlen); } /** * @brief 获取流缓存 */ const Buffer& buffer() const { return m_buffer; } private: LogStream(const LogStream& ls); //no copyable LogStream& operator=(const LogStream& ls); template<typename T> void formatInteger(T v); Buffer m_buffer; // 流缓存 static const int kMaxNumericSize = 32; }; class Fmt { public: template<typename T> Fmt(const char* fmt, T val); const char* data() const { return m_buf; } int length() const { return m_length; } private: char m_buf[32]; // 字符串 int m_length; // 字符串长度 }; /** * @brief 追加流(实现与cout一样输出格式的关键) * @param p_stLog: 流 * @param p_fmt:格式化类 */ inline LogStream& operator<<(LogStream& p_stLog, const Fmt& p_fmt) { p_stLog.append(p_fmt.data(), p_fmt.length()); return p_stLog; }
- log_stream.cpp
复制代码
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//LogStream #include <stdio.h> #include <assert.h> #include <algorithm> #include "log_stream.h" LogStream::LogStream() {} LogStream::~LogStream() {} LogStream& LogStream::operator<<(bool v) { m_buffer.append(v ? "1" : "0", 1); return *this; } LogStream& LogStream::operator<<(short v) { *this << static_cast<int>(v); return *this; } LogStream& LogStream::operator<<(unsigned short v) { *this << static_cast<unsigned int>(v); return *this; } LogStream& LogStream::operator<<(int v) { formatInteger(v); return *this; } LogStream& LogStream::operator<<(unsigned int v) { formatInteger(v); return *this; } LogStream& LogStream::operator<<(long v) { formatInteger(v); return *this; } LogStream& LogStream::operator<<(unsigned long v) { formatInteger(v); return *this; } LogStream& LogStream::operator<<(long long v) { formatInteger(v); return *this; } LogStream& LogStream::operator<<(unsigned long long v) { formatInteger(v); return *this; } LogStream& LogStream::operator<<(const void*) { printf("undefinen"); return *this; } LogStream& LogStream::operator<<(float v) { *this << static_cast<double>(v); return *this; } LogStream& LogStream::operator<<(double v) { if (m_buffer.avail() >= kMaxNumericSize) { int len = snprintf(m_buffer.current(), kMaxNumericSize, "%.12g", v); m_buffer.add(len); } return *this; } LogStream& LogStream::operator<<(char v) { m_buffer.append(&v, 1); return *this; } LogStream& LogStream::operator<<(const char* str) { if (str) { m_buffer.append(str, strlen(str)); } else { m_buffer.append("(NULL)", 6); } return *this; } const char digits[] = "9876543210123456789"; const char* zero = digits + 9; //convert to str template<typename T> size_t convert(char buf[], T value) { T i = value; char* p = buf; do { int lsd = static_cast<int>(i % 10); i /= 10; *p++ = zero[lsd]; } while (i != 0); if (value < 0) { *p++ = '-'; } *p = ''; std::reverse(buf, p); return p - buf; } template<typename T> void LogStream::formatInteger(T v) { if (m_buffer.avail() >= kMaxNumericSize) { size_t len = convert(m_buffer.current(), v); m_buffer.add(len); } } template<typename T> Fmt::Fmt(const char* fmt, T val) { m_length = snprintf(m_buf, sizeof(m_buf), fmt, val); assert(static_cast<size_t>(m_length) < sizeof(m_buf)); } // Explicit instantiations template Fmt::Fmt(const char* fmt, char); template Fmt::Fmt(const char* fmt, short); template Fmt::Fmt(const char* fmt, unsigned short); template Fmt::Fmt(const char* fmt, int); template Fmt::Fmt(const char* fmt, unsigned int); template Fmt::Fmt(const char* fmt, long); template Fmt::Fmt(const char* fmt, unsigned long); template Fmt::Fmt(const char* fmt, long long); template Fmt::Fmt(const char* fmt, unsigned long long); template Fmt::Fmt(const char* fmt, float); template Fmt::Fmt(const char* fmt, double);
- main.cpp
复制代码
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#include "logger.h" int main() { // 计时 auto begintime = std::chrono::system_clock::now(); auto func_Print = []() ->void { for (int i = 0; i < 3; ++i) { log_info << "1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs."; log_debug << "2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test."; log_error << "3、这只是其中一部分。это только часть .これはほんの一部です。This is just part of it.Das ist nur ein Teil davon."; log_fatal << "4、Это тест.これはテストです,this is a test, Das ist ein Test."; } }; std::thread j1print(func_Print); std::thread j2print(func_Print); std::thread j3print(func_Print); if (j1print.joinable()) j1print.join(); if (j2print.joinable()) j2print.join(); if (j3print.joinable()) j3print.join(); auto endtime = std::chrono::system_clock::now(); auto TimeCount = std::chrono::duration<double, std::milli>(endtime - begintime).count(); log_info << "**************************************程序运行所用时间:" << TimeCount << "ms.**************************************"; return 0; }
- 打印输出
复制代码
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[2022-11-17 20:20:17:582:739:100] [FATAL] [F:VsProjectsloglog.cpp:15] [5504] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:582:456:500] [DEBUG] [F:VsProjectsloglog.cpp:13] [9680] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:582:802:900] [INFO ] [F:VsProjectsloglog.cpp:12] [20120] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs. [2022-11-17 20:20:17:582:879:000] [ERROR] [F:VsProjectsloglog.cpp:14] [9680] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:582:879:700] [INFO ] [F:VsProjectsloglog.cpp:12] [5504] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs. [2022-11-17 20:20:17:582:982:400] [FATAL] [F:VsProjectsloglog.cpp:15] [9680] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:582:939:100] [DEBUG] [F:VsProjectsloglog.cpp:13] [20120] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:583:067:400] [DEBUG] [F:VsProjectsloglog.cpp:13] [5504] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:583:239:100] [ERROR] [F:VsProjectsloglog.cpp:14] [20120] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:583:112:100] [INFO ] [F:VsProjectsloglog.cpp:12] [9680] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs. [2022-11-17 20:20:17:583:316:600] [ERROR] [F:VsProjectsloglog.cpp:14] [5504] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:584:568:000] [FATAL] [F:VsProjectsloglog.cpp:15] [5504] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:584:265:200] [DEBUG] [F:VsProjectsloglog.cpp:13] [9680] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:583:647:400] [FATAL] [F:VsProjectsloglog.cpp:15] [20120] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:585:002:800] [INFO ] [F:VsProjectsloglog.cpp:12] [5504] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs. [2022-11-17 20:20:17:589:688:300] [DEBUG] [F:VsProjectsloglog.cpp:13] [5504] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:589:930:600] [ERROR] [F:VsProjectsloglog.cpp:14] [5504] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:589:356:900] [INFO ] [F:VsProjectsloglog.cpp:12] [20120] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs. [2022-11-17 20:20:17:588:917:900] [ERROR] [F:VsProjectsloglog.cpp:14] [9680] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:590:575:100] [FATAL] [F:VsProjectsloglog.cpp:15] [9680] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:590:112:200] [FATAL] [F:VsProjectsloglog.cpp:15] [5504] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:590:371:700] [DEBUG] [F:VsProjectsloglog.cpp:13] [20120] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:594:118:200] [INFO ] [F:VsProjectsloglog.cpp:12] [9680] 1、演讲的名字。название лекции.スピーチの名前。The names for the discourse.Die bezeichnungen für den diskurs. [2022-11-17 20:20:17:594:105:500] [ERROR] [F:VsProjectsloglog.cpp:14] [20120] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:594:282:000] [DEBUG] [F:VsProjectsloglog.cpp:13] [9680] 2、这是一个测试,Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:594:575:900] [FATAL] [F:VsProjectsloglog.cpp:15] [20120] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:594:619:600] [ERROR] [F:VsProjectsloglog.cpp:14] [9680] 3、这只是其中一部分。это только часть?.これはほんの一部です。This is just part of it.Das ist nur ein Teil davon. [2022-11-17 20:20:17:596:351:200] [FATAL] [F:VsProjectsloglog.cpp:15] [9680] 4、Это тест.これはテストです,this is a test, Das ist ein Test. [2022-11-17 20:20:17:596:792:800] [INFO ] [F:VsProjectsloglog.cpp:33] [20084] **************************************程序运行所用时间:25.8867ms.**************************************
参考链接: 一个轻巧高效的多线程c++stream风格异步日志(一)
最后
以上就是鲜艳绿草最近收集整理的关于仿muduo日志库:c++小巧日志库实现仿muduo日志库:c++小巧日志库实现的全部内容,更多相关仿muduo日志库内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复