日期:2025-11-06 项目地址:https://gitcode.com/cj-awaresome/cjlog
日志记录是软件开发中最基础也是最重要的功能之一。无论是调试问题、监控系统运行状态,还是进行性能分析,日志都扮演着不可或缺的角色。
随着仓颉语言的发布,作为华为推出的新一代编程语言,其生态系统正在快速发展。然而,在仓颉语言的早期阶段,缺少一个简单易用、功能完善的日志库。这正是 cjlog 诞生的初衷。
在开发 cjlog 时,我们设定了以下核心目标:
cjlog 采用了经典的分层架构和接口驱动设计,将日志系统拆分为三个核心层次:
┌─────────────────────────────────────────┐
│ 应用层(User Code) │
└─────────────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ Logger Interface(日志接口层) │
│ - debug() - info() - warning() │
│ - error() - critical() - log() │
└─────────────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ BaseLogger(核心实现层) │
│ 管理多个 Handler,分发日志消息 │
└─────────────────┬───────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ LogHandler Interface(处理器接口层) │
│ handle(level, message) │
└─────────────────┬───────────────────────┘
│
┌───────┴────────┐
▼ ▼
┌──────────────────┐ ┌──────────────┐
│ ConsoleHandler │ │ FileHandler │
│ (控制台输出) │ │ (文件输出) │
└──────────────────┘ └──────────────┘
LogLevel(日志级别枚举)
public enum LogLevel {
DEBUG // 调试信息
INFO // 一般信息
WARN // 警告信息
ERROR // 错误信息
FATAL // 致命错误
}
Logger(日志接口)
public interface Logger {
func log(level: LogLevel, message: String): Unit
func debug(message: String): Unit
func info(message: String): Unit
func warning(message: String): Unit
func error(message: String): Unit
func critical(message: String): Unit
}
LogConfig(配置结构体)
public struct LogConfig {
let level: LogLevel
let output: String // "console" | "file" | "both"
let filePath: String
let format: String
}
LogHandler(处理器接口)
public interface LogHandler {
func handle(level: LogLevel, message: String): Bool
}
这个接口是整个系统的扩展点。任何人都可以实现这个接口,创建自定义的日志处理器,比如:
ConsoleHandler(控制台处理器)
[yyyy-MM-dd HH:mm:ss] [LEVEL] messageFileHandler(文件处理器)
BaseLogger(核心日志类)
LoggerFactory(工厂类)
createConsoleLogger():仅控制台输出createFileLogger(filePath):仅文件输出createMultiHandlerLogger(console, filePath):同时输出到控制台和文件cjlog 运用了多个经典设计模式:
Logger 和 LogHandler 职责清晰分离LoggerFactory 封装对象创建逻辑所有日志输出都遵循统一格式:
[2025-11-03 14:30:25] [INFO] 应用程序启动
[2025-11-03 14:30:26] [DEBUG] 正在加载配置文件
[2025-11-03 14:30:27] [WARN] 配置项缺失,使用默认值
[2025-11-03 14:30:28] [ERROR] 连接数据库失败
[2025-11-03 14:30:29] [FATAL] 系统崩溃
这种格式具有以下优点:
BaseLogger 的核心功能是将一条日志消息分发到多个 Handler:
public class BaseLogger <: Logger {
private let handlers: Array<LogHandler>
public func log(level: LogLevel, message: String): Unit {
for handler in handlers {
handler.handle(level, message)
}
}
}
这种设计的好处:
ConsoleHandler 将不同级别的日志输出到不同的流:
这样做的好处:
最简单的用法,只需一行代码:
import cjlog.core.LoggerFactory
main() {
let logger = LoggerFactory.createConsoleLogger()
logger.info("Hello, cjlog!")
}
输出:
[2025-11-03 14:30:25] [INFO] Hello, cjlog!
将日志保存到文件:
import cjlog.core.LoggerFactory
main() {
let logger = LoggerFactory.createFileLogger("./log/app.log")
logger.info("应用程序启动")
logger.debug("执行初始化")
logger.error("发生错误")
}
同时输出到控制台和文件:
import cjlog.core.LoggerFactory
main() {
let logger = LoggerFactory.createMultiHandlerLogger(true, "./log/app.log")
logger.info("应用程序启动")
logger.debug("用户登录成功")
logger.warning("缓存即将过期")
logger.error("数据库连接失败")
logger.critical("系统内存不足")
}
扩展 cjlog 非常简单,只需实现 LogHandler 接口:
package my
import cjlog.handler.LogHandler
import cjlog.model.LogLevel
// 自定义 HTTP 日志处理器
public class HttpHandler <: LogHandler {
private let endpoint: String
public init(endpoint: String) {
this.endpoint = endpoint
}
public func handle(level: LogLevel, message: String): Bool {
// 发送日志到远程服务器
// let response = httpClient.post(endpoint, {"level": level, "message": message})
return true
}
}
使用自定义 Handler:
import cjlog.core.BaseLogger
import cjlog.handler.ConsoleHandler
main() {
let logger = BaseLogger([
ConsoleHandler(),
HttpHandler("https://log.example.com/api/logs")
])
logger.info("这条日志会同时输出到控制台和远程服务器")
}
一个实际应用场景:
import cjlog.core.LoggerFactory
import cjlog.model.Logger
class Application {
private let logger: Logger
public init() {
// 创建组合日志记录器
this.logger = LoggerFactory.createMultiHandlerLogger(
true,
"./log/myapp.log"
)
}
public func start(): Unit {
logger.info("应用程序启动中...")
try {
loadConfig()
connectDatabase()
startServer()
logger.info("应用程序启动成功")
} catch (e: Exception) {
logger.critical("应用程序启动失败: ${e.message}")
}
}
private func loadConfig(): Unit {
logger.debug("正在加载配置文件")
// ...
logger.info("配置文件加载完成")
}
private func connectDatabase(): Unit {
logger.debug("正在连接数据库")
// ...
logger.info("数据库连接成功")
}
private func startServer(): Unit {
logger.info("正在启动 HTTP 服务器")
// ...
logger.info("HTTP 服务器已在 8080 端口启动")
}
}
main() {
let app = Application()
app.start()
}
控制台输出
文件输出
多处理器场景
1. 合理选择日志级别
// ✅ 好的做法
logger.debug("用户ID: ${userId}, 查询参数: ${params}") // 调试信息
logger.info("用户 ${username} 登录成功") // 业务日志
logger.warning("缓存命中率低于 50%") // 警告信息
logger.error("数据库查询失败: ${error}") // 错误信息
logger.critical("系统内存不足,即将崩溃") // 致命错误
// ❌ 不好的做法
logger.info("进入 main 函数") // 过于详细,应使用 debug
logger.error("用户登录") // 不是错误,应使用 info
2. 生产环境关闭 DEBUG 日志
// 通过配置控制日志级别
let minLevel = if (isProduction) { LogLevel.INFO } else { LogLevel.DEBUG }
3. 避免在循环中记录过多日志
// ❌ 不好的做法
for (i in 0..1000000) {
logger.debug("处理第 ${i} 条数据") // 会产生 100 万条日志
}
// ✅ 好的做法
logger.info("开始处理 100 万条数据")
for (i in 0..1000000) {
// 处理数据
}
logger.info("数据处理完成")
4. 日志文件轮转
目前 cjlog 采用追加模式,长时间运行会导致日志文件过大。建议:
通过定义清晰的接口(Logger、LogHandler),实现了:
cjlog 不依赖任何第三方库,仅使用仓颉语言标准库:
项目包含完善的测试用例,测试覆盖率达到 89.8%,确保代码质量和稳定性。
cjpm test

