first version

This commit is contained in:
2026-08-16 12:46:15 +08:00
commit 932fce1b9e
40 changed files with 4005 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
/*
* Copyright (c) 2025 SimcuTeam. All rights reserved.
* 移植自 C# 项目 SimApiE:\simcu\simapi-net),遵循 MIT 许可证。
*/
package simapi.logger
import std.collection.concurrent.*
import std.env.*
import std.time.*
import soulsoft_extensions_logging.*
/**
* SimApi 日志记录器:输出格式对齐 C# 原版 SimApiLogger。
* 格式:`[ 分类 ][ 时间 ][ 级别 ]\n消息\n[异常]`
* 按日志级别着色输出。
*/
public class SimApiLogger <: ILogger {
private let _name: String
public init(name: String) {
_name = name
}
public func log<TState>(logLevel: LogLevel, eventId: EventId, state: TState, exception: ?Exception,
formatter: (TState, ?Exception) -> String): Unit where TState <: ToString {
if (!isEnabled(logLevel)) {
return
}
let now = DateTime.now()
let timeStr = formatTime(now)
let levelStr = levelName(logLevel)
var sb = StringBuilder()
sb.append("${color(levelColor(logLevel))}[ ${_name} ][ ${timeStr} ][ ${levelStr} ]\n")
sb.append("${state}\n")
if (let Some(ex) <- exception) {
sb.append("${ex}\n")
}
sb.append(resetColor())
// 对齐 C# Console.WriteLinemessage 末尾 \n 之后再补一个 \n,形成空行分隔
sb.append("\n")
let writer = getStdOut()
writer.write(sb.toString())
writer.flush()
}
public func isEnabled(logLevel: LogLevel): Bool {
logLevel != LogLevel.Off
}
/**
* 级别名称,对齐 C# 的 LogLevel.ToString()。
*/
private static func levelName(logLevel: LogLevel): String {
match (logLevel) {
case LogLevel.Trace => "Trace"
case LogLevel.Debug => "Debug"
case LogLevel.Info => "Information"
case LogLevel.Warn => "Warning"
case LogLevel.Error => "Error"
case LogLevel.Fatal => "Critical"
case _ => "None"
}
}
/**
* 级别对应 ANSI 前景色(对齐 C# ConsoleColor):
* Debug→DarkMagenta, Info→DarkCyan, Warn→Yellow, Error→Red, Fatal→DarkRed, 其他→White
*/
private static func levelColor(logLevel: LogLevel): String {
match (logLevel) {
case LogLevel.Debug => "35" // DarkMagenta
case LogLevel.Info => "36" // DarkCyan
case LogLevel.Warn => "33" // Yellow
case LogLevel.Error => "31" // Red
case LogLevel.Fatal => "31;1" // DarkRed(粗体近似)
case _ => "37" // White
}
}
private static func color(code: String): String {
"\u{1b}[${code}m"
}
private static func resetColor(): String {
"\u{1b}[0m"
}
private static func formatTime(dt: DateTime): String {
let year = dt.year
let month = pad2(dt.monthValue)
let day = pad2(dt.dayOfMonth)
let hour = pad2(dt.hour)
let minute = pad2(dt.minute)
let second = pad2(dt.second)
let millis = pad3(dt.nanosecond / 1000000)
"${year}-${month}-${day} ${hour}:${minute}:${second}:${millis}"
}
private static func pad2(v: Int64): String {
if (v < 10) {
return "0${v}"
}
"${v}"
}
private static func pad3(v: Int64): String {
if (v < 10) {
return "00${v}"
}
if (v < 100) {
return "0${v}"
}
"${v}"
}
}
/**
* SimApi 日志提供程序:按分类缓存日志记录器。
*/
public class SimApiLoggerProvider <: ILoggerProvider {
private let _loggers = ConcurrentHashMap<String, SimApiLogger>()
public init() {}
public func createLogger(categoryName: String): ILogger {
if (let Some(logger) <- _loggers.get(categoryName)) {
return logger
}
return _loggers.entryView(categoryName) {
view => if (view.value.isNone()) {
view.value = SimApiLogger(categoryName)
}
}.getOrThrow()
}
public func close(): Unit {}
public func isClosed(): Bool {
false
}
}