【Project】sylar——C++高性能服务器框架

tiny_star Lv3

本文记录了学习和实现 sylar——C++高性能服务器框架的笔记,包含日志模块,配置模块,线程模块,协程模块,协程调度模块,io协程调度模块,hook模块,socket模块,bytearray序列化,http模块,TcpServer模块,Websocket模块,Https模块等,Smtp邮件模块,MySQL,SQLite3,ORM,Redis,Zookeeper。后续可能会对其进行扩展🤓

项目介绍

来源:本科学长推荐

视频学习:[C++高级教程]从零开始开发服务器框架(sylar)_哔哩哔哩_bilibili

博主主页:http://www.sylar.top

项目地址:https://github.com/sylar-yin/sylar

开发环境

Ubuntu 22.04.2 LTS gcc 11.4.0(博主是 gcc 9.1) C++20 cmake
GCC 11:支持了大部分 C++20 核心语言特性,但标准库部分(如 <format>)的实现不完整
将gcc 11.4.0 更新到 gcc 13.1.0
使用PPA安装GCC 13

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 更新包列表
sudo apt update
# 添加提供GCC 13的PPA源
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
# 添加PPA后,再次更新包列表以应用更改
sudo apt update
# 安装GCC 13和G++ 13(C++编译器)
sudo apt install gcc-13 g++-13
# 将GCC 13设置为默认的C和C++编译器,可以使用update-alternatives命令
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 60
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-13 60
# 验证GCC 13是否正确安装
gcc-13 --version
g++-13 --version

Ubuntu 22.04.2 LTS gcc 13.1.0(博主是 gcc 9.1) C++20 cmake

项目路径

/home/sylar/workspace/sylar

bin — 二进制
build — 中间文件路径
cmake — cmake函数文件夹
CMakeLists.txt — cmake的定义文件
lib — 库的输出路径
Makefile sylar — 源代码路径
tests — 测试代码

日志系统

命名

文件命名:蛇形命名法(snake_case)

全小写,只使用字母、数字和下划线,且不以数字开头
示例:log_manager.cpp, socket_handler.hpp

文件扩展名

源文件扩展名(都表示 C++ 源文件)

1
2
3
4
5
.cc   // Unix/Linux 系统常用(如 GCC)
.cpp // Windows 和跨平台项目常用
.cxx // 较少使用,但同样有效
.C // 注意大写(某些 Unix 系统)
.c++ // 极少使用

头文件扩展名

1
2
3
4
.hpp  // C++ 头文件(推荐,明确区分 C)
.h // 传统头文件(C/C++ 通用)
.hxx // 较少使用
.inc // 包含文件(通常用于模板实现)

类命名:帕斯卡命名法(PascalCase)

大驼峰式
示例:LogManager, TcpSocket

运行CMakeLists.txt(根目录)

1
2
3
4
5
mkdir build
cd build
rm -rf * # 清理
cmake ..
make

Log4J

Logger(定义日志类别)
|
|———Formatter(日志格式)
|
Appender(日志输出地方)

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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
/**
* @file log.h
* @brief 日志模块封装
*/
#ifndef __SYLAR_LOG_H__
#define __SYLAR_LOG_H__

#include <string>
#include <stdint.h>
#include <memory>
#include <list>
#include <sstream>
#include <fstream>
#include <vector>
#include <map>
#include "util.h"
#include "singleton.h"
#include "thread.h"

/**
* @brief 使用流式方式将日志级别 level 的日志写入到 logger
*/
#define SYLAR_LOG_LEVEL(logger, level) \ // 当定义的宏不能用一行表达完整时,可以用\(反斜线)表示下一行继续此宏的定义
if(logger->getLevel() <= level) \
sylar::LogEventWrap(sylar::LogEvent::ptr(new sylar::LogEvent(logger, level, \
__FILE__, __LINE__, 0, sylar::GetThreadId(), \
sylar::GetFiberId(), time(0), sylar::Thread::GetName()))).getSS()

/**
* @brief 使用流式方式将日志级别 debug 的日志写入到 logger
*/
#define SYLAR_LOG_DEBUG(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::DEBUG)

/**
* @brief 使用流式方式将日志级别 info 的日志写入到 logger
*/
#define SYLAR_LOG_INFO(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::INFO)

/**
* @brief 使用流式方式将日志级别 warn 的日志写入到 logger
*/
#define SYLAR_LOG_WARN(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::WARN)

/**
* @brief 使用流式方式将日志级别 error 的日志写入到 logger
*/
#define SYLAR_LOG_ERROR(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::ERROR)

/**
* @brief 使用流式方式将日志级别 fatal 的日志写入到 logger
*/
#define SYLAR_LOG_FATAL(logger) SYLAR_LOG_LEVEL(logger, sylar::LogLevel::FATAL)