cjlog 目前处于 v1.0.2 版本,已经具备了基础的日志功能。未来我们计划添加以下特性:
支持自定义日志格式:
// JSON 格式
{"timestamp": "2025-11-03T14:30:25", "level": "INFO", "message": "应用启动"}
// 自定义格式
[INFO] 2025-11-03 14:30:25 - 应用启动
自动管理日志文件:
提升高并发场景下的性能:
支持结构化数据:
logger.info("用户登录", {
"userId": 12345,
"username": "john",
"ip": "192.168.1.1"
})
动态控制哪些日志需要记录:
logger.addFilter((level, message) => {
// 只记录 ERROR 级别以上的日志
return level >= LogLevel.ERROR
})
内置性能统计:
cjlog 采用 Apache License 2.0 开源协议,允许:
我们欢迎所有形式的贡献:
提交 Issue
提交 Pull Request
参与讨论
doc/ 目录src/cjlog.cjsrc/cj_log_test.cjcjlog 是为仓颉语言打造的首个系统化日志库,它具有以下特点:
作为仓颉语言生态的一部分,cjlog 希望能帮助开发者更好地进行日志记录和问题排查。如果你在使用过程中有任何问题或建议,欢迎随时联系我们!
让我们一起构建更好的仓颉生态! 🎉
# 克隆项目
git clone https://gitcode.com/cj-awaresome/cjlog.git
# 更新依赖
cjpm update
# 构建项目
cjpm build
# 运行示例
cjpm run
# 运行测试
cjpm test
方法 | 说明 | 使用场景 |
|---|---|---|
debug(msg) | 调试信息 | 开发调试、详细追踪 |
info(msg) | 一般信息 | 业务日志、操作记录 |
warning(msg) | 警告信息 | 潜在问题、需要注意的情况 |
error(msg) | 错误信息 | 错误但不影响系统运行 |
critical(msg) | 致命错误 | 系统崩溃、严重故障 |
方法 | 说明 | 返回类型 |
|---|---|---|
LoggerFactory.createConsoleLogger() | 创建控制台日志记录器 | Logger |
LoggerFactory.createFileLogger(path) | 创建文件日志记录器 | Logger |
LoggerFactory.createMultiHandlerLogger(console, path) | 创建组合日志记录器 | Logger |