本模块为 Logloom 系统提供统一的多语言支持,确保日志与系统消息能够根据配置动态切换语言,同时兼容内核态与用户态环境。
- 多语言资源维护简单(采用 YAML 源文件)
- 构建阶段自动生成 C 头文件供内核态使用
- 用户态直接加载 YAML 文件
- 支持格式化插值(如 "发生错误:%s")
- 保持高性能(查询接口快速,支持静态编译)
- 标准化 Key 命名与访问接口
-
每种语言单独一个 YAML 文件。
-
结构要求:
- 一级分类表示模块(如 system、auth)
- 二级键表示具体消息
-
示例(
locales/zh.yaml):system: start_message: "程序启动" error_message: "发生错误:%s" auth: login_success: "登录成功" login_failed: "登录失败,请重试"
-
每种语言生成一个对应的
.h文件(如lang_zh.h,lang_en.h) -
内容格式:
typedef struct { const char* key; const char* value; } lang_entry_t;- 静态数组 + NULL 结束
- 自动生成宏定义,统一前缀为
LOGLOOM_LANG_
-
示例(
lang_zh.h):
typedef struct {
const char* key;
const char* value;
} lang_entry_t;
static const lang_entry_t zh_lang_table[] = {
{"system.start_message", "程序启动"},
{"system.error_message", "发生错误:%s"},
{"auth.login_success", "登录成功"},
{"auth.login_failed", "登录失败,请重试"},
{NULL, NULL}
};
// 自动生成宏
#define LOGLOOM_LANG_SYSTEM_START_MESSAGE "system.start_message"
#define LOGLOOM_LANG_SYSTEM_ERROR_MESSAGE "system.error_message"
#define LOGLOOM_LANG_AUTH_LOGIN_SUCCESS "auth.login_success"
#define LOGLOOM_LANG_AUTH_LOGIN_FAILED "auth.login_failed"| 接口 | 功能描述 |
|---|---|
const char* lang_get(const char* key); |
获取指定 key 的文本 |
char* lang_getf(const char* key, ...); |
获取带格式化插值的文本,动态分配内存 |
void lang_set_language(const char* lang_code); |
切换当前语言环境 |
- 查找当前语言的静态表。
- 线性搜索或哈希加速(后续可扩展)。
- 找不到时返回默认提示或 NULL。
lang_getf在内部调用lang_get后格式化字符串。
- 按需加载:系统启动时只加载默认语言表。
- 切换语言时:
- 释放当前语言表占用资源(如果有需要)
- 加载新的目标语言表
- 默认语言配置:
- 在初始化配置中指定,如
zh、en - 若切换失败(目标语言表不存在或加载失败),系统应回退到默认语言,并打印警告日志。
- 在初始化配置中指定,如
启动阶段:
- 从配置读取默认语言代码
- 加载对应语言的静态表
- 设置当前语言上下文指针
运行阶段:
- 调用 lang_set_language(new_lang_code)
- 检查当前语言是否已是目标语言
- 如果不同:
- 释放旧语言资源(如果需要)
- 加载新语言表
- 更新当前语言上下文指针
- 内核模块:
- 语言表作为静态常量数据编译进模块,不需要动态分配/释放内存。
- 切换语言仅切换指针,不涉及实际内存操作。
- 用户态应用:
- 通过读取 YAML 文件动态分配内存,需要在切换时释放旧语言表占用内存,防止泄漏。
%s:字符串%d:有符号整数(十进制)%u:无符号整数(十进制)%f:浮点数(小数)%x:无符号整数(十六进制表示)
- 使用 C 标准库函数
vsnprintf()实现变参格式化。 lang_getf流程:- 根据 key 查询模板字符串。
- 创建格式化缓冲区(动态分配)。
- 使用
va_list处理可变参数并格式化输出。 - 返回格式化后字符串,调用者负责释放内存。
示例伪代码:
char* lang_getf(const char* key, ...) {
const char* template = lang_get(key);
if (!template) return NULL;
va_list args;
va_start(args, key);
char* buffer = kmalloc(BUFFER_SIZE, GFP_KERNEL); // 内核态使用 kmalloc
if (!buffer) return NULL;
vsnprintf(buffer, BUFFER_SIZE, template, args);
va_end(args);
return buffer;
}- 用户态版本使用
malloc()和同样的vsnprintf()流程。
- 调用者负责释放
lang_getf返回的动态内存,防止内存泄漏。 - 格式字符串必须与参数匹配,错误使用可能导致未定义行为。
- 内核态需确保缓冲区大小合理,防止缓冲区溢出。
- 当前语言表中找不到指定 key 时:
- 自动回退到默认语言表(英语
en)查找。 - 如果在默认语言也找不到,则返回统一字符串:
"Unknown Error" - 记录一条 WARN 日志,内容如:
[WARN] Language key not found: {key}
- 自动回退到默认语言表(英语
- 调用
vsnprintf失败(返回负值)时:- 返回统一字符串:
"[FORMAT ERROR: Check argument count and types!]" - 记录一条 WARN 日志,内容如:
[WARN] Format failed for key: {key},并提示可能原因包括:参数数量错误、类型不匹配或模板格式非法。
- 返回统一字符串:
- 切换语言失败(加载语言表失败或不支持的语言代码):
- 自动回退到默认语言
en - 如果连默认语言表也加载失败,则系统进入降级模式,仅输出 Key 名称本身。
- 记录一条 ERROR 日志,内容如:
[ERROR] Failed to switch language to {lang_code}
- 自动回退到默认语言
本文档提供Logloom库所有公开API的完整参考,适用于将Logloom作为库集成到其他项目中的开发者。
// 语言表项结构
typedef struct {
const char* key; // 语言键
const char* value; // 翻译文本
} lang_entry_t;| 函数 | 说明 |
|---|---|
int lang_init(const char* default_lang) |
初始化语言模块,设置默认语言代码 |
bool lang_set_language(const char* lang_code) |
设置当前语言,成功返回true,失败返回false |
const char* lang_get(const char* key) |
获取指定key的不带格式化的文本,未找到则返回NULL |
char* lang_getf(const char* key, ...) |
获取带格式化插值的文本,返回动态分配的内存,需调用者释放 |
const char* lang_get_current() |
获取当前设置的语言代码 |
void lang_cleanup() |
清理语言模块资源 |
// 日志级别定义
typedef enum {
LOG_LEVEL_DEBUG = 0,
LOG_LEVEL_INFO = 1,
LOG_LEVEL_WARN = 2,
LOG_LEVEL_ERROR = 3,
LOG_LEVEL_FATAL = 4
} log_level_t;
// 日志条目结构
typedef struct {
unsigned long timestamp; // Unix 时间戳
log_level_t level; // 日志级别
const char* module; // 模块名称
const char* message; // 日志消息
const char* lang_key; // 对应的语言键(可选)
} log_entry_t;| 函数 | 说明 |
|---|---|
int log_init(const char* level, const char* log_file) |
初始化日志系统,设置初始日志级别和日志文件 |
void log_set_file(const char* filepath) |
设置日志输出文件路径,NULL表示禁用文件输出 |
void log_set_level(const char* level) |
设置日志级别,参数为级别字符串("DEBUG", "INFO", "WARN", "ERROR", "FATAL") |
int log_level_from_string(const char* level) |
从字符串获取日志级别枚举值 |
const char* log_level_to_string(int level) |
将日志级别枚举值转换为字符串 |
const char* log_get_level_string(void) |
获取当前日志级别的字符串表示 |
void log_set_console_enabled(int enabled) |
开启/关闭控制台输出 (0=禁用, 1=启用) |
void log_set_max_file_size(size_t max_bytes) |
设置最大日志文件大小(超过后自动轮转) |
void log_set_max_backup_files(size_t count) |
设置最大历史日志文件数量 |
size_t log_get_max_backup_files(void) |
获取最大历史日志文件数量 |
bool log_rotate_now(void) |
手动触发日志文件轮转 |
void log_debug(const char* module, const char* format, ...) |
输出调试级别日志 |
void log_info(const char* module, const char* format, ...) |
输出信息级别日志 |
void log_warn(const char* module, const char* format, ...) |
输出警告级别日志 |
void log_error(const char* module, const char* format, ...) |
输出错误级别日志 |
void log_fatal(const char* module, const char* format, ...) |
输出严重错误级别日志 |
void log_with_lang(log_level_t level, const char* module, const char* lang_key, ...) |
使用语言键输出国际化日志 |
int log_get_level(void) |
获取当前日志级别枚举值 |
bool log_is_console_enabled(void) |
检查控制台输出是否启用 |
const char* log_get_file_path(void) |
获取当前日志文件路径,未设置则返回NULL |
size_t log_get_max_file_size(void) |
获取最大日志文件大小(字节) |
void log_cleanup(void) |
清理日志系统资源 |
void log_lock(void) |
显式加锁日志系统(用于连续多条日志或事务) |
void log_unlock(void) |
解锁日志系统 |
| 函数 | 说明 |
|---|---|
int config_init(const char* config_file) |
初始化配置系统并加载指定的配置文件 |
const char* config_get_string(const char* key, const char* default_value) |
获取字符串配置项,未找到则返回默认值 |
int config_get_int(const char* key, int default_value) |
获取整数配置项,未找到则返回默认值 |
float config_get_float(const char* key, float default_value) |
获取浮点数配置项,未找到则返回默认值 |
int config_get_bool(const char* key, int default_value) |
获取布尔配置项,未找到则返回默认值 |
void config_cleanup(void) |
清理配置系统资源 |
// 插件操作结构
typedef struct {
void* (*init)(void); // 插件初始化函数
void (*process)(void* ctx, log_entry_t* entry); // 处理日志条目
void (*cleanup)(void* ctx); // 清理插件资源
} plugin_ops_t;
// 插件注册结构(面向实现插件的开发者)
typedef struct {
const char* name; // 插件名称
const char* version; // 插件版本
const char* description; // 插件描述
plugin_ops_t ops; // 插件操作函数
} plugin_t;| 函数 | 说明 |
|---|---|
int plugin_init(void) |
初始化插件系统 |
int plugin_register(plugin_t* plugin) |
注册插件 |
int plugin_load(const char* path) |
从指定路径加载单个插件 |
int plugin_load_directory(const char* path) |
从指定目录加载所有插件 |
void plugin_process(log_entry_t* entry) |
使用所有插件处理日志条目 |
void plugin_cleanup(void) |
清理插件系统资源 |
Python API通过C扩展提供,主要类和函数如下:
方法:
| 方法 | 说明 |
|---|---|
Logger(module_name) |
创建指定模块的日志记录器 |
set_level(level) |
设置日志级别(LogLevel枚举) |
set_file(file_path) |
设置日志文件路径 |
set_console_enabled(enabled) |
启用/禁用控制台输出 |
set_rotation_size(max_bytes) |
设置日志文件轮转大小 |
set_max_backup_files(count) |
设置最大历史日志文件数 |
debug(message, *args, **kwargs) |
记录调试级别日志 |
info(message, *args, **kwargs) |
记录信息级别日志 |
warning(message, *args, **kwargs) |
记录警告级别日志 |
error(message, *args, **kwargs) |
记录错误级别日志 |
critical(message, *args, **kwargs) |
记录严重错误级别日志 |
函数:
| 函数 | 说明 |
|---|---|
set_language(language_code) |
设置当前语言,如"en", "zh" |
get_current_language() |
获取当前语言代码 |
get_text(key) |
获取指定键的文本 |
format_text(key, *args, **kwargs) |
获取指定键的格式化文本 |
函数:
| 函数 | 说明 |
|---|---|
initialize(config_path) |
使用配置文件初始化Logloom系统 |
get_config_string(key, default_value) |
获取字符串配置 |
get_config_int(key, default_value) |
获取整数配置 |
get_config_float(key, default_value) |
获取浮点数配置 |
get_config_bool(key, default_value) |
获取布尔值配置 |
class LogLevel:
DEBUG = 0
INFO = 1
WARNING = 2
ERROR = 3
CRITICAL = 4import logloom_py as ll
# 初始化系统
ll.initialize("./config.yaml")
# 设置语言
ll.set_language("zh")
# 创建日志记录器
logger = ll.Logger("main")
logger.set_level(ll.LogLevel.DEBUG)
logger.set_file("app.log")
logger.set_rotation_size(1024 * 1024) # 1MB
# 记录日志
logger.info("应用启动")
logger.debug("调试信息: {}", "测试")
logger.warning("警告信息: {msg}", msg="发现异常")
# 使用国际化文本
welcome = ll.format_text("welcome", name="张三")
logger.info(welcome)开发C语言插件需要实现以下结构:
#include <logloom/plugin.h>
#include <logloom/log.h>
// 插件上下文结构(自定义)
typedef struct {
// 插件私有数据
} my_plugin_ctx_t;
// 初始化函数
void* my_plugin_init(void) {
my_plugin_ctx_t* ctx = malloc(sizeof(my_plugin_ctx_t));
// 初始化上下文
return ctx;
}
// 处理函数
void my_plugin_process(void* ctx, log_entry_t* entry) {
my_plugin_ctx_t* my_ctx = (my_plugin_ctx_t*)ctx;
// 处理日志条目
}
// 清理函数
void my_plugin_cleanup(void* ctx) {
my_plugin_ctx_t* my_ctx = (my_plugin_ctx_t*)ctx;
// 清理资源
free(ctx);
}
// 插件注册
plugin_t my_plugin = {
.name = "my_plugin",
.version = "1.0.0",
.description = "这是一个示例插件",
.ops = {
.init = my_plugin_init,
.process = my_plugin_process,
.cleanup = my_plugin_cleanup
}
};
// 导出插件(必须使用此名称和签名)
plugin_t* logloom_plugin_init(void) {
return &my_plugin;
}Python插件应继承基础插件类并实现所需方法:
from logloom.plugin import LogPlugin
class MyPlugin(LogPlugin):
def __init__(self):
# 初始化插件
pass
def process(self, log_entry):
# 处理日志条目
# log_entry是包含timestamp, level, module, message等字段的字典
pass
def cleanup(self):
# 清理资源
pass插件文件应放在插件目录中,并通过plugin_info.json注册:
{
"name": "my_plugin",
"version": "1.0.0",
"description": "这是一个Python示例插件",
"module": "my_plugin",
"class": "MyPlugin"
}