mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-30 23:14:22 +00:00
🔖 prepare 0.5.2 release notes
This commit is contained in:
@@ -59,6 +59,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
moon check src-async --target js
|
moon check src-async --target js
|
||||||
|
|
||||||
|
- name: Test bitlogger_async native
|
||||||
|
run: |
|
||||||
|
moon test src-async --target native
|
||||||
|
|
||||||
- name: Test bitlogger_async wasm-gc
|
- name: Test bitlogger_async wasm-gc
|
||||||
run: |
|
run: |
|
||||||
moon test src-async --target wasm-gc
|
moon test src-async --target wasm-gc
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ ignore(logger.flush())
|
|||||||
|
|
||||||
## 支持情况
|
## 支持情况
|
||||||
|
|
||||||
- 当前已验证目标:`native`、`js`、`wasm`、`wasm-gc`
|
- `BitLogger` 当前在 CI 中检查/验证的目标是 `native`、`js`、`wasm-gc`
|
||||||
|
- `bitlogger_async` 当前在 CI 中检查 `native`、`js`、`wasm-gc`,测试覆盖 `native`、`js`、`wasm-gc`
|
||||||
|
- `wasm` 目标在源码 `moon.pkg` 中保留声明,但当前未纳入 CI 验证口径
|
||||||
- `llvm` 目前按实验性目标处理,当前环境未完成验证
|
- `llvm` 目前按实验性目标处理,当前环境未完成验证
|
||||||
- 文件输出是 native 能力;跨端代码里建议先判断 `native_files_supported()`
|
- 文件输出是 native 能力;跨端代码里建议先判断 `native_files_supported()`
|
||||||
- `src-async` 可用,但示例 `examples/async_basic` 目前仍按 native 入口提供
|
- `src-async` 可用,但示例 `examples/async_basic` 目前仍按 native 入口提供
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
## BitLogger Update Changes
|
||||||
|
|
||||||
|
version 0.5.2
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
- docs: align the README support matrix with the actual CI validation scope for both `BitLogger` and `bitlogger_async`
|
||||||
|
|
||||||
|
### Test
|
||||||
|
|
||||||
|
- test: add sync config parser failure-path coverage for malformed JSON, wrong field types, and invalid enum values
|
||||||
|
- test: add async config parser failure-path coverage for malformed input, wrong async field types, invalid build roots, and nested sync config parse failures
|
||||||
|
- test: cover async worker failure reporting and `wait_idle()` early-stop behavior when batch flush fails
|
||||||
|
- test: extend CI so `bitlogger_async` native tests run alongside the existing `js` and `wasm-gc` coverage
|
||||||
|
|
||||||
|
### Runtime
|
||||||
|
|
||||||
|
- runtime: allow async flush callbacks to raise so async worker failure state and `last_error()` reporting are reachable through the public API
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- this release is a focused validation follow-up that closes the gap between published verification claims and the real test matrix
|
||||||
|
- release verification now covers sync checks/tests plus async checks/tests across `native`, `js`, and `wasm-gc`
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
suberror TestFlushError {
|
||||||
|
TestFlushError(String)
|
||||||
|
}
|
||||||
|
|
||||||
async test "shutdown drains pending records" {
|
async test "shutdown drains pending records" {
|
||||||
inspect(async_runtime_mode_label(async_runtime_mode()) == "native_worker" || async_runtime_mode_label(async_runtime_mode()) == "compatibility", content="true")
|
inspect(async_runtime_mode_label(async_runtime_mode()) == "native_worker" || async_runtime_mode_label(async_runtime_mode()) == "compatibility", content="true")
|
||||||
let written : Ref[Array[String]] = Ref([])
|
let written : Ref[Array[String]] = Ref([])
|
||||||
@@ -150,6 +154,48 @@ test "async build config stringify roundtrips nested logger and async fields" {
|
|||||||
}, content="Shutdown")
|
}, content="Shutdown")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "async config parsers reject malformed input" {
|
||||||
|
let invalid_json_error = (fn() -> String raise {
|
||||||
|
ignore(parse_async_logger_config_text("{"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
err => err.to_string()
|
||||||
|
}
|
||||||
|
inspect(invalid_json_error.contains("UnexpectedToken"), content="true")
|
||||||
|
|
||||||
|
let wrong_type_error = (fn() -> String raise {
|
||||||
|
ignore(parse_async_logger_config_text("{\"max_pending\":\"many\"}"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
err => err.to_string()
|
||||||
|
}
|
||||||
|
inspect(wrong_type_error.contains("Expected number at async_config.max_pending"), content="true")
|
||||||
|
|
||||||
|
let invalid_enum_error = (fn() -> String raise {
|
||||||
|
ignore(parse_async_logger_config_text("{\"overflow\":\"Burst\"}"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
err => err.to_string()
|
||||||
|
}
|
||||||
|
inspect(invalid_enum_error.contains("Unsupported async overflow policy: Burst"), content="true")
|
||||||
|
|
||||||
|
let invalid_build_root_error = (fn() -> String raise {
|
||||||
|
ignore(parse_async_logger_build_config_text("[]"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
err => err.to_string()
|
||||||
|
}
|
||||||
|
inspect(invalid_build_root_error.contains("Expected object at async logger build config root"), content="true")
|
||||||
|
|
||||||
|
let nested_sync_error = (fn() -> String raise {
|
||||||
|
ignore(parse_async_logger_build_config_text("{\"logger\":{\"timestamp\":\"true\"}}"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
err => err.to_string()
|
||||||
|
}
|
||||||
|
inspect(nested_sync_error.contains("ConfigError.InvalidConfig"), content="true")
|
||||||
|
}
|
||||||
|
|
||||||
test "async runtime capability helpers stay consistent" {
|
test "async runtime capability helpers stay consistent" {
|
||||||
let mode = async_runtime_mode()
|
let mode = async_runtime_mode()
|
||||||
let state = async_runtime_state()
|
let state = async_runtime_state()
|
||||||
@@ -251,6 +297,41 @@ async test "run drains queued records in compatibility backends too" {
|
|||||||
inspect(written.val[1], content="two")
|
inspect(written.val[1], content="two")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async test "async logger records worker failures and wait_idle stops early" {
|
||||||
|
let writes : Ref[Int] = Ref(0)
|
||||||
|
let logger = async_logger(
|
||||||
|
@bitlogger.callback_sink(fn(_) {
|
||||||
|
writes.val += 1
|
||||||
|
}),
|
||||||
|
config=AsyncLoggerConfig::new(
|
||||||
|
max_pending=4,
|
||||||
|
overflow=AsyncOverflowPolicy::Blocking,
|
||||||
|
flush=AsyncFlushPolicy::Batch,
|
||||||
|
),
|
||||||
|
min_level=@bitlogger.Level::Info,
|
||||||
|
target="async.failure",
|
||||||
|
flush=fn(_) -> Int raise {
|
||||||
|
raise TestFlushError("flush exploded")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
@async.with_task_group(group => {
|
||||||
|
group.spawn_bg(allow_failure=true, () => logger.run())
|
||||||
|
logger.info("ok")
|
||||||
|
logger.info("flush-now")
|
||||||
|
logger.wait_idle()
|
||||||
|
inspect(logger.has_failed(), content="true")
|
||||||
|
inspect(logger.pending_count(), content="1")
|
||||||
|
logger.close(clear=true)
|
||||||
|
})
|
||||||
|
|
||||||
|
inspect(writes.val, content="1")
|
||||||
|
inspect(logger.has_failed(), content="true")
|
||||||
|
inspect(logger.last_error().contains("TestFlushError"), content="true")
|
||||||
|
inspect(logger.is_running(), content="false")
|
||||||
|
inspect(logger.pending_count(), content="0")
|
||||||
|
}
|
||||||
|
|
||||||
async test "library async logger keeps a smaller async facade" {
|
async test "library async logger keeps a smaller async facade" {
|
||||||
let written_targets : Ref[Array[String]] = Ref([])
|
let written_targets : Ref[Array[String]] = Ref([])
|
||||||
let written_messages : Ref[Array[String]] = Ref([])
|
let written_messages : Ref[Array[String]] = Ref([])
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ pub struct AsyncLogger[S] {
|
|||||||
linger_ms : Int
|
linger_ms : Int
|
||||||
flush_policy : AsyncFlushPolicy
|
flush_policy : AsyncFlushPolicy
|
||||||
sink : S
|
sink : S
|
||||||
flush_sink : (S) -> Int
|
flush_sink : (S) -> Int raise
|
||||||
context_fields : Array[@bitlogger.Field]
|
context_fields : Array[@bitlogger.Field]
|
||||||
filter : (@bitlogger.Record) -> Bool
|
filter : (@bitlogger.Record) -> Bool
|
||||||
patch : @bitlogger.RecordPatch
|
patch : @bitlogger.RecordPatch
|
||||||
@@ -106,7 +106,7 @@ pub fn[S] async_logger(
|
|||||||
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||||
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
||||||
target~ : String = "",
|
target~ : String = "",
|
||||||
flush~ : (S) -> Int = fn(_) { 0 },
|
flush~ : (S) -> Int raise = fn(_) { 0 },
|
||||||
) -> AsyncLogger[S] {
|
) -> AsyncLogger[S] {
|
||||||
{
|
{
|
||||||
min_level,
|
min_level,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub fn[S] LibraryAsyncLogger::new(
|
|||||||
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||||
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
||||||
target~ : String = "",
|
target~ : String = "",
|
||||||
flush~ : (S) -> Int = fn(_) { 0 },
|
flush~ : (S) -> Int raise = fn(_) { 0 },
|
||||||
) -> LibraryAsyncLogger[S] {
|
) -> LibraryAsyncLogger[S] {
|
||||||
library_async_logger(
|
library_async_logger(
|
||||||
async_logger(
|
async_logger(
|
||||||
|
|||||||
@@ -116,6 +116,32 @@ test "logger config parser reads file rotation options" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "logger config parser rejects malformed sync config input" {
|
||||||
|
let invalid_json_error = (fn() -> String raise ConfigError {
|
||||||
|
ignore(parse_logger_config_text("{"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
ConfigError::InvalidConfig(message) => message
|
||||||
|
}
|
||||||
|
inspect(invalid_json_error.contains("Invalid JSON:"), content="true")
|
||||||
|
|
||||||
|
let wrong_type_error = (fn() -> String raise ConfigError {
|
||||||
|
ignore(parse_logger_config_text("{\"timestamp\":\"true\"}"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
ConfigError::InvalidConfig(message) => message
|
||||||
|
}
|
||||||
|
inspect(wrong_type_error, content="Expected bool at key timestamp")
|
||||||
|
|
||||||
|
let invalid_enum_error = (fn() -> String raise ConfigError {
|
||||||
|
ignore(parse_logger_config_text("{\"sink\":{\"kind\":\"console\",\"text_formatter\":{\"color_mode\":\"loud\"}}}"))
|
||||||
|
"no error"
|
||||||
|
})() catch {
|
||||||
|
ConfigError::InvalidConfig(message) => message
|
||||||
|
}
|
||||||
|
inspect(invalid_enum_error, content="Unsupported color mode: loud")
|
||||||
|
}
|
||||||
|
|
||||||
test "logger config stringify roundtrips stable fields" {
|
test "logger config stringify roundtrips stable fields" {
|
||||||
let text = stringify_logger_config(
|
let text = stringify_logger_config(
|
||||||
LoggerConfig::new(
|
LoggerConfig::new(
|
||||||
|
|||||||
Reference in New Issue
Block a user