需求分析

  • 日志模块: 收集记录各级别下系统运行信息, 包括事件、运行情况、错误。
  • 输出模块: 实现类printf式的格式输出。
  • 设备管理模块: 能够模拟虚拟设备并实现与系统的交互接口。
  • 文件系统管理: 实现对文件系统的操作、维护。
  • 图形化窗口: 实现对系统状态的捕捉和图形化展示。

实现设计

日志模块

  • C++实现,模仿Linux系统日志模块。
  • 采用debug、info、notice、warning、error、critical、alert、emergency 8个级别日志等级对日志优先级进行分类。
  • 设计系统日志api,创建日志守护进程来获取系统及应用的日志信息。
  • 通过日志旋转来实现对日志的单个日志的定期清理,通过脚本来实现对所有日志的定期清理。
  • 通过脚本实现对日志的定期备份从而在需要时实现日志回滚。

输出模块

  • C++实现,模仿printf函数。
  • 提供不同的格式说明符,包括一些输出需要的系统变量。
  • 实现输出到定义接口的功能。

设备管理模块

  • C++实现。
  • 通过类实现一个设备管理器,提供设备注册机制和设备间通信
  • 使用文件来模拟设备的数据储存。

文件系统管理

  • C++实现,模仿Linux文件系统管理。
  • 实现对文件的CRUD,文件的权限、所有权等功能。

图形化窗口

  • C++实现,使用QT框架。
  • 通过与其他模块的接口捕捉系统状态,并对系统状态图形化展示。

实现

日志&输出

类详解

LogLevel类描述

LogLevel 类定义了日志系统中使用的日志级别。这个类使用枚举类型表示不同的日志级别,从而方便日志的分类和过滤。每个级别代表了日志信息的重要性和紧急程度,从调试信息到致命错误。

属性

Level:枚举类型,定义了各种可能的日志级别。包括:

  • UNKNOW:未知级别,通常用于初始化或错误处理。
  • DEBUG:调试级别,用于详细的系统调试信息。
  • INFO:信息级别,用于常规的操作信息。
  • WARN:警告级别,表示可能的问题,但不一定影响系统运行。
  • ERROR:错误级别,表示发生了影响操作的问题。
  • FATAL:致命级别,表示严重的问题,可能导致系统停止运行。
方法
  • ToString(Level level)

静态方法,用于将日志级别枚举转换为相应的字符串表示。这个方法通过一个switch语句实现,对应每个枚举值返回一个固定的字符串。例如,DEBUG级别返回"DEBUG"字符串,这对于日志输出和调试非常有用。

  • FromString(const std::string& str)

静态方法,用于将字符串转换回相应的日志级别枚举。此方法通常通过一系列的 if 或 else if 语句实现,对比输入字符串与各日志级别名称,返回匹配的枚举值。如果没有找到匹配项,通常返回 UNKNOW。

使用方法
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
// 转换日志级别为字符串
std::string levelStr = LogLevel::ToString(LogLevel::DEBUG);
std::cout << "Log level is: " << levelStr << std::endl;

// 将字符串转换回日志级别
LogLevel::Level level = LogLevel::FromString("DEBUG");
std::cout << "Converted log level from string is: " << static_cast<int>(level) << std::endl;

