日志记录
内置现代化、高性能的日志记录框架,提供了统一的日志记录接口,支持多种输出目标、灵活的过滤机制和丰富的日志级别控制。
快速启动
只需要以下 3 个步骤即可开始使用日志系统:
cangjie
import spire_extensions_logging.*
main() {
// 1. 创建并配置日志系统
let logging = LoggingBuilder()
.addConsole() // 添加控制台输出
.setMinimumLevel(LogLevel.Info) // 设置最低日志级别
.build()
// 2. 创建日志器
let logger = logging.createLogger("spire.hosting.lifetime")
// 3. 记录日志
logger.debug("This is a debug.") // 不打印,因为被过滤了
logger.info("This is a info.")
logger.warn("This is a warning.")
logger.error("This is an Error!")
}日志级别
日志级别(LogLevel)定义了日志信息的重要性和详细程度:
cangjie
public enum LogLevel <: Comparable<LogLevel> & ToString {
Trace | Debug | Info | Warn | Error | Fatal | Off
}| 级别 | 优先级 | 使用场景 | 典型内容 |
|---|---|---|---|
| Trace | 0 (最低) | 非常详细的调试 | 方法进入/退出、变量值 |
| Debug | 1 | 开发调试 | 业务逻辑流程、中间结果 |
| Info | 2 | 一般信息 | 业务操作完成、状态变更 |
| Warn | 3 | 警告信息 | 潜在问题、性能问题 |
| Error | 4 | 错误信息 | 处理失败、异常情况 |
| Fatal | 5 | 致命错误 | 系统崩溃、无法恢复 |
| Off | 6 (最高) | 关闭日志 | 不输出任何日志 |
日志过滤
日志过滤允许精确控制哪些日志应该被记录:
设置最低级别
cangjie
let logging = LoggingBuilder()
.addConsole()
.setMinimumLevel(LogLevel.Warn) // 全局最低级别为警告
.build()
let logger = logging.createLogger("spire.hosting.lifetime")
logger.info("This is a info.") // 不打印
logger.warn("This is a warning.") // 打印
logger.error("This is an Error!") // 打印使用简单过滤器
cangjie
let logging = LoggingBuilder()
// 该日志提供程序名为:console
.addConsole()
// 设置日志提供程序名为console的,日志名称spire.hosting.*开头的日志最低级别为:Warn
.addFilter("console", "spire.hosting.*", LogLevel.Warn).build()
let logger1 = logging.createLogger("spire.hosting.lifetime")
logger1.info("This is a warning.") // 不打印
logger1.error("This is an Error!") // 打印
println('=================================')
let logger2 = logging.createLogger("spire.web.lifetime")
logger2.info("This is a warning.") // 打印,因为日志名称不匹配
logger2.error("This is an Error!") // 打印
filter的优先级要高于setMinimumLevel
使用lambda过滤器
cangjie
let logging = LoggingBuilder()
.addConsole()
.addFilter{_, categoryName, logLevel =>
// 名称为"spire.hosting."并且日志级别大于Warn,才打印
categoryName.startsWith("spire.hosting.") && logLevel > LogLevel.Warn
}.build()
let logger1 = logging.createLogger("spire.hosting.lifetime")
logger1.info("This is a warning.") // 不打印
logger1.error("This is an Error!") // 打印
println('=================================')
let logger2 = logging.createLogger("spire.web.lifetime")
logger2.info("This is a warning.") // 不打印
logger2.error("This is an Error!") // 不打印使用配置文件配置
我们支持通过 JSON 配置文件来配置日志过滤器,并与 extensions_configuration 模块进行了集成。
配置规则如下:
bash
{providerName}:{categoryName}:{logLevel}参数说明:
providerName(日志提供程序名称)
- 如果是根节点下的
logLevel,表示不区分日志提供程序。
- 如果是根节点下的
categoryName(日志名称)
- 如果是
default,表示不区分日志名称。
- 如果是
logLevel(日志级别)
- 支持前置匹配和后置
*通配符。
- 支持前置匹配和后置
最后,系统会使用解析后的参数调用前面提到的 addFilter(providerName, categoryName, logLevel) 函数。
cangjie
import spire_extensions_logging.*
import spire_extensions_configuration.*
import spire_extensions_logging_configuration.*
main() {
let configuration = ConfigurationManager()
.addJsonString(#"
{
"logging": {
"logLevel": {
"default": "Info",
"spire.hosting.*": "Warn"
},
"file": {
"logLevel": {
"default": "Error"
}
}
}
}
"#)
.build()
let section = configuration.getSection("logging")
let logging = LoggingBuilder()
.addConsole()
.addConfiguration(section)
.build()
let logger1 = logging.createLogger("spire.hosting.lifetime")
logger1.info("This is an Info!")
logger1.error("This is an Error!")
let logger2 = logging.createLogger("spire.web.lifetime")
logger2.info("This is an Info!")
logger2.error("This is an Error!")
}自定义提供程序
定义文件日志
cangjie
// 定义文件日志器
class FileLogger <: ILogger {
FileLogger(let categoryName: String) {
}
public func log(logLevel: LogLevel, message: String, exception: ?Exception): Unit {
let path = getFileName()
try (sw = StringWriter(getFileStream(path))){
sw.write("${DateTime.now()}|${logLevel}|${categoryName}: ")
if (let Some(exception) <- exception) {
sw.writeln(exception.toString())
} else {
sw.writeln(message)
}
}
}
private func getFileName() {
let name = DateTime.now().format("yyyyMMdd")
if (!exists("logs")) {
Directory.create("logs", recursive: true)
}
return Path("./logs/${name}.log")
}
private func getFileStream(path: Path) {
if (!exists(path)) {
return File(path, OpenMode.Write)
}
return File(path, OpenMode.Append)
}
}
// 定义文件日志提供程序
class FileLoggerProvider <: ILoggerProvider {
public prop name: String {
get() {
"file"
}
}
public func createLogger(categoryName: String): ILogger {
return FileLogger(categoryName)
}
}
// 扩展到LoggingBuilder
extend LoggingBuilder{
public func addFile() {
addProvider(FileLoggerProvider())
return this
}
}测试打印效果
cangjie
let logging = LoggingBuilder()
.addConsole()
.addFile()
.build()
let logger = logging.createLogger("spire.hosting.lifetime")
logger.error("This is an Error!")此时我们可以看到控制台打印了日志,同时在当前项目路径下创建了一个logs文件夹,并且里面有一个文件,也记录了这个日志。