/**
* @brief 使用格式化方式将日志级别 level 的日志写入到 logger
*/
#define SYLAR_LOG_FMT_LEVEL(logger, level, fmt, ...) \
if(logger->getLevel() <= level) \
sylar::LogEventWrap(sylar::LogEvent::ptr(new sylar::LogEvent(logger, level, \
__FILE__, __LINE__, 0, sylar::GetThreadId(), \
sylar::GetFiberId(), time(0), sylar::Thread::GetName()))).getEvent()->format(fmt, __VA_ARGS__)

/**
* @brief 使用格式化方式将日志级别 debug 的日志写入到 logger
*/
#define SYLAR_LOG_FMT_DEBUG(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::DEBUG, fmt, __VA_ARGS__)

/**
* @brief 使用格式化方式将日志级别 info 的日志写入到 logger
*/
#define SYLAR_LOG_FMT_INFO(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::INFO, fmt, __VA_ARGS__)

/**
* @brief 使用格式化方式将日志级别 warn 的日志写入到 logger
*/
#define SYLAR_LOG_FMT_WARN(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::WARN, fmt, __VA_ARGS__)

/**
* @brief 使用格式化方式将日志级别 error 的日志写入到 logger
*/
#define SYLAR_LOG_FMT_ERROR(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::ERROR, fmt, __VA_ARGS__)

/**
* @brief 使用格式化方式将日志级别 fatal 的日志写入到 logger
*/
#define SYLAR_LOG_FMT_FATAL(logger, fmt, ...) SYLAR_LOG_FMT_LEVEL(logger, sylar::LogLevel::FATAL, fmt, __VA_ARGS__)

/**
* @brief 获取主日志器
*/
#define SYLAR_LOG_ROOT() sylar::LoggerMgr::GetInstance()->getRoot()

/**
* @brief 获取 name 的日志器
*/
#define SYLAR_LOG_NAME(name) sylar::LoggerMgr::GetInstance()->getLogger(name)