```

##### LogEvent类描述

LogEvent 类是一个封装了单个日志事件的详细信息的类,用于在日志系统中表示一个具体的日志记录点。这个类包含了日志发生时的各种环境信息,如时间、文件名、行号以及线程和协程的标识,使得每条日志能够提供足够的上下文信息。

###### 属性

- logger:关联的 Logger 对象的智能指针,表示产生此日志事件的日志器。
- level:日志级别,由 LogLevel::Level 枚举表示。
- file:生成日志事件的源文件名。
- line:生成日志事件的行号。
- elapse:程序启动后到日志事件创建时的毫秒数。
- threadId:生成日志的线程ID。
- fiberId:生成日志的协程ID(如果使用协程)。
- time:日志事件生成的时间戳。
- threadName:生成日志的线程名称。
- ss:一个字符串流,用于收集日志信息。

###### 方法

- LogEvent

> 构造函数,初始化所有的日志相关信息。它接收与属性对应的参数,并将它们存储在类的成员变量中。

- getFile()

> 返回日志事件相关的文件名。

- getLine()

> 返回产生日志事件的代码行号。

- getTime()

> 返回日志事件的时间戳。

- getThreadId()

> 返回生成日志的线程ID。

- getFiberId()

> 返回生成日志的协程ID。

- getElapsedTime()

> 返回自程序启动以来到日志事件发生时的时间差(毫秒)。

- getThreadName()

> 返回生成日志的线程名称。

- getLogger()

> 返回产生此日志事件的 Logger 对象的智能指针。

- getSS()

> 返回用于收集日志内容的字符串流。
- format(const char* fmt, ...)

> 格式化输出日志信息,可以接受格式化参数并写入到 ss。

###### 使用方法

```cpp
Logger::ptr logger = std::make_shared<Logger>("example");
LogEvent::ptr event(new LogEvent(
logger, LogLevel::INFO, __FILE__, __LINE__, 0,
GetCurrentThreadId(), GetCurrentFiberId(), time(nullptr), "main_thread"
));
event->getSS() << "This is a log message";
logger->log(LogLevel::INFO, event);
```

##### LogEventWrap类描述

LogEventWrap 类是一个用于自动管理日志事件生命周期的辅助类,主要功能是在其生命周期结束时自动完成日志的记录。该类封装了一个 LogEvent 对象,并在析构时确保日志事件被正确处理,这样可以减少在函数中显式调用日志记录的需要。

###### 属性

- m_event:LogEvent 对象的智能指针,存储实际的日志事件。

###### 方法

- LogEventWrap(LogEvent::ptr e)

> 构造函数,接收一个 LogEvent 的智能指针,并将其存储在成员变量 m_event 中。这个构造函数允许 LogEventWrap 对象在创建时就持有一个日志事件的引用。

- ~LogEventWrap()

> 析构函数,在 LogEventWrap 对象生命周期结束时被调用。它的主要作用是自动触发日志事件的处理,如将其内容写入到日志系统。这样设计可以确保即使在复杂的函数调用中也不会丢失日志记录。

- getEvent() const

> 返回存储在 m_event 中的 LogEvent 对象的智能指针。这允许外部访问封装的日志事件,可能用于进一步处理或查询。

- getSS()

> 返回与 m_event 关联的字符串流引用。这个方法通常用于向日志事件中添加具体的日志信息,例如通过 getSS() << "Some log message"; 的方式。

###### 使用方法

```cpp
Logger::ptr logger = std::make_shared<Logger>("example");
LogEvent::ptr event(new LogEvent(logger, LogLevel::INFO, __FILE__, __LINE__, 0, GetCurrentThreadId(), 0, time(nullptr), "main_thread"));
{
LogEventWrap event_wrap(event);
event_wrap.getSS() << "This is a log message.";
}
LogFormatter类描述

LogFormatter 类是用于将 LogEvent 对象格式化为字符串的关键组件,以便日志可以被输出到各种媒介。该类通过一个定义明确的格式模板对日志事件进行结构化表示,该模板支持丰富的格式化指令来包含或排除日志内容的特定部分。

属性
  • m_pattern:字符串,保存日志格式化模板。
  • m_items:FormatItem 对象的列表,每个对象代表模板中的一个格式化指令。
  • m_error:布尔值,表示在格式化过程中是否遇到错误。
方法
  • LogFormatter(const std::string& pattern)

构造函数,接收一个格式化模板字符串并初始化 m_pattern。构造时还会调用 init() 方法来解析模板并构建 m_items。

  • format(std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event)

将 LogEvent 对象格式化为字符串。这个方法遍历 m_items,使用每个 FormatItem 对象来转换日志事件的相应部分。

  • format(std::ostream& ofs, std::shared_ptr logger, LogLevel::Level level, LogEvent::ptr event)

类似于上一个 format 方法,但这里的输出是写入到一个输出流中,使其可以直接输出到文件或控制台。

  • init()

解析 m_pattern 字符串,并根据解析结果创建相应的 FormatItem 对象填充到 m_items。这个方法处理模板中的各种格式化指令,并对应生成处理这些指令的 FormatItem 对象。

  • isError() const

返回一个布尔值,表示格式化过程中是否有错误发生。

  • getPattern() const

返回格式化模板字符串。

使用方法
std::string pattern = "%d