Files
Alicho/docs/api/common.md
2025-10-28 10:27:49 +08:00

763 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 公共组件API参考
## 目录
- [公共组件API参考](#公共组件api参考)
- [目录](#目录)
- [概述](#概述)
- [错误处理系统](#错误处理系统)
- [错误码](#错误码)
- [异常层次结构](#异常层次结构)
- [错误处理器](#错误处理器)
- [工具函数](#工具函数)
- [宏定义](#宏定义)
- [日志系统](#日志系统)
- [日志级别](#日志级别)
- [日志接口](#日志接口)
- [模块日志](#模块日志)
- [日志配置](#日志配置)
- [使用示例](#使用示例)
- [错误处理示例](#错误处理示例)
- [日志记录示例](#日志记录示例)
- [集成示例](#集成示例)
- [最佳实践](#最佳实践)
- [错误处理最佳实践](#错误处理最佳实践)
- [日志记录最佳实践](#日志记录最佳实践)
- [跨平台考虑](#跨平台考虑)
## 概述
公共组件模块提供了错误处理和日志记录等基础功能,为整个音频后端系统提供统一的异常处理和日志记录机制。这些组件设计为高性能、线程安全且跨平台,使开发者能够轻松地进行错误处理和系统状态监控。
核心特性:
- **统一的错误处理**:提供清晰的错误码、异常层次结构和错误处理工具
- **灵活的日志系统**:支持多级别、多目标(控制台/文件)的日志记录
- **模块化设计**:允许按模块进行日志和错误处理
- **高性能**:所有组件设计时考虑了性能开销,适用于实时音频处理
- **线程安全**:支持多线程环境下的并发操作
## 错误处理系统
错误处理系统提供了一套完整的错误处理机制,包括错误码、异常类和错误处理工具。
### 错误码
`ErrorCode`枚举定义了系统中所有可能的错误状态:
```cpp
enum class ErrorCode {
// 通用错误 (0-999)
SUCCESS = 0,
UNKNOWN_ERROR = 1,
INVALID_ARGUMENT = 2,
INVALID_OPERATION = 3,
NOT_IMPLEMENTED = 4,
OUT_OF_MEMORY = 5,
OPERATION_TIMED_OUT = 6,
NOT_INITIALIZED = 7,
ALREADY_INITIALIZED = 8,
// 文件和I/O错误 (1000-1999)
FILE_NOT_FOUND = 1000,
FILE_ACCESS_DENIED = 1001,
FILE_READ_ERROR = 1002,
FILE_WRITE_ERROR = 1003,
FILE_FORMAT_ERROR = 1004,
// 音频处理错误 (2000-2999)
AUDIO_FORMAT_ERROR = 2000,
AUDIO_DEVICE_ERROR = 2001,
AUDIO_BUFFER_UNDERRUN = 2002,
AUDIO_BUFFER_OVERRUN = 2003,
AUDIO_SAMPLE_RATE_MISMATCH = 2004,
AUDIO_CHANNEL_COUNT_MISMATCH = 2005,
// 插件错误 (3000-3999)
PLUGIN_LOAD_ERROR = 3000,
PLUGIN_NOT_FOUND = 3001,
PLUGIN_VERSION_MISMATCH = 3002,
PLUGIN_INITIALIZATION_ERROR = 3003,
PLUGIN_COMMUNICATION_ERROR = 3004,
PLUGIN_EXECUTION_ERROR = 3005,
PLUGIN_TIMEOUT = 3006,
// 通信错误 (4000-4999)
COMMUNICATION_ERROR = 4000,
CONNECTION_ERROR = 4001,
DISCONNECTED = 4002,
MESSAGE_FORMAT_ERROR = 4003,
PROTOCOL_ERROR = 4004,
TIMEOUT = 4005,
// 系统错误 (5000-5999)
SYSTEM_ERROR = 5000,
PERMISSION_DENIED = 5001,
NOT_ENOUGH_RESOURCES = 5002
};
```
错误码按功能域分组,便于管理和扩展。系统还提供了错误分类枚举:
```cpp
enum class ErrorCategory {
GENERAL,
FILE,
AUDIO,
PLUGIN,
COMMUNICATION,
SYSTEM
};
```
获取错误描述和分类的辅助函数:
```cpp
// 获取错误分类
ErrorCategory get_error_category(ErrorCode code);
// 获取错误码对应的描述信息
std::string get_error_description(ErrorCode code);
```
### 异常层次结构
系统定义了一个异常层次结构,以`AudioBackendException`为基类:
```cpp
// 基础异常类
class AudioBackendException : public std::exception {
public:
explicit AudioBackendException(ErrorCode code,
const std::string& message = "",
const std::string& details = "");
// 获取错误码
ErrorCode code() const noexcept;
// 获取错误消息
const std::string& message() const noexcept;
// 获取详细信息
const std::string& details() const noexcept;
// 获取完整错误消息
const char* what() const noexcept override;
// 获取错误分类
ErrorCategory category() const noexcept;
// 获取std::error_code
std::error_code error_code() const noexcept;
// 是否是某个错误码
bool is(ErrorCode code) const noexcept;
// 是否属于某个错误分类
bool is_category(ErrorCategory category) const noexcept;
};
```
基于基础异常类,系统还定义了特定领域的异常类:
```cpp
// 文件异常
class FileException : public AudioBackendException;
// 音频异常
class AudioException : public AudioBackendException;
// 插件异常
class PluginException : public AudioBackendException;
// 通信异常
class CommunicationException : public AudioBackendException;
// 系统异常
class SystemException : public AudioBackendException;
```
### 错误处理器
`ErrorHandler`类提供了集中式的错误处理机制:
```cpp
class ErrorHandler {
public:
// 错误处理回调函数类型
using ErrorCallback = std::function<void(const AudioBackendException&)>;
// 获取单例实例
static ErrorHandler& instance();
// 添加全局错误处理回调
void add_error_handler(const ErrorCallback& handler);
// 移除错误处理回调
void remove_error_handler(const ErrorCallback& handler);
// 处理错误
void handle_error(const AudioBackendException& exception);
// 处理错误(从错误码创建异常)
void handle_error(ErrorCode code,
const std::string& message = "",
const std::string& details = "");
// 处理异常捕获
void handle_exception(std::exception_ptr eptr);
// 清除所有错误处理回调
void clear_handlers();
};
```
系统还提供了RAII风格的错误处理辅助类
```cpp
class ScopedErrorHandler {
public:
explicit ScopedErrorHandler(ErrorHandler::ErrorCallback handler);
~ScopedErrorHandler();
};
```
### 工具函数
错误处理系统提供了一系列工具函数:
```cpp
// 根据错误码创建适当的异常
std::exception_ptr create_exception(ErrorCode code,
const std::string& message = "",
const std::string& details = "");
// 根据错误码抛出异常
[[noreturn]] void throw_exception(ErrorCode code,
const std::string& message = "",
const std::string& details = "");
// 错误检查函数条件为true时抛出异常
void check_error(bool condition,
ErrorCode error_code,
const std::string& message = "",
const std::string& details = "");
// 将系统错误码转换为AudioBackend错误码
ErrorCode system_error_to_error_code(int system_error);
// 将std::error_code转换为AudioBackend错误码
ErrorCode std_error_to_error_code(const std::error_code& ec);
```
### 宏定义
系统提供了便捷的错误处理宏:
```cpp
// 检查条件并抛出异常
#define AUDIO_CHECK_ERROR(condition, error_code, message)
// 直接抛出异常
#define AUDIO_THROW_ERROR(error_code, message)
// 处理错误调用ErrorHandler
#define AUDIO_HANDLE_ERROR(error_code, message)
// try-catch简化宏
#define AUDIO_TRY_CATCH_ALL()
#define AUDIO_CATCH_ALL()
```
## 日志系统
日志系统基于spdlog库实现提供了灵活、高性能的日志记录功能。
### 日志级别
日志系统定义了以下日志级别:
```cpp
enum class LogLevel {
TRACE, // 最详细的调试信息
DEBUG, // 详细的调试信息
INFO, // 一般信息
WARN, // 警告信息
ERR, // 错误信息
CRITICAL, // 严重错误
OFF // 关闭日志
};
```
### 日志接口
`Logger`类提供了日志系统的核心功能:
```cpp
class Logger {
public:
// 获取单例实例
static Logger& instance();
// 初始化日志系统
void initialize(const std::string& app_name = "AudioBackend",
LogLevel console_level = LogLevel::INFO,
bool file_logging = true,
const std::string& log_dir = "logs",
size_t max_file_size = 5 * 1024 * 1024,
size_t max_files = 3);
// 关闭日志系统
void shutdown();
// 设置全局日志级别
void set_level(LogLevel level);
// 设置控制台日志级别
void set_console_level(LogLevel level);
// 设置文件日志级别
void set_file_level(LogLevel level);
// 获取当前日志级别
LogLevel get_level() const;
// 获取日志器
std::shared_ptr<spdlog::logger> get_logger() const;
// 获取特定模块的日志器
std::shared_ptr<spdlog::logger> get_module_logger(const std::string& module_name);
// 刷新日志缓冲区
void flush();
// 便捷的日志记录方法
template<typename... Args>
void trace(std::string_view fmt, const Args&... args);
template<typename... Args>
void debug(std::string_view fmt, const Args&... args);
template<typename... Args>
void info(std::string_view fmt, const Args&... args);
template<typename... Args>
void warn(std::string_view fmt, const Args&... args);
template<typename... Args>
void err(std::string_view fmt, const Args&... args);
template<typename... Args>
void critical(std::string_view fmt, const Args&... args);
};
```
系统还提供了全局日志函数无需直接访问Logger实例
```cpp
template<typename... Args>
inline void log_trace(std::string_view fmt, const Args&... args);
template<typename... Args>
inline void log_debug(std::string_view fmt, const Args&... args);
template<typename... Args>
inline void log_info(std::string_view fmt, const Args&... args);
template<typename... Args>
inline void log_warn(std::string_view fmt, const Args&... args);
template<typename... Args>
inline void log_err(std::string_view fmt, const Args&... args);
template<typename... Args>
inline void log_critical(std::string_view fmt, const Args&... args);
```
### 模块日志
系统支持按模块进行日志记录,提供了便捷的模块日志宏:
```cpp
// 创建模块日志器
#define AUDIO_MODULE_LOGGER(module_name)
// 模块级别日志记录宏
#define AUDIO_LOG_TRACE(...)
#define AUDIO_LOG_DEBUG(...)
#define AUDIO_LOG_INFO(...)
#define AUDIO_LOG_WARN(...)
#define AUDIO_LOG_ERR(...)
#define AUDIO_LOG_CRITICAL(...)
```
### 日志配置
日志系统支持以下配置选项:
- **应用名称**:日志中显示的应用名称
- **控制台日志级别**:显示在控制台的最低日志级别
- **文件日志**:是否启用文件日志
- **日志目录**:日志文件的存储目录
- **最大文件大小**:单个日志文件的最大大小
- **最大文件数**:轮转日志的最大文件数量
## 使用示例
### 错误处理示例
**基本错误检查和处理:**
```cpp
#include "common/error.h"
#include <iostream>
using namespace audio_backend::common;
void example_error_handling() {
// 使用错误检查宏
try {
bool condition = false; // 假设这是一个失败条件
AUDIO_CHECK_ERROR(condition, ErrorCode::INVALID_OPERATION,
"操作无法执行,参数无效");
} catch (const AudioBackendException& e) {
std::cout << "捕获异常: " << e.what() << std::endl;
std::cout << "错误码: " << static_cast<int>(e.code()) << std::endl;
std::cout << "错误类别: " << static_cast<int>(e.category()) << std::endl;
}
// 直接抛出异常
try {
AUDIO_THROW_ERROR(ErrorCode::FILE_NOT_FOUND, "找不到配置文件");
} catch (const FileException& e) {
std::cout << "捕获文件异常: " << e.what() << std::endl;
} catch (const AudioBackendException& e) {
std::cout << "这不会被执行因为FileException已经捕获" << std::endl;
}
// 使用错误处理器
ErrorHandler::instance().add_error_handler([](const AudioBackendException& e) {
std::cout << "错误处理器: " << e.what() << std::endl;
});
// 当触发错误时,会调用错误处理器
AUDIO_HANDLE_ERROR(ErrorCode::AUDIO_DEVICE_ERROR, "音频设备初始化失败");
}
```
**使用作用域错误处理器:**
```cpp
void example_scoped_error_handler() {
// 创建一个局部作用域的错误处理器
{
ScopedErrorHandler handler([](const AudioBackendException& e) {
std::cout << "作用域错误处理器: " << e.what() << std::endl;
});
// 在这个作用域内,所有错误都会被处理器捕获
AUDIO_HANDLE_ERROR(ErrorCode::COMMUNICATION_ERROR, "连接超时");
} // 离开作用域,错误处理器自动移除
// 此处的错误不会被上面的处理器捕获
AUDIO_HANDLE_ERROR(ErrorCode::PLUGIN_LOAD_ERROR, "插件加载失败");
}
```
**全局错误处理:**
```cpp
// 全局错误处理函数
void global_error_handler(const AudioBackendException& e) {
std::cerr << "全局错误处理: " << e.what() << std::endl;
// 可以根据错误类别执行不同操作
switch (e.category()) {
case ErrorCategory::FILE:
// 处理文件错误...
break;
case ErrorCategory::AUDIO:
// 处理音频错误...
break;
// 其他错误类别...
}
}
int main() {
// 设置全局错误处理器
ErrorHandler::instance().add_error_handler(global_error_handler);
// 现在所有通过ErrorHandler处理的错误都会被全局处理器捕获
try {
// 应用代码...
} catch (...) {
// 捕获所有未处理的异常
ErrorHandler::instance().handle_exception(std::current_exception());
}
return 0;
}
```
### 日志记录示例
**基本日志记录:**
```cpp
#include "common/logger.h"
using namespace audio_backend::common;
void example_logging() {
// 初始化日志系统
Logger::instance().initialize("MyAudioApp", LogLevel::DEBUG);
// 使用全局日志函数
log_info("应用启动");
log_debug("调试信息: {}", "测试消息");
// 带参数的日志
int param1 = 42;
std::string param2 = "测试";
log_info("参数值: {} 和 {}", param1, param2);
// 错误日志
log_err("发生错误: {}", "找不到文件");
// 直接使用Logger实例
Logger::instance().critical("严重错误: 系统无法继续运行");
// 刷新日志缓冲区(确保写入磁盘)
Logger::instance().flush();
}
```
**模块日志:**
```cpp
#include "common/logger.h"
using namespace audio_backend::common;
// 定义模块日志器
AUDIO_MODULE_LOGGER("AudioEngine");
class AudioEngine {
public:
void initialize() {
AUDIO_LOG_INFO("音频引擎初始化中...");
// 一些初始化代码...
if (true /* 初始化成功 */) {
AUDIO_LOG_INFO("音频引擎初始化成功");
} else {
AUDIO_LOG_ERR("音频引擎初始化失败");
}
}
void process() {
AUDIO_LOG_TRACE("处理音频数据...");
// 一些处理代码...
if (false /* 假设发生了问题 */) {
AUDIO_LOG_WARN("处理过程中发生警告");
}
AUDIO_LOG_DEBUG("完成音频处理,输出样本数: {}", 1024);
}
};
```
**日志配置:**
```cpp
void configure_logging() {
// 完整配置
Logger::instance().initialize(
"MyAudioApp", // 应用名称
LogLevel::INFO, // 控制台日志级别
true, // 启用文件日志
"logs", // 日志目录
5 * 1024 * 1024, // 最大文件大小5MB
3 // 最大文件数
);
// 动态调整日志级别
Logger::instance().set_level(LogLevel::DEBUG); // 全局级别
Logger::instance().set_console_level(LogLevel::INFO); // 控制台级别
Logger::instance().set_file_level(LogLevel::TRACE); // 文件级别
// 为特定模块创建日志器
auto engine_logger = Logger::instance().get_module_logger("Engine");
auto plugin_logger = Logger::instance().get_module_logger("Plugin");
// 使用模块日志器
engine_logger->info("引擎模块信息");
plugin_logger->debug("插件模块调试信息");
}
```
### 集成示例
以下示例展示了如何将错误处理和日志系统集成在一起:
```cpp
#include "common/error.h"
#include "common/logger.h"
#include <iostream>
#include <stdexcept>
using namespace audio_backend::common;
// 自定义错误处理器,将错误记录到日志
void log_error_handler(const AudioBackendException& e) {
// 根据错误严重性选择合适的日志级别
switch (e.category()) {
case ErrorCategory::SYSTEM:
case ErrorCategory::PLUGIN:
log_critical("严重错误: {}", e.what());
break;
case ErrorCategory::AUDIO:
case ErrorCategory::COMMUNICATION:
log_err("错误: {}", e.what());
break;
case ErrorCategory::FILE:
case ErrorCategory::GENERAL:
default:
log_warn("警告: {}", e.what());
break;
}
}
// 示例函数,模拟可能出错的操作
void perform_risky_operation() {
// 假设条件检查失败
bool success = false;
if (!success) {
// 记录错误并抛出异常
log_debug("操作失败,即将抛出异常");
AUDIO_THROW_ERROR(ErrorCode::OPERATION_TIMED_OUT, "操作超时");
}
}
// 完整集成示例
int main() {
try {
// 初始化日志系统
Logger::instance().initialize("AudioApp", LogLevel::DEBUG);
log_info("应用程序启动");
// 设置将错误记录到日志的处理器
ErrorHandler::instance().add_error_handler(log_error_handler);
log_debug("已注册错误处理器");
try {
// 尝试执行风险操作
log_info("开始执行操作...");
perform_risky_operation();
} catch (const AudioBackendException& e) {
// 本地处理异常,但不退出
log_debug("捕获到异常: {}", e.what());
// 也可以重新抛出
throw;
}
log_info("应用程序正常退出");
} catch (const std::exception& e) {
// 捕获所有未处理的异常
log_critical("未处理的异常: {}", e.what());
return 1;
}
return 0;
}
```
## 最佳实践
### 错误处理最佳实践
1. **选择适当的错误处理方式**
- 使用错误码返回值处理预期的错误
- 使用异常处理非预期的错误和严重故障
- 在性能关键路径上避免使用异常
2. **合理分类错误**
- 按照错误的性质和严重程度分类
- 为不同类型的错误提供明确的上下文信息
3. **提供详细的错误信息**
- 描述发生了什么(错误内容)
- 解释为什么会发生(错误原因)
- 建议如何解决(修复方法)
4. **集中处理错误**
- 使用全局错误处理器统一处理错误
- 将错误处理与业务逻辑分离
5. **实时系统的错误处理**
- 避免在音频回调线程中抛出异常
- 使用错误标志和延迟处理
- 预先分配错误处理资源,避免动态内存分配
### 日志记录最佳实践
1. **选择适当的日志级别**
- TRACE: 最详细的调试信息,通常仅在开发时启用
- DEBUG: 详细的调试信息,有助于问题诊断
- INFO: 正常操作信息,记录系统状态和重要事件
- WARN: 警告信息,表明可能的问题,但不会导致系统失败
- ERR: 错误信息,表明功能无法正常工作
- CRITICAL: 严重错误,系统无法继续运行
2. **结构化日志信息**
- 使用一致的格式记录日志
- 包含时间戳、日志级别、模块名称、线程ID等元数据
- 使用参数化日志而不是字符串拼接
3. **避免过多日志**
- 避免在高频率循环中记录日志
- 使用采样或节流技术减少重复日志
- 注意日志对性能的影响
4. **按模块记录日志**
- 每个模块使用专门的日志器
- 模块名称应反映代码结构
5. **实时系统的日志记录**
- 使用异步日志记录,避免阻塞音频线程
- 考虑使用环形缓冲区进行临时日志存储
- 定期刷新日志,而不是每条日志都刷新
## 跨平台考虑
公共组件模块设计为跨平台工作,但在不同平台上仍有一些注意事项:
1. **文件路径处理**
- Windows使用反斜杠`\`)作为路径分隔符
- Unix/Linux/macOS使用正斜杠`/`)作为路径分隔符
- 使用平台无关的路径处理函数
2. **文件权限和访问**
- 不同平台的文件权限模型存在差异
- 日志文件创建可能受系统权限限制
3. **系统错误转换**
- 不同平台的系统错误码不同
- 使用`system_error_to_error_code()`函数进行统一转换
4. **线程安全性**
- 所有公共组件都设计为线程安全
- 不同平台的线程模型存在差异但API保持一致
5. **性能考虑**
- 不同平台上日志和错误处理的性能特性可能有所不同
- 高性能应用应当在各目标平台上进行性能测试