namespace sylar{

class Logger;
class LoggerManager;

/**
* @brief 日志级别
*/
class LogLevel{
public:
/**
* @brief 日志级别枚举
*/
enum Level{
/// 未知级别
UNKNOW = 0,
/// DEBUG 级别
DEBUG = 1,
/// INFO 级别
INFO = 2,
/// WARN 级别
WARN = 3,
/// ERROR 级别
ERROR = 4,
/// FATAL 级别
FATAL = 5
};

/**
* @brief 将日志级别转成文本输出
* @param[in] level 日志级别 // param[in] 输入参数
*/
static const char* ToString(LogLevel::Level level);

/**
* @brief 将文本转换成日志级别
* @param[in] str 日志级别文本
*/
static LogLevel::Level FormString(const std::string& str);
};

/**
* @brief 日志事件
*/
class LogEvent{
public:
typedef std::shared_ptr<LogEvent> ptr;
/**
* @brief 构造函数
* @param[in] logger 日志器
* @param[in] level 日志级别
* @param[in] file 文件名
* @param[in] line 文件行号
* @param[in] elapse 程序启动依赖的耗时(毫秒)
* @param[in] thread_id 线程 id
* @param[in] fiber_id 协程 id
* @param[in] time 日志事件(秒)
* @param[in] thread_name 线程名称
*/
LogEvent(std::shared_ptr<Logger> logger, LogLevel::Level level
, const char* file, int32_t m_line, uint32_t elapse
, uint32_t thread_id, uint32_t fiber_id, uint64_t time);

/**
* @brief 返回文件名
*/
const char* getFile() const { return m_file; }

/**
* @brief 返回行号
*/
int32_t getLine() const { return m_line; }

/**
* @brief 返回耗时
*/
uint32_t getElapse() const { return m_elapse; }

/**
* @brief 返回线程 ID
*/
uint32_t getThreadId() const { return m_threadId; }

/**
* @brief 返回协程 ID
*/
uint32_t getFiberId() const { return m_fiberId; }

/**
* @brief 返回时间
*/
uint64_t getTime() const { return m_time; }

/**
* @brief 返回线程名称
*/
const std::string& getThreadName() const { return m_threadName; }

/**
* @brief 返回日志内容
*/
std::string getContent() const { return m_ss.str(); }

/**
* @brief 返回日志器
*/
std::shared_ptr<Logger> getLogger() const { return m_logger; }

/**
* @brief 返回日志级别
*/
LogLevel::Level getLevel() const { return m_level; }

/**
* @brief 返回日志内容字符串流
*/
std::stringstream& getSS() { return m_ss; }

/**
* @brief 格式化写入日志内容
*/
void format(const char* fmt, ...);

/**
* @brief 格式化写入日志内容
*/
void format(const char* fmt, va_list al);
private:
/// 文件名,64位机器指针占8字节
const char* m_file = nullptr;
/// 行号
int32_t m_line = 0;
/// 程序启动开始到现在的毫秒数,64位机器边界对齐
uint32_t m_elapse = 0;
/// 线程 ID
uint32_t m_threadId = 0;
/// 协程 ID
uint32_t m_fiberId = 0;
/// 时间戳
uint64_t m_time = 0;
/// 线程名称
std::string m_threadName;
/// 日志内容流
std::stringstream m_ss;
/// 日志器
std::shared_ptr<Logger> m_logger;
/// 日志级别
LogLevel::Level m_level;
};

/**
* @brief 日志事件包装器
*/
class LogEventWrap
{
public:
/**
* @brief 构造函数
* @param[in] e 日志事件
*/
LogEventWrap(LogEvent::ptr e);

/**
* @brief 析构函数
*/
~LogEventWrap();

/**
* @brief 获取日志事件
*/
LogEvent::ptr getEvent() const { return m_event; }

/**
* @brief 获取日志内容流
*/
std::stringstream& getSS();
private:
/**
* @brief 日志事件
*/
LogEvent::ptr m_event;
};

/**
* @brief 日志格式化
*/
class LogFormatter{
public:
typedef std::shared_ptr<LogFormatter> ptr;
/**
* @brief 构造函数
* @param[in] pattern 格式模板
* @details
* %m 消息
* %p 日志级别
* %r 累计毫秒数
* %c 日志名称
* %t 线程 id
* %n 换行
* %d 时间
* %f 文件名
* %l 行号
* %T 制表符
* %F 协程 id
* %N 线程名称
*
* 默认格式 "%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"
*/
LogFormatter(const std::string& pattern);

/**
* @brief 返回格式化日志文本
* @param[in] logger 日志器
* @param[in] level 日志级别
* @param[in] event 日志事件
*/
std::string format(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event);
std::ostream& format(std::ostream& ofs, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event);
public:

/**
* @brief 日志内容项格式化
*/
class FormatItem
{
public:
typedef std::shared_ptr<FormatItem> ptr;
/**
* @brief 析构函数
*/
virtual ~FormatItem() {}
/**
* @brief 格式化日志到流
* @param[in, out] os 日志输出流
* @param[in] logger 日志器
* @param[in] level 日志等级
* @param[in] event 日志事件
*/
virtual void format(std::ostream& os, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;
};

/**
* @brief 初始化,解析日志模板
*/
void init();

/**
* @brief 是否有错误
*/
bool isError() const { return m_error; }

/**
* @brief 返回日志模板
*/
const std::string getPattern() const { return m_pattern; }
private:
/// 日志格式模板
std::string m_pattern;
/// 日志格式解析后格式
std::vector<FormatItem::ptr> m_items;
/// 是否有错误
bool m_error = false;
};

/**
* @brief 日志输出目标
*/
class LogAppender{
friend class Logger;
public:
typedef std::shared_ptr<LogAppender> ptr;
typedef Spinlock MutexType;

/**
* @brief 析构函数
*/
virtual ~LogAppender() {}

/**
* @brief 写入日志
* @param[in] logger 日志器
* @param[in] level 日志级别
* @param[in] event 日志事件
*/
virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event) = 0;

/**
* @brief 将日志输出目标的配置转成 YAML String
*/
virtual std::string toYamlString() = 0;

/**
* @brief 更改日志格式器
*/
void setFormatter(LogFormatter::ptr val);

/**
* @brief 获取日志格式器
*/
LogFormatter::ptr getFormatter();

/**
* @brief 获取日志级别
*/
LogLevel::Level getLevel() const { return m_level; }

/**
* @brief 设置日志级别
*/
void setLevel(LogLevel::Level val) { m_level = val; }
protected:
/// 日志级别
LogLevel::level m_level = LogLevel::DEBUG;
/// 是否有自己的日志格式器
bool m_hasFormatter = false;
/// Mutex
MutexType m_mutex;
/// 日志格式器
LogFormatter::ptr m_formatter;
};

/**
* @brief 日志器
*/
class Logger : public std::enable_shared_from_this<Logger>{
public:
typedef std::shared_ptr<Logger> ptr;
typedef Spinlock MutexType;

/**
* @brief 构造函数
* @param[in] name 日志器名称
*/
Logger(const std::string& name = "root");

/**
* @brief 写日志
* @param[in] level 日志级别
* @param[in] event 日志事件
*/
void log(LogLevel::Level level, LogEvent::ptr event);

/**
* @brief 写 debug 级别日志
* @param[in] event 日志事件
*/
void debug(LogEvent::ptr event);

/**
* @brief 写 info 级别日志
* @param[in] event 日志事件
*/
void info(LogEvent::ptr event);

/**
* @brief 写 warn 级别日志
* @param[in] event 日志事件
*/
void warn(LogEvent::ptr event);

/**
* @brief 写 error 级别日志
* @param[in] event 日志事件
*/
void error(LogEvent::ptr event);

/**
* @brief 写 fatal 级别日志
* @param[in] event 日志事件
*/
void fatal(LogEvent::ptr event);

/**
* @brief 添加日志目标
* @param[in] appender 日志目标
*/
void addAppender(LogAppender::ptr appender);

/**
* @brief 删除日志目标
* @param[in] appender 日志目标
*/
void delAppender(LogAppender::ptr appender);

/**
* @brief 清空日志目标
*/
void clearAppenders();

/**
* @brief 返回日志级别
*/
LogLevel::Level getLevel() const { return m_level; }

/**
* @brief 设置日志级别
*/
void setLevel(LogLevel::Level val) { m_level = val; }

/**
* @brief 返回日志名称
*/
const std::string& getName() const { return m_name; }

/**
* @brief 设置日志格式器
*/
void setFormatter(LogFormatter::ptr val);

/**
* @brief 设置日志格式模板
*/
void setFormatter(const std::string& val);

/**
* @brief 获取日志格式器
*/
LogFormatter::ptr getFormatter();

/**
* @brief 将日志器的配置转成YAML String
*/
std::string toYamlString();
private:
/// 日志名称
std::string m_name;
/// 日志级别
LogLevel::Level m_level;
/// Mutex
MutexType m_mutex;
// 日志目标集合
std::list<LogAppender::ptr> m_appenders;
/// 日志格式器
LogFormatter::ptr m_formatter;
/// 主日志器
Logger::ptr m_root;
};

/**
* @brief 输出到控制台的 Appender
*/
class StdoutLogAppender : public LogAppender{
public:
typedef std::shared_ptr<StdoutLogAppender> ptr;
void log(Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override;
std::string toYamlString() override;
};

/**
* @brief 输出到文件的 Appender
*/
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;
std::string toYamlString() override;

/**
* @brief 重新打开日志文件
* @return 成功返回 true
*/
bool reopen();
private:
/// 文件路径
std::string m_filename;
/// 文件流
std::ofstream m_filestream;
/// 上次重新打开时间
uint64_t m_lastTime = 0;
};

/**
* @brief 日志器管理类
*/
class LoggerManager
{
public:
typedef Spinlock MutexType;
/**
* @brief 构造函数
*/
LoggerManager();

/**
* @brief 获取日志器
* @param[in] name 日志器名称
*/
Logger::ptr getLogger(const std::string& name);

/**
* @brief 初始化
*/
void init();

/**
* @brief 返回主日志器
*/
Logger::ptr getRoot() const { return m_root; }

/**
* @brief 将所有的日志器配置转成 YAML String
*/
std::string toYamlString();
private:
/// Mutex
MutexType m_mutex;
/// 日志器容器
std::map<std::string, Logger::ptr> m_loggers;
/// 主日志器
Logger:ptr m_root;
};

/// 日志器管理类单例模式(单件模式)
typedef sylar::Singleton<LoggerManager> LoggerMgr;

}

