# 公共组件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; // 获取单例实例 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 get_logger() const; // 获取特定模块的日志器 std::shared_ptr get_module_logger(const std::string& module_name); // 刷新日志缓冲区 void flush(); // 便捷的日志记录方法 template void trace(std::string_view fmt, const Args&... args); template void debug(std::string_view fmt, const Args&... args); template void info(std::string_view fmt, const Args&... args); template void warn(std::string_view fmt, const Args&... args); template void err(std::string_view fmt, const Args&... args); template void critical(std::string_view fmt, const Args&... args); }; ``` 系统还提供了全局日志函数,无需直接访问Logger实例: ```cpp template inline void log_trace(std::string_view fmt, const Args&... args); template inline void log_debug(std::string_view fmt, const Args&... args); template inline void log_info(std::string_view fmt, const Args&... args); template inline void log_warn(std::string_view fmt, const Args&... args); template inline void log_err(std::string_view fmt, const Args&... args); template 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 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(e.code()) << std::endl; std::cout << "错误类别: " << static_cast(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 #include 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. **性能考虑**: - 不同平台上日志和错误处理的性能特性可能有所不同 - 高性能应用应当在各目标平台上进行性能测试