Add async config serialization and test seeds

This commit is contained in:
Nanaloveyuki
2026-05-08 18:34:28 +08:00
parent 27f7651c9a
commit 95ccb72093
3 changed files with 194 additions and 2 deletions
+116
View File
@@ -0,0 +1,116 @@
async test "shutdown drains pending records" {
let written : Ref[Array[String]] = Ref::new([])
let logger = async_logger(
@bitlogger.callback_sink(fn(rec) {
written.val.push(rec.message)
}),
config=AsyncLoggerConfig::new(
max_pending=4,
overflow=AsyncOverflowPolicy::Blocking,
),
min_level=@bitlogger.Level::Info,
target="async.test",
)
@async.with_task_group(group => {
group.spawn_bg(() => logger.run())
logger.info("one")
logger.info("two")
logger.shutdown()
})
inspect(logger.is_closed(), content="true")
inspect(logger.is_running(), content="false")
inspect(logger.has_failed(), content="false")
inspect(logger.pending_count(), content="0")
inspect(written.val.length(), content="2")
inspect(written.val[0], content="one")
inspect(written.val[1], content="two")
}
async test "close clear counts abandoned records as dropped" {
let logger = async_logger(
@bitlogger.callback_sink(fn(_) {
}),
config=AsyncLoggerConfig::new(
max_pending=4,
overflow=AsyncOverflowPolicy::Blocking,
),
min_level=@bitlogger.Level::Info,
target="async.clear",
)
logger.info("one")
logger.info("two")
inspect(logger.pending_count(), content="2")
inspect(logger.dropped_count(), content="0")
logger.close(clear=true)
inspect(logger.is_closed(), content="true")
inspect(logger.pending_count(), content="0")
inspect(logger.dropped_count(), content="2")
}
async test "shutdown clear closes without worker startup" {
let logger = async_logger(
@bitlogger.callback_sink(fn(_) {
}),
config=AsyncLoggerConfig::new(
max_pending=2,
overflow=AsyncOverflowPolicy::Blocking,
),
min_level=@bitlogger.Level::Info,
target="async.noworker",
)
logger.info("one")
logger.shutdown(clear=true)
inspect(logger.is_closed(), content="true")
inspect(logger.is_running(), content="false")
inspect(logger.pending_count(), content="0")
inspect(logger.dropped_count(), content="1")
}
test "async logger config stringify roundtrips stable fields" {
let text = stringify_async_logger_config(
AsyncLoggerConfig::new(
max_pending=8,
overflow=AsyncOverflowPolicy::DropOldest,
),
)
let config = parse_async_logger_config_text(text)
inspect(config.max_pending, content="8")
inspect(match config.overflow {
AsyncOverflowPolicy::Blocking => "Blocking"
AsyncOverflowPolicy::DropOldest => "DropOldest"
AsyncOverflowPolicy::DropNewest => "DropNewest"
}, content="DropOldest")
}
test "async build config stringify roundtrips nested logger and async fields" {
let text = stringify_async_logger_build_config(
AsyncLoggerBuildConfig::new(
logger=@bitlogger.LoggerConfig::new(
min_level=@bitlogger.Level::Warn,
target="async.roundtrip",
timestamp=true,
sink=@bitlogger.SinkConfig::new(kind=@bitlogger.SinkKind::TextConsole),
),
async_config=AsyncLoggerConfig::new(
max_pending=2,
overflow=AsyncOverflowPolicy::DropNewest,
),
),
)
let config = parse_async_logger_build_config_text(text)
inspect(config.logger.min_level.label(), content="WARN")
inspect(config.logger.target, content="async.roundtrip")
inspect(config.logger.timestamp, content="true")
inspect(config.async_config.max_pending, content="2")
inspect(match config.async_config.overflow {
AsyncOverflowPolicy::Blocking => "Blocking"
AsyncOverflowPolicy::DropOldest => "DropOldest"
AsyncOverflowPolicy::DropNewest => "DropNewest"
}, content="DropNewest")
}
+46 -2
View File
@@ -30,7 +30,7 @@ fn parse_async_overflow(name : String) -> AsyncOverflowPolicy raise {
}
}
fn parse_async_logger_config_text(input : String) -> AsyncLoggerConfig raise {
pub fn parse_async_logger_config_text(input : String) -> AsyncLoggerConfig raise {
let root = @json_parser.parse(input)
let obj = match root.as_object() {
Some(obj) => obj
@@ -53,6 +53,26 @@ fn parse_async_logger_config_text(input : String) -> AsyncLoggerConfig raise {
AsyncLoggerConfig::new(max_pending=max_pending, overflow=overflow)
}
pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {
@json_parser.JsonValue::Object({
"max_pending": @json_parser.JsonValue::Number(config.max_pending.to_double()),
"overflow": @json_parser.JsonValue::String(match config.overflow {
AsyncOverflowPolicy::Blocking => "Blocking"
AsyncOverflowPolicy::DropOldest => "DropOldest"
AsyncOverflowPolicy::DropNewest => "DropNewest"
}),
})
}
pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool = false) -> String {
let value = async_logger_config_to_json(config)
if pretty {
@json_parser.stringify_pretty(value, 2)
} else {
@json_parser.stringify(value)
}
}
pub struct AsyncLoggerBuildConfig {
logger : @bitlogger.LoggerConfig
async_config : AsyncLoggerConfig
@@ -82,6 +102,27 @@ pub fn parse_async_logger_build_config_text(input : String) -> AsyncLoggerBuildC
AsyncLoggerBuildConfig::new(logger=logger, async_config=async_config)
}
pub fn async_logger_build_config_to_json(
config : AsyncLoggerBuildConfig,
) -> @json_parser.JsonValue {
@json_parser.JsonValue::Object({
"logger": @bitlogger.logger_config_to_json(config.logger),
"async_config": async_logger_config_to_json(config.async_config),
})
}
pub fn stringify_async_logger_build_config(
config : AsyncLoggerBuildConfig,
pretty~ : Bool = false,
) -> String {
let value = async_logger_build_config_to_json(config)
if pretty {
@json_parser.stringify_pretty(value, 2)
} else {
@json_parser.stringify(value)
}
}
pub struct AsyncLogger[S] {
min_level : @bitlogger.Level
target : String
@@ -351,7 +392,10 @@ pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = fal
}
pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {
while self.pending_count() > 0 && self.is_running() {
while self.pending_count() > 0 {
if self.has_failed() {
break
}
@async.pause()
}
}
+32
View File
@@ -39,6 +39,38 @@ pub fn parse_async_logger_build_config_text(input : String) -> AsyncLoggerBuildC
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn parse_async_logger_config_text(input : String) -> AsyncLoggerConfig raise {
ignore(input)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {
ignore(config)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool = false) -> String {
ignore(config)
ignore(pretty)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn async_logger_build_config_to_json(
config : AsyncLoggerBuildConfig,
) -> @json_parser.JsonValue {
ignore(config)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn stringify_async_logger_build_config(
config : AsyncLoggerBuildConfig,
pretty~ : Bool = false,
) -> String {
ignore(config)
ignore(pretty)
abort("bitlogger_async currently only supports native/llvm backends")
}
pub fn async_logger[S : @bitlogger.Sink](
sink : S,
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),