#endif
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
/*
* 程序名:log.cc
*/
#include "log.h"
#include <map>
#include <iostream>
#include <functional>
#include <time.h>
#include <string.h>
#include "config.h"
#include "util.h"
#include "macro.h"
#include "env.h"

namespace sylar{

const char* LogLevel::ToString(LogLevel::Level level)
{
switch(level)
{
#define XX(name) \
case LogLevel::name: \
return #name; \ // #name,给 name 加双引号,转换成字符串
break;

XX(DEBUG);
XX(INFO);
XX(WARN);
XX(ERROR);
XX(FATAL);
#undef XX // #undef 终止宏指令,终止宏的作用域。若没有设置终止宏指令,则宏名作用域是从宏定义开始到源文件结束为止
default:
return "UNKNOW";
}
return "UNKNOW";
}

LogLevel::Level LogLevel::FromString(const std::string& str)
{
#define XX(level, v) \
if(str == #v) { \
return LogLevel::level; \
}
XX(DEBUG, debug);
XX(INFO, info);
XX(WARN, warn);
XX(ERROR, error);
XX(FATAL, fatal);

XX(DEBUG, DEBUG);
XX(INFO, INFO);
XX(WARN, WARN);
XX(ERROR, ERROR);
XX(FATAL, FATAL);
return LogLevel::UNKNOW;
#undef XX
}

LogEventWrap::LogEventWrap(LogEvent::ptr e) : m_event(e)
{}

LogEventWrap::~LogEventWrap()
{
m_event->getLogger()->log(m_event->getLevel(), m_event);
}

void LogEvent::format(const char* fmt, ...)
{
va_list al;
va_start(al, fmt);
format(fmt, al);
va_end(al);
}

void LogEvent::format(const char* fmt, va_list al)
{
char* buf = nullptr;
int len = vasprintf(&buf, fmt, al);
if(len != -1)
{
m_ss << std::string(buf, len);
free(buf);
}
}

std::stringstream& LogEventWrap::getSS()
{
return m_event->getSS();
}

void LogAppender::setFormatter(LogFormatter::ptr val)
{
MutexType::Lock lock(m_mutex);
m_formatter = val;
if(m_formatter)
{
m_hasFormatter = true;
}else
{
m_hasFormatter = false;
}
}

LogFormatter::ptr LogAppender::getFormatter()
{
MutexType::Lock lock(m_mutex);
return m_formatter;
}

class MessageFormatItem : public LogFormatter::FormatItem
{
public:
MessageFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getContent();
}
};

class LevelFormatItem : public LogFormatter::FormatItem
{
public:
LevelFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << LogLevel::ToString(level);
}
};

class ElapseFormatItem : public LogFormatter::FormatItem
{
public:
ElapseFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getElapse();
}
};

class NameFormatItem : public LogFormatter::FormatItem
{
public:
NameFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getLogger()->getName();
}
};

class ThreadIdFormatItem : public LogFormatter::FormatItem
{
public:
ThreadIdFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getThreadId();
}
};

class FiberIdFormatItem : public LogFormatter::FormatItem
{
public:
FiberIdFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getFiberId();
}
};

class ThreadNameFormatItem : public LogFormatter::FormatItem
{
public:
ThreadNameFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getThreadName();
}
};

class DateTimeFormatItem : public LogFormatter::FormatItem
{
public:
DateTimeFormatItem(const std::string& format = "%Y-%m-%d %H:%M:%S") : m_format(format)
{
if(m_format.empty())
{
m_format = "%Y-%m-%d %H:%M:%s";
}
}

void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
struct tm tm;
time_t time = event->getTime();
localtime_r(&time, &tm);
char buf[64];
strftime(buf, sizeof(buf), m_format.c_str(), &tm);
os << buf;
}
private:
std::string m_format;
};

class FilenameFormatItem : public LogFormatter::FormatItem
{
public:
FilenameFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getFile();
}
};

class LineFormatItem : public LogFormatter::FormatItem
{
public:
LineFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << event->getLine();
}
};

class NewLineFormatItem : public LogFormatter::FormatItem
{
public:
NewLineFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << std::endl;
}
};

class StringFormatItem : public LogFormatter::FormatItem
{
public:
StringFormatItem(const std::string& str) : m_string(str) {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << m_string;
}
private:
std::string m_string;
};

class TabFormatItem : public LogFormatter::FormatItem
{
public:
TabFormatItem(const std::string& str = "") {}
void format(std::ostream& os, Logger::ptr logger, LogLevel::Level level, LogEvent::ptr event) override
{
os << "\t";
}
private:
std::string m_string;
};

LogEvent::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 std::string& thread_name)
: m_file(file)
, m_line(line)
, m_elapse(elapse)
, m_threadId(thread_id)
, m_fiberId(fiber_id)
, m_time(time)
, m_threadName(thread_name)
, m_logger(logger)
, m_level(level)
{}

Logger::Logger(const std::string& name) : m_name(name), m_level(LogLevel::DEBUG)
{
m_formatter.reset(new LogFormatter("%d{%Y-%m-%d %H:%M:%S}%T%t%T%N%T%F%T[%p]%T[%c]%T%f:%l%T%m%n"));
}

void Logger::setFormatter(LogFormatter::ptr val)
{
MutexType::Lock lock(m_mutex);
m_formatter = val;

for(auto& i : m_appenders)
{
MutexType::Lock ll(i->m_mutex);
if(!i->m_hasFormatter)
{
i->m_formatter = m_formatter;
}
}
}

void Logger::setFormatter(const std::string& val)
{
std::cout << "---" << val << std::endl;
sylar::LogFormatter::ptr new_val(new sylar::LogFormatter(val));
if(new_val->isError())
{
std::cout << "Logger setFormatter name=" << m_name
<< " value=" << val << " invalid formatter"
<< std::endl;
return;
}
// m_formatter = new_val;
setFormatter(new_val);
}

std::string Logger::toYamlString()
{
MutexType::Lock lock(m_mutex);
YAML::Node node;
node["name"] = m_name;
if(m_level != LogLevel::UNKNOW)
{
node["level"] = LogLevel::ToString(m_level);
}
if(m_formatter)
{
node["formatter"] = m_formatter->getPattern();
}

for(auto& i : m_appenders)
{
node["appenders"].push_back(YAML::Load(i->toYamlString()));
}
std::stringstream ss;
ss << node;
return ss.str();
}

LogFormatter::ptr Logger::getFormatter()
{
MutexType::Lock lock(m_mutex);
return m_formatter;
}

void Logger::addAppender(LogAppender::ptr appender)
{
MutexType::Lock lock(m_mutex);
if(!appender->getFormatter())
{
MutexType::Lock ll(appender->m_mutex);
appender->m_formatter = m_formatter;
}
m_appenders.push_back(appender);
}

void Logger::delAppender(LogAppender::ptr appender)
{
MutexType::Lock lock(m_mutex);
for(auto it = m_appenders.begin(); it != m_appenders.end(); ++it)
{
if(*it == appender)
{
m_appenders.erase(it);
break;
}
}
}

void Logger::clearAppenders()
{
MutexType::Lock lock(m_mutex);
m_appenders.clear();
}

void Logger::log(LogLevel::Level level, LogEvent::ptr event)
{
if(level >= m_level)
{
auto self = shared_from_this();
MutexType::Lock lock(m_mutex);
if(!m_appenders.empty())
{
for(auto& i : m_appenders)
{
i->log(self, level, event);
}
}else if(m_root)
{
m_root->log(level, event);
}
}
}

void Logger::debug(LogEvent::ptr event)
{
log(LogLevel::DEBUG, event);
}

void Logger::info(LogEvent::ptr event)
{
log(LogLevel::INFO, event);
}

void Logger::warn(LogEvent::ptr event)
{
log(LogLevel::WARN, event);
}

void Logger::error(LogEvent::ptr event)
{
log(LogLevel::ERROR, event);
}

void Logger::fatal(LogEvent::ptr event)
{
log(LogLevel::FATAL, event);
}

FileLogAppender::FileLogAppender(const std::string& filename) : m_filename(filename)
{
reopen();
}

void FileLogAppender::log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event)
{
if(level >= m_level)
{
uint64_t now = event->getTime();
if(now >= (m_lastTime + 3))
{
reopen();
m_lastTime = now;
}
MutexType::Lock lock(m_mutex);
// if(!(m_filestream << m_formatter->format(logger, level, event)))
if(!m_formatter->format(m_filestream, logger, level, event))
{
std::cout << "error" << std::endl;
}
}
}

std::string FileLogAppender::toYamlString()
{
MutexType::Lock lock(m_mutex);
YAML::Node node;
node["type"] = "FileLogAppender";
node["file"] = m_filename;
if(m_level != LogLevel::UNKNOW)
{
node["level"] = LogLevel::ToString(m_level);
}
if(m_hasFormatter && m_formatter)
{
node["formatter"] = m_formatter->getPattern();
}
std::stringstream ss;
ss << node;
return ss.str();
}

bool FileLogAppender::reopen()
{
MutexType::Lock lock(m_mutex);
if(m_filestream)
{
m_filestream.close();
}
return FSUtil::OpenForWrite(m_filestream, m_filename, std::ios::app);
}

void StdoutLogAppender::log(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event)
{
if(level >= m_level)
{
MutexType::Lock lock(m_mutex);
m_formatter->format(std::cout, logger, level, event);
}
}

std::string StdoutLogAppender::toYamlString()
{
MutexType::Lock lock(m_mutex);
YAML::Node node;
node["type"] = "StdoutLogAppender";
if(m_level != LogLevel::UNKNOW)
{
node["level"] = LogLevel::ToString(m_level);
}
if(m_hasFormatter && m_formatter)
{
node["formatter"] = m_formatter->getPattern();
}
std::stringstream ss;
ss << node;
return ss.str();
}

LogFormatter::LogFormatter(const std::string& pattern) : m_pattern(pattern)
{
init();
}

std::string LogFormatter::format(std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event)
{
std::stringstream ss;
for(auto& i : m_items)
{
i->format(ss, logger, level, event);
}
return ss.str();
}

std::ostream& LogFormatter::format(std::ostream& ofs, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event)
{
for(auto& i : m_items)
{
i->format(ofs, logger, level, event);
}
return ofs;
}

// %xxx %xxx{xxx} %%
void LogFormatter::init()
{
// str, format, type
std::vector<std::tuple<std::string, std::string, int>> vec;
std::string nstr;
for(size_t i = 0; i < m_pattern.size(); ++i)
{
if(m_pattern[i] != '%')
{
nstr.append(1, m_pattern[i]);
continue;
}

if((i+1) < m_pattern.size())
{
if(m_pattern[i + 1] == '%')
{
nstr.append(1, '%');
continue;
}
}

size_t n = i + 1;
int fmt_status = 0;
size_t fmt_begin = 0;

std::string str;
std::string fmt;
while(n < m_pattern.size())
{
if(!fmt_status && (!isalpha(m_pattern[n]) && m_pattern[n] != '{' && m_pattern[n] != '}'))
{
str = m_pattern.substr(i + 1, n - i - 1);
break;
}
if(fmt_status == 0)
{
if(m_pattern[n] == '{')
{
str = m_pattern.substr(i + 1, n - i - 1);
// std::cout << "*" << std << std::endl;
fmt_status = 1; // 解析格式
fmt_begin = n;
++n;
continue;
}
}else if(fmt_status == 1)
{
if(m_pattern[n] == '}')
{
fmt = m_pattern.substr(fmt_begin + 1, n - fmt_begin - 1);
// std::cout << "#" << fmt << std::endl;
fmt_status = 0;
++n;
break;
}
}
++n;
if(n == m_pattern.size())
{
if(str.empty())
{
str = m_pattern.substr(i + 1);
}
}
}

if(fmt_status == 0)
{
if(!nstr.empty())
{
vec.push_back(std::make_tuple(nstr, std::string(), 0));
nstr.clear();
}
vec.push_back(std::make_tuple(str, fmt, 1));
i = n - 1;
}else if(fmt_status == 1)
{
std::cout << "pattern parse error: " << m_pattern << " - " << m_pattern.substr(i) << std::endl;
m_error = true;
vec.push_back(std::make_tuple("<<pattern_error>>", fmt, 0));
}
}

if(!nstr.empty())
{
vec.push_back(std::make_tuple(nstr, "", 0));
}
static std::map<std::string, std::function<FormatItem::ptr(const std::string& str)>> s_format_items =
{
#define XX(str, C) \
{#str, [](const std::string& fmt) { return FormatItem::ptr(new C(fmt)); }}

XX(m, MessageFormatItem), // m: 消息
XX(p, LevelFormatItem), // p:日志级别
XX(r, ElapseFormatItem), // r:累计毫秒数
XX(c, NameFormatItem), // c:日志名称
XX(t, ThreadIdFormatItem), // t:线程 id
XX(n, NewLineFormatItem), // n:换行
XX(d, DateTimeFormatItem), // d:时间
XX(f, FilenameFormatItem), // f:文件名
XX(l, LineFormatItem), // l:行号
XX(T, TabFormatItem), // T:Tab
XX(F, FIberIdFormatItem), // F:协程 id
XX(N, ThreadNameFormatItem), // N:线程名称
#undef XX
};

for(auto& i : vec)
{
if(std::get<2>(i) == 0)
{
m_items.push_back(FormatItem::ptr(new StringFormatItem(std::get<0>(i))));
}else
{
auto it = s_format_items.find(std::get<0>(i));
if(it == s_format_items.end())
{
m_items.push_back(FormatItem::ptr(new StringFormatItem("<<error_format %" + std::get<0>(i) + ">>")));
m_error = true;
}else
{
m_items.push_back(it->second(std::get<1>(i)));
}
}

// std::cout << "(" << std::get<0>(i) << ") - (" << std::get<1>(i) << ") - (" << std::get<2>(i) << ")" << std::endl;
}
// std::cout << m_items.size() << std::endl;
// %m --- 信息体,输出代码中指定的消息
// %p --- level,输出优先级,即 DEBUG,INFO,WARN,ERROR,FATAL
// %r --- 启动后的时间,输出自应用启动到输出该 log 信息耗费的毫秒数
// %c --- 日志名称,输出所属的类目,通常就是所在类的全名
// %t --- 线程 id,输出产生该日志事件的线程名
// %n --- 回车换行,输出一个回车换行符,Windows 平台为 "\\r\\n",Unix 平台为 "\\n"
// %d --- 时间,输出日志时间点的日期或时间,默认格式为 ISO8601
// %f --- 文件名,输出文件名
// %l --- 行号,输出日志事件的发生位置,包括类目名、发生的线程,以及在代码中的行数
}

LoggerManager::LoggerManager()
{
m_root.reset(new Logger);
m_root->addAppender(LogAppender::ptr(new StdoutLogAppender));

m_loggers[m_root->m_name] = m_root;

init();
}

Logger:ptr LoggerManager::getLogger(const std::string& name)
{
MutexType::Lock lock(m_mutex);
auto it = m_loggers.find(name);
if(it != m_loggers.end())
{
return it->second;
}

Logger::ptr logger(new Logger(name));
logger->m_root = m_root;
m_loggers[name] = logger;
return logger;
}

struct LogAppenderDefine
{
int type = 0; // 1 File, 2 Stdout
LogLevel::Level level = LogLevel::UNKNOW;
std::string formatter;
std::string file;

bool operator==(const LogAppenderDefine& oth) const
{
return type == oth.type && level == oth.level && formatter == oth.formatter && file == oth.file;
}
};

struct LogDefine
{
std::string name;
LogLevel:Level level LogLevel::UNKNOW;
std::string formatter;
std::vector<LogAppenderDefine> appenders;

bool operator==(const LogDefine& oth) const
{
return name == oth.name && level == oth.level && formatter == oth.formatter && appenders == appenders;
}

bool operator<(const LogDefine& oth) const
{
return name < oth.name;
}

bool isValid() const
{
return !name.empty();
}
};

}
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
/*
* 程序名:test.cc
*/
#include <iostream>
#include "sylar/log.h"
#include "sylar/util.h"

int main(int argc, char** argv)
{
sylar::Logger::ptr logger(new sylar::Logger);
logger->addAppender(sylar::LogAppender::ptr(new sylar::StdoutLogAppender));

sylar::FileLogAppender::ptr file_appender(new sylar::FileLogAppender("./log.txt"));
sylar::LogFormatter::ptr fmt(new sylar::LogFormatter("%d%T%p%T%m%n"));
file_appender->setFormatter(fmt);
file_appender->setLevel(sylar::LogLevel::ERROR);

logger->addAppender(file_appender);

// sylar::LogEvent::ptr event(new sylar::LogEvent(__FILE__, __LINE__, 0, sylar::GetThreadId(), sylar::GetFiberId(), time(0)));
// event->getSS() << "hello sylar log";
// logger->log(sylar::LogLevel::DEBUG, event);
std::cout << "hello sylar log" << std::endl;

SYLAR_LOG_INFO(logger) << "test macro";
SYLAR_LOG_ERROR(logger) << "test macro error";

SYLAR_LOG_FMT_ERROR(logger, "test macro fmt error %s", "aa");

auto l = sylar::LoggerMgr::GetInstance()->getLogger("xx");
SYLAR_LOG_INFO(l) << "xxx";
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
/*
* 程序名:CMakeLists.txt
*/
cmake_minimum_required(VERSION 2.8)
project(sylar)

set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CXX_FLAGS "$SENV{CXXFLAGS} -rdynamic -O3 -g -std=c++11 -Wall -Wno-deprecated -Werror -Wno-unused-function")

set(LIB_SRC
sylar/log.cc
sylar/util.cc
)

add_library(sylar SHARED ${LIB_SRC})
#add_library(sylar_static STATIC ${LIB_SRC})
#SET_TARGET_PROPERTIES (sylar_static PROPERTIES OUTPUT_NAME "sylar")

add_executable(test tests/test.cc)
add_dependencies(test sylar)
target_link_libraries(test sylar)

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
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
/*
* @file util.h
* @brief 常用的工具函数
*/
#ifndef __SYLAR_UTIL_H__
#define __SYLAR_UTIL_H__

#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdint.h>

namespace sylar
{
/**
* @brief 返回当前线程的 ID
*/
pid_t GetThreadId();

/**
* @brief 返回当前协程的 ID
*/
uint32_t GetFiberId();

}

#endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @file util.cc
*/
#include "util.h"

namespace sylar
{
pid_t GetThreadId()
{
return syscall(SYS_gettid)
}

uint32_t GetFiberId()
{
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
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
/**
* @file singleton.h
* @brief 单例模式封装
*/
#ifndef __SYLAR_SINGLETON_H__
#define __SYLAR_SINGLETON_H__

#include <memory>

namespace sylar
{

/**
* @brief 单例模式封装类
* @details T 类型
* X 为了创造多个实例对应的 Tag
* N 同一个 Tag 创造多个实例索引
*/
template<class T, class X = void, int N = 0>
class Singleton
{
public:
/**
* @brief 返回单例裸指针
*/
static T* GetInstance()
{
static T v;
return &v;
// return &GetInstanceX<T, X, N>();
}
};

/**
* @brief 单例模式智能指针封装类
* @details T 类型
* X 为了创造多个实例对应的 Tag
* N 同一个 Tag 创造多个实例索引
*/
template<class T, class X = void, int N = 0>
class SingletonPtr
{
public:
/**
* @brief 返回单例智能指针
*/
static std::shared_ptr<T> GetInstance()
{
static std::shared_ptr<T> v(new T);
return v;
// return GetInstancePtr<T, X, N>();
}
};

}

#endif

安装 Boost 库

1
2
sudo apt update
sudo apt install libboost-all-dev

协程库封装

协程 (C++20) - cppreference.cn - C++参考手册

socket 函数库

http 协议开发

分布协议

推荐系统

  • Titre: 【Project】sylar——C++高性能服务器框架
  • Auteur: tiny_star
  • Créé à : 2025-10-15 09:16:13
  • Mis à jour à : 2026-01-05 23:22:43
  • Lien: https://tiny-star3.github.io/2025/10/15/Cpp/[Project]Star C++ High-Performance Server Framework/
  • Licence: Cette œuvre est sous licence CC BY-NC-SA 4.0.
Commentaires