mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-31 23:44:39 +00:00
🔊 Update 1.0.0
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
## BitLogger Update Changes
|
||||||
|
|
||||||
|
version 1.0.0
|
||||||
|
|
||||||
|
### Migration
|
||||||
|
|
||||||
|
- migration: run the MoonBit 0.10 formatter migration across the repository and adopt the current `trait` / `impl` formatting and `fn`-prefixed impl method style
|
||||||
|
- migration: replace the legacy root manifest with `moon.mod`, aligning the package root with the current MoonBit manifest format
|
||||||
|
- migration: update the async dependency to `moonbitlang/async@0.20.0`
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
- docs: refresh the README example and project command notes after the formatter migration so examples match the current MoonBit surface
|
||||||
|
- docs: document that `async_basic` depends on `moonbitlang/async`, whose upstream README currently only claims native/LLVM support on Linux/MacOS
|
||||||
|
- docs: narrow the repository prompt validation guidance so Windows-local `src-async --target native` failures are not treated as BitLogger regressions unless reproduced on a supported native platform
|
||||||
|
|
||||||
|
### Verification
|
||||||
|
|
||||||
|
- verify: keep the main package passing `moon check`, `moon test`, `moon check --target native`, `moon check --target wasm-gc`, and `moon check --target js`
|
||||||
|
- verify: keep `src-async` passing `moon check` / `moon test` on `wasm-gc` and `js`, and confirm the native async path on a supported environment baseline
|
||||||
|
- verify: keep the example path healthy with `moon run examples/basic` and `moon check examples/async_basic --target native`
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- this release marks the MoonBit 0.10 generation as the new BitLogger baseline
|
||||||
|
- the repository now treats Linux/MacOS as the supported native baseline for `moonbitlang/async` until upstream Windows native support is stated clearly
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Versioned BitLogger change summaries.
|
Versioned BitLogger change summaries.
|
||||||
|
|
||||||
|
- [1.0.0](./1.0.0.md)
|
||||||
- [0.5.3](./0.5.3.md)
|
- [0.5.3](./0.5.3.md)
|
||||||
- [0.5.2](./0.5.2.md)
|
- [0.5.2](./0.5.2.md)
|
||||||
- [0.5.1](./0.5.1.md)
|
- [0.5.1](./0.5.1.md)
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
|
///|
|
||||||
async fn main {
|
async fn main {
|
||||||
println("examples/async_basic is shipped as a native-only example because async fn main entry support is still limited on non-native targets, even though src-async itself keeps compatibility behavior.")
|
println(
|
||||||
println(@lib_async.stringify_async_runtime_state(@lib_async.async_runtime_state(), pretty=true))
|
"examples/async_basic is shipped as a native-only example because async fn main entry support is still limited on non-native targets, even though src-async itself keeps compatibility behavior.",
|
||||||
|
)
|
||||||
|
println(
|
||||||
|
@lib_async.stringify_async_runtime_state(
|
||||||
|
@lib_async.async_runtime_state(),
|
||||||
|
pretty=true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
let raw = "{\"logger\":{\"min_level\":\"info\",\"target\":\"async.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"separator\":\" | \"}}},\"async_config\":{\"max_pending\":2,\"overflow\":\"DropOldest\",\"max_batch\":4,\"linger_ms\":5,\"flush\":\"Batch\"}}"
|
let raw = "{\"logger\":{\"min_level\":\"info\",\"target\":\"async.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"separator\":\" | \"}}},\"async_config\":{\"max_pending\":2,\"overflow\":\"DropOldest\",\"max_batch\":4,\"linger_ms\":5,\"flush\":\"Batch\"}}"
|
||||||
let config = @lib_async.parse_async_logger_build_config_text(raw) catch {
|
let config = @lib_async.parse_async_logger_build_config_text(raw) catch {
|
||||||
@@ -14,10 +22,12 @@ async fn main {
|
|||||||
let logger = @lib_async.build_async_logger(config)
|
let logger = @lib_async.build_async_logger(config)
|
||||||
.with_context_fields([@lib.field("service", "bitlogger")])
|
.with_context_fields([@lib.field("service", "bitlogger")])
|
||||||
.with_filter(@lib.target_has_prefix("async"))
|
.with_filter(@lib.target_has_prefix("async"))
|
||||||
.with_patch(@lib.compose_patches([
|
.with_patch(
|
||||||
|
@lib.compose_patches([
|
||||||
@lib.prefix_message("[async] "),
|
@lib.prefix_message("[async] "),
|
||||||
@lib.redact_fields(["token"]),
|
@lib.redact_fields(["token"]),
|
||||||
]))
|
]),
|
||||||
|
)
|
||||||
|
|
||||||
println(@lib_async.stringify_async_logger_state(logger.state(), pretty=true))
|
println(@lib_async.stringify_async_logger_state(logger.state(), pretty=true))
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
"Nanaloveyuki/BitLogger/src" @lib,
|
"Nanaloveyuki/BitLogger/src" @lib,
|
||||||
"Nanaloveyuki/BitLogger/src-async" @lib_async,
|
"Nanaloveyuki/BitLogger/src-async" @lib_async,
|
||||||
"moonbitlang/async" @async,
|
"moonbitlang/async",
|
||||||
}
|
}
|
||||||
|
|
||||||
supported_targets = "+native"
|
supported_targets = "+native"
|
||||||
|
|||||||
+66
-24
@@ -1,10 +1,14 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
let preset_logger = @lib.build_logger(
|
let preset_logger = @lib.build_logger(
|
||||||
@lib.with_queue(
|
@lib.with_queue(
|
||||||
@lib.text_console(
|
@lib.text_console(
|
||||||
min_level=@lib.Level::Info,
|
min_level=@lib.Level::Info,
|
||||||
target="preset",
|
target="preset",
|
||||||
text_formatter=@lib.TextFormatterConfig::new(show_timestamp=false, separator=" | "),
|
text_formatter=@lib.TextFormatterConfig::new(
|
||||||
|
show_timestamp=false,
|
||||||
|
separator=" | ",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
max_pending=2,
|
max_pending=2,
|
||||||
overflow=@lib.QueueOverflowPolicy::DropOldest,
|
overflow=@lib.QueueOverflowPolicy::DropOldest,
|
||||||
@@ -20,8 +24,11 @@ fn main {
|
|||||||
@lib.info("hello from BitLogger", fields=[@lib.field("mode", "demo")])
|
@lib.info("hello from BitLogger", fields=[@lib.field("mode", "demo")])
|
||||||
|
|
||||||
// Direct Logger::new(...) composition stays useful for custom sink graphs.
|
// Direct Logger::new(...) composition stays useful for custom sink graphs.
|
||||||
let logger = @lib.Logger::new(@lib.console_sink(), min_level=@lib.Level::Trace, target="custom")
|
let logger = @lib.Logger::new(
|
||||||
.with_context_fields([@lib.field("service", "bitlogger")])
|
@lib.console_sink(),
|
||||||
|
min_level=@lib.Level::Trace,
|
||||||
|
target="custom",
|
||||||
|
).with_context_fields([@lib.field("service", "bitlogger")])
|
||||||
logger.debug("custom logger ready", fields=[@lib.field("sink", "console")])
|
logger.debug("custom logger ready", fields=[@lib.field("sink", "console")])
|
||||||
|
|
||||||
let bound_logger = @lib.Logger::new(
|
let bound_logger = @lib.Logger::new(
|
||||||
@@ -31,7 +38,11 @@ fn main {
|
|||||||
).bind(@lib.fields([("service", "bitlogger"), ("scope", "audit")]))
|
).bind(@lib.fields([("service", "bitlogger"), ("scope", "audit")]))
|
||||||
bound_logger.info("bound logger ready", fields=[@lib.field("mode", "demo")])
|
bound_logger.info("bound logger ready", fields=[@lib.field("mode", "demo")])
|
||||||
|
|
||||||
let json_logger = @lib.Logger::new(@lib.json_console_sink(), min_level=@lib.Level::Info, target="json")
|
let json_logger = @lib.Logger::new(
|
||||||
|
@lib.json_console_sink(),
|
||||||
|
min_level=@lib.Level::Info,
|
||||||
|
target="json",
|
||||||
|
)
|
||||||
json_logger.info("json output", fields=[@lib.field("kind", "example")])
|
json_logger.info("json output", fields=[@lib.field("kind", "example")])
|
||||||
|
|
||||||
let fanout_logger = @lib.Logger::new(
|
let fanout_logger = @lib.Logger::new(
|
||||||
@@ -55,12 +66,18 @@ fn main {
|
|||||||
split_logger.info("normal output")
|
split_logger.info("normal output")
|
||||||
split_logger.warn("warning output")
|
split_logger.warn("warning output")
|
||||||
|
|
||||||
let timed_logger = @lib.Logger::new(@lib.console_sink(), min_level=@lib.Level::Info, target="timed")
|
let timed_logger = @lib.Logger::new(
|
||||||
.with_timestamp()
|
@lib.console_sink(),
|
||||||
|
min_level=@lib.Level::Info,
|
||||||
|
target="timed",
|
||||||
|
).with_timestamp()
|
||||||
timed_logger.info("timestamp enabled", fields=[@lib.field("kind", "time")])
|
timed_logger.info("timestamp enabled", fields=[@lib.field("kind", "time")])
|
||||||
|
|
||||||
let child_logger = @lib.Logger::new(@lib.console_sink(), min_level=@lib.Level::Info, target="app")
|
let child_logger = @lib.Logger::new(
|
||||||
.child("worker")
|
@lib.console_sink(),
|
||||||
|
min_level=@lib.Level::Info,
|
||||||
|
target="app",
|
||||||
|
).child("worker")
|
||||||
child_logger.info("child target ready")
|
child_logger.info("child target ready")
|
||||||
|
|
||||||
let callback_logger = @lib.Logger::new(
|
let callback_logger = @lib.Logger::new(
|
||||||
@@ -109,25 +126,36 @@ fn main {
|
|||||||
min_level=@lib.Level::Info,
|
min_level=@lib.Level::Info,
|
||||||
target="file",
|
target="file",
|
||||||
)
|
)
|
||||||
file_logger.info("native file sink ready", fields=[@lib.field("kind", "file")])
|
file_logger.info("native file sink ready", fields=[
|
||||||
|
@lib.field("kind", "file"),
|
||||||
|
])
|
||||||
ignore(file_logger.sink.flush())
|
ignore(file_logger.sink.flush())
|
||||||
ignore(file_logger.sink.close())
|
ignore(file_logger.sink.close())
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffered = @lib.buffered_sink(@lib.console_sink(), flush_limit=2)
|
let buffered = @lib.buffered_sink(@lib.console_sink(), flush_limit=2)
|
||||||
let buffered_logger = @lib.Logger::new(buffered, min_level=@lib.Level::Info, target="buffered")
|
let buffered_logger = @lib.Logger::new(
|
||||||
|
buffered,
|
||||||
|
min_level=@lib.Level::Info,
|
||||||
|
target="buffered",
|
||||||
|
)
|
||||||
buffered_logger.info("buffered one")
|
buffered_logger.info("buffered one")
|
||||||
buffered_logger.info("buffered two")
|
buffered_logger.info("buffered two")
|
||||||
buffered.flush()
|
buffered.flush()
|
||||||
|
|
||||||
let filtered = @lib.filter_sink(
|
let filtered = @lib.filter_sink(@lib.console_sink(), fn(rec) {
|
||||||
@lib.console_sink(),
|
|
||||||
fn(rec) {
|
|
||||||
rec.target == "kept"
|
rec.target == "kept"
|
||||||
},
|
})
|
||||||
|
let kept_logger = @lib.Logger::new(
|
||||||
|
filtered,
|
||||||
|
min_level=@lib.Level::Info,
|
||||||
|
target="kept",
|
||||||
|
)
|
||||||
|
let dropped_logger = @lib.Logger::new(
|
||||||
|
filtered,
|
||||||
|
min_level=@lib.Level::Info,
|
||||||
|
target="dropped",
|
||||||
)
|
)
|
||||||
let kept_logger = @lib.Logger::new(filtered, min_level=@lib.Level::Info, target="kept")
|
|
||||||
let dropped_logger = @lib.Logger::new(filtered, min_level=@lib.Level::Info, target="dropped")
|
|
||||||
kept_logger.info("filter kept this")
|
kept_logger.info("filter kept this")
|
||||||
dropped_logger.info("filter dropped this")
|
dropped_logger.info("filter dropped this")
|
||||||
|
|
||||||
@@ -135,10 +163,12 @@ fn main {
|
|||||||
@lib.console_sink(),
|
@lib.console_sink(),
|
||||||
min_level=@lib.Level::Info,
|
min_level=@lib.Level::Info,
|
||||||
target="service",
|
target="service",
|
||||||
).with_filter(@lib.all_of([
|
).with_filter(
|
||||||
|
@lib.all_of([
|
||||||
@lib.target_has_prefix("service"),
|
@lib.target_has_prefix("service"),
|
||||||
@lib.message_contains("kept"),
|
@lib.message_contains("kept"),
|
||||||
]))
|
]),
|
||||||
|
)
|
||||||
filtered_logger.info("logger filter dropped this")
|
filtered_logger.info("logger filter dropped this")
|
||||||
filtered_logger.child("api").info("logger filter kept this")
|
filtered_logger.child("api").info("logger filter kept this")
|
||||||
|
|
||||||
@@ -146,12 +176,17 @@ fn main {
|
|||||||
@lib.console_sink(),
|
@lib.console_sink(),
|
||||||
min_level=@lib.Level::Info,
|
min_level=@lib.Level::Info,
|
||||||
target="auth",
|
target="auth",
|
||||||
).with_patch(@lib.compose_patches([
|
).with_patch(
|
||||||
|
@lib.compose_patches([
|
||||||
@lib.prefix_message("[safe] "),
|
@lib.prefix_message("[safe] "),
|
||||||
@lib.redact_fields(["token"]),
|
@lib.redact_fields(["token"]),
|
||||||
@lib.append_fields([@lib.field("service", "bitlogger")]),
|
@lib.append_fields([@lib.field("service", "bitlogger")]),
|
||||||
]))
|
]),
|
||||||
patched_logger.info("login", fields=[@lib.field("user", "alice"), @lib.field("token", "secret")])
|
)
|
||||||
|
patched_logger.info("login", fields=[
|
||||||
|
@lib.field("user", "alice"),
|
||||||
|
@lib.field("token", "secret"),
|
||||||
|
])
|
||||||
|
|
||||||
let config_logger = @lib.parse_and_build_logger(
|
let config_logger = @lib.parse_and_build_logger(
|
||||||
"{\"min_level\":\"debug\",\"target\":\"config.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"field_separator\":\",\",\"template\":\"[{level}] {target} {message} :: {fields}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
|
"{\"min_level\":\"debug\",\"target\":\"config.demo\",\"timestamp\":true,\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"field_separator\":\",\",\"template\":\"[{level}] {target} {message} :: {fields}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
|
||||||
@@ -165,7 +200,10 @@ fn main {
|
|||||||
config_logger.info("configured from json")
|
config_logger.info("configured from json")
|
||||||
ignore(config_logger.flush())
|
ignore(config_logger.flush())
|
||||||
|
|
||||||
let queue_config = @lib.QueueConfig::new(4, overflow=@lib.QueueOverflowPolicy::DropOldest)
|
let queue_config = @lib.QueueConfig::new(
|
||||||
|
4,
|
||||||
|
overflow=@lib.QueueOverflowPolicy::DropOldest,
|
||||||
|
)
|
||||||
println(@lib.stringify_queue_config(queue_config))
|
println(@lib.stringify_queue_config(queue_config))
|
||||||
|
|
||||||
let formatter_config = @lib.TextFormatterConfig::new(
|
let formatter_config = @lib.TextFormatterConfig::new(
|
||||||
@@ -195,13 +233,17 @@ fn main {
|
|||||||
|
|
||||||
let file_runtime_logger = @lib.build_logger(
|
let file_runtime_logger = @lib.build_logger(
|
||||||
@lib.LoggerConfig::new(
|
@lib.LoggerConfig::new(
|
||||||
sink=@lib.SinkConfig::new(kind=@lib.SinkKind::File, path="bitlogger-runtime-demo.log"),
|
sink=@lib.SinkConfig::new(
|
||||||
|
kind=@lib.SinkKind::File,
|
||||||
|
path="bitlogger-runtime-demo.log",
|
||||||
|
),
|
||||||
queue=Some(@lib.QueueConfig::new(8)),
|
queue=Some(@lib.QueueConfig::new(8)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
file_runtime_logger.info("runtime file logger ready")
|
file_runtime_logger.info("runtime file logger ready")
|
||||||
match file_runtime_logger.file_runtime_state() {
|
match file_runtime_logger.file_runtime_state() {
|
||||||
Some(snapshot) => println(@lib.stringify_runtime_file_state(snapshot, pretty=true))
|
Some(snapshot) =>
|
||||||
|
println(@lib.stringify_runtime_file_state(snapshot, pretty=true))
|
||||||
None => ()
|
None => ()
|
||||||
}
|
}
|
||||||
ignore(file_runtime_logger.file_close())
|
ignore(file_runtime_logger.file_close())
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
let config = @lib.parse_logger_config_text(
|
let config = @lib.parse_logger_config_text(
|
||||||
"{\"min_level\":\"debug\",\"target\":\"demo.config\",\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"separator\":\" | \",\"template\":\"[{level}] {target} {message}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
|
"{\"min_level\":\"debug\",\"target\":\"demo.config\",\"sink\":{\"kind\":\"text_console\",\"text_formatter\":{\"show_timestamp\":false,\"separator\":\" | \",\"template\":\"[{level}] {target} {message}\"}},\"queue\":{\"max_pending\":2,\"overflow\":\"DropOldest\"}}",
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
let logger = @lib.build_logger(
|
let logger = @lib.build_logger(
|
||||||
@lib.console(min_level=@lib.Level::Info, target="demo.console"),
|
@lib.console(min_level=@lib.Level::Info, target="demo.console"),
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
if !@lib.native_files_supported() {
|
if !@lib.native_files_supported() {
|
||||||
println("native file sink is not available on this backend; examples/presets stays portable, while file_rotation remains native-focused")
|
println(
|
||||||
|
"native file sink is not available on this backend; examples/presets stays portable, while file_rotation remains native-focused",
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
let config = @lib.with_queue(
|
let config = @lib.with_queue(
|
||||||
@lib.text_console(
|
@lib.text_console(
|
||||||
@@ -36,10 +37,14 @@ fn main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let file_logger = @lib.build_logger(file_config)
|
let file_logger = @lib.build_logger(file_config)
|
||||||
file_logger.info("file preset ready", fields=[@lib.field("kind", "native-only")])
|
file_logger.info("file preset ready", fields=[
|
||||||
|
@lib.field("kind", "native-only"),
|
||||||
|
])
|
||||||
ignore(file_logger.flush())
|
ignore(file_logger.flush())
|
||||||
ignore(file_logger.file_close())
|
ignore(file_logger.file_close())
|
||||||
} else {
|
} else {
|
||||||
println("file presets are skipped on this backend because native file support is unavailable")
|
println(
|
||||||
|
"file presets are skipped on this backend because native file support is unavailable",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
let logger = @lib.build_logger(
|
let logger = @lib.build_logger(
|
||||||
@lib.text_console(
|
@lib.text_console(
|
||||||
@@ -6,9 +7,7 @@ fn main {
|
|||||||
text_formatter=@lib.TextFormatterConfig::new(
|
text_formatter=@lib.TextFormatterConfig::new(
|
||||||
show_timestamp=false,
|
show_timestamp=false,
|
||||||
color_mode=@lib.ColorMode::Always,
|
color_mode=@lib.ColorMode::Always,
|
||||||
style_tags={
|
style_tags={ "accent": @lib.text_style(fg=Some("#4cc9f0"), bold=true) },
|
||||||
"accent": @lib.text_style(fg=Some("#4cc9f0"), bold=true),
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
fn main {
|
fn main {
|
||||||
let logger = @lib.build_logger(
|
let logger = @lib.build_logger(
|
||||||
@lib.text_console(
|
@lib.text_console(
|
||||||
@@ -11,5 +12,8 @@ fn main {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
logger.info("formatted output", fields=[@lib.field("user", "alice"), @lib.field("request_id", "42")])
|
logger.info("formatted output", fields=[
|
||||||
|
@lib.field("user", "alice"),
|
||||||
|
@lib.field("request_id", "42"),
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
+1229
-402
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,26 @@
|
|||||||
|
///|
|
||||||
pub type ApplicationAsyncLogger = AsyncLogger[@bitlogger.RuntimeSink]
|
pub type ApplicationAsyncLogger = AsyncLogger[@bitlogger.RuntimeSink]
|
||||||
|
|
||||||
pub type ApplicationTextAsyncLogger = AsyncLogger[@bitlogger.FormattedConsoleSink]
|
///|
|
||||||
|
pub type ApplicationTextAsyncLogger = AsyncLogger[
|
||||||
|
@bitlogger.FormattedConsoleSink,
|
||||||
|
]
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_application_async_logger(
|
pub fn build_application_async_logger(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> ApplicationAsyncLogger {
|
) -> ApplicationAsyncLogger {
|
||||||
build_async_logger(config)
|
build_async_logger(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_application_text_async_logger(
|
pub fn build_application_text_async_logger(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> ApplicationTextAsyncLogger {
|
) -> ApplicationTextAsyncLogger {
|
||||||
build_async_text_logger(config)
|
build_async_text_logger(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn parse_and_build_application_async_logger(
|
pub fn parse_and_build_application_async_logger(
|
||||||
input : String,
|
input : String,
|
||||||
) -> ApplicationAsyncLogger raise {
|
) -> ApplicationAsyncLogger raise {
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
|
///|
|
||||||
pub fn async_runtime_mode() -> AsyncRuntimeMode {
|
pub fn async_runtime_mode() -> AsyncRuntimeMode {
|
||||||
@utils.native_worker_async_runtime_mode()
|
@utils.native_worker_async_runtime_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_runtime_supports_background_worker() -> Bool {
|
pub fn async_runtime_supports_background_worker() -> Bool {
|
||||||
ignore(all_async_runtime_modes())
|
ignore(all_async_runtime_modes())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_runtime_guard_closed_on_log() -> Bool {
|
fn async_runtime_guard_closed_on_log() -> Bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_runtime_shutdown_clears_pending_after_wait_idle() -> Bool {
|
fn async_runtime_shutdown_clears_pending_after_wait_idle() -> Bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_runtime_shutdown_waits_for_worker() -> Bool {
|
fn async_runtime_shutdown_waits_for_worker() -> Bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,84 +1,125 @@
|
|||||||
|
///|
|
||||||
pub(all) suberror AsyncLoggerClosed {
|
pub(all) suberror AsyncLoggerClosed {
|
||||||
AsyncLoggerClosed
|
AsyncLoggerClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncOverflowPolicy = @utils.AsyncOverflowPolicy
|
pub type AsyncOverflowPolicy = @utils.AsyncOverflowPolicy
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncFlushPolicy = @utils.AsyncFlushPolicy
|
pub type AsyncFlushPolicy = @utils.AsyncFlushPolicy
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncRuntimeMode = @utils.AsyncRuntimeMode
|
pub type AsyncRuntimeMode = @utils.AsyncRuntimeMode
|
||||||
|
|
||||||
|
///|
|
||||||
fn all_async_runtime_modes() -> Array[AsyncRuntimeMode] {
|
fn all_async_runtime_modes() -> Array[AsyncRuntimeMode] {
|
||||||
[@utils.native_worker_async_runtime_mode(), @utils.compatibility_async_runtime_mode()]
|
[
|
||||||
|
@utils.native_worker_async_runtime_mode(),
|
||||||
|
@utils.compatibility_async_runtime_mode(),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncRuntimeState = @utils.AsyncRuntimeState
|
pub type AsyncRuntimeState = @utils.AsyncRuntimeState
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncLoggerState = @utils.AsyncLoggerState
|
pub type AsyncLoggerState = @utils.AsyncLoggerState
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {
|
pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {
|
||||||
@utils.async_runtime_mode_label(mode)
|
@utils.async_runtime_mode_label(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_runtime_state() -> AsyncRuntimeState {
|
pub fn async_runtime_state() -> AsyncRuntimeState {
|
||||||
AsyncRuntimeState::new(async_runtime_mode(), async_runtime_supports_background_worker())
|
AsyncRuntimeState::new(
|
||||||
|
async_runtime_mode(),
|
||||||
|
async_runtime_supports_background_worker(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_runtime_state_to_json(state : AsyncRuntimeState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn async_runtime_state_to_json(
|
||||||
|
state : AsyncRuntimeState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.async_runtime_state_to_json(state)
|
@utils.async_runtime_state_to_json(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_async_runtime_state(
|
pub fn stringify_async_runtime_state(
|
||||||
state : AsyncRuntimeState,
|
state : AsyncRuntimeState,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
@utils.stringify_async_runtime_state(state, pretty=pretty)
|
@utils.stringify_async_runtime_state(state, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn async_logger_state_to_json(
|
||||||
|
state : AsyncLoggerState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.async_logger_state_to_json(state)
|
@utils.async_logger_state_to_json(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_async_logger_state(
|
pub fn stringify_async_logger_state(
|
||||||
state : AsyncLoggerState,
|
state : AsyncLoggerState,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
@utils.stringify_async_logger_state(state, pretty=pretty)
|
@utils.stringify_async_logger_state(state, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncLoggerConfig = @utils.AsyncLoggerConfig
|
pub type AsyncLoggerConfig = @utils.AsyncLoggerConfig
|
||||||
|
|
||||||
pub fn parse_async_logger_config_text(input : String) -> AsyncLoggerConfig raise {
|
///|
|
||||||
|
pub fn parse_async_logger_config_text(
|
||||||
|
input : String,
|
||||||
|
) -> AsyncLoggerConfig raise {
|
||||||
@utils.parse_async_logger_config_text(input)
|
@utils.parse_async_logger_config_text(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn async_logger_config_to_json(
|
||||||
|
config : AsyncLoggerConfig,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.async_logger_config_to_json(config)
|
@utils.async_logger_config_to_json(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_async_logger_config(config, pretty=pretty)
|
pub fn stringify_async_logger_config(
|
||||||
|
config : AsyncLoggerConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_async_logger_config(config, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type AsyncLoggerBuildConfig = @utils.AsyncLoggerBuildConfig
|
pub type AsyncLoggerBuildConfig = @utils.AsyncLoggerBuildConfig
|
||||||
|
|
||||||
pub fn parse_async_logger_build_config_text(input : String) -> AsyncLoggerBuildConfig raise {
|
///|
|
||||||
|
pub fn parse_async_logger_build_config_text(
|
||||||
|
input : String,
|
||||||
|
) -> AsyncLoggerBuildConfig raise {
|
||||||
@utils.parse_async_logger_build_config_text(input)
|
@utils.parse_async_logger_build_config_text(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_logger_build_config_to_json(
|
pub fn async_logger_build_config_to_json(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> @json_parser.JsonValue {
|
) -> @json_parser.JsonValue {
|
||||||
@utils.async_logger_build_config_to_json(config)
|
@utils.async_logger_build_config_to_json(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_async_logger_build_config(
|
pub fn stringify_async_logger_build_config(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
@utils.stringify_async_logger_build_config(config, pretty=pretty)
|
@utils.stringify_async_logger_build_config(config, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct AsyncLogger[S] {
|
pub struct AsyncLogger[S] {
|
||||||
min_level : @bitlogger.Level
|
min_level : @bitlogger.Level
|
||||||
target : String
|
target : String
|
||||||
@@ -101,12 +142,13 @@ pub struct AsyncLogger[S] {
|
|||||||
last_error : Ref[String]
|
last_error : Ref[String]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] async_logger(
|
pub fn[S] async_logger(
|
||||||
sink : S,
|
sink : S,
|
||||||
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 raise = fn(_) { 0 },
|
flush? : (S) -> Int raise = fn(_) { 0 },
|
||||||
) -> AsyncLogger[S] {
|
) -> AsyncLogger[S] {
|
||||||
{
|
{
|
||||||
min_level,
|
min_level,
|
||||||
@@ -131,6 +173,7 @@ pub fn[S] async_logger(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn queue_kind_of(config : AsyncLoggerConfig) -> @aqueue.Kind {
|
fn queue_kind_of(config : AsyncLoggerConfig) -> @aqueue.Kind {
|
||||||
let limit = if config.max_pending < 0 { 0 } else { config.max_pending }
|
let limit = if config.max_pending < 0 { 0 } else { config.max_pending }
|
||||||
match config.overflow {
|
match config.overflow {
|
||||||
@@ -140,14 +183,23 @@ fn queue_kind_of(config : AsyncLoggerConfig) -> @aqueue.Kind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] AsyncLogger::with_timestamp(self : AsyncLogger[S], enabled~ : Bool = true) -> AsyncLogger[S] {
|
///|
|
||||||
|
pub fn[S] AsyncLogger::with_timestamp(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
enabled? : Bool = true,
|
||||||
|
) -> AsyncLogger[S] {
|
||||||
{ ..self, timestamp: enabled }
|
{ ..self, timestamp: enabled }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] AsyncLogger::with_target(self : AsyncLogger[S], target : String) -> AsyncLogger[S] {
|
///|
|
||||||
{ ..self, target }
|
pub fn[S] AsyncLogger::with_target(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
target : String,
|
||||||
|
) -> AsyncLogger[S] {
|
||||||
|
{ ..self, target, }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::with_context_fields(
|
pub fn[S] AsyncLogger::with_context_fields(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
fields : Array[@bitlogger.Field],
|
fields : Array[@bitlogger.Field],
|
||||||
@@ -155,39 +207,33 @@ pub fn[S] AsyncLogger::with_context_fields(
|
|||||||
{ ..self, context_fields: fields }
|
{ ..self, context_fields: fields }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::with_filter(
|
pub fn[S] AsyncLogger::with_filter(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
predicate : (@bitlogger.Record) -> Bool,
|
predicate : (@bitlogger.Record) -> Bool,
|
||||||
) -> AsyncLogger[S] {
|
) -> AsyncLogger[S] {
|
||||||
let current = self.filter
|
let current = self.filter
|
||||||
{
|
{ ..self, filter: fn(rec) { current(rec) && predicate(rec) } }
|
||||||
..self,
|
|
||||||
filter: fn(rec) {
|
|
||||||
current(rec) && predicate(rec)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::with_patch(
|
pub fn[S] AsyncLogger::with_patch(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
patch : @bitlogger.RecordPatch,
|
patch : @bitlogger.RecordPatch,
|
||||||
) -> AsyncLogger[S] {
|
) -> AsyncLogger[S] {
|
||||||
let current = self.patch
|
let current = self.patch
|
||||||
{
|
{ ..self, patch: fn(rec) { patch(current(rec)) } }
|
||||||
..self,
|
|
||||||
patch: fn(rec) {
|
|
||||||
patch(current(rec))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::with_min_level(
|
pub fn[S] AsyncLogger::with_min_level(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
min_level : @bitlogger.Level,
|
min_level : @bitlogger.Level,
|
||||||
) -> AsyncLogger[S] {
|
) -> AsyncLogger[S] {
|
||||||
{ ..self, min_level }
|
{ ..self, min_level, }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn combine_targets(parent : String, child : String) -> String {
|
fn combine_targets(parent : String, child : String) -> String {
|
||||||
if parent == "" {
|
if parent == "" {
|
||||||
child
|
child
|
||||||
@@ -198,14 +244,23 @@ fn combine_targets(parent : String, child : String) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] AsyncLogger::child(self : AsyncLogger[S], target : String) -> AsyncLogger[S] {
|
///|
|
||||||
|
pub fn[S] AsyncLogger::child(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
target : String,
|
||||||
|
) -> AsyncLogger[S] {
|
||||||
{ ..self, target: combine_targets(self.target, target) }
|
{ ..self, target: combine_targets(self.target, target) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] AsyncLogger::is_enabled(self : AsyncLogger[S], level : @bitlogger.Level) -> Bool {
|
///|
|
||||||
|
pub fn[S] AsyncLogger::is_enabled(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
level : @bitlogger.Level,
|
||||||
|
) -> Bool {
|
||||||
level.enabled(self.min_level)
|
level.enabled(self.min_level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn merge_fields(
|
fn merge_fields(
|
||||||
left : Array[@bitlogger.Field],
|
left : Array[@bitlogger.Field],
|
||||||
right : Array[@bitlogger.Field],
|
right : Array[@bitlogger.Field],
|
||||||
@@ -219,32 +274,27 @@ fn merge_fields(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::log(
|
pub async fn[S] AsyncLogger::log(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
level : @bitlogger.Level,
|
level : @bitlogger.Level,
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
target? : String = "",
|
target? : String = "",
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
guard !(async_runtime_guard_closed_on_log() && self.is_closed()) else {
|
guard !(async_runtime_guard_closed_on_log() && self.is_closed()) else { () }
|
||||||
()
|
guard self.is_enabled(level) else { () }
|
||||||
}
|
|
||||||
guard self.is_enabled(level) else {
|
|
||||||
()
|
|
||||||
}
|
|
||||||
let actual_target = if target == "" { self.target } else { target }
|
let actual_target = if target == "" { self.target } else { target }
|
||||||
let timestamp_ms = if self.timestamp { @env.now() } else { 0UL }
|
let timestamp_ms = if self.timestamp { @env.now() } else { 0UL }
|
||||||
let rec = @bitlogger.Record::new(
|
let rec = @bitlogger.Record::new(
|
||||||
level,
|
level,
|
||||||
message,
|
message,
|
||||||
timestamp_ms=timestamp_ms,
|
timestamp_ms~,
|
||||||
target=actual_target,
|
target=actual_target,
|
||||||
fields=merge_fields(self.context_fields, fields),
|
fields=merge_fields(self.context_fields, fields),
|
||||||
)
|
)
|
||||||
let rec = (self.patch)(rec)
|
let rec = (self.patch)(rec)
|
||||||
guard (self.filter)(rec) else {
|
guard (self.filter)(rec) else { () }
|
||||||
()
|
|
||||||
}
|
|
||||||
let accepted = self.queue.try_put(rec) catch {
|
let accepted = self.queue.try_put(rec) catch {
|
||||||
err if err is AsyncLoggerClosed => false
|
err if err is AsyncLoggerClosed => false
|
||||||
err => raise err
|
err => raise err
|
||||||
@@ -254,7 +304,7 @@ pub async fn[S] AsyncLogger::log(
|
|||||||
} else {
|
} else {
|
||||||
match self.overflow {
|
match self.overflow {
|
||||||
AsyncOverflowPolicy::Blocking => {
|
AsyncOverflowPolicy::Blocking => {
|
||||||
let accepted = (async fn() -> Bool raise {
|
let accepted = (async fn() -> Bool {
|
||||||
self.queue.put(rec)
|
self.queue.put(rec)
|
||||||
true
|
true
|
||||||
})() catch {
|
})() catch {
|
||||||
@@ -265,81 +315,93 @@ pub async fn[S] AsyncLogger::log(
|
|||||||
self.pending_count.val += 1
|
self.pending_count.val += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AsyncOverflowPolicy::DropOldest | AsyncOverflowPolicy::DropNewest => {
|
AsyncOverflowPolicy::DropOldest | AsyncOverflowPolicy::DropNewest =>
|
||||||
self.dropped_count.val += 1
|
self.dropped_count.val += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::trace(
|
pub async fn[S] AsyncLogger::trace(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.log(@bitlogger.Level::Trace, message, fields=fields)
|
self.log(@bitlogger.Level::Trace, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::debug(
|
pub async fn[S] AsyncLogger::debug(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.log(@bitlogger.Level::Debug, message, fields=fields)
|
self.log(@bitlogger.Level::Debug, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::info(
|
pub async fn[S] AsyncLogger::info(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.log(@bitlogger.Level::Info, message, fields=fields)
|
self.log(@bitlogger.Level::Info, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::warn(
|
pub async fn[S] AsyncLogger::warn(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.log(@bitlogger.Level::Warn, message, fields=fields)
|
self.log(@bitlogger.Level::Warn, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::error(
|
pub async fn[S] AsyncLogger::error(
|
||||||
self : AsyncLogger[S],
|
self : AsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.log(@bitlogger.Level::Error, message, fields=fields)
|
self.log(@bitlogger.Level::Error, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::pending_count(self : AsyncLogger[S]) -> Int {
|
pub fn[S] AsyncLogger::pending_count(self : AsyncLogger[S]) -> Int {
|
||||||
self.pending_count.val
|
self.pending_count.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::dropped_count(self : AsyncLogger[S]) -> Int {
|
pub fn[S] AsyncLogger::dropped_count(self : AsyncLogger[S]) -> Int {
|
||||||
self.dropped_count.val
|
self.dropped_count.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::is_closed(self : AsyncLogger[S]) -> Bool {
|
pub fn[S] AsyncLogger::is_closed(self : AsyncLogger[S]) -> Bool {
|
||||||
self.is_closed.val
|
self.is_closed.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::is_running(self : AsyncLogger[S]) -> Bool {
|
pub fn[S] AsyncLogger::is_running(self : AsyncLogger[S]) -> Bool {
|
||||||
self.is_running.val
|
self.is_running.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::has_failed(self : AsyncLogger[S]) -> Bool {
|
pub fn[S] AsyncLogger::has_failed(self : AsyncLogger[S]) -> Bool {
|
||||||
self.has_failed.val
|
self.has_failed.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::last_error(self : AsyncLogger[S]) -> String {
|
pub fn[S] AsyncLogger::last_error(self : AsyncLogger[S]) -> String {
|
||||||
self.last_error.val
|
self.last_error.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::flush_policy(self : AsyncLogger[S]) -> AsyncFlushPolicy {
|
pub fn[S] AsyncLogger::flush_policy(self : AsyncLogger[S]) -> AsyncFlushPolicy {
|
||||||
self.flush_policy
|
self.flush_policy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {
|
pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {
|
||||||
AsyncLoggerState::new(
|
AsyncLoggerState::new(
|
||||||
async_runtime_state(),
|
async_runtime_state(),
|
||||||
@@ -353,7 +415,11 @@ pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] AsyncLogger::close(self : AsyncLogger[S], clear? : Bool = false) -> Unit {
|
///|
|
||||||
|
pub fn[S] AsyncLogger::close(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
clear? : Bool = false,
|
||||||
|
) -> Unit {
|
||||||
self.is_closed.val = true
|
self.is_closed.val = true
|
||||||
if clear {
|
if clear {
|
||||||
let abandoned = self.pending_count()
|
let abandoned = self.pending_count()
|
||||||
@@ -362,9 +428,10 @@ pub fn[S] AsyncLogger::close(self : AsyncLogger[S], clear? : Bool = false) -> Un
|
|||||||
self.pending_count.val = 0
|
self.pending_count.val = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.queue.close(error=AsyncLoggerClosed, clear=clear)
|
self.queue.close(error=AsyncLoggerClosed, clear~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {
|
pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {
|
||||||
while self.pending_count() > 0 {
|
while self.pending_count() > 0 {
|
||||||
if self.has_failed() {
|
if self.has_failed() {
|
||||||
@@ -374,12 +441,17 @@ pub async fn[S] AsyncLogger::wait_idle(self : AsyncLogger[S]) -> Unit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = false) -> Unit {
|
///|
|
||||||
|
pub async fn[S] AsyncLogger::shutdown(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
clear? : Bool = false,
|
||||||
|
) -> Unit {
|
||||||
if clear {
|
if clear {
|
||||||
self.close(clear=true)
|
self.close(clear=true)
|
||||||
} else {
|
} else {
|
||||||
self.wait_idle()
|
self.wait_idle()
|
||||||
if async_runtime_shutdown_clears_pending_after_wait_idle() && self.pending_count() > 0 {
|
if async_runtime_shutdown_clears_pending_after_wait_idle() &&
|
||||||
|
self.pending_count() > 0 {
|
||||||
self.close(clear=true)
|
self.close(clear=true)
|
||||||
} else {
|
} else {
|
||||||
self.close()
|
self.close()
|
||||||
@@ -392,6 +464,7 @@ pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = fal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
||||||
while true {
|
while true {
|
||||||
let rec = logger.queue.get() catch {
|
let rec = logger.queue.get() catch {
|
||||||
@@ -419,7 +492,9 @@ async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
|||||||
if logger.linger_ms <= 0 {
|
if logger.linger_ms <= 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
let waited = @async.with_timeout_opt(logger.linger_ms, () => logger.queue.get()) catch {
|
let waited = @async.with_timeout_opt(logger.linger_ms, () => {
|
||||||
|
logger.queue.get()
|
||||||
|
}) catch {
|
||||||
err if err is AsyncLoggerClosed => None
|
err if err is AsyncLoggerClosed => None
|
||||||
err => raise err
|
err => raise err
|
||||||
}
|
}
|
||||||
@@ -447,7 +522,10 @@ async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn[S : @bitlogger.Sink] AsyncLogger::run(self : AsyncLogger[S]) -> Unit {
|
///|
|
||||||
|
pub async fn[S : @bitlogger.Sink] AsyncLogger::run(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
) -> Unit {
|
||||||
self.is_running.val = true
|
self.is_running.val = true
|
||||||
self.has_failed.val = false
|
self.has_failed.val = false
|
||||||
self.last_error.val = ""
|
self.last_error.val = ""
|
||||||
@@ -462,6 +540,7 @@ pub async fn[S : @bitlogger.Sink] AsyncLogger::run(self : AsyncLogger[S]) -> Uni
|
|||||||
self.is_running.val = false
|
self.is_running.val = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_async_logger(
|
pub fn build_async_logger(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> AsyncLogger[@bitlogger.RuntimeSink] {
|
) -> AsyncLogger[@bitlogger.RuntimeSink] {
|
||||||
@@ -475,9 +554,14 @@ pub fn build_async_logger(
|
|||||||
).with_timestamp(enabled=logger.timestamp)
|
).with_timestamp(enabled=logger.timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_async_text_logger(config : AsyncLoggerBuildConfig) -> AsyncLogger[@bitlogger.FormattedConsoleSink] {
|
///|
|
||||||
|
pub fn build_async_text_logger(
|
||||||
|
config : AsyncLoggerBuildConfig,
|
||||||
|
) -> AsyncLogger[@bitlogger.FormattedConsoleSink] {
|
||||||
async_logger(
|
async_logger(
|
||||||
@bitlogger.text_console_sink(config.logger.sink.text_formatter.to_formatter()),
|
@bitlogger.text_console_sink(
|
||||||
|
config.logger.sink.text_formatter.to_formatter(),
|
||||||
|
),
|
||||||
config=config.async_config,
|
config=config.async_config,
|
||||||
min_level=config.logger.min_level,
|
min_level=config.logger.min_level,
|
||||||
target=config.logger.target,
|
target=config.logger.target,
|
||||||
|
|||||||
@@ -1,20 +1,25 @@
|
|||||||
|
///|
|
||||||
pub fn async_runtime_mode() -> AsyncRuntimeMode {
|
pub fn async_runtime_mode() -> AsyncRuntimeMode {
|
||||||
@utils.compatibility_async_runtime_mode()
|
@utils.compatibility_async_runtime_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_runtime_supports_background_worker() -> Bool {
|
pub fn async_runtime_supports_background_worker() -> Bool {
|
||||||
ignore(all_async_runtime_modes())
|
ignore(all_async_runtime_modes())
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_runtime_guard_closed_on_log() -> Bool {
|
fn async_runtime_guard_closed_on_log() -> Bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_runtime_shutdown_clears_pending_after_wait_idle() -> Bool {
|
fn async_runtime_shutdown_clears_pending_after_wait_idle() -> Bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_runtime_shutdown_waits_for_worker() -> Bool {
|
fn async_runtime_shutdown_waits_for_worker() -> Bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,61 +1,67 @@
|
|||||||
|
///|
|
||||||
pub struct LibraryAsyncLogger[S] {
|
pub struct LibraryAsyncLogger[S] {
|
||||||
inner : AsyncLogger[S]
|
inner : AsyncLogger[S]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn[S] library_async_logger(logger : AsyncLogger[S]) -> LibraryAsyncLogger[S] {
|
fn[S] library_async_logger(logger : AsyncLogger[S]) -> LibraryAsyncLogger[S] {
|
||||||
{ inner: logger }
|
{ inner: logger }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] AsyncLogger::to_library_async_logger(self : AsyncLogger[S]) -> LibraryAsyncLogger[S] {
|
///|
|
||||||
|
pub fn[S] AsyncLogger::to_library_async_logger(
|
||||||
|
self : AsyncLogger[S],
|
||||||
|
) -> LibraryAsyncLogger[S] {
|
||||||
library_async_logger(self)
|
library_async_logger(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryAsyncLogger::new(
|
pub fn[S] LibraryAsyncLogger::new(
|
||||||
sink : S,
|
sink : S,
|
||||||
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 raise = fn(_) { 0 },
|
flush? : (S) -> Int raise = fn(_) { 0 },
|
||||||
) -> LibraryAsyncLogger[S] {
|
) -> LibraryAsyncLogger[S] {
|
||||||
library_async_logger(
|
library_async_logger(async_logger(sink, config~, min_level~, target~, flush~))
|
||||||
async_logger(
|
|
||||||
sink,
|
|
||||||
config=config,
|
|
||||||
min_level=min_level,
|
|
||||||
target=target,
|
|
||||||
flush=flush,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] LibraryAsyncLogger::to_async_logger(self : LibraryAsyncLogger[S]) -> AsyncLogger[S] {
|
///|
|
||||||
|
pub fn[S] LibraryAsyncLogger::to_async_logger(
|
||||||
|
self : LibraryAsyncLogger[S],
|
||||||
|
) -> AsyncLogger[S] {
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn[S] configured_library_async_logger(
|
fn[S] configured_library_async_logger(
|
||||||
logger : AsyncLogger[S],
|
logger : AsyncLogger[S],
|
||||||
) -> LibraryAsyncLogger[S] {
|
) -> LibraryAsyncLogger[S] {
|
||||||
library_async_logger(logger)
|
library_async_logger(logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_library_async_logger(
|
pub fn build_library_async_logger(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> LibraryAsyncLogger[@bitlogger.RuntimeSink] {
|
) -> LibraryAsyncLogger[@bitlogger.RuntimeSink] {
|
||||||
configured_library_async_logger(build_async_logger(config))
|
configured_library_async_logger(build_async_logger(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_library_async_text_logger(
|
pub fn build_library_async_text_logger(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> LibraryAsyncLogger[@bitlogger.FormattedConsoleSink] {
|
) -> LibraryAsyncLogger[@bitlogger.FormattedConsoleSink] {
|
||||||
configured_library_async_logger(build_async_text_logger(config))
|
configured_library_async_logger(build_async_text_logger(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn parse_and_build_library_async_logger(
|
pub fn parse_and_build_library_async_logger(
|
||||||
input : String,
|
input : String,
|
||||||
) -> LibraryAsyncLogger[@bitlogger.RuntimeSink] raise {
|
) -> LibraryAsyncLogger[@bitlogger.RuntimeSink] raise {
|
||||||
build_library_async_logger(parse_async_logger_build_config_text(input))
|
build_library_async_logger(parse_async_logger_build_config_text(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryAsyncLogger::with_target(
|
pub fn[S] LibraryAsyncLogger::with_target(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
target : String,
|
target : String,
|
||||||
@@ -63,6 +69,7 @@ pub fn[S] LibraryAsyncLogger::with_target(
|
|||||||
library_async_logger(self.inner.with_target(target))
|
library_async_logger(self.inner.with_target(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryAsyncLogger::child(
|
pub fn[S] LibraryAsyncLogger::child(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
target : String,
|
target : String,
|
||||||
@@ -70,6 +77,7 @@ pub fn[S] LibraryAsyncLogger::child(
|
|||||||
library_async_logger(self.inner.child(target))
|
library_async_logger(self.inner.child(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryAsyncLogger::with_context_fields(
|
pub fn[S] LibraryAsyncLogger::with_context_fields(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
fields : Array[@bitlogger.Field],
|
fields : Array[@bitlogger.Field],
|
||||||
@@ -77,6 +85,7 @@ pub fn[S] LibraryAsyncLogger::with_context_fields(
|
|||||||
library_async_logger(self.inner.with_context_fields(fields))
|
library_async_logger(self.inner.with_context_fields(fields))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryAsyncLogger::bind(
|
pub fn[S] LibraryAsyncLogger::bind(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
fields : Array[@bitlogger.Field],
|
fields : Array[@bitlogger.Field],
|
||||||
@@ -84,6 +93,7 @@ pub fn[S] LibraryAsyncLogger::bind(
|
|||||||
self.with_context_fields(fields)
|
self.with_context_fields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryAsyncLogger::is_enabled(
|
pub fn[S] LibraryAsyncLogger::is_enabled(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
level : @bitlogger.Level,
|
level : @bitlogger.Level,
|
||||||
@@ -91,47 +101,55 @@ pub fn[S] LibraryAsyncLogger::is_enabled(
|
|||||||
self.inner.is_enabled(level)
|
self.inner.is_enabled(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] LibraryAsyncLogger::log(
|
pub async fn[S] LibraryAsyncLogger::log(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
level : @bitlogger.Level,
|
level : @bitlogger.Level,
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
target? : String = "",
|
target? : String = "",
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.log(level, message, fields=fields, target=target)
|
self.inner.log(level, message, fields~, target~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] LibraryAsyncLogger::info(
|
pub async fn[S] LibraryAsyncLogger::info(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.info(message, fields=fields)
|
self.inner.info(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] LibraryAsyncLogger::warn(
|
pub async fn[S] LibraryAsyncLogger::warn(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.warn(message, fields=fields)
|
self.inner.warn(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] LibraryAsyncLogger::error(
|
pub async fn[S] LibraryAsyncLogger::error(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[@bitlogger.Field] = [],
|
fields? : Array[@bitlogger.Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.error(message, fields=fields)
|
self.inner.error(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn[S : @bitlogger.Sink] LibraryAsyncLogger::run(self : LibraryAsyncLogger[S]) -> Unit {
|
///|
|
||||||
|
pub async fn[S : @bitlogger.Sink] LibraryAsyncLogger::run(
|
||||||
|
self : LibraryAsyncLogger[S],
|
||||||
|
) -> Unit {
|
||||||
self.inner.run()
|
self.inner.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub async fn[S] LibraryAsyncLogger::shutdown(
|
pub async fn[S] LibraryAsyncLogger::shutdown(
|
||||||
self : LibraryAsyncLogger[S],
|
self : LibraryAsyncLogger[S],
|
||||||
clear? : Bool = false,
|
clear? : Bool = false,
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.shutdown(clear=clear)
|
self.inner.shutdown(clear~)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-6
@@ -1,17 +1,23 @@
|
|||||||
import {
|
import {
|
||||||
"Nanaloveyuki/BitLogger/src" @bitlogger,
|
"Nanaloveyuki/BitLogger/src" @bitlogger,
|
||||||
"Nanaloveyuki/BitLogger/src-async/utils" @utils,
|
"Nanaloveyuki/BitLogger/src-async/utils",
|
||||||
"maria/json_parser" @json_parser,
|
"maria/json_parser",
|
||||||
"moonbitlang/async" @async,
|
"moonbitlang/async",
|
||||||
"moonbitlang/async/aqueue" @aqueue,
|
"moonbitlang/async/aqueue",
|
||||||
"moonbitlang/core/env" @env,
|
"moonbitlang/core/env",
|
||||||
"moonbitlang/core/ref",
|
"moonbitlang/core/ref",
|
||||||
}
|
}
|
||||||
|
|
||||||
options(
|
options(
|
||||||
targets: {
|
targets: {
|
||||||
"async_logger_shared.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
"async_logger_shared.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
||||||
"application_async_logger.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
"application_async_logger.mbt": [
|
||||||
|
"native",
|
||||||
|
"llvm",
|
||||||
|
"js",
|
||||||
|
"wasm",
|
||||||
|
"wasm-gc",
|
||||||
|
],
|
||||||
"library_async_logger.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
"library_async_logger.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
||||||
"async_logger_native.mbt": [ "native", "llvm" ],
|
"async_logger_native.mbt": [ "native", "llvm" ],
|
||||||
"async_logger_stub.mbt": [ "js", "wasm", "wasm-gc" ],
|
"async_logger_stub.mbt": [ "js", "wasm", "wasm-gc" ],
|
||||||
|
|||||||
@@ -1,20 +1,24 @@
|
|||||||
|
///|
|
||||||
pub(all) enum AsyncOverflowPolicy {
|
pub(all) enum AsyncOverflowPolicy {
|
||||||
Blocking
|
Blocking
|
||||||
DropOldest
|
DropOldest
|
||||||
DropNewest
|
DropNewest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub(all) enum AsyncFlushPolicy {
|
pub(all) enum AsyncFlushPolicy {
|
||||||
Never
|
Never
|
||||||
Batch
|
Batch
|
||||||
Shutdown
|
Shutdown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub enum AsyncRuntimeMode {
|
pub enum AsyncRuntimeMode {
|
||||||
NativeWorker
|
NativeWorker
|
||||||
Compatibility
|
Compatibility
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {
|
pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {
|
||||||
match mode {
|
match mode {
|
||||||
AsyncRuntimeMode::NativeWorker => "native_worker"
|
AsyncRuntimeMode::NativeWorker => "native_worker"
|
||||||
@@ -22,19 +26,23 @@ pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn native_worker_async_runtime_mode() -> AsyncRuntimeMode {
|
pub fn native_worker_async_runtime_mode() -> AsyncRuntimeMode {
|
||||||
AsyncRuntimeMode::NativeWorker
|
AsyncRuntimeMode::NativeWorker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn compatibility_async_runtime_mode() -> AsyncRuntimeMode {
|
pub fn compatibility_async_runtime_mode() -> AsyncRuntimeMode {
|
||||||
AsyncRuntimeMode::Compatibility
|
AsyncRuntimeMode::Compatibility
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct AsyncRuntimeState {
|
pub struct AsyncRuntimeState {
|
||||||
mode : AsyncRuntimeMode
|
mode : AsyncRuntimeMode
|
||||||
background_worker : Bool
|
background_worker : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn AsyncRuntimeState::new(
|
pub fn AsyncRuntimeState::new(
|
||||||
mode : AsyncRuntimeMode,
|
mode : AsyncRuntimeMode,
|
||||||
background_worker : Bool,
|
background_worker : Bool,
|
||||||
@@ -42,6 +50,7 @@ pub fn AsyncRuntimeState::new(
|
|||||||
{ mode, background_worker }
|
{ mode, background_worker }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct AsyncLoggerState {
|
pub struct AsyncLoggerState {
|
||||||
runtime : AsyncRuntimeState
|
runtime : AsyncRuntimeState
|
||||||
pending_count : Int
|
pending_count : Int
|
||||||
@@ -53,6 +62,7 @@ pub struct AsyncLoggerState {
|
|||||||
flush_policy : AsyncFlushPolicy
|
flush_policy : AsyncFlushPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn AsyncLoggerState::new(
|
pub fn AsyncLoggerState::new(
|
||||||
runtime : AsyncRuntimeState,
|
runtime : AsyncRuntimeState,
|
||||||
pending_count : Int,
|
pending_count : Int,
|
||||||
@@ -75,16 +85,20 @@ pub fn AsyncLoggerState::new(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_runtime_state_to_json(state : AsyncRuntimeState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn async_runtime_state_to_json(
|
||||||
|
state : AsyncRuntimeState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@json_parser.JsonValue::Object({
|
@json_parser.JsonValue::Object({
|
||||||
"mode": @json_parser.JsonValue::String(async_runtime_mode_label(state.mode)),
|
"mode": @json_parser.JsonValue::String(async_runtime_mode_label(state.mode)),
|
||||||
"background_worker": @json_parser.JsonValue::Bool(state.background_worker),
|
"background_worker": @json_parser.JsonValue::Bool(state.background_worker),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_async_runtime_state(
|
pub fn stringify_async_runtime_state(
|
||||||
state : AsyncRuntimeState,
|
state : AsyncRuntimeState,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
let value = async_runtime_state_to_json(state)
|
let value = async_runtime_state_to_json(state)
|
||||||
if pretty {
|
if pretty {
|
||||||
@@ -94,6 +108,7 @@ pub fn stringify_async_runtime_state(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn async_flush_policy_label(policy : AsyncFlushPolicy) -> String {
|
fn async_flush_policy_label(policy : AsyncFlushPolicy) -> String {
|
||||||
match policy {
|
match policy {
|
||||||
AsyncFlushPolicy::Never => "Never"
|
AsyncFlushPolicy::Never => "Never"
|
||||||
@@ -102,26 +117,39 @@ fn async_flush_policy_label(policy : AsyncFlushPolicy) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn async_logger_state_to_json_value(state : AsyncLoggerState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
fn async_logger_state_to_json_value(
|
||||||
|
state : AsyncLoggerState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@json_parser.JsonValue::Object({
|
@json_parser.JsonValue::Object({
|
||||||
"runtime": async_runtime_state_to_json(state.runtime),
|
"runtime": async_runtime_state_to_json(state.runtime),
|
||||||
"pending_count": @json_parser.JsonValue::Number(state.pending_count.to_double()),
|
"pending_count": @json_parser.JsonValue::Number(
|
||||||
"dropped_count": @json_parser.JsonValue::Number(state.dropped_count.to_double()),
|
state.pending_count.to_double(),
|
||||||
|
),
|
||||||
|
"dropped_count": @json_parser.JsonValue::Number(
|
||||||
|
state.dropped_count.to_double(),
|
||||||
|
),
|
||||||
"is_closed": @json_parser.JsonValue::Bool(state.is_closed),
|
"is_closed": @json_parser.JsonValue::Bool(state.is_closed),
|
||||||
"is_running": @json_parser.JsonValue::Bool(state.is_running),
|
"is_running": @json_parser.JsonValue::Bool(state.is_running),
|
||||||
"has_failed": @json_parser.JsonValue::Bool(state.has_failed),
|
"has_failed": @json_parser.JsonValue::Bool(state.has_failed),
|
||||||
"last_error": @json_parser.JsonValue::String(state.last_error),
|
"last_error": @json_parser.JsonValue::String(state.last_error),
|
||||||
"flush_policy": @json_parser.JsonValue::String(async_flush_policy_label(state.flush_policy)),
|
"flush_policy": @json_parser.JsonValue::String(
|
||||||
|
async_flush_policy_label(state.flush_policy),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn async_logger_state_to_json(
|
||||||
|
state : AsyncLoggerState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
async_logger_state_to_json_value(state)
|
async_logger_state_to_json_value(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_async_logger_state(
|
pub fn stringify_async_logger_state(
|
||||||
state : AsyncLoggerState,
|
state : AsyncLoggerState,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
let value = async_logger_state_to_json_value(state)
|
let value = async_logger_state_to_json_value(state)
|
||||||
if pretty {
|
if pretty {
|
||||||
@@ -131,6 +159,7 @@ pub fn stringify_async_logger_state(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct AsyncLoggerConfig {
|
pub struct AsyncLoggerConfig {
|
||||||
max_pending : Int
|
max_pending : Int
|
||||||
overflow : AsyncOverflowPolicy
|
overflow : AsyncOverflowPolicy
|
||||||
@@ -139,22 +168,32 @@ pub struct AsyncLoggerConfig {
|
|||||||
flush : AsyncFlushPolicy
|
flush : AsyncFlushPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn AsyncLoggerConfig::new(
|
pub fn AsyncLoggerConfig::new(
|
||||||
max_pending~ : Int = 0,
|
max_pending? : Int = 0,
|
||||||
overflow~ : AsyncOverflowPolicy = AsyncOverflowPolicy::Blocking,
|
overflow? : AsyncOverflowPolicy = AsyncOverflowPolicy::Blocking,
|
||||||
max_batch~ : Int = 1,
|
max_batch? : Int = 1,
|
||||||
linger_ms~ : Int = 0,
|
linger_ms? : Int = 0,
|
||||||
flush~ : AsyncFlushPolicy = AsyncFlushPolicy::Never,
|
flush? : AsyncFlushPolicy = AsyncFlushPolicy::Never,
|
||||||
) -> AsyncLoggerConfig {
|
) -> AsyncLoggerConfig {
|
||||||
{
|
{
|
||||||
max_pending,
|
max_pending,
|
||||||
overflow,
|
overflow,
|
||||||
max_batch: if max_batch <= 1 { 1 } else { max_batch },
|
max_batch: if max_batch <= 1 {
|
||||||
linger_ms: if linger_ms < 0 { 0 } else { linger_ms },
|
1
|
||||||
|
} else {
|
||||||
|
max_batch
|
||||||
|
},
|
||||||
|
linger_ms: if linger_ms < 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
linger_ms
|
||||||
|
},
|
||||||
flush,
|
flush,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_async_overflow(name : String) -> AsyncOverflowPolicy raise {
|
fn parse_async_overflow(name : String) -> AsyncOverflowPolicy raise {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"BLOCKING" => AsyncOverflowPolicy::Blocking
|
"BLOCKING" => AsyncOverflowPolicy::Blocking
|
||||||
@@ -165,6 +204,7 @@ fn parse_async_overflow(name : String) -> AsyncOverflowPolicy raise {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_async_flush(name : String) -> AsyncFlushPolicy raise {
|
fn parse_async_flush(name : String) -> AsyncFlushPolicy raise {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"NEVER" => AsyncFlushPolicy::Never
|
"NEVER" => AsyncFlushPolicy::Never
|
||||||
@@ -175,75 +215,100 @@ fn parse_async_flush(name : String) -> AsyncFlushPolicy raise {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub 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 root = @json_parser.parse(input)
|
||||||
let obj = match root.as_object() {
|
let obj = match root.as_object() {
|
||||||
Some(obj) => obj
|
Some(obj) => obj
|
||||||
None => raise Failure::Failure("Expected object for async logger config")
|
None => raise Failure::Failure("Expected object for async logger config")
|
||||||
}
|
}
|
||||||
let max_pending = match obj.get("max_pending") {
|
let max_pending = match obj.get("max_pending") {
|
||||||
Some(value) => match value.as_number() {
|
Some(value) =>
|
||||||
|
match value.as_number() {
|
||||||
Some(number) => number.to_int()
|
Some(number) => number.to_int()
|
||||||
None => raise Failure::Failure("Expected number at async_config.max_pending")
|
None =>
|
||||||
|
raise Failure::Failure("Expected number at async_config.max_pending")
|
||||||
}
|
}
|
||||||
None => 0
|
None => 0
|
||||||
}
|
}
|
||||||
let overflow = match obj.get("overflow") {
|
let overflow = match obj.get("overflow") {
|
||||||
Some(value) => match value.as_string() {
|
Some(value) =>
|
||||||
|
match value.as_string() {
|
||||||
Some(text) => parse_async_overflow(text)
|
Some(text) => parse_async_overflow(text)
|
||||||
None => raise Failure::Failure("Expected string at async_config.overflow")
|
None =>
|
||||||
|
raise Failure::Failure("Expected string at async_config.overflow")
|
||||||
}
|
}
|
||||||
None => AsyncOverflowPolicy::Blocking
|
None => AsyncOverflowPolicy::Blocking
|
||||||
}
|
}
|
||||||
let max_batch = match obj.get("max_batch") {
|
let max_batch = match obj.get("max_batch") {
|
||||||
Some(value) => match value.as_number() {
|
Some(value) =>
|
||||||
|
match value.as_number() {
|
||||||
Some(number) => number.to_int()
|
Some(number) => number.to_int()
|
||||||
None => raise Failure::Failure("Expected number at async_config.max_batch")
|
None =>
|
||||||
|
raise Failure::Failure("Expected number at async_config.max_batch")
|
||||||
}
|
}
|
||||||
None => 1
|
None => 1
|
||||||
}
|
}
|
||||||
let linger_ms = match obj.get("linger_ms") {
|
let linger_ms = match obj.get("linger_ms") {
|
||||||
Some(value) => match value.as_number() {
|
Some(value) =>
|
||||||
|
match value.as_number() {
|
||||||
Some(number) => number.to_int()
|
Some(number) => number.to_int()
|
||||||
None => raise Failure::Failure("Expected number at async_config.linger_ms")
|
None =>
|
||||||
|
raise Failure::Failure("Expected number at async_config.linger_ms")
|
||||||
}
|
}
|
||||||
None => 0
|
None => 0
|
||||||
}
|
}
|
||||||
let flush = match obj.get("flush") {
|
let flush = match obj.get("flush") {
|
||||||
Some(value) => match value.as_string() {
|
Some(value) =>
|
||||||
|
match value.as_string() {
|
||||||
Some(text) => parse_async_flush(text)
|
Some(text) => parse_async_flush(text)
|
||||||
None => raise Failure::Failure("Expected string at async_config.flush")
|
None => raise Failure::Failure("Expected string at async_config.flush")
|
||||||
}
|
}
|
||||||
None => AsyncFlushPolicy::Never
|
None => AsyncFlushPolicy::Never
|
||||||
}
|
}
|
||||||
AsyncLoggerConfig::new(
|
AsyncLoggerConfig::new(
|
||||||
max_pending=max_pending,
|
max_pending~,
|
||||||
overflow=overflow,
|
overflow~,
|
||||||
max_batch=max_batch,
|
max_batch~,
|
||||||
linger_ms=linger_ms,
|
linger_ms~,
|
||||||
flush=flush,
|
flush~,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn async_logger_config_to_json(
|
||||||
|
config : AsyncLoggerConfig,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@json_parser.JsonValue::Object({
|
@json_parser.JsonValue::Object({
|
||||||
"max_pending": @json_parser.JsonValue::Number(config.max_pending.to_double()),
|
"max_pending": @json_parser.JsonValue::Number(
|
||||||
|
config.max_pending.to_double(),
|
||||||
|
),
|
||||||
"max_batch": @json_parser.JsonValue::Number(config.max_batch.to_double()),
|
"max_batch": @json_parser.JsonValue::Number(config.max_batch.to_double()),
|
||||||
"linger_ms": @json_parser.JsonValue::Number(config.linger_ms.to_double()),
|
"linger_ms": @json_parser.JsonValue::Number(config.linger_ms.to_double()),
|
||||||
"overflow": @json_parser.JsonValue::String(match config.overflow {
|
"overflow": @json_parser.JsonValue::String(
|
||||||
|
match config.overflow {
|
||||||
AsyncOverflowPolicy::Blocking => "Blocking"
|
AsyncOverflowPolicy::Blocking => "Blocking"
|
||||||
AsyncOverflowPolicy::DropOldest => "DropOldest"
|
AsyncOverflowPolicy::DropOldest => "DropOldest"
|
||||||
AsyncOverflowPolicy::DropNewest => "DropNewest"
|
AsyncOverflowPolicy::DropNewest => "DropNewest"
|
||||||
}),
|
},
|
||||||
"flush": @json_parser.JsonValue::String(match config.flush {
|
),
|
||||||
|
"flush": @json_parser.JsonValue::String(
|
||||||
|
match config.flush {
|
||||||
AsyncFlushPolicy::Never => "Never"
|
AsyncFlushPolicy::Never => "Never"
|
||||||
AsyncFlushPolicy::Batch => "Batch"
|
AsyncFlushPolicy::Batch => "Batch"
|
||||||
AsyncFlushPolicy::Shutdown => "Shutdown"
|
AsyncFlushPolicy::Shutdown => "Shutdown"
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_async_logger_config(
|
||||||
|
config : AsyncLoggerConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = async_logger_config_to_json(config)
|
let value = async_logger_config_to_json(config)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
@@ -252,35 +317,45 @@ pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct AsyncLoggerBuildConfig {
|
pub struct AsyncLoggerBuildConfig {
|
||||||
logger : @bitlogger.LoggerConfig
|
logger : @bitlogger.LoggerConfig
|
||||||
async_config : AsyncLoggerConfig
|
async_config : AsyncLoggerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn AsyncLoggerBuildConfig::new(
|
pub fn AsyncLoggerBuildConfig::new(
|
||||||
logger~ : @bitlogger.LoggerConfig = @bitlogger.default_logger_config(),
|
logger? : @bitlogger.LoggerConfig = @bitlogger.default_logger_config(),
|
||||||
async_config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
async_config? : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||||
) -> AsyncLoggerBuildConfig {
|
) -> AsyncLoggerBuildConfig {
|
||||||
{ logger, async_config }
|
{ logger, async_config }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_async_logger_build_config_text(input : String) -> AsyncLoggerBuildConfig raise {
|
///|
|
||||||
|
pub fn parse_async_logger_build_config_text(
|
||||||
|
input : String,
|
||||||
|
) -> AsyncLoggerBuildConfig raise {
|
||||||
let root = @json_parser.parse(input)
|
let root = @json_parser.parse(input)
|
||||||
let obj = match root.as_object() {
|
let obj = match root.as_object() {
|
||||||
Some(obj) => obj
|
Some(obj) => obj
|
||||||
None => raise Failure::Failure("Expected object at async logger build config root")
|
None =>
|
||||||
|
raise Failure::Failure(
|
||||||
|
"Expected object at async logger build config root",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
let logger = match obj.get("logger") {
|
let logger = match obj.get("logger") {
|
||||||
Some(value) => @bitlogger.parse_logger_config_text(@json_parser.stringify(value))
|
Some(value) =>
|
||||||
|
@bitlogger.parse_logger_config_text(@json_parser.stringify(value))
|
||||||
None => @bitlogger.default_logger_config()
|
None => @bitlogger.default_logger_config()
|
||||||
}
|
}
|
||||||
let async_config = match obj.get("async_config") {
|
let async_config = match obj.get("async_config") {
|
||||||
Some(value) => parse_async_logger_config_text(@json_parser.stringify(value))
|
Some(value) => parse_async_logger_config_text(@json_parser.stringify(value))
|
||||||
None => AsyncLoggerConfig::new()
|
None => AsyncLoggerConfig::new()
|
||||||
}
|
}
|
||||||
AsyncLoggerBuildConfig::new(logger=logger, async_config=async_config)
|
AsyncLoggerBuildConfig::new(logger~, async_config~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn async_logger_build_config_to_json(
|
pub fn async_logger_build_config_to_json(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
) -> @json_parser.JsonValue {
|
) -> @json_parser.JsonValue {
|
||||||
@@ -290,9 +365,10 @@ pub fn async_logger_build_config_to_json(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_async_logger_build_config(
|
pub fn stringify_async_logger_build_config(
|
||||||
config : AsyncLoggerBuildConfig,
|
config : AsyncLoggerBuildConfig,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
let value = async_logger_build_config_to_json(config)
|
let value = async_logger_build_config_to_json(config)
|
||||||
if pretty {
|
if pretty {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
"Nanaloveyuki/BitLogger/src" @bitlogger,
|
"Nanaloveyuki/BitLogger/src" @bitlogger,
|
||||||
"maria/json_parser" @json_parser,
|
"maria/json_parser",
|
||||||
}
|
}
|
||||||
|
|||||||
+1646
-424
File diff suppressed because it is too large
Load Diff
+247
-132
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
test "default logger can be reconfigured" {
|
test "default logger can be reconfigured" {
|
||||||
set_default_min_level(Level::Debug)
|
set_default_min_level(Level::Debug)
|
||||||
set_default_target("global")
|
set_default_target("global")
|
||||||
@@ -6,6 +7,7 @@ test "default logger can be reconfigured" {
|
|||||||
inspect(logger.target, content="global")
|
inspect(logger.target, content="global")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "default logger snapshots shared defaults at creation time" {
|
test "default logger snapshots shared defaults at creation time" {
|
||||||
set_default_min_level(Level::Warn)
|
set_default_min_level(Level::Warn)
|
||||||
set_default_target("before")
|
set_default_target("before")
|
||||||
@@ -24,24 +26,30 @@ test "default logger snapshots shared defaults at creation time" {
|
|||||||
inspect(after.target, content="after")
|
inspect(after.target, content="after")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "logger can enable timestamps" {
|
test "logger can enable timestamps" {
|
||||||
let logger = Logger::new(console_sink(), min_level=Level::Info, target="time")
|
let logger = Logger::new(console_sink(), min_level=Level::Info, target="time").with_timestamp()
|
||||||
.with_timestamp()
|
|
||||||
inspect(logger.timestamp, content="true")
|
inspect(logger.timestamp, content="true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can customize visible parts" {
|
test "text formatter can customize visible parts" {
|
||||||
let rec = record(
|
let rec = record(Level::Info, "hello", timestamp_ms=123UL, target="svc.api", fields=[
|
||||||
Level::Info,
|
field("user", "alice"),
|
||||||
"hello",
|
field("request_id", "42"),
|
||||||
timestamp_ms=123UL,
|
])
|
||||||
target="svc.api",
|
let compact = text_formatter(
|
||||||
fields=[field("user", "alice"), field("request_id", "42")],
|
show_timestamp=false,
|
||||||
|
show_target=false,
|
||||||
|
field_separator=",",
|
||||||
|
)
|
||||||
|
inspect(
|
||||||
|
format_text(rec, formatter=compact),
|
||||||
|
content="[INFO] hello user=alice,request_id=42",
|
||||||
)
|
)
|
||||||
let compact = text_formatter(show_timestamp=false, show_target=false, field_separator=",")
|
|
||||||
inspect(format_text(rec, formatter=compact), content="[INFO] hello user=alice,request_id=42")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can emit message only" {
|
test "text formatter can emit message only" {
|
||||||
let rec = record(
|
let rec = record(
|
||||||
Level::Warn,
|
Level::Warn,
|
||||||
@@ -59,6 +67,7 @@ test "text formatter can emit message only" {
|
|||||||
inspect(format_text(rec, formatter=message_only), content="just message")
|
inspect(format_text(rec, formatter=message_only), content="just message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter supports template rendering" {
|
test "text formatter supports template rendering" {
|
||||||
let rec = record(
|
let rec = record(
|
||||||
Level::Info,
|
Level::Info,
|
||||||
@@ -73,20 +82,22 @@ test "text formatter supports template rendering" {
|
|||||||
template="[{level}] {target} {message} :: {fields} @{timestamp}",
|
template="[{level}] {target} {message} :: {fields} @{timestamp}",
|
||||||
)
|
)
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="[INFO] svc.api template hello :: user=alice,request_id=42 @123",
|
content="[INFO] svc.api template hello :: user=alice,request_id=42 @123",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can render ansi level colors" {
|
test "text formatter can render ansi level colors" {
|
||||||
let rec = record(Level::Error, "boom", target="svc")
|
let rec = record(Level::Error, "boom", target="svc")
|
||||||
let formatter = text_formatter(color_mode=ColorMode::Always)
|
let formatter = text_formatter(color_mode=ColorMode::Always)
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="[\u{001b}[31;1mERROR\u{001b}[0m] [\u{001b}[34msvc\u{001b}[0m] boom",
|
content="[\u{001b}[31;1mERROR\u{001b}[0m] [\u{001b}[34msvc\u{001b}[0m] boom",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter auto color respects NO_COLOR" {
|
test "text formatter auto color respects NO_COLOR" {
|
||||||
let rec = record(Level::Warn, "boom", target="svc")
|
let rec = record(Level::Warn, "boom", target="svc")
|
||||||
let previous = @env.get_env_var("NO_COLOR")
|
let previous = @env.get_env_var("NO_COLOR")
|
||||||
@@ -101,6 +112,7 @@ test "text formatter auto color respects NO_COLOR" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter renders named inline color tags in ansi mode" {
|
test "text formatter renders named inline color tags in ansi mode" {
|
||||||
let rec = record(Level::Info, "<red>boom</>", target="svc")
|
let rec = record(Level::Info, "<red>boom</>", target="svc")
|
||||||
inspect(
|
inspect(
|
||||||
@@ -109,6 +121,7 @@ test "text formatter renders named inline color tags in ansi mode" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter strips inline tags in plain mode" {
|
test "text formatter strips inline tags in plain mode" {
|
||||||
let rec = record(Level::Info, "<red>boom</> <b>bold</>", target="svc")
|
let rec = record(Level::Info, "<red>boom</> <b>bold</>", target="svc")
|
||||||
inspect(
|
inspect(
|
||||||
@@ -117,46 +130,83 @@ test "text formatter strips inline tags in plain mode" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter supports nested inline tags" {
|
test "text formatter supports nested inline tags" {
|
||||||
let rec = record(Level::Info, "<red><b>fatal</></>")
|
let rec = record(Level::Info, "<red><b>fatal</></>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
),
|
||||||
|
),
|
||||||
content="\u{001b}[31;1mfatal\u{001b}[0m",
|
content="\u{001b}[31;1mfatal\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter supports named closing tags" {
|
test "text formatter supports named closing tags" {
|
||||||
let rec = record(Level::Info, "<red>boom</red>")
|
let rec = record(Level::Info, "<red>boom</red>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
),
|
||||||
|
),
|
||||||
content="\u{001b}[31mboom\u{001b}[0m",
|
content="\u{001b}[31mboom\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter supports mixed short and named closing tags" {
|
test "text formatter supports mixed short and named closing tags" {
|
||||||
let rec = record(Level::Info, "<red><b>fatal</b></red>")
|
let rec = record(Level::Info, "<red><b>fatal</b></red>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
),
|
||||||
|
),
|
||||||
content="\u{001b}[31;1mfatal\u{001b}[0m",
|
content="\u{001b}[31;1mfatal\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter keeps unmatched named closing tags as plain text" {
|
test "text formatter keeps unmatched named closing tags as plain text" {
|
||||||
let rec = record(Level::Info, "boom</red>")
|
let rec = record(Level::Info, "boom</red>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(show_level=false, show_target=false),
|
||||||
|
),
|
||||||
content="boom</red>",
|
content="boom</red>",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter supports hex inline colors" {
|
test "text formatter supports hex inline colors" {
|
||||||
let rec = record(Level::Info, "<#ff0000>hot</> <bg:#010203>bg</>")
|
let rec = record(Level::Info, "<#ff0000>hot</> <bg:#010203>bg</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
),
|
||||||
|
),
|
||||||
content="\u{001b}[38;2;255;0;0mhot\u{001b}[0m \u{001b}[48;2;1;2;3mbg\u{001b}[0m",
|
content="\u{001b}[38;2;255;0;0mhot\u{001b}[0m \u{001b}[48;2;1;2;3mbg\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can downgrade hex colors to basic ansi" {
|
test "text formatter can downgrade hex colors to basic ansi" {
|
||||||
let rec = record(Level::Info, "<#ff0000>hot</> <bg:#010203>bg</>")
|
let rec = record(Level::Info, "<#ff0000>hot</> <bg:#010203>bg</>")
|
||||||
inspect(
|
inspect(
|
||||||
@@ -173,14 +223,19 @@ test "text formatter can downgrade hex colors to basic ansi" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter keeps unknown inline tags as plain text" {
|
test "text formatter keeps unknown inline tags as plain text" {
|
||||||
let rec = record(Level::Info, "<unknown>boom</>")
|
let rec = record(Level::Info, "<unknown>boom</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(show_level=false, show_target=false),
|
||||||
|
),
|
||||||
content="<unknown>boom</>",
|
content="<unknown>boom</>",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can disable style markup parsing" {
|
test "text formatter can disable style markup parsing" {
|
||||||
let rec = record(Level::Info, "<red>boom</> <b>bold</>", target="svc")
|
let rec = record(Level::Info, "<red>boom</> <b>bold</>", target="svc")
|
||||||
inspect(
|
inspect(
|
||||||
@@ -192,6 +247,7 @@ test "text formatter can disable style markup parsing" {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter builtin style markup mode ignores custom tags" {
|
test "text formatter builtin style markup mode ignores custom tags" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
@@ -203,17 +259,22 @@ test "text formatter builtin style markup mode ignores custom tags" {
|
|||||||
)
|
)
|
||||||
let rec = record(Level::Info, "<brand>custom</> <red>builtin</>")
|
let rec = record(Level::Info, "<brand>custom</> <red>builtin</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="<brand>custom</> \u{001b}[31mbuiltin\u{001b}[0m",
|
content="<brand>custom</> \u{001b}[31mbuiltin\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "style markup mode label is stable" {
|
test "style markup mode label is stable" {
|
||||||
inspect(style_markup_mode_label(StyleMarkupMode::Disabled), content="disabled")
|
inspect(
|
||||||
|
style_markup_mode_label(StyleMarkupMode::Disabled),
|
||||||
|
content="disabled",
|
||||||
|
)
|
||||||
inspect(style_markup_mode_label(StyleMarkupMode::Builtin), content="builtin")
|
inspect(style_markup_mode_label(StyleMarkupMode::Builtin), content="builtin")
|
||||||
inspect(style_markup_mode_label(StyleMarkupMode::Full), content="full")
|
inspect(style_markup_mode_label(StyleMarkupMode::Full), content="full")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter supports custom style tags" {
|
test "text formatter supports custom style tags" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
@@ -224,83 +285,103 @@ test "text formatter supports custom style tags" {
|
|||||||
)
|
)
|
||||||
let rec = record(Level::Info, "<accent>api</>")
|
let rec = record(Level::Info, "<accent>api</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="\u{001b}[38;2;76;201;240;1mapi\u{001b}[0m",
|
content="\u{001b}[38;2;76;201;240;1mapi\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can override builtin style tags" {
|
test "text formatter can override builtin style tags" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
show_target=false,
|
show_target=false,
|
||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
).with_style_tags(
|
).with_style_tags(
|
||||||
default_style_tag_registry().set_tag("red", fg=Some("#ff5a5f"), underline=true),
|
default_style_tag_registry().set_tag(
|
||||||
|
"red",
|
||||||
|
fg=Some("#ff5a5f"),
|
||||||
|
underline=true,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
let rec = record(Level::Info, "<red>alert</>")
|
let rec = record(Level::Info, "<red>alert</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="\u{001b}[38;2;255;90;95;4malert\u{001b}[0m",
|
content="\u{001b}[38;2;255;90;95;4malert\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "formatter style tags take priority over global style tags" {
|
test "formatter style tags take priority over global style tags" {
|
||||||
let previous = global_style_tag_registry()
|
let previous = global_style_tag_registry()
|
||||||
set_global_style_tag_registry(style_tag_registry().set_tag("accent", fg=Some("#123456")))
|
set_global_style_tag_registry(
|
||||||
|
style_tag_registry().set_tag("accent", fg=Some("#123456")),
|
||||||
|
)
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
show_target=false,
|
show_target=false,
|
||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
).with_style_tags(
|
).with_style_tags(style_tag_registry().set_tag("accent", fg=Some("#abcdef")))
|
||||||
style_tag_registry().set_tag("accent", fg=Some("#abcdef")),
|
|
||||||
)
|
|
||||||
let rec = record(Level::Info, "<accent>tag</>")
|
let rec = record(Level::Info, "<accent>tag</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="\u{001b}[38;2;171;205;239mtag\u{001b}[0m",
|
content="\u{001b}[38;2;171;205;239mtag\u{001b}[0m",
|
||||||
)
|
)
|
||||||
set_global_style_tag_registry(previous)
|
set_global_style_tag_registry(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "global style tags apply when formatter has no local registry" {
|
test "global style tags apply when formatter has no local registry" {
|
||||||
let previous = global_style_tag_registry()
|
let previous = global_style_tag_registry()
|
||||||
set_global_style_tag_registry(style_tag_registry().set_tag("accent", fg=Some("#102030"), dim=true))
|
set_global_style_tag_registry(
|
||||||
|
style_tag_registry().set_tag("accent", fg=Some("#102030"), dim=true),
|
||||||
|
)
|
||||||
let rec = record(Level::Info, "<accent>tag</>")
|
let rec = record(Level::Info, "<accent>tag</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always)),
|
format_text(
|
||||||
|
rec,
|
||||||
|
formatter=text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
),
|
||||||
|
),
|
||||||
content="\u{001b}[38;2;16;32;48;2mtag\u{001b}[0m",
|
content="\u{001b}[38;2;16;32;48;2mtag\u{001b}[0m",
|
||||||
)
|
)
|
||||||
set_global_style_tag_registry(previous)
|
set_global_style_tag_registry(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "reset global style tag registry restores builtin defaults" {
|
test "reset global style tag registry restores builtin defaults" {
|
||||||
set_global_style_tag_registry(style_tag_registry().set_tag("accent", fg=Some("#123456"), bold=true))
|
set_global_style_tag_registry(
|
||||||
|
style_tag_registry().set_tag("accent", fg=Some("#123456"), bold=true),
|
||||||
|
)
|
||||||
reset_global_style_tag_registry()
|
reset_global_style_tag_registry()
|
||||||
let rec = record(Level::Info, "<success>ok</>")
|
let rec = record(Level::Info, "<success>ok</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(
|
format_text(
|
||||||
rec,
|
rec,
|
||||||
formatter=text_formatter(show_level=false, show_target=false, color_mode=ColorMode::Always),
|
formatter=text_formatter(
|
||||||
|
show_level=false,
|
||||||
|
show_target=false,
|
||||||
|
color_mode=ColorMode::Always,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
content="\u{001b}[32;1mok\u{001b}[0m",
|
content="\u{001b}[32;1mok\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "style tag alias can reuse builtin tags" {
|
test "style tag alias can reuse builtin tags" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
show_target=false,
|
show_target=false,
|
||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
).with_style_tags(
|
).with_style_tags(style_tag_registry().define_alias("danger", "red"))
|
||||||
style_tag_registry().define_alias("danger", "red"),
|
|
||||||
)
|
|
||||||
let rec = record(Level::Info, "<danger>boom</>")
|
let rec = record(Level::Info, "<danger>boom</>")
|
||||||
inspect(
|
inspect(format_text(rec, formatter~), content="\u{001b}[31mboom\u{001b}[0m")
|
||||||
format_text(rec, formatter=formatter),
|
|
||||||
content="\u{001b}[31mboom\u{001b}[0m",
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "builtin semantic style tags are available" {
|
test "builtin semantic style tags are available" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
@@ -308,28 +389,37 @@ test "builtin semantic style tags are available" {
|
|||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
style_markup=StyleMarkupMode::Builtin,
|
style_markup=StyleMarkupMode::Builtin,
|
||||||
)
|
)
|
||||||
let rec = record(Level::Info, "<success>ok</> <warning>careful</> <danger>boom</> <muted>quiet</>")
|
let rec = record(
|
||||||
|
Level::Info,
|
||||||
|
"<success>ok</> <warning>careful</> <danger>boom</> <muted>quiet</>",
|
||||||
|
)
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="\u{001b}[32;1mok\u{001b}[0m \u{001b}[33;1mcareful\u{001b}[0m \u{001b}[31;1mboom\u{001b}[0m \u{001b}[90;2mquiet\u{001b}[0m",
|
content="\u{001b}[32;1mok\u{001b}[0m \u{001b}[33;1mcareful\u{001b}[0m \u{001b}[31;1mboom\u{001b}[0m \u{001b}[90;2mquiet\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "builtin semantic style tags can still be overridden" {
|
test "builtin semantic style tags can still be overridden" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
show_target=false,
|
show_target=false,
|
||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
).with_style_tags(
|
).with_style_tags(
|
||||||
default_style_tag_registry().set_tag("success", fg=Some("#00ffaa"), underline=true),
|
default_style_tag_registry().set_tag(
|
||||||
|
"success",
|
||||||
|
fg=Some("#00ffaa"),
|
||||||
|
underline=true,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
let rec = record(Level::Info, "<success>ok</>")
|
let rec = record(Level::Info, "<success>ok</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="\u{001b}[38;2;0;255;170;4mok\u{001b}[0m",
|
content="\u{001b}[38;2;0;255;170;4mok\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can enable markup for target separately" {
|
test "text formatter can enable markup for target separately" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
@@ -338,11 +428,12 @@ test "text formatter can enable markup for target separately" {
|
|||||||
)
|
)
|
||||||
let rec = record(Level::Info, "hello", target="<danger>svc</>")
|
let rec = record(Level::Info, "hello", target="<danger>svc</>")
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="[\u{001b}[34m\u{001b}[31;1msvc\u{001b}[0m\u{001b}[0m] hello",
|
content="[\u{001b}[34m\u{001b}[31;1msvc\u{001b}[0m\u{001b}[0m] hello",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter can enable markup for field values separately" {
|
test "text formatter can enable markup for field values separately" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
@@ -350,13 +441,16 @@ test "text formatter can enable markup for field values separately" {
|
|||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
fields_style_markup=StyleMarkupMode::Builtin,
|
fields_style_markup=StyleMarkupMode::Builtin,
|
||||||
)
|
)
|
||||||
let rec = record(Level::Info, "hello", fields=[field("status", "<success>ok</>")])
|
let rec = record(Level::Info, "hello", fields=[
|
||||||
|
field("status", "<success>ok</>"),
|
||||||
|
])
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="hello \u{001b}[35mstatus=\u{001b}[32;1mok\u{001b}[0m\u{001b}[0m",
|
content="hello \u{001b}[35mstatus=\u{001b}[32;1mok\u{001b}[0m\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter leaves field keys raw when field markup is enabled" {
|
test "text formatter leaves field keys raw when field markup is enabled" {
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
show_level=false,
|
show_level=false,
|
||||||
@@ -364,13 +458,16 @@ test "text formatter leaves field keys raw when field markup is enabled" {
|
|||||||
color_mode=ColorMode::Always,
|
color_mode=ColorMode::Always,
|
||||||
fields_style_markup=StyleMarkupMode::Builtin,
|
fields_style_markup=StyleMarkupMode::Builtin,
|
||||||
)
|
)
|
||||||
let rec = record(Level::Info, "hello", fields=[field("<danger>status</>", "ok")])
|
let rec = record(Level::Info, "hello", fields=[
|
||||||
|
field("<danger>status</>", "ok"),
|
||||||
|
])
|
||||||
inspect(
|
inspect(
|
||||||
format_text(rec, formatter=formatter),
|
format_text(rec, formatter~),
|
||||||
content="hello \u{001b}[35m<danger>status</>=ok\u{001b}[0m",
|
content="hello \u{001b}[35m<danger>status</>=ok\u{001b}[0m",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "text formatter template respects disabled fields" {
|
test "text formatter template respects disabled fields" {
|
||||||
let rec = record(Level::Warn, "just message", target="svc")
|
let rec = record(Level::Warn, "just message", target="svc")
|
||||||
let formatter = text_formatter(
|
let formatter = text_formatter(
|
||||||
@@ -378,26 +475,30 @@ test "text formatter template respects disabled fields" {
|
|||||||
show_fields=false,
|
show_fields=false,
|
||||||
template="[{level}] {target}{message}{fields}",
|
template="[{level}] {target}{message}{fields}",
|
||||||
)
|
)
|
||||||
inspect(format_text(rec, formatter=formatter), content="[WARN] just message")
|
inspect(format_text(rec, formatter~), content="[WARN] just message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "formatted callback sink receives rendered text" {
|
test "formatted callback sink receives rendered text" {
|
||||||
let rendered : Ref[String] = Ref("")
|
let rendered : Ref[String] = Ref("")
|
||||||
let sink = text_callback_sink(
|
let sink = text_callback_sink(
|
||||||
text_formatter(show_timestamp=false, separator=" | "),
|
text_formatter(show_timestamp=false, separator=" | "),
|
||||||
fn(text) {
|
fn(text) { rendered.val = text },
|
||||||
rendered.val = text
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
let logger = Logger::new(sink, min_level=Level::Info, target="svc")
|
let logger = Logger::new(sink, min_level=Level::Info, target="svc")
|
||||||
logger.info("hello", fields=[field("user", "alice")])
|
logger.info("hello", fields=[field("user", "alice")])
|
||||||
inspect(rendered.val, content="[INFO] | [svc] | hello | user=alice")
|
inspect(rendered.val, content="[INFO] | [svc] | hello | user=alice")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "native file support flag is queryable" {
|
test "native file support flag is queryable" {
|
||||||
inspect(native_files_supported() == true || native_files_supported() == false, content="true")
|
inspect(
|
||||||
|
native_files_supported() == true || native_files_supported() == false,
|
||||||
|
content="true",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink availability reflects backend support" {
|
test "file sink availability reflects backend support" {
|
||||||
let sink = file_sink("bitlogger-test.log")
|
let sink = file_sink("bitlogger-test.log")
|
||||||
let state = sink.state()
|
let state = sink.state()
|
||||||
@@ -407,12 +508,18 @@ test "file sink availability reflects backend support" {
|
|||||||
inspect(state.available == sink.is_available(), content="true")
|
inspect(state.available == sink.is_available(), content="true")
|
||||||
inspect(state.append == sink.append_mode(), content="true")
|
inspect(state.append == sink.append_mode(), content="true")
|
||||||
inspect(state.auto_flush == sink.auto_flush_enabled(), content="true")
|
inspect(state.auto_flush == sink.auto_flush_enabled(), content="true")
|
||||||
inspect((state.rotation is None) == (sink.rotation_config() is None), content="true")
|
inspect(
|
||||||
|
(state.rotation is None) == (sink.rotation_config() is None),
|
||||||
|
content="true",
|
||||||
|
)
|
||||||
inspect(sink.append_mode(), content="true")
|
inspect(sink.append_mode(), content="true")
|
||||||
inspect(sink.auto_flush_enabled(), content="true")
|
inspect(sink.auto_flush_enabled(), content="true")
|
||||||
inspect(sink.rotation_enabled(), content="false")
|
inspect(sink.rotation_enabled(), content="false")
|
||||||
inspect(sink.rotation_config() is None, content="true")
|
inspect(sink.rotation_config() is None, content="true")
|
||||||
inspect(sink.open_failures(), content=if sink.is_available() { "0" } else { "1" })
|
inspect(
|
||||||
|
sink.open_failures(),
|
||||||
|
content=if sink.is_available() { "0" } else { "1" },
|
||||||
|
)
|
||||||
inspect(sink.write_failures(), content="0")
|
inspect(sink.write_failures(), content="0")
|
||||||
inspect(sink.flush_failures(), content="0")
|
inspect(sink.flush_failures(), content="0")
|
||||||
if sink.is_available() {
|
if sink.is_available() {
|
||||||
@@ -424,8 +531,12 @@ test "file sink availability reflects backend support" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink unavailable backend keeps stable fallback state" {
|
test "file sink unavailable backend keeps stable fallback state" {
|
||||||
let sink = file_sink("bitlogger-unavailable.log", rotation=Some(file_rotation(64, max_backups=2)))
|
let sink = file_sink(
|
||||||
|
"bitlogger-unavailable.log",
|
||||||
|
rotation=Some(file_rotation(64, max_backups=2)),
|
||||||
|
)
|
||||||
if sink.is_available() {
|
if sink.is_available() {
|
||||||
inspect(sink.state().available, content="true")
|
inspect(sink.state().available, content="true")
|
||||||
ignore(sink.close())
|
ignore(sink.close())
|
||||||
@@ -449,6 +560,7 @@ test "file sink unavailable backend keeps stable fallback state" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink rotation config normalizes invalid inputs" {
|
test "file sink rotation config normalizes invalid inputs" {
|
||||||
let rotation = file_rotation(0, max_backups=0)
|
let rotation = file_rotation(0, max_backups=0)
|
||||||
inspect(rotation.max_bytes, content="1")
|
inspect(rotation.max_bytes, content="1")
|
||||||
@@ -464,6 +576,7 @@ test "file sink rotation config normalizes invalid inputs" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink setters update auto flush and rotation state" {
|
test "file sink setters update auto flush and rotation state" {
|
||||||
let sink = file_sink("bitlogger-setters.log")
|
let sink = file_sink("bitlogger-setters.log")
|
||||||
let default_policy = sink.default_policy()
|
let default_policy = sink.default_policy()
|
||||||
@@ -490,7 +603,10 @@ test "file sink setters update auto flush and rotation state" {
|
|||||||
sink.clear_rotation()
|
sink.clear_rotation()
|
||||||
inspect(sink.rotation_enabled(), content="false")
|
inspect(sink.rotation_enabled(), content="false")
|
||||||
inspect(sink.rotation_config() is None, content="true")
|
inspect(sink.rotation_config() is None, content="true")
|
||||||
inspect(sink.reopen(), content=if sink.is_available() { "true" } else { "false" })
|
inspect(
|
||||||
|
sink.reopen(),
|
||||||
|
content=if sink.is_available() { "true" } else { "false" },
|
||||||
|
)
|
||||||
inspect(sink.append_mode(), content="false")
|
inspect(sink.append_mode(), content="false")
|
||||||
let state = sink.state()
|
let state = sink.state()
|
||||||
let policy = sink.policy()
|
let policy = sink.policy()
|
||||||
@@ -508,6 +624,7 @@ test "file sink setters update auto flush and rotation state" {
|
|||||||
inspect(sink.policy_matches_default(), content="true")
|
inspect(sink.policy_matches_default(), content="true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink reset policy restores configured defaults" {
|
test "file sink reset policy restores configured defaults" {
|
||||||
let sink = file_sink(
|
let sink = file_sink(
|
||||||
"bitlogger-reset-policy.log",
|
"bitlogger-reset-policy.log",
|
||||||
@@ -535,6 +652,7 @@ test "file sink reset policy restores configured defaults" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink set policy applies bundled runtime policy" {
|
test "file sink set policy applies bundled runtime policy" {
|
||||||
let sink = file_sink("bitlogger-set-policy.log")
|
let sink = file_sink("bitlogger-set-policy.log")
|
||||||
let default_policy = sink.default_policy()
|
let default_policy = sink.default_policy()
|
||||||
@@ -561,6 +679,7 @@ test "file sink set policy applies bundled runtime policy" {
|
|||||||
inspect(sink.policy_matches_default(), content="false")
|
inspect(sink.policy_matches_default(), content="false")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink tracks rotation failures on unavailable backend" {
|
test "file sink tracks rotation failures on unavailable backend" {
|
||||||
let path = "bitlogger-rotate.log"
|
let path = "bitlogger-rotate.log"
|
||||||
ignore(remove_file_internal(path))
|
ignore(remove_file_internal(path))
|
||||||
@@ -579,6 +698,7 @@ test "file sink tracks rotation failures on unavailable backend" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink reopen and failure counters reflect backend state" {
|
test "file sink reopen and failure counters reflect backend state" {
|
||||||
let sink = file_sink("bitlogger-reopen.log")
|
let sink = file_sink("bitlogger-reopen.log")
|
||||||
if sink.is_available() {
|
if sink.is_available() {
|
||||||
@@ -630,6 +750,7 @@ test "file sink reopen and failure counters reflect backend state" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file sink can rotate on native backend" {
|
test "file sink can rotate on native backend" {
|
||||||
let path = "bitlogger-rotate-native.log"
|
let path = "bitlogger-rotate-native.log"
|
||||||
ignore(remove_file_internal(path))
|
ignore(remove_file_internal(path))
|
||||||
@@ -666,20 +787,18 @@ test "file sink can rotate on native backend" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "json formatter keeps structured shape" {
|
test "json formatter keeps structured shape" {
|
||||||
let rec = record(
|
let rec = record(Level::Error, "failed", timestamp_ms=55UL, target="svc", fields=[
|
||||||
Level::Error,
|
field("code", "500"),
|
||||||
"failed",
|
])
|
||||||
timestamp_ms=55UL,
|
|
||||||
target="svc",
|
|
||||||
fields=[field("code", "500")],
|
|
||||||
)
|
|
||||||
inspect(
|
inspect(
|
||||||
format_json(rec),
|
format_json(rec),
|
||||||
content="{\"level\":\"ERROR\",\"message\":\"failed\",\"fields\":{\"code\":\"500\"},\"timestamp_ms\":\"55\",\"target\":\"svc\"}",
|
content="{\"level\":\"ERROR\",\"message\":\"failed\",\"fields\":{\"code\":\"500\"},\"timestamp_ms\":\"55\",\"target\":\"svc\"}",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "callback sink receives record" {
|
test "callback sink receives record" {
|
||||||
let captured_target : Ref[String] = Ref("")
|
let captured_target : Ref[String] = Ref("")
|
||||||
let captured_message : Ref[String] = Ref("")
|
let captured_message : Ref[String] = Ref("")
|
||||||
@@ -696,20 +815,15 @@ test "callback sink receives record" {
|
|||||||
inspect(captured_message.val, content="hello")
|
inspect(captured_message.val, content="hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "split sink routes records by predicate" {
|
test "split sink routes records by predicate" {
|
||||||
let left_messages : Ref[Array[String]] = Ref([])
|
let left_messages : Ref[Array[String]] = Ref([])
|
||||||
let right_messages : Ref[Array[String]] = Ref([])
|
let right_messages : Ref[Array[String]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
split_sink(
|
split_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { left_messages.val.push(rec.message) }),
|
||||||
left_messages.val.push(rec.message)
|
callback_sink(fn(rec) { right_messages.val.push(rec.message) }),
|
||||||
}),
|
fn(rec) { rec.target == "audit" },
|
||||||
callback_sink(fn(rec) {
|
|
||||||
right_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
fn(rec) {
|
|
||||||
rec.target == "audit"
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="main",
|
target="main",
|
||||||
@@ -722,6 +836,7 @@ test "split sink routes records by predicate" {
|
|||||||
inspect(right_messages.val[0], content="drop to right")
|
inspect(right_messages.val[0], content="drop to right")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "split_by_level routes warn and error separately" {
|
test "split_by_level routes warn and error separately" {
|
||||||
let high_messages : Ref[Array[String]] = Ref([])
|
let high_messages : Ref[Array[String]] = Ref([])
|
||||||
let low_messages : Ref[Array[String]] = Ref([])
|
let low_messages : Ref[Array[String]] = Ref([])
|
||||||
@@ -748,6 +863,7 @@ test "split_by_level routes warn and error separately" {
|
|||||||
inspect(low_messages.val[0], content="INFO:info")
|
inspect(low_messages.val[0], content="INFO:info")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "callback sink sees child target and context logger shape" {
|
test "callback sink sees child target and context logger shape" {
|
||||||
let captured_target : Ref[String] = Ref("")
|
let captured_target : Ref[String] = Ref("")
|
||||||
let captured_message : Ref[String] = Ref("")
|
let captured_message : Ref[String] = Ref("")
|
||||||
@@ -773,6 +889,7 @@ test "callback sink sees child target and context logger shape" {
|
|||||||
inspect(captured_timestamp.val > 0UL, content="true")
|
inspect(captured_timestamp.val > 0UL, content="true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "bind aliases context fields ergonomically" {
|
test "bind aliases context fields ergonomically" {
|
||||||
let captured_target : Ref[String] = Ref("")
|
let captured_target : Ref[String] = Ref("")
|
||||||
let captured_message : Ref[String] = Ref("")
|
let captured_message : Ref[String] = Ref("")
|
||||||
@@ -798,12 +915,11 @@ test "bind aliases context fields ergonomically" {
|
|||||||
inspect(captured_fields.val[2].value, content="test")
|
inspect(captured_fields.val[2].value, content="test")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "buffered sink flushes manually" {
|
test "buffered sink flushes manually" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let sink = buffered_sink(
|
let sink = buffered_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
flush_limit=10,
|
flush_limit=10,
|
||||||
)
|
)
|
||||||
let logger = Logger::new(sink, min_level=Level::Info, target="buffered")
|
let logger = Logger::new(sink, min_level=Level::Info, target="buffered")
|
||||||
@@ -818,12 +934,11 @@ test "buffered sink flushes manually" {
|
|||||||
inspect(flushed_messages.val[1], content="two")
|
inspect(flushed_messages.val[1], content="two")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "buffered sink flushes automatically at limit" {
|
test "buffered sink flushes automatically at limit" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let sink = buffered_sink(
|
let sink = buffered_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
flush_limit=2,
|
flush_limit=2,
|
||||||
)
|
)
|
||||||
let logger = Logger::new(sink, min_level=Level::Info, target="buffered")
|
let logger = Logger::new(sink, min_level=Level::Info, target="buffered")
|
||||||
@@ -836,15 +951,12 @@ test "buffered sink flushes automatically at limit" {
|
|||||||
inspect(flushed_messages.val[1], content="two")
|
inspect(flushed_messages.val[1], content="two")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "filter sink only forwards matching records" {
|
test "filter sink only forwards matching records" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let sink = filter_sink(
|
let sink = filter_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
fn(rec) { rec.target == "kept" },
|
||||||
}),
|
|
||||||
fn(rec) {
|
|
||||||
rec.target == "kept"
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
let kept = Logger::new(sink, min_level=Level::Info, target="kept")
|
let kept = Logger::new(sink, min_level=Level::Info, target="kept")
|
||||||
let dropped = Logger::new(sink, min_level=Level::Info, target="dropped")
|
let dropped = Logger::new(sink, min_level=Level::Info, target="dropped")
|
||||||
@@ -856,37 +968,34 @@ test "filter sink only forwards matching records" {
|
|||||||
inspect(flushed_messages.val[1], content="three")
|
inspect(flushed_messages.val[1], content="three")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "logger with_filter composes naturally" {
|
test "logger with_filter composes naturally" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="app",
|
target="app",
|
||||||
)
|
).with_filter(fn(rec) { rec.target == "app.worker" })
|
||||||
.with_filter(fn(rec) {
|
|
||||||
rec.target == "app.worker"
|
|
||||||
})
|
|
||||||
logger.info("drop at app")
|
logger.info("drop at app")
|
||||||
logger.child("worker").info("keep at worker")
|
logger.child("worker").info("keep at worker")
|
||||||
inspect(flushed_messages.val.length(), content="1")
|
inspect(flushed_messages.val.length(), content="1")
|
||||||
inspect(flushed_messages.val[0], content="keep at worker")
|
inspect(flushed_messages.val[0], content="keep at worker")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "filter helpers support target level and message composition" {
|
test "filter helpers support target level and message composition" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
min_level=Level::Trace,
|
min_level=Level::Trace,
|
||||||
target="service",
|
target="service",
|
||||||
).with_filter(all_of([
|
).with_filter(
|
||||||
|
all_of([
|
||||||
target_has_prefix("service"),
|
target_has_prefix("service"),
|
||||||
level_at_least(Level::Info),
|
level_at_least(Level::Info),
|
||||||
message_contains("visible"),
|
message_contains("visible"),
|
||||||
]))
|
]),
|
||||||
|
)
|
||||||
logger.debug("visible debug")
|
logger.debug("visible debug")
|
||||||
logger.info("hidden info")
|
logger.info("hidden info")
|
||||||
logger.child("api").info("visible info")
|
logger.child("api").info("visible info")
|
||||||
@@ -894,39 +1003,46 @@ test "filter helpers support target level and message composition" {
|
|||||||
inspect(flushed_messages.val[0], content="visible info")
|
inspect(flushed_messages.val[0], content="visible info")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "field helpers can match and negate records" {
|
test "field helpers can match and negate records" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="fields",
|
target="fields",
|
||||||
).with_filter(all_of([
|
).with_filter(
|
||||||
|
all_of([
|
||||||
has_field("request_id"),
|
has_field("request_id"),
|
||||||
field_equals("kind", "audit"),
|
field_equals("kind", "audit"),
|
||||||
not_(target_is("fields.drop")),
|
not_(target_is("fields.drop")),
|
||||||
]))
|
]),
|
||||||
|
)
|
||||||
logger.info("missing field")
|
logger.info("missing field")
|
||||||
logger.info("wrong kind", fields=[field("request_id", "1"), field("kind", "trace")])
|
logger.info("wrong kind", fields=[
|
||||||
logger.child("drop").info("blocked target", fields=[field("request_id", "2"), field("kind", "audit")])
|
field("request_id", "1"),
|
||||||
|
field("kind", "trace"),
|
||||||
|
])
|
||||||
|
logger
|
||||||
|
.child("drop")
|
||||||
|
.info("blocked target", fields=[
|
||||||
|
field("request_id", "2"),
|
||||||
|
field("kind", "audit"),
|
||||||
|
])
|
||||||
logger.info("kept", fields=[field("request_id", "3"), field("kind", "audit")])
|
logger.info("kept", fields=[field("request_id", "3"), field("kind", "audit")])
|
||||||
inspect(flushed_messages.val.length(), content="1")
|
inspect(flushed_messages.val.length(), content="1")
|
||||||
inspect(flushed_messages.val[0], content="kept")
|
inspect(flushed_messages.val[0], content="kept")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "any_of helper accepts multiple predicates" {
|
test "any_of helper accepts multiple predicates" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="multi",
|
target="multi",
|
||||||
).with_filter(any_of([
|
).with_filter(
|
||||||
target_is("multi.keep"),
|
any_of([target_is("multi.keep"), field_equals("force", "true")]),
|
||||||
field_equals("force", "true"),
|
)
|
||||||
]))
|
|
||||||
logger.info("drop")
|
logger.info("drop")
|
||||||
logger.child("keep").info("keep by target")
|
logger.child("keep").info("keep by target")
|
||||||
logger.info("keep by field", fields=[field("force", "true")])
|
logger.info("keep by field", fields=[field("force", "true")])
|
||||||
@@ -935,6 +1051,7 @@ test "any_of helper accepts multiple predicates" {
|
|||||||
inspect(flushed_messages.val[1], content="keep by field")
|
inspect(flushed_messages.val[1], content="keep by field")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "patch sink can rewrite message target and fields" {
|
test "patch sink can rewrite message target and fields" {
|
||||||
let captured_target : Ref[String] = Ref("")
|
let captured_target : Ref[String] = Ref("")
|
||||||
let captured_message : Ref[String] = Ref("")
|
let captured_message : Ref[String] = Ref("")
|
||||||
@@ -947,12 +1064,14 @@ test "patch sink can rewrite message target and fields" {
|
|||||||
}),
|
}),
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="auth",
|
target="auth",
|
||||||
).with_patch(compose_patches([
|
).with_patch(
|
||||||
|
compose_patches([
|
||||||
set_target("audit.auth"),
|
set_target("audit.auth"),
|
||||||
prefix_message("[safe] "),
|
prefix_message("[safe] "),
|
||||||
redact_field("token"),
|
redact_field("token"),
|
||||||
append_fields([field("service", "bitlogger")]),
|
append_fields([field("service", "bitlogger")]),
|
||||||
]))
|
]),
|
||||||
|
)
|
||||||
logger.info("login", fields=[field("token", "secret"), field("user", "alice")])
|
logger.info("login", fields=[field("token", "secret"), field("user", "alice")])
|
||||||
inspect(captured_target.val, content="audit.auth")
|
inspect(captured_target.val, content="audit.auth")
|
||||||
inspect(captured_message.val, content="[safe] login")
|
inspect(captured_message.val, content="[safe] login")
|
||||||
@@ -965,31 +1084,30 @@ test "patch sink can rewrite message target and fields" {
|
|||||||
inspect(captured_fields.val[2].value, content="bitlogger")
|
inspect(captured_fields.val[2].value, content="bitlogger")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "patch helpers can redact multiple fields" {
|
test "patch helpers can redact multiple fields" {
|
||||||
let captured_fields : Ref[Array[Field]] = Ref([])
|
let captured_fields : Ref[Array[Field]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { captured_fields.val = rec.fields }),
|
||||||
captured_fields.val = rec.fields
|
|
||||||
}),
|
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="audit",
|
target="audit",
|
||||||
).with_patch(redact_fields(["token", "password"], placeholder="[redacted]"))
|
).with_patch(redact_fields(["token", "password"], placeholder="[redacted]"))
|
||||||
logger.info(
|
logger.info("credentials", fields=[
|
||||||
"credentials",
|
field("token", "abc"),
|
||||||
fields=[field("token", "abc"), field("password", "123"), field("user", "alice")],
|
field("password", "123"),
|
||||||
)
|
field("user", "alice"),
|
||||||
|
])
|
||||||
inspect(captured_fields.val.length(), content="3")
|
inspect(captured_fields.val.length(), content="3")
|
||||||
inspect(captured_fields.val[0].value, content="[redacted]")
|
inspect(captured_fields.val[0].value, content="[redacted]")
|
||||||
inspect(captured_fields.val[1].value, content="[redacted]")
|
inspect(captured_fields.val[1].value, content="[redacted]")
|
||||||
inspect(captured_fields.val[2].value, content="alice")
|
inspect(captured_fields.val[2].value, content="alice")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "queued sink drains in order" {
|
test "queued sink drains in order" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let sink = queued_sink(
|
let sink = queued_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
)
|
)
|
||||||
let logger = Logger::new(sink, min_level=Level::Info, target="queue")
|
let logger = Logger::new(sink, min_level=Level::Info, target="queue")
|
||||||
logger.info("one")
|
logger.info("one")
|
||||||
@@ -1007,12 +1125,11 @@ test "queued sink drains in order" {
|
|||||||
inspect(flushed_messages.val[2], content="three")
|
inspect(flushed_messages.val[2], content="three")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "queued sink can drop newest when full" {
|
test "queued sink can drop newest when full" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let sink = queued_sink(
|
let sink = queued_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
max_pending=2,
|
max_pending=2,
|
||||||
overflow=QueueOverflowPolicy::DropNewest,
|
overflow=QueueOverflowPolicy::DropNewest,
|
||||||
)
|
)
|
||||||
@@ -1028,12 +1145,11 @@ test "queued sink can drop newest when full" {
|
|||||||
inspect(flushed_messages.val[1], content="two")
|
inspect(flushed_messages.val[1], content="two")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "queued sink can drop oldest when full" {
|
test "queued sink can drop oldest when full" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let sink = queued_sink(
|
let sink = queued_sink(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
max_pending=2,
|
max_pending=2,
|
||||||
overflow=QueueOverflowPolicy::DropOldest,
|
overflow=QueueOverflowPolicy::DropOldest,
|
||||||
)
|
)
|
||||||
@@ -1049,12 +1165,11 @@ test "queued sink can drop oldest when full" {
|
|||||||
inspect(flushed_messages.val[1], content="three")
|
inspect(flushed_messages.val[1], content="three")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "logger with_queue preserves chaining ergonomics" {
|
test "logger with_queue preserves chaining ergonomics" {
|
||||||
let flushed_messages : Ref[Array[String]] = Ref([])
|
let flushed_messages : Ref[Array[String]] = Ref([])
|
||||||
let logger = Logger::new(
|
let logger = Logger::new(
|
||||||
callback_sink(fn(rec) {
|
callback_sink(fn(rec) { flushed_messages.val.push(rec.message) }),
|
||||||
flushed_messages.val.push(rec.message)
|
|
||||||
}),
|
|
||||||
min_level=Level::Info,
|
min_level=Level::Info,
|
||||||
target="service",
|
target="service",
|
||||||
)
|
)
|
||||||
|
|||||||
+8
-2
@@ -19,13 +19,17 @@ BitLogger 是一个使用 MoonBit 编写的结构化日志库.
|
|||||||
|
|
||||||
## Example / 示例
|
## Example / 示例
|
||||||
|
|
||||||
```moonbit
|
```moonbit nocheck
|
||||||
|
///|
|
||||||
test {
|
test {
|
||||||
let logger = build_logger(
|
let logger = build_logger(
|
||||||
text_console(
|
text_console(
|
||||||
min_level=Level::Debug,
|
min_level=Level::Debug,
|
||||||
target="demo",
|
target="demo",
|
||||||
text_formatter=TextFormatterConfig::new(show_timestamp=false, separator=" | "),
|
text_formatter=TextFormatterConfig::new(
|
||||||
|
show_timestamp=false,
|
||||||
|
separator=" | ",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
logger.info("starting", fields=[field("port", "8080")])
|
logger.info("starting", fields=[field("port", "8080")])
|
||||||
@@ -76,7 +80,9 @@ Project command note / 项目命令说明:
|
|||||||
- `console_basic` / `text_formatter` / `style_tags` / `config_build` / `presets` are the portable-first set
|
- `console_basic` / `text_formatter` / `style_tags` / `config_build` / `presets` are the portable-first set
|
||||||
- `console_basic` / `text_formatter` / `style_tags` / `config_build` / `presets` 是 portable-first 示例集
|
- `console_basic` / `text_formatter` / `style_tags` / `config_build` / `presets` 是 portable-first 示例集
|
||||||
- `file_rotation` is native-sensitive, and `async_basic` stays native-only because of the current `async fn main` entry limitation
|
- `file_rotation` is native-sensitive, and `async_basic` stays native-only because of the current `async fn main` entry limitation
|
||||||
|
- `async_basic` currently relies on `moonbitlang/async`, whose upstream README only claims native/LLVM support on Linux/MacOS; do not treat Windows native as a supported baseline for this example until upstream support is stated clearly
|
||||||
- `file_rotation` 是 native-sensitive,`async_basic` 的 native-only 限制来自当前 `async fn main` 入口能力
|
- `file_rotation` 是 native-sensitive,`async_basic` 的 native-only 限制来自当前 `async fn main` 入口能力
|
||||||
|
- `async_basic` 当前依赖 `moonbitlang/async`,其上游 README 目前只明确承诺 Linux/MacOS 的 native/LLVM 支持;在上游明确支持之前,不要把 Windows native 当作这个示例的支持基线
|
||||||
- package-level API docs / 单接口 API 文档:
|
- package-level API docs / 单接口 API 文档:
|
||||||
- `../docs/api/`
|
- `../docs/api/`
|
||||||
- common entry points / 常用入口:
|
- common entry points / 常用入口:
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
///|
|
||||||
pub type ApplicationLogger = ConfiguredLogger
|
pub type ApplicationLogger = ConfiguredLogger
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_application_logger(config : LoggerConfig) -> ApplicationLogger {
|
pub fn build_application_logger(config : LoggerConfig) -> ApplicationLogger {
|
||||||
build_logger(config)
|
build_logger(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn parse_and_build_application_logger(
|
pub fn parse_and_build_application_logger(
|
||||||
input : String,
|
input : String,
|
||||||
) -> ApplicationLogger raise ConfigError {
|
) -> ApplicationLogger raise ConfigError {
|
||||||
|
|||||||
+45
-11
@@ -1,66 +1,100 @@
|
|||||||
|
///|
|
||||||
pub type ConfigError = @utils.ConfigError
|
pub type ConfigError = @utils.ConfigError
|
||||||
|
|
||||||
|
///|
|
||||||
pub type SinkKind = @utils.SinkKind
|
pub type SinkKind = @utils.SinkKind
|
||||||
|
|
||||||
|
///|
|
||||||
pub type TextFormatterConfig = @utils.TextFormatterConfig
|
pub type TextFormatterConfig = @utils.TextFormatterConfig
|
||||||
|
|
||||||
|
///|
|
||||||
pub type QueueConfig = @utils.QueueConfig
|
pub type QueueConfig = @utils.QueueConfig
|
||||||
|
|
||||||
|
///|
|
||||||
pub type SinkConfig = @utils.SinkConfig
|
pub type SinkConfig = @utils.SinkConfig
|
||||||
|
|
||||||
|
///|
|
||||||
pub type LoggerConfig = @utils.LoggerConfig
|
pub type LoggerConfig = @utils.LoggerConfig
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_text_formatter_config() -> TextFormatterConfig {
|
pub fn default_text_formatter_config() -> TextFormatterConfig {
|
||||||
@utils.default_text_formatter_config()
|
@utils.default_text_formatter_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_sink_config() -> SinkConfig {
|
pub fn default_sink_config() -> SinkConfig {
|
||||||
@utils.default_sink_config()
|
@utils.default_sink_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_logger_config() -> LoggerConfig {
|
pub fn default_logger_config() -> LoggerConfig {
|
||||||
@utils.default_logger_config()
|
@utils.default_logger_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_logger_config_text(input : String) -> LoggerConfig raise ConfigError {
|
///|
|
||||||
|
pub fn parse_logger_config_text(
|
||||||
|
input : String,
|
||||||
|
) -> LoggerConfig raise ConfigError {
|
||||||
@utils.parse_logger_config_text(input)
|
@utils.parse_logger_config_text(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
||||||
@utils.queue_config_to_json(queue)
|
@utils.queue_config_to_json(queue)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_queue_config(queue, pretty=pretty)
|
pub fn stringify_queue_config(
|
||||||
|
queue : QueueConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_queue_config(queue, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn text_formatter_config_to_json(
|
||||||
|
config : TextFormatterConfig,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.text_formatter_config_to_json(config)
|
@utils.text_formatter_config_to_json(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_text_formatter_config(
|
pub fn stringify_text_formatter_config(
|
||||||
config : TextFormatterConfig,
|
config : TextFormatterConfig,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
@utils.stringify_text_formatter_config(config, pretty=pretty)
|
@utils.stringify_text_formatter_config(config, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_rotation_config_to_json(config : FileRotation) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn file_rotation_config_to_json(
|
||||||
|
config : FileRotation,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.file_rotation_config_to_json(config)
|
@utils.file_rotation_config_to_json(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||||
@utils.sink_config_to_json(config)
|
@utils.sink_config_to_json(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_sink_config(config, pretty=pretty)
|
pub fn stringify_sink_config(
|
||||||
|
config : SinkConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_sink_config(config, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
||||||
@utils.logger_config_to_json(config)
|
@utils.logger_config_to_json(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_logger_config(config : LoggerConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_logger_config(config, pretty=pretty)
|
pub fn stringify_logger_config(
|
||||||
|
config : LoggerConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_logger_config(config, pretty~)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
pub(all) enum Level {
|
pub(all) enum Level {
|
||||||
Trace
|
Trace
|
||||||
Debug
|
Debug
|
||||||
@@ -6,6 +7,7 @@ pub(all) enum Level {
|
|||||||
Error
|
Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Level::priority(self : Level) -> Int {
|
pub fn Level::priority(self : Level) -> Int {
|
||||||
match self {
|
match self {
|
||||||
Level::Trace => 10
|
Level::Trace => 10
|
||||||
@@ -16,6 +18,7 @@ pub fn Level::priority(self : Level) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Level::label(self : Level) -> String {
|
pub fn Level::label(self : Level) -> String {
|
||||||
match self {
|
match self {
|
||||||
Level::Trace => "TRACE"
|
Level::Trace => "TRACE"
|
||||||
@@ -26,6 +29,7 @@ pub fn Level::label(self : Level) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Level::enabled(self : Level, min_level : Level) -> Bool {
|
pub fn Level::enabled(self : Level, min_level : Level) -> Bool {
|
||||||
self.priority() >= min_level.priority()
|
self.priority() >= min_level.priority()
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-8
@@ -1,18 +1,20 @@
|
|||||||
|
///|
|
||||||
pub struct Field {
|
pub struct Field {
|
||||||
key : String
|
key : String
|
||||||
value : String
|
value : String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn field(key : String, value : String) -> Field {
|
pub fn field(key : String, value : String) -> Field {
|
||||||
{ key, value }
|
{ key, value }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn fields(entries : Array[(String, String)]) -> Array[Field] {
|
pub fn fields(entries : Array[(String, String)]) -> Array[Field] {
|
||||||
entries.map(fn(entry) {
|
entries.map(fn(entry) { field(entry.0, entry.1) })
|
||||||
field(entry.0, entry.1)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct Record {
|
pub struct Record {
|
||||||
level : Level
|
level : Level
|
||||||
timestamp_ms : UInt64
|
timestamp_ms : UInt64
|
||||||
@@ -21,30 +23,34 @@ pub struct Record {
|
|||||||
fields : Array[Field]
|
fields : Array[Field]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Record::new(
|
pub fn Record::new(
|
||||||
level : Level,
|
level : Level,
|
||||||
message : String,
|
message : String,
|
||||||
timestamp_ms~ : UInt64 = 0UL,
|
timestamp_ms? : UInt64 = 0UL,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
) -> Record {
|
) -> Record {
|
||||||
{ level, timestamp_ms, target, message, fields }
|
{ level, timestamp_ms, target, message, fields }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Field::with_value(self : Field, value : String) -> Field {
|
pub fn Field::with_value(self : Field, value : String) -> Field {
|
||||||
field(self.key, value)
|
field(self.key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Record::with_target(self : Record, target : String) -> Record {
|
pub fn Record::with_target(self : Record, target : String) -> Record {
|
||||||
Record::new(
|
Record::new(
|
||||||
self.level,
|
self.level,
|
||||||
self.message,
|
self.message,
|
||||||
timestamp_ms=self.timestamp_ms,
|
timestamp_ms=self.timestamp_ms,
|
||||||
target=target,
|
target~,
|
||||||
fields=self.fields,
|
fields=self.fields,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Record::with_message(self : Record, message : String) -> Record {
|
pub fn Record::with_message(self : Record, message : String) -> Record {
|
||||||
Record::new(
|
Record::new(
|
||||||
self.level,
|
self.level,
|
||||||
@@ -55,16 +61,18 @@ pub fn Record::with_message(self : Record, message : String) -> Record {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Record::with_fields(self : Record, fields : Array[Field]) -> Record {
|
pub fn Record::with_fields(self : Record, fields : Array[Field]) -> Record {
|
||||||
Record::new(
|
Record::new(
|
||||||
self.level,
|
self.level,
|
||||||
self.message,
|
self.message,
|
||||||
timestamp_ms=self.timestamp_ms,
|
timestamp_ms=self.timestamp_ms,
|
||||||
target=self.target,
|
target=self.target,
|
||||||
fields=fields,
|
fields~,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn Record::copy(self : Record) -> Record {
|
pub fn Record::copy(self : Record) -> Record {
|
||||||
Record::new(
|
Record::new(
|
||||||
self.level,
|
self.level,
|
||||||
|
|||||||
@@ -1,37 +1,47 @@
|
|||||||
|
///|
|
||||||
type FileHandle = @utils.FileHandle
|
type FileHandle = @utils.FileHandle
|
||||||
|
|
||||||
|
///|
|
||||||
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||||
@utils.open_file_handle_internal(path, append)
|
@utils.open_file_handle_internal(path, append)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
||||||
@utils.write_file_handle_internal(handle, content)
|
@utils.write_file_handle_internal(handle, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
@utils.flush_file_handle_internal(handle)
|
@utils.flush_file_handle_internal(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
@utils.close_file_handle_internal(handle)
|
@utils.close_file_handle_internal(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn file_size_internal(handle : FileHandle) -> Int {
|
fn file_size_internal(handle : FileHandle) -> Int {
|
||||||
@utils.file_size_internal(handle)
|
@utils.file_size_internal(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||||
@utils.rename_file_internal(from_path, to_path)
|
@utils.rename_file_internal(from_path, to_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn remove_file_internal(path : String) -> Bool {
|
fn remove_file_internal(path : String) -> Bool {
|
||||||
@utils.remove_file_internal(path)
|
@utils.remove_file_internal(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn string_byte_length_internal(content : String) -> Int {
|
fn string_byte_length_internal(content : String) -> Int {
|
||||||
@utils.string_byte_length_internal(content)
|
@utils.string_byte_length_internal(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn native_files_supported_internal() -> Bool {
|
fn native_files_supported_internal() -> Bool {
|
||||||
@utils.native_files_supported_internal()
|
@utils.native_files_supported_internal()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,47 @@
|
|||||||
|
///|
|
||||||
type FileHandle = @utils.FileHandle
|
type FileHandle = @utils.FileHandle
|
||||||
|
|
||||||
|
///|
|
||||||
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||||
@utils.open_file_handle_internal(path, append)
|
@utils.open_file_handle_internal(path, append)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
||||||
@utils.write_file_handle_internal(handle, content)
|
@utils.write_file_handle_internal(handle, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
@utils.flush_file_handle_internal(handle)
|
@utils.flush_file_handle_internal(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
@utils.close_file_handle_internal(handle)
|
@utils.close_file_handle_internal(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn file_size_internal(handle : FileHandle) -> Int {
|
fn file_size_internal(handle : FileHandle) -> Int {
|
||||||
@utils.file_size_internal(handle)
|
@utils.file_size_internal(handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||||
@utils.rename_file_internal(from_path, to_path)
|
@utils.rename_file_internal(from_path, to_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn remove_file_internal(path : String) -> Bool {
|
fn remove_file_internal(path : String) -> Bool {
|
||||||
@utils.remove_file_internal(path)
|
@utils.remove_file_internal(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn string_byte_length_internal(content : String) -> Int {
|
fn string_byte_length_internal(content : String) -> Int {
|
||||||
@utils.string_byte_length_internal(content)
|
@utils.string_byte_length_internal(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn native_files_supported_internal() -> Bool {
|
fn native_files_supported_internal() -> Bool {
|
||||||
@utils.native_files_supported_internal()
|
@utils.native_files_supported_internal()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,47 @@
|
|||||||
|
///|
|
||||||
pub type RecordPredicate = @utils.RecordPredicate
|
pub type RecordPredicate = @utils.RecordPredicate
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn level_at_least(min_level : Level) -> RecordPredicate {
|
pub fn level_at_least(min_level : Level) -> RecordPredicate {
|
||||||
@utils.level_at_least(min_level)
|
@utils.level_at_least(min_level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn target_is(target : String) -> RecordPredicate {
|
pub fn target_is(target : String) -> RecordPredicate {
|
||||||
@utils.target_is(target)
|
@utils.target_is(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
||||||
@utils.target_has_prefix(prefix)
|
@utils.target_has_prefix(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn message_contains(fragment : String) -> RecordPredicate {
|
pub fn message_contains(fragment : String) -> RecordPredicate {
|
||||||
@utils.message_contains(fragment)
|
@utils.message_contains(fragment)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn has_field(key : String) -> RecordPredicate {
|
pub fn has_field(key : String) -> RecordPredicate {
|
||||||
@utils.has_field(key)
|
@utils.has_field(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||||
@utils.field_equals(key, value)
|
@utils.field_equals(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
||||||
@utils.not_(predicate)
|
@utils.not_(predicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||||
@utils.all_of(predicates)
|
@utils.all_of(predicates)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||||
@utils.any_of(predicates)
|
@utils.any_of(predicates)
|
||||||
}
|
}
|
||||||
|
|||||||
+57
-42
@@ -1,103 +1,118 @@
|
|||||||
|
///|
|
||||||
pub type RecordFormatter = @utils.RecordFormatter
|
pub type RecordFormatter = @utils.RecordFormatter
|
||||||
|
|
||||||
|
///|
|
||||||
pub type ColorMode = @utils.ColorMode
|
pub type ColorMode = @utils.ColorMode
|
||||||
|
|
||||||
|
///|
|
||||||
pub type ColorSupport = @utils.ColorSupport
|
pub type ColorSupport = @utils.ColorSupport
|
||||||
|
|
||||||
|
///|
|
||||||
pub type StyleMarkupMode = @utils.StyleMarkupMode
|
pub type StyleMarkupMode = @utils.StyleMarkupMode
|
||||||
|
|
||||||
|
///|
|
||||||
pub type TextStyle = @utils.TextStyle
|
pub type TextStyle = @utils.TextStyle
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_style(
|
pub fn text_style(
|
||||||
fg~ : String? = None,
|
fg? : String? = None,
|
||||||
bg~ : String? = None,
|
bg? : String? = None,
|
||||||
bold~ : Bool = false,
|
bold? : Bool = false,
|
||||||
dim~ : Bool = false,
|
dim? : Bool = false,
|
||||||
italic~ : Bool = false,
|
italic? : Bool = false,
|
||||||
underline~ : Bool = false,
|
underline? : Bool = false,
|
||||||
) -> TextStyle {
|
) -> TextStyle {
|
||||||
@utils.text_style(
|
@utils.text_style(fg~, bg~, bold~, dim~, italic~, underline~)
|
||||||
fg=fg,
|
|
||||||
bg=bg,
|
|
||||||
bold=bold,
|
|
||||||
dim=dim,
|
|
||||||
italic=italic,
|
|
||||||
underline=underline,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type StyleTagRegistry = @utils.StyleTagRegistry
|
pub type StyleTagRegistry = @utils.StyleTagRegistry
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn style_tag_registry() -> StyleTagRegistry {
|
pub fn style_tag_registry() -> StyleTagRegistry {
|
||||||
@utils.style_tag_registry()
|
@utils.style_tag_registry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
||||||
@utils.default_style_tag_registry()
|
@utils.default_style_tag_registry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
||||||
@utils.global_style_tag_registry()
|
@utils.global_style_tag_registry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
||||||
@utils.set_global_style_tag_registry(registry)
|
@utils.set_global_style_tag_registry(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn reset_global_style_tag_registry() -> Unit {
|
pub fn reset_global_style_tag_registry() -> Unit {
|
||||||
@utils.reset_global_style_tag_registry()
|
@utils.reset_global_style_tag_registry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type TextFormatter = @utils.TextFormatter
|
pub type TextFormatter = @utils.TextFormatter
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_formatter(
|
pub fn text_formatter(
|
||||||
show_timestamp~ : Bool = true,
|
show_timestamp? : Bool = true,
|
||||||
show_level~ : Bool = true,
|
show_level? : Bool = true,
|
||||||
show_target~ : Bool = true,
|
show_target? : Bool = true,
|
||||||
show_fields~ : Bool = true,
|
show_fields? : Bool = true,
|
||||||
separator~ : String = " ",
|
separator? : String = " ",
|
||||||
field_separator~ : String = " ",
|
field_separator? : String = " ",
|
||||||
template~ : String = "",
|
template? : String = "",
|
||||||
color_mode~ : ColorMode = ColorMode::Never,
|
color_mode? : ColorMode = ColorMode::Never,
|
||||||
color_support~ : ColorSupport = ColorSupport::TrueColor,
|
color_support? : ColorSupport = ColorSupport::TrueColor,
|
||||||
style_markup~ : StyleMarkupMode = StyleMarkupMode::Full,
|
style_markup? : StyleMarkupMode = StyleMarkupMode::Full,
|
||||||
target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
target_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||||
fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
fields_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||||
style_tags~ : StyleTagRegistry? = None,
|
style_tags? : StyleTagRegistry? = None,
|
||||||
) -> TextFormatter {
|
) -> TextFormatter {
|
||||||
@utils.text_formatter(
|
@utils.text_formatter(
|
||||||
show_timestamp=show_timestamp,
|
show_timestamp~,
|
||||||
show_level=show_level,
|
show_level~,
|
||||||
show_target=show_target,
|
show_target~,
|
||||||
show_fields=show_fields,
|
show_fields~,
|
||||||
separator=separator,
|
separator~,
|
||||||
field_separator=field_separator,
|
field_separator~,
|
||||||
template=template,
|
template~,
|
||||||
color_mode=color_mode,
|
color_mode~,
|
||||||
color_support=color_support,
|
color_support~,
|
||||||
style_markup=style_markup,
|
style_markup~,
|
||||||
target_style_markup=target_style_markup,
|
target_style_markup~,
|
||||||
fields_style_markup=fields_style_markup,
|
fields_style_markup~,
|
||||||
style_tags=style_tags,
|
style_tags~,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn color_support_label(support : ColorSupport) -> String {
|
pub fn color_support_label(support : ColorSupport) -> String {
|
||||||
@utils.color_support_label(support)
|
@utils.color_support_label(support)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
||||||
@utils.style_markup_mode_label(mode)
|
@utils.style_markup_mode_label(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn color_mode_label(mode : ColorMode) -> String {
|
pub fn color_mode_label(mode : ColorMode) -> String {
|
||||||
@utils.color_mode_label(mode)
|
@utils.color_mode_label(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_text(rec : Record, formatter~ : TextFormatter = text_formatter()) -> String {
|
///|
|
||||||
@utils.format_text(rec, formatter=formatter)
|
pub fn format_text(
|
||||||
|
rec : Record,
|
||||||
|
formatter? : TextFormatter = text_formatter(),
|
||||||
|
) -> String {
|
||||||
|
@utils.format_text(rec, formatter~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn format_json(rec : Record) -> String {
|
pub fn format_json(rec : Record) -> String {
|
||||||
@utils.format_json(rec)
|
@utils.format_json(rec)
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -1,15 +1,27 @@
|
|||||||
|
///|
|
||||||
let default_console_sink : ConsoleSink = console_sink()
|
let default_console_sink : ConsoleSink = console_sink()
|
||||||
|
|
||||||
|
///|
|
||||||
let default_min_level_ref : Ref[Level] = Ref(Level::Info)
|
let default_min_level_ref : Ref[Level] = Ref(Level::Info)
|
||||||
|
|
||||||
|
///|
|
||||||
let default_target_ref : Ref[String] = Ref("")
|
let default_target_ref : Ref[String] = Ref("")
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn set_default_min_level(level : Level) -> Unit {
|
pub fn set_default_min_level(level : Level) -> Unit {
|
||||||
default_min_level_ref.val = level
|
default_min_level_ref.val = level
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn set_default_target(target : String) -> Unit {
|
pub fn set_default_target(target : String) -> Unit {
|
||||||
default_target_ref.val = target
|
default_target_ref.val = target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_logger() -> Logger[ConsoleSink] {
|
pub fn default_logger() -> Logger[ConsoleSink] {
|
||||||
Logger::new(default_console_sink, min_level=default_min_level_ref.val, target=default_target_ref.val)
|
Logger::new(
|
||||||
|
default_console_sink,
|
||||||
|
min_level=default_min_level_ref.val,
|
||||||
|
target=default_target_ref.val,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-12
@@ -1,23 +1,33 @@
|
|||||||
pub fn log(level : Level, message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
default_logger().log(level, message, fields=fields)
|
pub fn log(
|
||||||
|
level : Level,
|
||||||
|
message : String,
|
||||||
|
fields? : Array[Field] = [],
|
||||||
|
) -> Unit {
|
||||||
|
default_logger().log(level, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn trace(message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
default_logger().trace(message, fields=fields)
|
pub fn trace(message : String, fields? : Array[Field] = []) -> Unit {
|
||||||
|
default_logger().trace(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug(message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
default_logger().debug(message, fields=fields)
|
pub fn debug(message : String, fields? : Array[Field] = []) -> Unit {
|
||||||
|
default_logger().debug(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn info(message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
default_logger().info(message, fields=fields)
|
pub fn info(message : String, fields? : Array[Field] = []) -> Unit {
|
||||||
|
default_logger().info(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn warn(message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
default_logger().warn(message, fields=fields)
|
pub fn warn(message : String, fields? : Array[Field] = []) -> Unit {
|
||||||
|
default_logger().warn(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn error(message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
default_logger().error(message, fields=fields)
|
pub fn error(message : String, fields? : Array[Field] = []) -> Unit {
|
||||||
|
default_logger().error(message, fields~)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
|
///|
|
||||||
pub type Level = @core.Level
|
pub type Level = @core.Level
|
||||||
|
|||||||
+47
-16
@@ -1,49 +1,70 @@
|
|||||||
|
///|
|
||||||
pub struct LibraryLogger[S] {
|
pub struct LibraryLogger[S] {
|
||||||
inner : Logger[S]
|
inner : Logger[S]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn[S] library_logger(logger : Logger[S]) -> LibraryLogger[S] {
|
fn[S] library_logger(logger : Logger[S]) -> LibraryLogger[S] {
|
||||||
{ inner: logger }
|
{ inner: logger }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] Logger::to_library_logger(self : Logger[S]) -> LibraryLogger[S] {
|
pub fn[S] Logger::to_library_logger(self : Logger[S]) -> LibraryLogger[S] {
|
||||||
library_logger(self)
|
library_logger(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryLogger::new(
|
pub fn[S] LibraryLogger::new(
|
||||||
sink : S,
|
sink : S,
|
||||||
min_level~ : Level = Level::Info,
|
min_level? : Level = Level::Info,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
) -> LibraryLogger[S] {
|
) -> LibraryLogger[S] {
|
||||||
library_logger(Logger::new(sink, min_level=min_level, target=target))
|
library_logger(Logger::new(sink, min_level~, target~))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryLogger::to_logger(self : LibraryLogger[S]) -> Logger[S] {
|
pub fn[S] LibraryLogger::to_logger(self : LibraryLogger[S]) -> Logger[S] {
|
||||||
self.inner
|
self.inner
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configured_library_logger(logger : ConfiguredLogger) -> LibraryLogger[RuntimeSink] {
|
///|
|
||||||
|
fn configured_library_logger(
|
||||||
|
logger : ConfiguredLogger,
|
||||||
|
) -> LibraryLogger[RuntimeSink] {
|
||||||
library_logger(logger)
|
library_logger(logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_library_logger(config : LoggerConfig) -> LibraryLogger[RuntimeSink] {
|
///|
|
||||||
|
pub fn build_library_logger(
|
||||||
|
config : LoggerConfig,
|
||||||
|
) -> LibraryLogger[RuntimeSink] {
|
||||||
configured_library_logger(build_logger(config))
|
configured_library_logger(build_logger(config))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn parse_and_build_library_logger(
|
pub fn parse_and_build_library_logger(
|
||||||
input : String,
|
input : String,
|
||||||
) -> LibraryLogger[RuntimeSink] raise ConfigError {
|
) -> LibraryLogger[RuntimeSink] raise ConfigError {
|
||||||
configured_library_logger(parse_and_build_logger(input))
|
configured_library_logger(parse_and_build_logger(input))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] LibraryLogger::with_target(self : LibraryLogger[S], target : String) -> LibraryLogger[S] {
|
///|
|
||||||
|
pub fn[S] LibraryLogger::with_target(
|
||||||
|
self : LibraryLogger[S],
|
||||||
|
target : String,
|
||||||
|
) -> LibraryLogger[S] {
|
||||||
library_logger(self.inner.with_target(target))
|
library_logger(self.inner.with_target(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] LibraryLogger::child(self : LibraryLogger[S], target : String) -> LibraryLogger[S] {
|
///|
|
||||||
|
pub fn[S] LibraryLogger::child(
|
||||||
|
self : LibraryLogger[S],
|
||||||
|
target : String,
|
||||||
|
) -> LibraryLogger[S] {
|
||||||
library_logger(self.inner.child(target))
|
library_logger(self.inner.child(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryLogger::with_context_fields(
|
pub fn[S] LibraryLogger::with_context_fields(
|
||||||
self : LibraryLogger[S],
|
self : LibraryLogger[S],
|
||||||
fields : Array[Field],
|
fields : Array[Field],
|
||||||
@@ -51,6 +72,7 @@ pub fn[S] LibraryLogger::with_context_fields(
|
|||||||
library_logger(self.inner.with_context_fields(fields))
|
library_logger(self.inner.with_context_fields(fields))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] LibraryLogger::bind(
|
pub fn[S] LibraryLogger::bind(
|
||||||
self : LibraryLogger[S],
|
self : LibraryLogger[S],
|
||||||
fields : Array[Field],
|
fields : Array[Field],
|
||||||
@@ -58,44 +80,53 @@ pub fn[S] LibraryLogger::bind(
|
|||||||
self.with_context_fields(fields)
|
self.with_context_fields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] LibraryLogger::is_enabled(self : LibraryLogger[S], level : Level) -> Bool {
|
///|
|
||||||
|
pub fn[S] LibraryLogger::is_enabled(
|
||||||
|
self : LibraryLogger[S],
|
||||||
|
level : Level,
|
||||||
|
) -> Bool {
|
||||||
self.inner.is_enabled(level)
|
self.inner.is_enabled(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S : Sink] LibraryLogger::log(
|
pub fn[S : Sink] LibraryLogger::log(
|
||||||
self : LibraryLogger[S],
|
self : LibraryLogger[S],
|
||||||
level : Level,
|
level : Level,
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
target? : String = "",
|
target? : String = "",
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.log(level, message, fields=fields, target=target)
|
self.inner.log(level, message, fields~, target~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S : Sink] LibraryLogger::info(
|
pub fn[S : Sink] LibraryLogger::info(
|
||||||
self : LibraryLogger[S],
|
self : LibraryLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.info(message, fields=fields)
|
self.inner.info(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S : Sink] LibraryLogger::warn(
|
pub fn[S : Sink] LibraryLogger::warn(
|
||||||
self : LibraryLogger[S],
|
self : LibraryLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.warn(message, fields=fields)
|
self.inner.warn(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S : Sink] LibraryLogger::error(
|
pub fn[S : Sink] LibraryLogger::error(
|
||||||
self : LibraryLogger[S],
|
self : LibraryLogger[S],
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
self.inner.error(message, fields=fields)
|
self.inner.error(message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_library_logger() -> LibraryLogger[ConsoleSink] {
|
pub fn default_library_logger() -> LibraryLogger[ConsoleSink] {
|
||||||
library_logger(default_logger())
|
library_logger(default_logger())
|
||||||
}
|
}
|
||||||
|
|||||||
+47
-12
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
pub struct Logger[S] {
|
pub struct Logger[S] {
|
||||||
min_level : Level
|
min_level : Level
|
||||||
sink : S
|
sink : S
|
||||||
@@ -5,14 +6,21 @@ pub struct Logger[S] {
|
|||||||
timestamp : Bool
|
timestamp : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::new(sink : S, min_level~ : Level = Level::Info, target~ : String = "") -> Logger[S] {
|
///|
|
||||||
|
pub fn[S] Logger::new(
|
||||||
|
sink : S,
|
||||||
|
min_level? : Level = Level::Info,
|
||||||
|
target? : String = "",
|
||||||
|
) -> Logger[S] {
|
||||||
{ min_level, sink, target, timestamp: false }
|
{ min_level, sink, target, timestamp: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] Logger::with_target(self : Logger[S], target : String) -> Logger[S] {
|
pub fn[S] Logger::with_target(self : Logger[S], target : String) -> Logger[S] {
|
||||||
{ ..self, target }
|
{ ..self, target, }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn combine_targets(parent : String, child : String) -> String {
|
fn combine_targets(parent : String, child : String) -> String {
|
||||||
if parent == "" {
|
if parent == "" {
|
||||||
child
|
child
|
||||||
@@ -23,11 +31,16 @@ fn combine_targets(parent : String, child : String) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] Logger::child(self : Logger[S], target : String) -> Logger[S] {
|
pub fn[S] Logger::child(self : Logger[S], target : String) -> Logger[S] {
|
||||||
{ ..self, target: combine_targets(self.target, target) }
|
{ ..self, target: combine_targets(self.target, target) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::with_context_fields(self : Logger[S], fields : Array[Field]) -> Logger[ContextSink[S]] {
|
///|
|
||||||
|
pub fn[S] Logger::with_context_fields(
|
||||||
|
self : Logger[S],
|
||||||
|
fields : Array[Field],
|
||||||
|
) -> Logger[ContextSink[S]] {
|
||||||
{
|
{
|
||||||
min_level: self.min_level,
|
min_level: self.min_level,
|
||||||
sink: ContextSink::{ sink: self.sink, context_fields: fields },
|
sink: ContextSink::{ sink: self.sink, context_fields: fields },
|
||||||
@@ -36,11 +49,19 @@ pub fn[S] Logger::with_context_fields(self : Logger[S], fields : Array[Field]) -
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::bind(self : Logger[S], fields : Array[Field]) -> Logger[ContextSink[S]] {
|
///|
|
||||||
|
pub fn[S] Logger::bind(
|
||||||
|
self : Logger[S],
|
||||||
|
fields : Array[Field],
|
||||||
|
) -> Logger[ContextSink[S]] {
|
||||||
self.with_context_fields(fields)
|
self.with_context_fields(fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::with_filter(self : Logger[S], predicate : (Record) -> Bool) -> Logger[FilterSink[S]] {
|
///|
|
||||||
|
pub fn[S] Logger::with_filter(
|
||||||
|
self : Logger[S],
|
||||||
|
predicate : (Record) -> Bool,
|
||||||
|
) -> Logger[FilterSink[S]] {
|
||||||
{
|
{
|
||||||
min_level: self.min_level,
|
min_level: self.min_level,
|
||||||
sink: filter_sink(self.sink, predicate),
|
sink: filter_sink(self.sink, predicate),
|
||||||
@@ -49,7 +70,11 @@ pub fn[S] Logger::with_filter(self : Logger[S], predicate : (Record) -> Bool) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::with_patch(self : Logger[S], patch : RecordPatch) -> Logger[PatchSink[S]] {
|
///|
|
||||||
|
pub fn[S] Logger::with_patch(
|
||||||
|
self : Logger[S],
|
||||||
|
patch : RecordPatch,
|
||||||
|
) -> Logger[PatchSink[S]] {
|
||||||
{
|
{
|
||||||
min_level: self.min_level,
|
min_level: self.min_level,
|
||||||
sink: patch_sink(self.sink, patch),
|
sink: patch_sink(self.sink, patch),
|
||||||
@@ -58,27 +83,37 @@ pub fn[S] Logger::with_patch(self : Logger[S], patch : RecordPatch) -> Logger[Pa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] Logger::with_queue(
|
pub fn[S] Logger::with_queue(
|
||||||
self : Logger[S],
|
self : Logger[S],
|
||||||
max_pending~ : Int = 0,
|
max_pending? : Int = 0,
|
||||||
overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||||
) -> Logger[QueuedSink[S]] {
|
) -> Logger[QueuedSink[S]] {
|
||||||
{
|
{
|
||||||
min_level: self.min_level,
|
min_level: self.min_level,
|
||||||
sink: queued_sink(self.sink, max_pending=max_pending, overflow=overflow),
|
sink: queued_sink(self.sink, max_pending~, overflow~),
|
||||||
target: self.target,
|
target: self.target,
|
||||||
timestamp: self.timestamp,
|
timestamp: self.timestamp,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::with_min_level(self : Logger[S], min_level : Level) -> Logger[S] {
|
///|
|
||||||
{ ..self, min_level }
|
pub fn[S] Logger::with_min_level(
|
||||||
|
self : Logger[S],
|
||||||
|
min_level : Level,
|
||||||
|
) -> Logger[S] {
|
||||||
|
{ ..self, min_level, }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] Logger::with_timestamp(self : Logger[S], enabled~ : Bool = true) -> Logger[S] {
|
///|
|
||||||
|
pub fn[S] Logger::with_timestamp(
|
||||||
|
self : Logger[S],
|
||||||
|
enabled? : Bool = true,
|
||||||
|
) -> Logger[S] {
|
||||||
{ ..self, timestamp: enabled }
|
{ ..self, timestamp: enabled }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] Logger::is_enabled(self : Logger[S], level : Level) -> Bool {
|
pub fn[S] Logger::is_enabled(self : Logger[S], level : Level) -> Bool {
|
||||||
level.enabled(self.min_level)
|
level.enabled(self.min_level)
|
||||||
}
|
}
|
||||||
|
|||||||
+38
-12
@@ -1,8 +1,9 @@
|
|||||||
|
///|
|
||||||
pub fn[S : Sink] Logger::log(
|
pub fn[S : Sink] Logger::log(
|
||||||
self : Logger[S],
|
self : Logger[S],
|
||||||
level : Level,
|
level : Level,
|
||||||
message : String,
|
message : String,
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
target? : String = "",
|
target? : String = "",
|
||||||
) -> Unit {
|
) -> Unit {
|
||||||
if !self.is_enabled(level) {
|
if !self.is_enabled(level) {
|
||||||
@@ -11,27 +12,52 @@ pub fn[S : Sink] Logger::log(
|
|||||||
let actual_target = if target == "" { self.target } else { target }
|
let actual_target = if target == "" { self.target } else { target }
|
||||||
let timestamp_ms = if self.timestamp { @env.now() } else { 0UL }
|
let timestamp_ms = if self.timestamp { @env.now() } else { 0UL }
|
||||||
self.sink.write(
|
self.sink.write(
|
||||||
record(level, message, timestamp_ms=timestamp_ms, target=actual_target, fields=fields),
|
record(level, message, timestamp_ms~, target=actual_target, fields~),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S : Sink] Logger::trace(self : Logger[S], message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
self.log(Level::Trace, message, fields=fields)
|
pub fn[S : Sink] Logger::trace(
|
||||||
|
self : Logger[S],
|
||||||
|
message : String,
|
||||||
|
fields? : Array[Field] = [],
|
||||||
|
) -> Unit {
|
||||||
|
self.log(Level::Trace, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S : Sink] Logger::debug(self : Logger[S], message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
self.log(Level::Debug, message, fields=fields)
|
pub fn[S : Sink] Logger::debug(
|
||||||
|
self : Logger[S],
|
||||||
|
message : String,
|
||||||
|
fields? : Array[Field] = [],
|
||||||
|
) -> Unit {
|
||||||
|
self.log(Level::Debug, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S : Sink] Logger::info(self : Logger[S], message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
self.log(Level::Info, message, fields=fields)
|
pub fn[S : Sink] Logger::info(
|
||||||
|
self : Logger[S],
|
||||||
|
message : String,
|
||||||
|
fields? : Array[Field] = [],
|
||||||
|
) -> Unit {
|
||||||
|
self.log(Level::Info, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S : Sink] Logger::warn(self : Logger[S], message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
self.log(Level::Warn, message, fields=fields)
|
pub fn[S : Sink] Logger::warn(
|
||||||
|
self : Logger[S],
|
||||||
|
message : String,
|
||||||
|
fields? : Array[Field] = [],
|
||||||
|
) -> Unit {
|
||||||
|
self.log(Level::Warn, message, fields~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S : Sink] Logger::error(self : Logger[S], message : String, fields~ : Array[Field] = []) -> Unit {
|
///|
|
||||||
self.log(Level::Error, message, fields=fields)
|
pub fn[S : Sink] Logger::error(
|
||||||
|
self : Logger[S],
|
||||||
|
message : String,
|
||||||
|
fields? : Array[Field] = [],
|
||||||
|
) -> Unit {
|
||||||
|
self.log(Level::Error, message, fields~)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -1,12 +1,12 @@
|
|||||||
import {
|
import {
|
||||||
"Nanaloveyuki/BitLogger/src/core" @core,
|
"Nanaloveyuki/BitLogger/src/core",
|
||||||
"Nanaloveyuki/BitLogger/src/utils" @utils,
|
"Nanaloveyuki/BitLogger/src/utils",
|
||||||
"maria/json_parser" @json_parser,
|
"maria/json_parser",
|
||||||
"moonbitlang/core/array",
|
"moonbitlang/core/array",
|
||||||
"moonbitlang/core/builtin",
|
"moonbitlang/core/builtin",
|
||||||
"moonbitlang/core/env" @env,
|
"moonbitlang/core/env",
|
||||||
"moonbitlang/core/json",
|
"moonbitlang/core/json",
|
||||||
"moonbitlang/core/queue" @queue,
|
"moonbitlang/core/queue",
|
||||||
"moonbitlang/core/ref",
|
"moonbitlang/core/ref",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-4
@@ -1,29 +1,40 @@
|
|||||||
|
///|
|
||||||
pub type RecordPatch = @utils.RecordPatch
|
pub type RecordPatch = @utils.RecordPatch
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn identity_patch() -> RecordPatch {
|
pub fn identity_patch() -> RecordPatch {
|
||||||
@utils.identity_patch()
|
@utils.identity_patch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn set_target(target : String) -> RecordPatch {
|
pub fn set_target(target : String) -> RecordPatch {
|
||||||
@utils.set_target(target)
|
@utils.set_target(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn prefix_message(prefix : String) -> RecordPatch {
|
pub fn prefix_message(prefix : String) -> RecordPatch {
|
||||||
@utils.prefix_message(prefix)
|
@utils.prefix_message(prefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn append_fields(extra_fields : Array[Field]) -> RecordPatch {
|
pub fn append_fields(extra_fields : Array[Field]) -> RecordPatch {
|
||||||
@utils.append_fields(extra_fields)
|
@utils.append_fields(extra_fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redact_field(key : String, placeholder~ : String = "***") -> RecordPatch {
|
///|
|
||||||
@utils.redact_field(key, placeholder=placeholder)
|
pub fn redact_field(key : String, placeholder? : String = "***") -> RecordPatch {
|
||||||
|
@utils.redact_field(key, placeholder~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redact_fields(keys : Array[String], placeholder~ : String = "***") -> RecordPatch {
|
///|
|
||||||
@utils.redact_fields(keys, placeholder=placeholder)
|
pub fn redact_fields(
|
||||||
|
keys : Array[String],
|
||||||
|
placeholder? : String = "***",
|
||||||
|
) -> RecordPatch {
|
||||||
|
@utils.redact_fields(keys, placeholder~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
||||||
@utils.compose_patches(patches)
|
@utils.compose_patches(patches)
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-40
@@ -1,89 +1,95 @@
|
|||||||
|
///|
|
||||||
pub fn console(
|
pub fn console(
|
||||||
min_level~ : Level = Level::Info,
|
min_level? : Level = Level::Info,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
timestamp~ : Bool = false,
|
timestamp? : Bool = false,
|
||||||
) -> LoggerConfig {
|
) -> LoggerConfig {
|
||||||
LoggerConfig::new(
|
LoggerConfig::new(
|
||||||
min_level=min_level,
|
min_level~,
|
||||||
target=target,
|
target~,
|
||||||
timestamp=timestamp,
|
timestamp~,
|
||||||
sink=SinkConfig::new(kind=SinkKind::Console),
|
sink=SinkConfig::new(kind=SinkKind::Console),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn json_console(
|
pub fn json_console(
|
||||||
min_level~ : Level = Level::Info,
|
min_level? : Level = Level::Info,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
timestamp~ : Bool = false,
|
timestamp? : Bool = false,
|
||||||
) -> LoggerConfig {
|
) -> LoggerConfig {
|
||||||
LoggerConfig::new(
|
LoggerConfig::new(
|
||||||
min_level=min_level,
|
min_level~,
|
||||||
target=target,
|
target~,
|
||||||
timestamp=timestamp,
|
timestamp~,
|
||||||
sink=SinkConfig::new(kind=SinkKind::JsonConsole),
|
sink=SinkConfig::new(kind=SinkKind::JsonConsole),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_console(
|
pub fn text_console(
|
||||||
min_level~ : Level = Level::Info,
|
min_level? : Level = Level::Info,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
timestamp~ : Bool = false,
|
timestamp? : Bool = false,
|
||||||
text_formatter~ : TextFormatterConfig = default_text_formatter_config(),
|
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||||
) -> LoggerConfig {
|
) -> LoggerConfig {
|
||||||
LoggerConfig::new(
|
LoggerConfig::new(
|
||||||
min_level=min_level,
|
min_level~,
|
||||||
target=target,
|
target~,
|
||||||
timestamp=timestamp,
|
timestamp~,
|
||||||
sink=SinkConfig::new(kind=SinkKind::TextConsole, text_formatter=text_formatter),
|
sink=SinkConfig::new(kind=SinkKind::TextConsole, text_formatter~),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn file(
|
pub fn file(
|
||||||
path : String,
|
path : String,
|
||||||
min_level~ : Level = Level::Info,
|
min_level? : Level = Level::Info,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
timestamp~ : Bool = false,
|
timestamp? : Bool = false,
|
||||||
append~ : Bool = true,
|
append? : Bool = true,
|
||||||
auto_flush~ : Bool = true,
|
auto_flush? : Bool = true,
|
||||||
rotation~ : FileRotation? = None,
|
rotation? : FileRotation? = None,
|
||||||
text_formatter~ : TextFormatterConfig = default_text_formatter_config(),
|
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||||
) -> LoggerConfig raise ConfigError {
|
) -> LoggerConfig raise ConfigError {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
||||||
}
|
}
|
||||||
LoggerConfig::new(
|
LoggerConfig::new(
|
||||||
min_level=min_level,
|
min_level~,
|
||||||
target=target,
|
target~,
|
||||||
timestamp=timestamp,
|
timestamp~,
|
||||||
sink=SinkConfig::new(
|
sink=SinkConfig::new(
|
||||||
kind=SinkKind::File,
|
kind=SinkKind::File,
|
||||||
path=path,
|
path~,
|
||||||
append=append,
|
append~,
|
||||||
auto_flush=auto_flush,
|
auto_flush~,
|
||||||
rotation=rotation,
|
rotation~,
|
||||||
text_formatter=text_formatter,
|
text_formatter~,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn with_queue(
|
pub fn with_queue(
|
||||||
config : LoggerConfig,
|
config : LoggerConfig,
|
||||||
max_pending~ : Int = 0,
|
max_pending? : Int = 0,
|
||||||
overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||||
) -> LoggerConfig {
|
) -> LoggerConfig {
|
||||||
LoggerConfig::new(
|
LoggerConfig::new(
|
||||||
min_level=config.min_level,
|
min_level=config.min_level,
|
||||||
target=config.target,
|
target=config.target,
|
||||||
timestamp=config.timestamp,
|
timestamp=config.timestamp,
|
||||||
sink=config.sink,
|
sink=config.sink,
|
||||||
queue=Some(QueueConfig::new(max_pending, overflow=overflow)),
|
queue=Some(QueueConfig::new(max_pending, overflow~)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn with_file_rotation(
|
pub fn with_file_rotation(
|
||||||
config : LoggerConfig,
|
config : LoggerConfig,
|
||||||
max_bytes : Int,
|
max_bytes : Int,
|
||||||
max_backups~ : Int = 1,
|
max_backups? : Int = 1,
|
||||||
) -> LoggerConfig {
|
) -> LoggerConfig {
|
||||||
match config.sink.kind {
|
match config.sink.kind {
|
||||||
SinkKind::File =>
|
SinkKind::File =>
|
||||||
@@ -96,7 +102,7 @@ pub fn with_file_rotation(
|
|||||||
path=config.sink.path,
|
path=config.sink.path,
|
||||||
append=config.sink.append,
|
append=config.sink.append,
|
||||||
auto_flush=config.sink.auto_flush,
|
auto_flush=config.sink.auto_flush,
|
||||||
rotation=Some(file_rotation(max_bytes, max_backups=max_backups)),
|
rotation=Some(file_rotation(max_bytes, max_backups~)),
|
||||||
text_formatter=config.sink.text_formatter,
|
text_formatter=config.sink.text_formatter,
|
||||||
),
|
),
|
||||||
queue=config.queue,
|
queue=config.queue,
|
||||||
|
|||||||
+77
-25
@@ -1,39 +1,56 @@
|
|||||||
|
///|
|
||||||
test "logger config presets use expected defaults" {
|
test "logger config presets use expected defaults" {
|
||||||
let console_config = console()
|
let console_config = console()
|
||||||
inspect(console_config.min_level.label(), content="INFO")
|
inspect(console_config.min_level.label(), content="INFO")
|
||||||
inspect(console_config.target, content="")
|
inspect(console_config.target, content="")
|
||||||
inspect(console_config.timestamp, content="false")
|
inspect(console_config.timestamp, content="false")
|
||||||
inspect(match console_config.sink.kind {
|
inspect(
|
||||||
|
match console_config.sink.kind {
|
||||||
SinkKind::Console => "Console"
|
SinkKind::Console => "Console"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="Console")
|
},
|
||||||
|
content="Console",
|
||||||
|
)
|
||||||
inspect(console_config.queue is None, content="true")
|
inspect(console_config.queue is None, content="true")
|
||||||
|
|
||||||
let json_config = json_console()
|
let json_config = json_console()
|
||||||
inspect(match json_config.sink.kind {
|
inspect(
|
||||||
|
match json_config.sink.kind {
|
||||||
SinkKind::JsonConsole => "JsonConsole"
|
SinkKind::JsonConsole => "JsonConsole"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="JsonConsole")
|
},
|
||||||
|
content="JsonConsole",
|
||||||
|
)
|
||||||
inspect(json_config.queue is None, content="true")
|
inspect(json_config.queue is None, content="true")
|
||||||
|
|
||||||
let text_config = text_console()
|
let text_config = text_console()
|
||||||
inspect(match text_config.sink.kind {
|
inspect(
|
||||||
|
match text_config.sink.kind {
|
||||||
SinkKind::TextConsole => "TextConsole"
|
SinkKind::TextConsole => "TextConsole"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="TextConsole")
|
},
|
||||||
|
content="TextConsole",
|
||||||
|
)
|
||||||
inspect(text_config.sink.text_formatter.show_timestamp, content="true")
|
inspect(text_config.sink.text_formatter.show_timestamp, content="true")
|
||||||
inspect(color_mode_label(text_config.sink.text_formatter.color_mode), content="never")
|
inspect(
|
||||||
|
color_mode_label(text_config.sink.text_formatter.color_mode),
|
||||||
|
content="never",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file preset uses file sink defaults" {
|
test "file preset uses file sink defaults" {
|
||||||
let config = file("bitlogger.log")
|
let config = file("bitlogger.log")
|
||||||
inspect(config.min_level.label(), content="INFO")
|
inspect(config.min_level.label(), content="INFO")
|
||||||
inspect(config.target, content="")
|
inspect(config.target, content="")
|
||||||
inspect(config.timestamp, content="false")
|
inspect(config.timestamp, content="false")
|
||||||
inspect(match config.sink.kind {
|
inspect(
|
||||||
|
match config.sink.kind {
|
||||||
SinkKind::File => "File"
|
SinkKind::File => "File"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="File")
|
},
|
||||||
|
content="File",
|
||||||
|
)
|
||||||
inspect(config.sink.path, content="bitlogger.log")
|
inspect(config.sink.path, content="bitlogger.log")
|
||||||
inspect(config.sink.append, content="true")
|
inspect(config.sink.append, content="true")
|
||||||
inspect(config.sink.auto_flush, content="true")
|
inspect(config.sink.auto_flush, content="true")
|
||||||
@@ -41,6 +58,7 @@ test "file preset uses file sink defaults" {
|
|||||||
inspect(config.queue is None, content="true")
|
inspect(config.queue is None, content="true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file preset rejects empty path like parser file sink config" {
|
test "file preset rejects empty path like parser file sink config" {
|
||||||
let preset_error = (fn() -> String raise ConfigError {
|
let preset_error = (fn() -> String raise ConfigError {
|
||||||
ignore(file(""))
|
ignore(file(""))
|
||||||
@@ -51,7 +69,9 @@ test "file preset rejects empty path like parser file sink config" {
|
|||||||
inspect(preset_error, content="File sink requires non-empty path")
|
inspect(preset_error, content="File sink requires non-empty path")
|
||||||
|
|
||||||
let parser_error = (fn() -> String raise ConfigError {
|
let parser_error = (fn() -> String raise ConfigError {
|
||||||
ignore(parse_logger_config_text("{\"sink\":{\"kind\":\"file\",\"path\":\"\"}}"))
|
ignore(
|
||||||
|
parse_logger_config_text("{\"sink\":{\"kind\":\"file\",\"path\":\"\"}}"),
|
||||||
|
)
|
||||||
"no error"
|
"no error"
|
||||||
})() catch {
|
})() catch {
|
||||||
ConfigError::InvalidConfig(message) => message
|
ConfigError::InvalidConfig(message) => message
|
||||||
@@ -59,8 +79,12 @@ test "file preset rejects empty path like parser file sink config" {
|
|||||||
inspect(parser_error, content="File sink requires non-empty path")
|
inspect(parser_error, content="File sink requires non-empty path")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "preset helpers compose queue and file rotation without losing config" {
|
test "preset helpers compose queue and file rotation without losing config" {
|
||||||
let formatter = TextFormatterConfig::new(show_timestamp=false, separator=" | ")
|
let formatter = TextFormatterConfig::new(
|
||||||
|
show_timestamp=false,
|
||||||
|
separator=" | ",
|
||||||
|
)
|
||||||
let config = file(
|
let config = file(
|
||||||
"service.log",
|
"service.log",
|
||||||
min_level=Level::Warn,
|
min_level=Level::Warn,
|
||||||
@@ -86,10 +110,13 @@ test "preset helpers compose queue and file rotation without losing config" {
|
|||||||
match config.queue {
|
match config.queue {
|
||||||
Some(queue) => {
|
Some(queue) => {
|
||||||
inspect(queue.max_pending, content="32")
|
inspect(queue.max_pending, content="32")
|
||||||
inspect(match queue.overflow {
|
inspect(
|
||||||
|
match queue.overflow {
|
||||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||||
}, content="DropOldest")
|
},
|
||||||
|
content="DropOldest",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
None => inspect(false, content="true")
|
None => inspect(false, content="true")
|
||||||
}
|
}
|
||||||
@@ -102,6 +129,7 @@ test "preset helpers compose queue and file rotation without losing config" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "queue helper preserves file rotation when applied after rotation" {
|
test "queue helper preserves file rotation when applied after rotation" {
|
||||||
let config = with_queue(
|
let config = with_queue(
|
||||||
with_file_rotation(file("service.log", append=false), 256, max_backups=2),
|
with_file_rotation(file("service.log", append=false), 256, max_backups=2),
|
||||||
@@ -113,10 +141,13 @@ test "queue helper preserves file rotation when applied after rotation" {
|
|||||||
match config.queue {
|
match config.queue {
|
||||||
Some(queue) => {
|
Some(queue) => {
|
||||||
inspect(queue.max_pending, content="8")
|
inspect(queue.max_pending, content="8")
|
||||||
inspect(match queue.overflow {
|
inspect(
|
||||||
|
match queue.overflow {
|
||||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||||
}, content="DropNewest")
|
},
|
||||||
|
content="DropNewest",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
None => inspect(false, content="true")
|
None => inspect(false, content="true")
|
||||||
}
|
}
|
||||||
@@ -129,29 +160,44 @@ test "queue helper preserves file rotation when applied after rotation" {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file rotation helper leaves non-file presets unchanged" {
|
test "file rotation helper leaves non-file presets unchanged" {
|
||||||
let console_config = with_file_rotation(console(target="console"), 64, max_backups=2)
|
let console_config = with_file_rotation(
|
||||||
inspect(match console_config.sink.kind {
|
console(target="console"),
|
||||||
|
64,
|
||||||
|
max_backups=2,
|
||||||
|
)
|
||||||
|
inspect(
|
||||||
|
match console_config.sink.kind {
|
||||||
SinkKind::Console => "Console"
|
SinkKind::Console => "Console"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="Console")
|
},
|
||||||
|
content="Console",
|
||||||
|
)
|
||||||
inspect(console_config.target, content="console")
|
inspect(console_config.target, content="console")
|
||||||
inspect(console_config.sink.rotation is None, content="true")
|
inspect(console_config.sink.rotation is None, content="true")
|
||||||
|
|
||||||
let text_config = with_file_rotation(
|
let text_config = with_file_rotation(
|
||||||
text_console(target="text", text_formatter=TextFormatterConfig::new(separator=" :: ")),
|
text_console(
|
||||||
|
target="text",
|
||||||
|
text_formatter=TextFormatterConfig::new(separator=" :: "),
|
||||||
|
),
|
||||||
96,
|
96,
|
||||||
max_backups=4,
|
max_backups=4,
|
||||||
)
|
)
|
||||||
inspect(match text_config.sink.kind {
|
inspect(
|
||||||
|
match text_config.sink.kind {
|
||||||
SinkKind::TextConsole => "TextConsole"
|
SinkKind::TextConsole => "TextConsole"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="TextConsole")
|
},
|
||||||
|
content="TextConsole",
|
||||||
|
)
|
||||||
inspect(text_config.target, content="text")
|
inspect(text_config.target, content="text")
|
||||||
inspect(text_config.sink.text_formatter.separator, content=" :: ")
|
inspect(text_config.sink.text_formatter.separator, content=" :: ")
|
||||||
inspect(text_config.sink.rotation is None, content="true")
|
inspect(text_config.sink.rotation is None, content="true")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
test "file rotation helper keeps queued non-file presets unchanged" {
|
test "file rotation helper keeps queued non-file presets unchanged" {
|
||||||
let config = with_queue(
|
let config = with_queue(
|
||||||
json_console(min_level=Level::Error, target="json"),
|
json_console(min_level=Level::Error, target="json"),
|
||||||
@@ -161,18 +207,24 @@ test "file rotation helper keeps queued non-file presets unchanged" {
|
|||||||
let rotated = with_file_rotation(config, 512, max_backups=5)
|
let rotated = with_file_rotation(config, 512, max_backups=5)
|
||||||
inspect(rotated.min_level.label(), content="ERROR")
|
inspect(rotated.min_level.label(), content="ERROR")
|
||||||
inspect(rotated.target, content="json")
|
inspect(rotated.target, content="json")
|
||||||
inspect(match rotated.sink.kind {
|
inspect(
|
||||||
|
match rotated.sink.kind {
|
||||||
SinkKind::JsonConsole => "JsonConsole"
|
SinkKind::JsonConsole => "JsonConsole"
|
||||||
_ => "other"
|
_ => "other"
|
||||||
}, content="JsonConsole")
|
},
|
||||||
|
content="JsonConsole",
|
||||||
|
)
|
||||||
inspect(rotated.sink.rotation is None, content="true")
|
inspect(rotated.sink.rotation is None, content="true")
|
||||||
match rotated.queue {
|
match rotated.queue {
|
||||||
Some(queue) => {
|
Some(queue) => {
|
||||||
inspect(queue.max_pending, content="4")
|
inspect(queue.max_pending, content="4")
|
||||||
inspect(match queue.overflow {
|
inspect(
|
||||||
|
match queue.overflow {
|
||||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||||
}, content="DropOldest")
|
},
|
||||||
|
content="DropOldest",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
None => inspect(false, content="true")
|
None => inspect(false, content="true")
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -1,21 +1,26 @@
|
|||||||
|
///|
|
||||||
pub type Field = @core.Field
|
pub type Field = @core.Field
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn field(key : String, value : String) -> Field {
|
pub fn field(key : String, value : String) -> Field {
|
||||||
@core.field(key, value)
|
@core.field(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn fields(entries : Array[(String, String)]) -> Array[Field] {
|
pub fn fields(entries : Array[(String, String)]) -> Array[Field] {
|
||||||
@core.fields(entries)
|
@core.fields(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type Record = @core.Record
|
pub type Record = @core.Record
|
||||||
|
|
||||||
|
///|
|
||||||
fn record(
|
fn record(
|
||||||
level : Level,
|
level : Level,
|
||||||
message : String,
|
message : String,
|
||||||
timestamp_ms~ : UInt64 = 0UL,
|
timestamp_ms? : UInt64 = 0UL,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
fields~ : Array[Field] = [],
|
fields? : Array[Field] = [],
|
||||||
) -> Record {
|
) -> Record {
|
||||||
@core.Record::new(level, message, timestamp_ms=timestamp_ms, target=target, fields=fields)
|
@core.Record::new(level, message, timestamp_ms~, target~, fields~)
|
||||||
}
|
}
|
||||||
|
|||||||
+117
-20
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
pub fn RuntimeSink::file_available(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_available(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.is_available()
|
File(sink) => sink.is_available()
|
||||||
@@ -6,14 +7,19 @@ pub fn RuntimeSink::file_available(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RuntimeSink::file_reopen(self : RuntimeSink, append~ : Bool? = None) -> Bool {
|
///|
|
||||||
|
pub fn RuntimeSink::file_reopen(
|
||||||
|
self : RuntimeSink,
|
||||||
|
append? : Bool? = None,
|
||||||
|
) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.reopen(append=append)
|
File(sink) => sink.reopen(append~)
|
||||||
QueuedFile(sink) => sink.sink.reopen(append=append)
|
QueuedFile(sink) => sink.sink.reopen(append~)
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_reopen_with_current_policy(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_reopen_with_current_policy(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.reopen_with_current_policy()
|
File(sink) => sink.reopen_with_current_policy()
|
||||||
@@ -22,6 +28,7 @@ pub fn RuntimeSink::file_reopen_with_current_policy(self : RuntimeSink) -> Bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_reopen_append(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_reopen_append(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.reopen_append()
|
File(sink) => sink.reopen_append()
|
||||||
@@ -30,6 +37,7 @@ pub fn RuntimeSink::file_reopen_append(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_reopen_truncate(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_reopen_truncate(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.reopen_truncate()
|
File(sink) => sink.reopen_truncate()
|
||||||
@@ -38,6 +46,7 @@ pub fn RuntimeSink::file_reopen_truncate(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_append_mode(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_append_mode(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.append_mode()
|
File(sink) => sink.append_mode()
|
||||||
@@ -46,7 +55,11 @@ pub fn RuntimeSink::file_append_mode(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RuntimeSink::file_set_append_mode(self : RuntimeSink, append : Bool) -> Bool {
|
///|
|
||||||
|
pub fn RuntimeSink::file_set_append_mode(
|
||||||
|
self : RuntimeSink,
|
||||||
|
append : Bool,
|
||||||
|
) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
sink.set_append_mode(append)
|
sink.set_append_mode(append)
|
||||||
@@ -60,6 +73,7 @@ pub fn RuntimeSink::file_set_append_mode(self : RuntimeSink, append : Bool) -> B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_path(self : RuntimeSink) -> String {
|
pub fn RuntimeSink::file_path(self : RuntimeSink) -> String {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.path()
|
File(sink) => sink.path()
|
||||||
@@ -68,6 +82,7 @@ pub fn RuntimeSink::file_path(self : RuntimeSink) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_auto_flush(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_auto_flush(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.auto_flush_enabled()
|
File(sink) => sink.auto_flush_enabled()
|
||||||
@@ -76,6 +91,7 @@ pub fn RuntimeSink::file_auto_flush(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_rotation_enabled(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_rotation_enabled(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.rotation_enabled()
|
File(sink) => sink.rotation_enabled()
|
||||||
@@ -84,6 +100,7 @@ pub fn RuntimeSink::file_rotation_enabled(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_rotation_config(self : RuntimeSink) -> FileRotation? {
|
pub fn RuntimeSink::file_rotation_config(self : RuntimeSink) -> FileRotation? {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.rotation_config()
|
File(sink) => sink.rotation_config()
|
||||||
@@ -92,7 +109,11 @@ pub fn RuntimeSink::file_rotation_config(self : RuntimeSink) -> FileRotation? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RuntimeSink::file_set_auto_flush(self : RuntimeSink, enabled : Bool) -> Bool {
|
///|
|
||||||
|
pub fn RuntimeSink::file_set_auto_flush(
|
||||||
|
self : RuntimeSink,
|
||||||
|
enabled : Bool,
|
||||||
|
) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
sink.set_auto_flush(enabled)
|
sink.set_auto_flush(enabled)
|
||||||
@@ -106,7 +127,11 @@ pub fn RuntimeSink::file_set_auto_flush(self : RuntimeSink, enabled : Bool) -> B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RuntimeSink::file_set_policy(self : RuntimeSink, policy : FileSinkPolicy) -> Bool {
|
///|
|
||||||
|
pub fn RuntimeSink::file_set_policy(
|
||||||
|
self : RuntimeSink,
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
sink.set_policy(policy)
|
sink.set_policy(policy)
|
||||||
@@ -120,7 +145,11 @@ pub fn RuntimeSink::file_set_policy(self : RuntimeSink, policy : FileSinkPolicy)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RuntimeSink::file_set_rotation(self : RuntimeSink, rotation : FileRotation?) -> Bool {
|
///|
|
||||||
|
pub fn RuntimeSink::file_set_rotation(
|
||||||
|
self : RuntimeSink,
|
||||||
|
rotation : FileRotation?,
|
||||||
|
) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
sink.set_rotation(rotation)
|
sink.set_rotation(rotation)
|
||||||
@@ -134,6 +163,7 @@ pub fn RuntimeSink::file_set_rotation(self : RuntimeSink, rotation : FileRotatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_clear_rotation(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_clear_rotation(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
@@ -148,6 +178,7 @@ pub fn RuntimeSink::file_clear_rotation(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_flush(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_flush(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.flush()
|
File(sink) => sink.flush()
|
||||||
@@ -159,6 +190,7 @@ pub fn RuntimeSink::file_flush(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_close(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_close(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.close()
|
File(sink) => sink.close()
|
||||||
@@ -170,6 +202,7 @@ pub fn RuntimeSink::file_close(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_open_failures(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::file_open_failures(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.open_failures()
|
File(sink) => sink.open_failures()
|
||||||
@@ -178,6 +211,7 @@ pub fn RuntimeSink::file_open_failures(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_write_failures(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::file_write_failures(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.write_failures()
|
File(sink) => sink.write_failures()
|
||||||
@@ -186,6 +220,7 @@ pub fn RuntimeSink::file_write_failures(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_flush_failures(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::file_flush_failures(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.flush_failures()
|
File(sink) => sink.flush_failures()
|
||||||
@@ -194,6 +229,7 @@ pub fn RuntimeSink::file_flush_failures(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_rotation_failures(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::file_rotation_failures(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.rotation_failures()
|
File(sink) => sink.rotation_failures()
|
||||||
@@ -202,6 +238,7 @@ pub fn RuntimeSink::file_rotation_failures(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_reset_failure_counters(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_reset_failure_counters(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
@@ -216,6 +253,7 @@ pub fn RuntimeSink::file_reset_failure_counters(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_reset_policy(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_reset_policy(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => {
|
File(sink) => {
|
||||||
@@ -230,6 +268,7 @@ pub fn RuntimeSink::file_reset_policy(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_policy(self : RuntimeSink) -> FileSinkPolicy {
|
pub fn RuntimeSink::file_policy(self : RuntimeSink) -> FileSinkPolicy {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.policy()
|
File(sink) => sink.policy()
|
||||||
@@ -238,6 +277,7 @@ pub fn RuntimeSink::file_policy(self : RuntimeSink) -> FileSinkPolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_default_policy(self : RuntimeSink) -> FileSinkPolicy {
|
pub fn RuntimeSink::file_default_policy(self : RuntimeSink) -> FileSinkPolicy {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.default_policy()
|
File(sink) => sink.default_policy()
|
||||||
@@ -246,6 +286,7 @@ pub fn RuntimeSink::file_default_policy(self : RuntimeSink) -> FileSinkPolicy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_policy_matches_default(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::file_policy_matches_default(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.policy_matches_default()
|
File(sink) => sink.policy_matches_default()
|
||||||
@@ -254,11 +295,13 @@ pub fn RuntimeSink::file_policy_matches_default(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_state(self : RuntimeSink) -> FileSinkState {
|
pub fn RuntimeSink::file_state(self : RuntimeSink) -> FileSinkState {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => sink.state()
|
File(sink) => sink.state()
|
||||||
QueuedFile(sink) => sink.sink.state()
|
QueuedFile(sink) => sink.sink.state()
|
||||||
_ => FileSinkState::new(
|
_ =>
|
||||||
|
FileSinkState::new(
|
||||||
"",
|
"",
|
||||||
available=false,
|
available=false,
|
||||||
append=false,
|
append=false,
|
||||||
@@ -272,10 +315,12 @@ pub fn RuntimeSink::file_state(self : RuntimeSink) -> FileSinkState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::file_runtime_state(self : RuntimeSink) -> RuntimeFileState? {
|
pub fn RuntimeSink::file_runtime_state(self : RuntimeSink) -> RuntimeFileState? {
|
||||||
match self {
|
match self {
|
||||||
File(sink) => Some(RuntimeFileState::new(sink.state()))
|
File(sink) => Some(RuntimeFileState::new(sink.state()))
|
||||||
QueuedFile(sink) => Some(
|
QueuedFile(sink) =>
|
||||||
|
Some(
|
||||||
RuntimeFileState::new(
|
RuntimeFileState::new(
|
||||||
sink.sink.state(),
|
sink.sink.state(),
|
||||||
queued=true,
|
queued=true,
|
||||||
@@ -287,58 +332,88 @@ pub fn RuntimeSink::file_runtime_state(self : RuntimeSink) -> RuntimeFileState?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_available(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_available(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_available()
|
self.sink.file_available()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_reopen(self : ConfiguredLogger, append~ : Bool? = None) -> Bool {
|
///|
|
||||||
self.sink.file_reopen(append=append)
|
pub fn ConfiguredLogger::file_reopen(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
append? : Bool? = None,
|
||||||
|
) -> Bool {
|
||||||
|
self.sink.file_reopen(append~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_reopen_with_current_policy(self : ConfiguredLogger) -> Bool {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_reopen_with_current_policy(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
) -> Bool {
|
||||||
self.sink.file_reopen_with_current_policy()
|
self.sink.file_reopen_with_current_policy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_reopen_append(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_reopen_append(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_reopen_append()
|
self.sink.file_reopen_append()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_reopen_truncate(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_reopen_truncate(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_reopen_truncate()
|
self.sink.file_reopen_truncate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_append_mode(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_append_mode(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_append_mode()
|
self.sink.file_append_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_set_append_mode(self : ConfiguredLogger, append : Bool) -> Bool {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_set_append_mode(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
append : Bool,
|
||||||
|
) -> Bool {
|
||||||
self.sink.file_set_append_mode(append)
|
self.sink.file_set_append_mode(append)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_path(self : ConfiguredLogger) -> String {
|
pub fn ConfiguredLogger::file_path(self : ConfiguredLogger) -> String {
|
||||||
self.sink.file_path()
|
self.sink.file_path()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_auto_flush(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_auto_flush(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_auto_flush()
|
self.sink.file_auto_flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_rotation_enabled(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_rotation_enabled(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_rotation_enabled()
|
self.sink.file_rotation_enabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_rotation_config(self : ConfiguredLogger) -> FileRotation? {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_rotation_config(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
) -> FileRotation? {
|
||||||
self.sink.file_rotation_config()
|
self.sink.file_rotation_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_set_auto_flush(self : ConfiguredLogger, enabled : Bool) -> Bool {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_set_auto_flush(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
enabled : Bool,
|
||||||
|
) -> Bool {
|
||||||
self.sink.file_set_auto_flush(enabled)
|
self.sink.file_set_auto_flush(enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_set_policy(self : ConfiguredLogger, policy : FileSinkPolicy) -> Bool {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_set_policy(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
) -> Bool {
|
||||||
self.sink.file_set_policy(policy)
|
self.sink.file_set_policy(policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_set_rotation(
|
pub fn ConfiguredLogger::file_set_rotation(
|
||||||
self : ConfiguredLogger,
|
self : ConfiguredLogger,
|
||||||
rotation : FileRotation?,
|
rotation : FileRotation?,
|
||||||
@@ -346,58 +421,80 @@ pub fn ConfiguredLogger::file_set_rotation(
|
|||||||
self.sink.file_set_rotation(rotation)
|
self.sink.file_set_rotation(rotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_clear_rotation(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_clear_rotation(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_clear_rotation()
|
self.sink.file_clear_rotation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_flush(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_flush(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_flush()
|
self.sink.file_flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_close(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_close(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_close()
|
self.sink.file_close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_open_failures(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::file_open_failures(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.file_open_failures()
|
self.sink.file_open_failures()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_write_failures(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::file_write_failures(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.file_write_failures()
|
self.sink.file_write_failures()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_flush_failures(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::file_flush_failures(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.file_flush_failures()
|
self.sink.file_flush_failures()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_rotation_failures(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::file_rotation_failures(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.file_rotation_failures()
|
self.sink.file_rotation_failures()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_reset_failure_counters(self : ConfiguredLogger) -> Bool {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_reset_failure_counters(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
) -> Bool {
|
||||||
self.sink.file_reset_failure_counters()
|
self.sink.file_reset_failure_counters()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_reset_policy(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::file_reset_policy(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.file_reset_policy()
|
self.sink.file_reset_policy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_policy(self : ConfiguredLogger) -> FileSinkPolicy {
|
pub fn ConfiguredLogger::file_policy(self : ConfiguredLogger) -> FileSinkPolicy {
|
||||||
self.sink.file_policy()
|
self.sink.file_policy()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_default_policy(self : ConfiguredLogger) -> FileSinkPolicy {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_default_policy(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
) -> FileSinkPolicy {
|
||||||
self.sink.file_default_policy()
|
self.sink.file_default_policy()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_policy_matches_default(self : ConfiguredLogger) -> Bool {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_policy_matches_default(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
) -> Bool {
|
||||||
self.sink.file_policy_matches_default()
|
self.sink.file_policy_matches_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::file_state(self : ConfiguredLogger) -> FileSinkState {
|
pub fn ConfiguredLogger::file_state(self : ConfiguredLogger) -> FileSinkState {
|
||||||
self.sink.file_state()
|
self.sink.file_state()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::file_runtime_state(self : ConfiguredLogger) -> RuntimeFileState? {
|
///|
|
||||||
|
pub fn ConfiguredLogger::file_runtime_state(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
) -> RuntimeFileState? {
|
||||||
self.sink.file_runtime_state()
|
self.sink.file_runtime_state()
|
||||||
}
|
}
|
||||||
|
|||||||
+94
-29
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
pub(all) enum RuntimeSink {
|
pub(all) enum RuntimeSink {
|
||||||
Console(ConsoleSink)
|
Console(ConsoleSink)
|
||||||
JsonConsole(JsonConsoleSink)
|
JsonConsole(JsonConsoleSink)
|
||||||
@@ -9,33 +10,54 @@ pub(all) enum RuntimeSink {
|
|||||||
QueuedFile(QueuedSink[FileSink])
|
QueuedFile(QueuedSink[FileSink])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type RuntimeFileState = @utils.RuntimeFileState
|
pub type RuntimeFileState = @utils.RuntimeFileState
|
||||||
|
|
||||||
pub fn file_sink_policy_to_json(policy : FileSinkPolicy) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn file_sink_policy_to_json(
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.file_sink_policy_to_json(policy)
|
@utils.file_sink_policy_to_json(policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_file_sink_policy(policy : FileSinkPolicy, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_file_sink_policy(policy, pretty=pretty)
|
pub fn stringify_file_sink_policy(
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_file_sink_policy(policy, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||||
@utils.file_sink_state_to_json(state)
|
@utils.file_sink_state_to_json(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_file_sink_state(state : FileSinkState, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_file_sink_state(state, pretty=pretty)
|
pub fn stringify_file_sink_state(
|
||||||
|
state : FileSinkState,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_file_sink_state(state, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn runtime_file_state_to_json(state : RuntimeFileState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn runtime_file_state_to_json(
|
||||||
|
state : RuntimeFileState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@utils.runtime_file_state_to_json(state)
|
@utils.runtime_file_state_to_json(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_runtime_file_state(state : RuntimeFileState, pretty~ : Bool = false) -> String {
|
///|
|
||||||
@utils.stringify_runtime_file_state(state, pretty=pretty)
|
pub fn stringify_runtime_file_state(
|
||||||
|
state : RuntimeFileState,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
|
@utils.stringify_runtime_file_state(state, pretty~)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for RuntimeSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for RuntimeSink with fn write(self, rec) {
|
||||||
match self {
|
match self {
|
||||||
Console(sink) => sink.write(rec)
|
Console(sink) => sink.write(rec)
|
||||||
JsonConsole(sink) => sink.write(rec)
|
JsonConsole(sink) => sink.write(rec)
|
||||||
@@ -48,6 +70,7 @@ pub impl Sink for RuntimeSink with write(self, rec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::flush(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::flush(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
Console(_) => 0
|
Console(_) => 0
|
||||||
@@ -61,19 +84,21 @@ pub fn RuntimeSink::flush(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn RuntimeSink::drain(self : RuntimeSink, max_items~ : Int = -1) -> Int {
|
///|
|
||||||
|
pub fn RuntimeSink::drain(self : RuntimeSink, max_items? : Int = -1) -> Int {
|
||||||
match self {
|
match self {
|
||||||
Console(_) => 0
|
Console(_) => 0
|
||||||
JsonConsole(_) => 0
|
JsonConsole(_) => 0
|
||||||
TextConsole(_) => 0
|
TextConsole(_) => 0
|
||||||
File(sink) => if sink.flush() { 1 } else { 0 }
|
File(sink) => if sink.flush() { 1 } else { 0 }
|
||||||
QueuedConsole(sink) => sink.drain(max_items=max_items)
|
QueuedConsole(sink) => sink.drain(max_items~)
|
||||||
QueuedJsonConsole(sink) => sink.drain(max_items=max_items)
|
QueuedJsonConsole(sink) => sink.drain(max_items~)
|
||||||
QueuedTextConsole(sink) => sink.drain(max_items=max_items)
|
QueuedTextConsole(sink) => sink.drain(max_items~)
|
||||||
QueuedFile(sink) => sink.drain(max_items=max_items)
|
QueuedFile(sink) => sink.drain(max_items~)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::close(self : RuntimeSink) -> Bool {
|
pub fn RuntimeSink::close(self : RuntimeSink) -> Bool {
|
||||||
match self {
|
match self {
|
||||||
Console(_) => true
|
Console(_) => true
|
||||||
@@ -87,6 +112,7 @@ pub fn RuntimeSink::close(self : RuntimeSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::pending_count(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::pending_count(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
Console(_) => 0
|
Console(_) => 0
|
||||||
@@ -100,6 +126,7 @@ pub fn RuntimeSink::pending_count(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeSink::dropped_count(self : RuntimeSink) -> Int {
|
pub fn RuntimeSink::dropped_count(self : RuntimeSink) -> Int {
|
||||||
match self {
|
match self {
|
||||||
Console(_) => 0
|
Console(_) => 0
|
||||||
@@ -113,36 +140,48 @@ pub fn RuntimeSink::dropped_count(self : RuntimeSink) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type ConfiguredLogger = Logger[RuntimeSink]
|
pub type ConfiguredLogger = Logger[RuntimeSink]
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::flush(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::flush(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.flush()
|
self.sink.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ConfiguredLogger::drain(self : ConfiguredLogger, max_items~ : Int = -1) -> Int {
|
///|
|
||||||
self.sink.drain(max_items=max_items)
|
pub fn ConfiguredLogger::drain(
|
||||||
|
self : ConfiguredLogger,
|
||||||
|
max_items? : Int = -1,
|
||||||
|
) -> Int {
|
||||||
|
self.sink.drain(max_items~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::close(self : ConfiguredLogger) -> Bool {
|
pub fn ConfiguredLogger::close(self : ConfiguredLogger) -> Bool {
|
||||||
self.sink.close()
|
self.sink.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::pending_count(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::pending_count(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.pending_count()
|
self.sink.pending_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn ConfiguredLogger::dropped_count(self : ConfiguredLogger) -> Int {
|
pub fn ConfiguredLogger::dropped_count(self : ConfiguredLogger) -> Int {
|
||||||
self.sink.dropped_count()
|
self.sink.dropped_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn build_runtime_sink(config : SinkConfig) -> RuntimeSink {
|
fn build_runtime_sink(config : SinkConfig) -> RuntimeSink {
|
||||||
match config.kind {
|
match config.kind {
|
||||||
SinkKind::Console => RuntimeSink::Console(console_sink())
|
SinkKind::Console => RuntimeSink::Console(console_sink())
|
||||||
SinkKind::JsonConsole => RuntimeSink::JsonConsole(json_console_sink())
|
SinkKind::JsonConsole => RuntimeSink::JsonConsole(json_console_sink())
|
||||||
SinkKind::TextConsole => RuntimeSink::TextConsole(
|
SinkKind::TextConsole =>
|
||||||
|
RuntimeSink::TextConsole(
|
||||||
text_console_sink(config.text_formatter.to_formatter()),
|
text_console_sink(config.text_formatter.to_formatter()),
|
||||||
)
|
)
|
||||||
SinkKind::File => RuntimeSink::File(
|
SinkKind::File =>
|
||||||
|
RuntimeSink::File(
|
||||||
file_sink(
|
file_sink(
|
||||||
config.path,
|
config.path,
|
||||||
append=config.append,
|
append=config.append,
|
||||||
@@ -156,19 +195,40 @@ fn build_runtime_sink(config : SinkConfig) -> RuntimeSink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn apply_queue_config(sink : RuntimeSink, queue : QueueConfig) -> RuntimeSink {
|
fn apply_queue_config(sink : RuntimeSink, queue : QueueConfig) -> RuntimeSink {
|
||||||
match sink {
|
match sink {
|
||||||
Console(inner) => RuntimeSink::QueuedConsole(
|
Console(inner) =>
|
||||||
queued_sink(inner, max_pending=queue.max_pending, overflow=queue.overflow),
|
RuntimeSink::QueuedConsole(
|
||||||
|
queued_sink(
|
||||||
|
inner,
|
||||||
|
max_pending=queue.max_pending,
|
||||||
|
overflow=queue.overflow,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
JsonConsole(inner) => RuntimeSink::QueuedJsonConsole(
|
JsonConsole(inner) =>
|
||||||
queued_sink(inner, max_pending=queue.max_pending, overflow=queue.overflow),
|
RuntimeSink::QueuedJsonConsole(
|
||||||
|
queued_sink(
|
||||||
|
inner,
|
||||||
|
max_pending=queue.max_pending,
|
||||||
|
overflow=queue.overflow,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
TextConsole(inner) => RuntimeSink::QueuedTextConsole(
|
TextConsole(inner) =>
|
||||||
queued_sink(inner, max_pending=queue.max_pending, overflow=queue.overflow),
|
RuntimeSink::QueuedTextConsole(
|
||||||
|
queued_sink(
|
||||||
|
inner,
|
||||||
|
max_pending=queue.max_pending,
|
||||||
|
overflow=queue.overflow,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
File(inner) => RuntimeSink::QueuedFile(
|
File(inner) =>
|
||||||
queued_sink(inner, max_pending=queue.max_pending, overflow=queue.overflow),
|
RuntimeSink::QueuedFile(
|
||||||
|
queued_sink(
|
||||||
|
inner,
|
||||||
|
max_pending=queue.max_pending,
|
||||||
|
overflow=queue.overflow,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
QueuedConsole(_) => sink
|
QueuedConsole(_) => sink
|
||||||
QueuedJsonConsole(_) => sink
|
QueuedJsonConsole(_) => sink
|
||||||
@@ -177,16 +237,21 @@ fn apply_queue_config(sink : RuntimeSink, queue : QueueConfig) -> RuntimeSink {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {
|
pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {
|
||||||
let sink = build_runtime_sink(config.sink)
|
let sink = build_runtime_sink(config.sink)
|
||||||
let actual_sink = match config.queue {
|
let actual_sink = match config.queue {
|
||||||
None => sink
|
None => sink
|
||||||
Some(queue) => apply_queue_config(sink, queue)
|
Some(queue) => apply_queue_config(sink, queue)
|
||||||
}
|
}
|
||||||
Logger::new(actual_sink, min_level=config.min_level, target=config.target)
|
Logger::new(actual_sink, min_level=config.min_level, target=config.target).with_timestamp(
|
||||||
.with_timestamp(enabled=config.timestamp)
|
enabled=config.timestamp,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_and_build_logger(input : String) -> ConfiguredLogger raise ConfigError {
|
///|
|
||||||
|
pub fn parse_and_build_logger(
|
||||||
|
input : String,
|
||||||
|
) -> ConfiguredLogger raise ConfigError {
|
||||||
build_logger(parse_logger_config_text(input))
|
build_logger(parse_logger_config_text(input))
|
||||||
}
|
}
|
||||||
|
|||||||
+78
-29
@@ -1,26 +1,32 @@
|
|||||||
|
///|
|
||||||
pub trait Sink {
|
pub trait Sink {
|
||||||
write(Self, Record) -> Unit
|
fn write(Self, Record) -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct ConsoleSink {
|
pub struct ConsoleSink {
|
||||||
_dummy : Unit
|
_dummy : Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn console_sink() -> ConsoleSink {
|
pub fn console_sink() -> ConsoleSink {
|
||||||
{ _dummy: () }
|
{ _dummy: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for ConsoleSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for ConsoleSink with fn write(self, rec) {
|
||||||
ignore(self)
|
ignore(self)
|
||||||
println(format_text(rec))
|
println(format_text(rec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct ContextSink[S] {
|
pub struct ContextSink[S] {
|
||||||
sink : S
|
sink : S
|
||||||
context_fields : Array[Field]
|
context_fields : Array[Field]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[S : Sink] Sink for ContextSink[S] with write(self, rec) {
|
///|
|
||||||
|
pub impl[S : Sink] Sink for ContextSink[S] with fn write(self, rec) {
|
||||||
let merged = if self.context_fields.length() == 0 {
|
let merged = if self.context_fields.length() == 0 {
|
||||||
rec.fields
|
rec.fields
|
||||||
} else if rec.fields.length() == 0 {
|
} else if rec.fields.length() == 0 {
|
||||||
@@ -31,42 +37,51 @@ pub impl[S : Sink] Sink for ContextSink[S] with write(self, rec) {
|
|||||||
self.sink.write(rec.with_fields(merged))
|
self.sink.write(rec.with_fields(merged))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct JsonConsoleSink {
|
pub struct JsonConsoleSink {
|
||||||
_dummy : Unit
|
_dummy : Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn json_console_sink() -> JsonConsoleSink {
|
pub fn json_console_sink() -> JsonConsoleSink {
|
||||||
{ _dummy: () }
|
{ _dummy: () }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for JsonConsoleSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for JsonConsoleSink with fn write(self, rec) {
|
||||||
ignore(self)
|
ignore(self)
|
||||||
println(format_json(rec))
|
println(format_json(rec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FormattedConsoleSink {
|
pub struct FormattedConsoleSink {
|
||||||
formatter : RecordFormatter
|
formatter : RecordFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn formatted_console_sink(formatter : RecordFormatter) -> FormattedConsoleSink {
|
///|
|
||||||
|
pub fn formatted_console_sink(
|
||||||
|
formatter : RecordFormatter,
|
||||||
|
) -> FormattedConsoleSink {
|
||||||
{ formatter, }
|
{ formatter, }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_console_sink(formatter : TextFormatter) -> FormattedConsoleSink {
|
pub fn text_console_sink(formatter : TextFormatter) -> FormattedConsoleSink {
|
||||||
formatted_console_sink(fn(rec) {
|
formatted_console_sink(fn(rec) { format_text(rec, formatter~) })
|
||||||
format_text(rec, formatter=formatter)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for FormattedConsoleSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for FormattedConsoleSink with fn write(self, rec) {
|
||||||
println((self.formatter)(rec))
|
println((self.formatter)(rec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FormattedCallbackSink {
|
pub struct FormattedCallbackSink {
|
||||||
formatter : RecordFormatter
|
formatter : RecordFormatter
|
||||||
callback : (String) -> Unit
|
callback : (String) -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn formatted_callback_sink(
|
pub fn formatted_callback_sink(
|
||||||
formatter : RecordFormatter,
|
formatter : RecordFormatter,
|
||||||
callback : (String) -> Unit,
|
callback : (String) -> Unit,
|
||||||
@@ -74,54 +89,63 @@ pub fn formatted_callback_sink(
|
|||||||
{ formatter, callback }
|
{ formatter, callback }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_callback_sink(
|
pub fn text_callback_sink(
|
||||||
formatter : TextFormatter,
|
formatter : TextFormatter,
|
||||||
callback : (String) -> Unit,
|
callback : (String) -> Unit,
|
||||||
) -> FormattedCallbackSink {
|
) -> FormattedCallbackSink {
|
||||||
formatted_callback_sink(fn(rec) {
|
formatted_callback_sink(fn(rec) { format_text(rec, formatter~) }, callback)
|
||||||
format_text(rec, formatter=formatter)
|
|
||||||
}, callback)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for FormattedCallbackSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for FormattedCallbackSink with fn write(self, rec) {
|
||||||
(self.callback)((self.formatter)(rec))
|
(self.callback)((self.formatter)(rec))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FanoutSink[A, B] {
|
pub struct FanoutSink[A, B] {
|
||||||
left : A
|
left : A
|
||||||
right : B
|
right : B
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[A, B] fanout_sink(left : A, right : B) -> FanoutSink[A, B] {
|
pub fn[A, B] fanout_sink(left : A, right : B) -> FanoutSink[A, B] {
|
||||||
{ left, right }
|
{ left, right }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[A : Sink, B : Sink] Sink for FanoutSink[A, B] with write(self, rec) {
|
///|
|
||||||
|
pub impl[A : Sink, B : Sink] Sink for FanoutSink[A, B] with fn write(self, rec) {
|
||||||
self.left.write(rec)
|
self.left.write(rec)
|
||||||
self.right.write(rec.copy())
|
self.right.write(rec.copy())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct SplitSink[A, B] {
|
pub struct SplitSink[A, B] {
|
||||||
left : A
|
left : A
|
||||||
right : B
|
right : B
|
||||||
predicate : (Record) -> Bool
|
predicate : (Record) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[A, B] split_sink(left : A, right : B, predicate : (Record) -> Bool) -> SplitSink[A, B] {
|
///|
|
||||||
|
pub fn[A, B] split_sink(
|
||||||
|
left : A,
|
||||||
|
right : B,
|
||||||
|
predicate : (Record) -> Bool,
|
||||||
|
) -> SplitSink[A, B] {
|
||||||
{ left, right, predicate }
|
{ left, right, predicate }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[A, B] split_by_level(
|
pub fn[A, B] split_by_level(
|
||||||
left : A,
|
left : A,
|
||||||
right : B,
|
right : B,
|
||||||
min_level~ : Level = Level::Warn,
|
min_level? : Level = Level::Warn,
|
||||||
) -> SplitSink[A, B] {
|
) -> SplitSink[A, B] {
|
||||||
split_sink(left, right, fn(rec) {
|
split_sink(left, right, fn(rec) { rec.level.enabled(min_level) })
|
||||||
rec.level.enabled(min_level)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[A : Sink, B : Sink] Sink for SplitSink[A, B] with write(self, rec) {
|
///|
|
||||||
|
pub impl[A : Sink, B : Sink] Sink for SplitSink[A, B] with fn write(self, rec) {
|
||||||
if (self.predicate)(rec) {
|
if (self.predicate)(rec) {
|
||||||
self.left.write(rec)
|
self.left.write(rec)
|
||||||
} else {
|
} else {
|
||||||
@@ -129,33 +153,40 @@ pub impl[A : Sink, B : Sink] Sink for SplitSink[A, B] with write(self, rec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct CallbackSink {
|
pub struct CallbackSink {
|
||||||
callback : (Record) -> Unit
|
callback : (Record) -> Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn callback_sink(callback : (Record) -> Unit) -> CallbackSink {
|
pub fn callback_sink(callback : (Record) -> Unit) -> CallbackSink {
|
||||||
{ callback, }
|
{ callback, }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for CallbackSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for CallbackSink with fn write(self, rec) {
|
||||||
(self.callback)(rec)
|
(self.callback)(rec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct BufferedSink[S] {
|
pub struct BufferedSink[S] {
|
||||||
sink : S
|
sink : S
|
||||||
buffer : Ref[Array[Record]]
|
buffer : Ref[Array[Record]]
|
||||||
flush_limit : Int
|
flush_limit : Int
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S] buffered_sink(sink : S, flush_limit~ : Int = 1) -> BufferedSink[S] {
|
///|
|
||||||
|
pub fn[S] buffered_sink(sink : S, flush_limit? : Int = 1) -> BufferedSink[S] {
|
||||||
let actual_limit = if flush_limit <= 0 { 1 } else { flush_limit }
|
let actual_limit = if flush_limit <= 0 { 1 } else { flush_limit }
|
||||||
{ sink, buffer: Ref([]), flush_limit: actual_limit }
|
{ sink, buffer: Ref([]), flush_limit: actual_limit }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] BufferedSink::pending_count(self : BufferedSink[S]) -> Int {
|
pub fn[S] BufferedSink::pending_count(self : BufferedSink[S]) -> Int {
|
||||||
self.buffer.val.length()
|
self.buffer.val.length()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S : Sink] BufferedSink::flush(self : BufferedSink[S]) -> Unit {
|
pub fn[S : Sink] BufferedSink::flush(self : BufferedSink[S]) -> Unit {
|
||||||
if self.buffer.val.length() == 0 {
|
if self.buffer.val.length() == 0 {
|
||||||
()
|
()
|
||||||
@@ -168,15 +199,18 @@ pub fn[S : Sink] BufferedSink::flush(self : BufferedSink[S]) -> Unit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[S : Sink] Sink for BufferedSink[S] with write(self, rec) {
|
///|
|
||||||
|
pub impl[S : Sink] Sink for BufferedSink[S] with fn write(self, rec) {
|
||||||
self.buffer.val.push(rec)
|
self.buffer.val.push(rec)
|
||||||
if self.buffer.val.length() >= self.flush_limit {
|
if self.buffer.val.length() >= self.flush_limit {
|
||||||
self.flush()
|
self.flush()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type QueueOverflowPolicy = @utils.QueueOverflowPolicy
|
pub type QueueOverflowPolicy = @utils.QueueOverflowPolicy
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct QueuedSink[S] {
|
pub struct QueuedSink[S] {
|
||||||
sink : S
|
sink : S
|
||||||
queue : @queue.Queue[Record]
|
queue : @queue.Queue[Record]
|
||||||
@@ -185,10 +219,11 @@ pub struct QueuedSink[S] {
|
|||||||
dropped_count : Ref[Int]
|
dropped_count : Ref[Int]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] queued_sink(
|
pub fn[S] queued_sink(
|
||||||
sink : S,
|
sink : S,
|
||||||
max_pending~ : Int = 0,
|
max_pending? : Int = 0,
|
||||||
overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||||
) -> QueuedSink[S] {
|
) -> QueuedSink[S] {
|
||||||
{
|
{
|
||||||
sink,
|
sink,
|
||||||
@@ -199,15 +234,21 @@ pub fn[S] queued_sink(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] QueuedSink::pending_count(self : QueuedSink[S]) -> Int {
|
pub fn[S] QueuedSink::pending_count(self : QueuedSink[S]) -> Int {
|
||||||
self.queue.length()
|
self.queue.length()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] QueuedSink::dropped_count(self : QueuedSink[S]) -> Int {
|
pub fn[S] QueuedSink::dropped_count(self : QueuedSink[S]) -> Int {
|
||||||
self.dropped_count.val
|
self.dropped_count.val
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn[S : Sink] QueuedSink::drain(self : QueuedSink[S], max_items~ : Int = -1) -> Int {
|
///|
|
||||||
|
pub fn[S : Sink] QueuedSink::drain(
|
||||||
|
self : QueuedSink[S],
|
||||||
|
max_items? : Int = -1,
|
||||||
|
) -> Int {
|
||||||
if max_items == 0 {
|
if max_items == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -225,11 +266,13 @@ pub fn[S : Sink] QueuedSink::drain(self : QueuedSink[S], max_items~ : Int = -1)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S : Sink] QueuedSink::flush(self : QueuedSink[S]) -> Int {
|
pub fn[S : Sink] QueuedSink::flush(self : QueuedSink[S]) -> Int {
|
||||||
self.drain()
|
self.drain()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[S] Sink for QueuedSink[S] with write(self, rec) {
|
///|
|
||||||
|
pub impl[S] Sink for QueuedSink[S] with fn write(self, rec) {
|
||||||
let full = self.max_pending > 0 && self.pending_count() >= self.max_pending
|
let full = self.max_pending > 0 && self.pending_count() >= self.max_pending
|
||||||
if !full {
|
if !full {
|
||||||
self.queue.push(rec)
|
self.queue.push(rec)
|
||||||
@@ -245,30 +288,36 @@ pub impl[S] Sink for QueuedSink[S] with write(self, rec) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FilterSink[S] {
|
pub struct FilterSink[S] {
|
||||||
sink : S
|
sink : S
|
||||||
predicate : (Record) -> Bool
|
predicate : (Record) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] filter_sink(sink : S, predicate : (Record) -> Bool) -> FilterSink[S] {
|
pub fn[S] filter_sink(sink : S, predicate : (Record) -> Bool) -> FilterSink[S] {
|
||||||
{ sink, predicate }
|
{ sink, predicate }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[S : Sink] Sink for FilterSink[S] with write(self, rec) {
|
///|
|
||||||
|
pub impl[S : Sink] Sink for FilterSink[S] with fn write(self, rec) {
|
||||||
if (self.predicate)(rec) {
|
if (self.predicate)(rec) {
|
||||||
self.sink.write(rec)
|
self.sink.write(rec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct PatchSink[S] {
|
pub struct PatchSink[S] {
|
||||||
sink : S
|
sink : S
|
||||||
patch : RecordPatch
|
patch : RecordPatch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn[S] patch_sink(sink : S, patch : RecordPatch) -> PatchSink[S] {
|
pub fn[S] patch_sink(sink : S, patch : RecordPatch) -> PatchSink[S] {
|
||||||
{ sink, patch }
|
{ sink, patch }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl[S : Sink] Sink for PatchSink[S] with write(self, rec) {
|
///|
|
||||||
|
pub impl[S : Sink] Sink for PatchSink[S] with fn write(self, rec) {
|
||||||
self.sink.write((self.patch)(rec))
|
self.sink.write((self.patch)(rec))
|
||||||
}
|
}
|
||||||
|
|||||||
+68
-22
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
pub struct FileSink {
|
pub struct FileSink {
|
||||||
path : String
|
path : String
|
||||||
append : Ref[Bool]
|
append : Ref[Bool]
|
||||||
@@ -14,28 +15,32 @@ pub struct FileSink {
|
|||||||
rotation_failures : Ref[Int]
|
rotation_failures : Ref[Int]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub type FileRotation = @utils.FileRotation
|
pub type FileRotation = @utils.FileRotation
|
||||||
|
|
||||||
|
///|
|
||||||
pub type FileSinkState = @utils.FileSinkState
|
pub type FileSinkState = @utils.FileSinkState
|
||||||
|
|
||||||
|
///|
|
||||||
pub type FileSinkPolicy = @utils.FileSinkPolicy
|
pub type FileSinkPolicy = @utils.FileSinkPolicy
|
||||||
|
|
||||||
pub fn file_rotation(max_bytes : Int, max_backups~ : Int = 1) -> FileRotation {
|
///|
|
||||||
@utils.file_rotation(max_bytes, max_backups=max_backups)
|
pub fn file_rotation(max_bytes : Int, max_backups? : Int = 1) -> FileRotation {
|
||||||
|
@utils.file_rotation(max_bytes, max_backups~)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn native_files_supported() -> Bool {
|
pub fn native_files_supported() -> Bool {
|
||||||
native_files_supported_internal()
|
native_files_supported_internal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn file_sink(
|
pub fn file_sink(
|
||||||
path : String,
|
path : String,
|
||||||
append~ : Bool = true,
|
append? : Bool = true,
|
||||||
auto_flush~ : Bool = true,
|
auto_flush? : Bool = true,
|
||||||
rotation~ : FileRotation? = None,
|
rotation? : FileRotation? = None,
|
||||||
formatter~ : RecordFormatter = fn(rec) {
|
formatter? : RecordFormatter = fn(rec) { format_text(rec) },
|
||||||
format_text(rec)
|
|
||||||
},
|
|
||||||
) -> FileSink {
|
) -> FileSink {
|
||||||
let handle = open_file_handle_internal(path, append)
|
let handle = open_file_handle_internal(path, append)
|
||||||
{
|
{
|
||||||
@@ -55,10 +60,12 @@ pub fn file_sink(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::is_available(self : FileSink) -> Bool {
|
pub fn FileSink::is_available(self : FileSink) -> Bool {
|
||||||
self.handle.val is Some(_)
|
self.handle.val is Some(_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::flush(self : FileSink) -> Bool {
|
pub fn FileSink::flush(self : FileSink) -> Bool {
|
||||||
match self.handle.val {
|
match self.handle.val {
|
||||||
None => false
|
None => false
|
||||||
@@ -72,48 +79,62 @@ pub fn FileSink::flush(self : FileSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::append_mode(self : FileSink) -> Bool {
|
pub fn FileSink::append_mode(self : FileSink) -> Bool {
|
||||||
self.append.val
|
self.append.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::set_append_mode(self : FileSink, append : Bool) -> Unit {
|
pub fn FileSink::set_append_mode(self : FileSink, append : Bool) -> Unit {
|
||||||
self.append.val = append
|
self.append.val = append
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::path(self : FileSink) -> String {
|
pub fn FileSink::path(self : FileSink) -> String {
|
||||||
self.path
|
self.path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::auto_flush_enabled(self : FileSink) -> Bool {
|
pub fn FileSink::auto_flush_enabled(self : FileSink) -> Bool {
|
||||||
self.auto_flush.val
|
self.auto_flush.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::rotation_enabled(self : FileSink) -> Bool {
|
pub fn FileSink::rotation_enabled(self : FileSink) -> Bool {
|
||||||
self.rotation.val is Some(_)
|
self.rotation.val is Some(_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::rotation_config(self : FileSink) -> FileRotation? {
|
pub fn FileSink::rotation_config(self : FileSink) -> FileRotation? {
|
||||||
self.rotation.val
|
self.rotation.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::set_auto_flush(self : FileSink, enabled : Bool) -> Unit {
|
pub fn FileSink::set_auto_flush(self : FileSink, enabled : Bool) -> Unit {
|
||||||
self.auto_flush.val = enabled
|
self.auto_flush.val = enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::set_policy(self : FileSink, policy : FileSinkPolicy) -> Unit {
|
pub fn FileSink::set_policy(self : FileSink, policy : FileSinkPolicy) -> Unit {
|
||||||
self.append.val = policy.append
|
self.append.val = policy.append
|
||||||
self.auto_flush.val = policy.auto_flush
|
self.auto_flush.val = policy.auto_flush
|
||||||
self.rotation.val = policy.rotation
|
self.rotation.val = policy.rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FileSink::set_rotation(self : FileSink, rotation : FileRotation?) -> Unit {
|
///|
|
||||||
|
pub fn FileSink::set_rotation(
|
||||||
|
self : FileSink,
|
||||||
|
rotation : FileRotation?,
|
||||||
|
) -> Unit {
|
||||||
self.rotation.val = rotation
|
self.rotation.val = rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::clear_rotation(self : FileSink) -> Unit {
|
pub fn FileSink::clear_rotation(self : FileSink) -> Unit {
|
||||||
self.rotation.val = None
|
self.rotation.val = None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::close(self : FileSink) -> Bool {
|
pub fn FileSink::close(self : FileSink) -> Bool {
|
||||||
match self.handle.val {
|
match self.handle.val {
|
||||||
None => false
|
None => false
|
||||||
@@ -125,22 +146,27 @@ pub fn FileSink::close(self : FileSink) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::rotation_failures(self : FileSink) -> Int {
|
pub fn FileSink::rotation_failures(self : FileSink) -> Int {
|
||||||
self.rotation_failures.val
|
self.rotation_failures.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::open_failures(self : FileSink) -> Int {
|
pub fn FileSink::open_failures(self : FileSink) -> Int {
|
||||||
self.open_failures.val
|
self.open_failures.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::write_failures(self : FileSink) -> Int {
|
pub fn FileSink::write_failures(self : FileSink) -> Int {
|
||||||
self.write_failures.val
|
self.write_failures.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::flush_failures(self : FileSink) -> Int {
|
pub fn FileSink::flush_failures(self : FileSink) -> Int {
|
||||||
self.flush_failures.val
|
self.flush_failures.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::reset_failure_counters(self : FileSink) -> Unit {
|
pub fn FileSink::reset_failure_counters(self : FileSink) -> Unit {
|
||||||
self.open_failures.val = 0
|
self.open_failures.val = 0
|
||||||
self.write_failures.val = 0
|
self.write_failures.val = 0
|
||||||
@@ -148,12 +174,14 @@ pub fn FileSink::reset_failure_counters(self : FileSink) -> Unit {
|
|||||||
self.rotation_failures.val = 0
|
self.rotation_failures.val = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::reset_policy(self : FileSink) -> Unit {
|
pub fn FileSink::reset_policy(self : FileSink) -> Unit {
|
||||||
self.append.val = self.default_append
|
self.append.val = self.default_append
|
||||||
self.auto_flush.val = self.default_auto_flush
|
self.auto_flush.val = self.default_auto_flush
|
||||||
self.rotation.val = self.default_rotation
|
self.rotation.val = self.default_rotation
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::policy(self : FileSink) -> FileSinkPolicy {
|
pub fn FileSink::policy(self : FileSink) -> FileSinkPolicy {
|
||||||
FileSinkPolicy::new(
|
FileSinkPolicy::new(
|
||||||
append=self.append.val,
|
append=self.append.val,
|
||||||
@@ -162,6 +190,7 @@ pub fn FileSink::policy(self : FileSink) -> FileSinkPolicy {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::default_policy(self : FileSink) -> FileSinkPolicy {
|
pub fn FileSink::default_policy(self : FileSink) -> FileSinkPolicy {
|
||||||
FileSinkPolicy::new(
|
FileSinkPolicy::new(
|
||||||
append=self.default_append,
|
append=self.default_append,
|
||||||
@@ -170,6 +199,7 @@ pub fn FileSink::default_policy(self : FileSink) -> FileSinkPolicy {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::policy_matches_default(self : FileSink) -> Bool {
|
pub fn FileSink::policy_matches_default(self : FileSink) -> Bool {
|
||||||
let current = self.policy()
|
let current = self.policy()
|
||||||
let default = self.default_policy()
|
let default = self.default_policy()
|
||||||
@@ -178,14 +208,20 @@ pub fn FileSink::policy_matches_default(self : FileSink) -> Bool {
|
|||||||
policy_rotation_equals_internal(current.rotation, default.rotation)
|
policy_rotation_equals_internal(current.rotation, default.rotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn policy_rotation_equals_internal(left : FileRotation?, right : FileRotation?) -> Bool {
|
///|
|
||||||
|
fn policy_rotation_equals_internal(
|
||||||
|
left : FileRotation?,
|
||||||
|
right : FileRotation?,
|
||||||
|
) -> Bool {
|
||||||
match (left, right) {
|
match (left, right) {
|
||||||
(None, None) => true
|
(None, None) => true
|
||||||
(Some(a), Some(b)) => a.max_bytes == b.max_bytes && a.max_backups == b.max_backups
|
(Some(a), Some(b)) =>
|
||||||
|
a.max_bytes == b.max_bytes && a.max_backups == b.max_backups
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::state(self : FileSink) -> FileSinkState {
|
pub fn FileSink::state(self : FileSink) -> FileSinkState {
|
||||||
FileSinkState::new(
|
FileSinkState::new(
|
||||||
self.path,
|
self.path,
|
||||||
@@ -200,7 +236,8 @@ pub fn FileSink::state(self : FileSink) -> FileSinkState {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn FileSink::reopen(self : FileSink, append~ : Bool? = None) -> Bool {
|
///|
|
||||||
|
pub fn FileSink::reopen(self : FileSink, append? : Bool? = None) -> Bool {
|
||||||
let append_mode = append.unwrap_or(self.append.val)
|
let append_mode = append.unwrap_or(self.append.val)
|
||||||
self.append.val = append_mode
|
self.append.val = append_mode
|
||||||
match self.handle.val {
|
match self.handle.val {
|
||||||
@@ -220,22 +257,27 @@ pub fn FileSink::reopen(self : FileSink, append~ : Bool? = None) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::reopen_with_current_policy(self : FileSink) -> Bool {
|
pub fn FileSink::reopen_with_current_policy(self : FileSink) -> Bool {
|
||||||
self.reopen()
|
self.reopen()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::reopen_append(self : FileSink) -> Bool {
|
pub fn FileSink::reopen_append(self : FileSink) -> Bool {
|
||||||
self.reopen(append=Some(true))
|
self.reopen(append=Some(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSink::reopen_truncate(self : FileSink) -> Bool {
|
pub fn FileSink::reopen_truncate(self : FileSink) -> Bool {
|
||||||
self.reopen(append=Some(false))
|
self.reopen(append=Some(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rotated_file_path(path : String, index : Int) -> String {
|
fn rotated_file_path(path : String, index : Int) -> String {
|
||||||
"\{path}.\{index}"
|
"\{path}.\{index}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rotate_file_sink_internal(sink : FileSink, rotation : FileRotation) -> Bool {
|
fn rotate_file_sink_internal(sink : FileSink, rotation : FileRotation) -> Bool {
|
||||||
let closed = match sink.handle.val {
|
let closed = match sink.handle.val {
|
||||||
None => true
|
None => true
|
||||||
@@ -249,7 +291,9 @@ fn rotate_file_sink_internal(sink : FileSink, rotation : FileRotation) -> Bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if rotation.max_backups > 0 {
|
if rotation.max_backups > 0 {
|
||||||
ignore(remove_file_internal(rotated_file_path(sink.path, rotation.max_backups)))
|
ignore(
|
||||||
|
remove_file_internal(rotated_file_path(sink.path, rotation.max_backups)),
|
||||||
|
)
|
||||||
for index = rotation.max_backups - 1; index >= 1; {
|
for index = rotation.max_backups - 1; index >= 1; {
|
||||||
let from_path = rotated_file_path(sink.path, index)
|
let from_path = rotated_file_path(sink.path, index)
|
||||||
let to_path = rotated_file_path(sink.path, index + 1)
|
let to_path = rotated_file_path(sink.path, index + 1)
|
||||||
@@ -264,10 +308,12 @@ fn rotate_file_sink_internal(sink : FileSink, rotation : FileRotation) -> Bool {
|
|||||||
sink.handle.val is Some(_)
|
sink.handle.val is Some(_)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rotate_if_needed_internal(sink : FileSink, next_line_bytes : Int) -> Bool {
|
fn rotate_if_needed_internal(sink : FileSink, next_line_bytes : Int) -> Bool {
|
||||||
match sink.rotation.val {
|
match sink.rotation.val {
|
||||||
None => true
|
None => true
|
||||||
Some(rotation) => match sink.handle.val {
|
Some(rotation) =>
|
||||||
|
match sink.handle.val {
|
||||||
None => false
|
None => false
|
||||||
Some(handle) => {
|
Some(handle) => {
|
||||||
let size = file_size_internal(handle)
|
let size = file_size_internal(handle)
|
||||||
@@ -285,19 +331,19 @@ fn rotate_if_needed_internal(sink : FileSink, next_line_bytes : Int) -> Bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub impl Sink for FileSink with write(self, rec) {
|
///|
|
||||||
|
pub impl Sink for FileSink with fn write(self, rec) {
|
||||||
match self.handle.val {
|
match self.handle.val {
|
||||||
None => {
|
None => self.write_failures.val += 1
|
||||||
self.write_failures.val += 1
|
|
||||||
}
|
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
let line = "\{(self.formatter)(rec)}\n"
|
let line = "\{(self.formatter)(rec)}\n"
|
||||||
let can_write = rotate_if_needed_internal(self, string_byte_length_internal(line))
|
let can_write = rotate_if_needed_internal(
|
||||||
|
self,
|
||||||
|
string_byte_length_internal(line),
|
||||||
|
)
|
||||||
if can_write {
|
if can_write {
|
||||||
match self.handle.val {
|
match self.handle.val {
|
||||||
None => {
|
None => self.write_failures.val += 1
|
||||||
self.write_failures.val += 1
|
|
||||||
}
|
|
||||||
Some(active) => {
|
Some(active) => {
|
||||||
let wrote = write_file_handle_internal(active, line)
|
let wrote = write_file_handle_internal(active, line)
|
||||||
if wrote {
|
if wrote {
|
||||||
|
|||||||
+182
-82
@@ -1,7 +1,9 @@
|
|||||||
|
///|
|
||||||
pub(all) suberror ConfigError {
|
pub(all) suberror ConfigError {
|
||||||
InvalidConfig(String)
|
InvalidConfig(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub(all) enum SinkKind {
|
pub(all) enum SinkKind {
|
||||||
Console
|
Console
|
||||||
JsonConsole
|
JsonConsole
|
||||||
@@ -9,6 +11,7 @@ pub(all) enum SinkKind {
|
|||||||
File
|
File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct TextFormatterConfig {
|
pub struct TextFormatterConfig {
|
||||||
show_timestamp : Bool
|
show_timestamp : Bool
|
||||||
show_level : Bool
|
show_level : Bool
|
||||||
@@ -25,20 +28,21 @@ pub struct TextFormatterConfig {
|
|||||||
style_tags : Map[String, TextStyle]
|
style_tags : Map[String, TextStyle]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn TextFormatterConfig::new(
|
pub fn TextFormatterConfig::new(
|
||||||
show_timestamp~ : Bool = true,
|
show_timestamp? : Bool = true,
|
||||||
show_level~ : Bool = true,
|
show_level? : Bool = true,
|
||||||
show_target~ : Bool = true,
|
show_target? : Bool = true,
|
||||||
show_fields~ : Bool = true,
|
show_fields? : Bool = true,
|
||||||
separator~ : String = " ",
|
separator? : String = " ",
|
||||||
field_separator~ : String = " ",
|
field_separator? : String = " ",
|
||||||
template~ : String = "",
|
template? : String = "",
|
||||||
color_mode~ : ColorMode = ColorMode::Never,
|
color_mode? : ColorMode = ColorMode::Never,
|
||||||
color_support~ : ColorSupport = ColorSupport::TrueColor,
|
color_support? : ColorSupport = ColorSupport::TrueColor,
|
||||||
style_markup~ : StyleMarkupMode = StyleMarkupMode::Full,
|
style_markup? : StyleMarkupMode = StyleMarkupMode::Full,
|
||||||
target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
target_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||||
fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
fields_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||||
style_tags~ : Map[String, TextStyle] = {},
|
style_tags? : Map[String, TextStyle] = {},
|
||||||
) -> TextFormatterConfig {
|
) -> TextFormatterConfig {
|
||||||
{
|
{
|
||||||
show_timestamp,
|
show_timestamp,
|
||||||
@@ -57,15 +61,21 @@ pub fn TextFormatterConfig::new(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style_tag_registry_from_config(style_tags : Map[String, TextStyle]) -> StyleTagRegistry {
|
///|
|
||||||
|
fn style_tag_registry_from_config(
|
||||||
|
style_tags : Map[String, TextStyle],
|
||||||
|
) -> StyleTagRegistry {
|
||||||
let registry = style_tag_registry()
|
let registry = style_tag_registry()
|
||||||
for name, style in style_tags {
|
for name, style in style_tags {
|
||||||
ignore(registry.set_tag(name, style=style))
|
ignore(registry.set_tag(name, style~))
|
||||||
}
|
}
|
||||||
registry
|
registry
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TextFormatterConfig::to_formatter(self : TextFormatterConfig) -> TextFormatter {
|
///|
|
||||||
|
pub fn TextFormatterConfig::to_formatter(
|
||||||
|
self : TextFormatterConfig,
|
||||||
|
) -> TextFormatter {
|
||||||
text_formatter(
|
text_formatter(
|
||||||
show_timestamp=self.show_timestamp,
|
show_timestamp=self.show_timestamp,
|
||||||
show_level=self.show_level,
|
show_level=self.show_level,
|
||||||
@@ -87,18 +97,21 @@ pub fn TextFormatterConfig::to_formatter(self : TextFormatterConfig) -> TextForm
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct QueueConfig {
|
pub struct QueueConfig {
|
||||||
max_pending : Int
|
max_pending : Int
|
||||||
overflow : QueueOverflowPolicy
|
overflow : QueueOverflowPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn QueueConfig::new(
|
pub fn QueueConfig::new(
|
||||||
max_pending : Int,
|
max_pending : Int,
|
||||||
overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||||
) -> QueueConfig {
|
) -> QueueConfig {
|
||||||
{ max_pending, overflow }
|
{ max_pending, overflow }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct SinkConfig {
|
pub struct SinkConfig {
|
||||||
kind : SinkKind
|
kind : SinkKind
|
||||||
path : String
|
path : String
|
||||||
@@ -108,24 +121,19 @@ pub struct SinkConfig {
|
|||||||
text_formatter : TextFormatterConfig
|
text_formatter : TextFormatterConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn SinkConfig::new(
|
pub fn SinkConfig::new(
|
||||||
kind~ : SinkKind = SinkKind::Console,
|
kind? : SinkKind = SinkKind::Console,
|
||||||
path~ : String = "",
|
path? : String = "",
|
||||||
append~ : Bool = true,
|
append? : Bool = true,
|
||||||
auto_flush~ : Bool = true,
|
auto_flush? : Bool = true,
|
||||||
rotation~ : FileRotation? = None,
|
rotation? : FileRotation? = None,
|
||||||
text_formatter~ : TextFormatterConfig = default_text_formatter_config(),
|
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||||
) -> SinkConfig {
|
) -> SinkConfig {
|
||||||
{
|
{ kind, path, append, auto_flush, rotation, text_formatter }
|
||||||
kind,
|
|
||||||
path,
|
|
||||||
append,
|
|
||||||
auto_flush,
|
|
||||||
rotation,
|
|
||||||
text_formatter,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct LoggerConfig {
|
pub struct LoggerConfig {
|
||||||
min_level : @core.Level
|
min_level : @core.Level
|
||||||
target : String
|
target : String
|
||||||
@@ -134,34 +142,33 @@ pub struct LoggerConfig {
|
|||||||
queue : QueueConfig?
|
queue : QueueConfig?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn LoggerConfig::new(
|
pub fn LoggerConfig::new(
|
||||||
min_level~ : @core.Level = @core.Level::Info,
|
min_level? : @core.Level = @core.Level::Info,
|
||||||
target~ : String = "",
|
target? : String = "",
|
||||||
timestamp~ : Bool = false,
|
timestamp? : Bool = false,
|
||||||
sink~ : SinkConfig = default_sink_config(),
|
sink? : SinkConfig = default_sink_config(),
|
||||||
queue~ : QueueConfig? = None,
|
queue? : QueueConfig? = None,
|
||||||
) -> LoggerConfig {
|
) -> LoggerConfig {
|
||||||
{
|
{ min_level, target, timestamp, sink, queue }
|
||||||
min_level,
|
|
||||||
target,
|
|
||||||
timestamp,
|
|
||||||
sink,
|
|
||||||
queue,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_text_formatter_config() -> TextFormatterConfig {
|
pub fn default_text_formatter_config() -> TextFormatterConfig {
|
||||||
TextFormatterConfig::new()
|
TextFormatterConfig::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_sink_config() -> SinkConfig {
|
pub fn default_sink_config() -> SinkConfig {
|
||||||
SinkConfig::new()
|
SinkConfig::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_logger_config() -> LoggerConfig {
|
pub fn default_logger_config() -> LoggerConfig {
|
||||||
LoggerConfig::new()
|
LoggerConfig::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn expect_object(
|
fn expect_object(
|
||||||
value : @json_parser.JsonValue,
|
value : @json_parser.JsonValue,
|
||||||
context : String,
|
context : String,
|
||||||
@@ -172,33 +179,40 @@ fn expect_object(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn get_string(
|
fn get_string(
|
||||||
obj : Map[String, @json_parser.JsonValue],
|
obj : Map[String, @json_parser.JsonValue],
|
||||||
key : String,
|
key : String,
|
||||||
default~ : String = "",
|
default? : String = "",
|
||||||
) -> String raise ConfigError {
|
) -> String raise ConfigError {
|
||||||
match obj.get(key) {
|
match obj.get(key) {
|
||||||
None => default
|
None => default
|
||||||
Some(value) => match value.as_string() {
|
Some(value) =>
|
||||||
|
match value.as_string() {
|
||||||
Some(text) => text
|
Some(text) => text
|
||||||
None => raise ConfigError::InvalidConfig("Expected string at key " + key)
|
None =>
|
||||||
|
raise ConfigError::InvalidConfig("Expected string at key " + key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn get_optional_string(
|
fn get_optional_string(
|
||||||
obj : Map[String, @json_parser.JsonValue],
|
obj : Map[String, @json_parser.JsonValue],
|
||||||
key : String,
|
key : String,
|
||||||
) -> String? raise ConfigError {
|
) -> String? raise ConfigError {
|
||||||
match obj.get(key) {
|
match obj.get(key) {
|
||||||
None => None
|
None => None
|
||||||
Some(value) => match value.as_string() {
|
Some(value) =>
|
||||||
|
match value.as_string() {
|
||||||
Some(text) => Some(text)
|
Some(text) => Some(text)
|
||||||
None => raise ConfigError::InvalidConfig("Expected string at key " + key)
|
None =>
|
||||||
|
raise ConfigError::InvalidConfig("Expected string at key " + key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn get_bool(
|
fn get_bool(
|
||||||
obj : Map[String, @json_parser.JsonValue],
|
obj : Map[String, @json_parser.JsonValue],
|
||||||
key : String,
|
key : String,
|
||||||
@@ -206,13 +220,15 @@ fn get_bool(
|
|||||||
) -> Bool raise ConfigError {
|
) -> Bool raise ConfigError {
|
||||||
match obj.get(key) {
|
match obj.get(key) {
|
||||||
None => default
|
None => default
|
||||||
Some(value) => match value.as_bool() {
|
Some(value) =>
|
||||||
|
match value.as_bool() {
|
||||||
Some(flag) => flag
|
Some(flag) => flag
|
||||||
None => raise ConfigError::InvalidConfig("Expected bool at key " + key)
|
None => raise ConfigError::InvalidConfig("Expected bool at key " + key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn get_int(
|
fn get_int(
|
||||||
obj : Map[String, @json_parser.JsonValue],
|
obj : Map[String, @json_parser.JsonValue],
|
||||||
key : String,
|
key : String,
|
||||||
@@ -220,13 +236,16 @@ fn get_int(
|
|||||||
) -> Int raise ConfigError {
|
) -> Int raise ConfigError {
|
||||||
match obj.get(key) {
|
match obj.get(key) {
|
||||||
None => default
|
None => default
|
||||||
Some(value) => match value.as_number() {
|
Some(value) =>
|
||||||
|
match value.as_number() {
|
||||||
Some(number) => number.to_int()
|
Some(number) => number.to_int()
|
||||||
None => raise ConfigError::InvalidConfig("Expected number at key " + key)
|
None =>
|
||||||
|
raise ConfigError::InvalidConfig("Expected number at key " + key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_level(name : String) -> @core.Level raise ConfigError {
|
fn parse_level(name : String) -> @core.Level raise ConfigError {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"TRACE" => @core.Level::Trace
|
"TRACE" => @core.Level::Trace
|
||||||
@@ -238,15 +257,20 @@ fn parse_level(name : String) -> @core.Level raise ConfigError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_overflow(name : String) -> QueueOverflowPolicy raise ConfigError {
|
fn parse_overflow(name : String) -> QueueOverflowPolicy raise ConfigError {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"DROPNEWEST" => QueueOverflowPolicy::DropNewest
|
"DROPNEWEST" => QueueOverflowPolicy::DropNewest
|
||||||
"DROPPOLDEST" => QueueOverflowPolicy::DropOldest
|
"DROPPOLDEST" => QueueOverflowPolicy::DropOldest
|
||||||
"DROPOLDEST" => QueueOverflowPolicy::DropOldest
|
"DROPOLDEST" => QueueOverflowPolicy::DropOldest
|
||||||
_ => raise ConfigError::InvalidConfig("Unsupported queue overflow policy: " + name)
|
_ =>
|
||||||
|
raise ConfigError::InvalidConfig(
|
||||||
|
"Unsupported queue overflow policy: " + name,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_sink_kind(name : String) -> SinkKind raise ConfigError {
|
fn parse_sink_kind(name : String) -> SinkKind raise ConfigError {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"CONSOLE" => SinkKind::Console
|
"CONSOLE" => SinkKind::Console
|
||||||
@@ -259,6 +283,7 @@ fn parse_sink_kind(name : String) -> SinkKind raise ConfigError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_color_mode(name : String) -> ColorMode raise ConfigError {
|
fn parse_color_mode(name : String) -> ColorMode raise ConfigError {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"NEVER" => ColorMode::Never
|
"NEVER" => ColorMode::Never
|
||||||
@@ -268,6 +293,7 @@ fn parse_color_mode(name : String) -> ColorMode raise ConfigError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_color_support(name : String) -> ColorSupport raise ConfigError {
|
fn parse_color_support(name : String) -> ColorSupport raise ConfigError {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"BASIC" => ColorSupport::Basic
|
"BASIC" => ColorSupport::Basic
|
||||||
@@ -276,15 +302,18 @@ fn parse_color_support(name : String) -> ColorSupport raise ConfigError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_style_markup_mode(name : String) -> StyleMarkupMode raise ConfigError {
|
fn parse_style_markup_mode(name : String) -> StyleMarkupMode raise ConfigError {
|
||||||
match name.to_upper() {
|
match name.to_upper() {
|
||||||
"DISABLED" => StyleMarkupMode::Disabled
|
"DISABLED" => StyleMarkupMode::Disabled
|
||||||
"BUILTIN" => StyleMarkupMode::Builtin
|
"BUILTIN" => StyleMarkupMode::Builtin
|
||||||
"FULL" => StyleMarkupMode::Full
|
"FULL" => StyleMarkupMode::Full
|
||||||
_ => raise ConfigError::InvalidConfig("Unsupported style markup mode: " + name)
|
_ =>
|
||||||
|
raise ConfigError::InvalidConfig("Unsupported style markup mode: " + name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn sink_kind_label(kind : SinkKind) -> String {
|
fn sink_kind_label(kind : SinkKind) -> String {
|
||||||
match kind {
|
match kind {
|
||||||
SinkKind::Console => "console"
|
SinkKind::Console => "console"
|
||||||
@@ -294,7 +323,10 @@ fn sink_kind_label(kind : SinkKind) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_text_formatter_config(value : @json_parser.JsonValue) -> TextFormatterConfig raise ConfigError {
|
///|
|
||||||
|
fn parse_text_formatter_config(
|
||||||
|
value : @json_parser.JsonValue,
|
||||||
|
) -> TextFormatterConfig raise ConfigError {
|
||||||
let obj = expect_object(value, "text_formatter")
|
let obj = expect_object(value, "text_formatter")
|
||||||
TextFormatterConfig::new(
|
TextFormatterConfig::new(
|
||||||
show_timestamp=get_bool(obj, "show_timestamp", default=true),
|
show_timestamp=get_bool(obj, "show_timestamp", default=true),
|
||||||
@@ -305,10 +337,18 @@ fn parse_text_formatter_config(value : @json_parser.JsonValue) -> TextFormatterC
|
|||||||
field_separator=get_string(obj, "field_separator", default=" "),
|
field_separator=get_string(obj, "field_separator", default=" "),
|
||||||
template=get_string(obj, "template", default=""),
|
template=get_string(obj, "template", default=""),
|
||||||
color_mode=parse_color_mode(get_string(obj, "color_mode", default="never")),
|
color_mode=parse_color_mode(get_string(obj, "color_mode", default="never")),
|
||||||
color_support=parse_color_support(get_string(obj, "color_support", default="truecolor")),
|
color_support=parse_color_support(
|
||||||
style_markup=parse_style_markup_mode(get_string(obj, "style_markup", default="full")),
|
get_string(obj, "color_support", default="truecolor"),
|
||||||
target_style_markup=parse_style_markup_mode(get_string(obj, "target_style_markup", default="disabled")),
|
),
|
||||||
fields_style_markup=parse_style_markup_mode(get_string(obj, "fields_style_markup", default="disabled")),
|
style_markup=parse_style_markup_mode(
|
||||||
|
get_string(obj, "style_markup", default="full"),
|
||||||
|
),
|
||||||
|
target_style_markup=parse_style_markup_mode(
|
||||||
|
get_string(obj, "target_style_markup", default="disabled"),
|
||||||
|
),
|
||||||
|
fields_style_markup=parse_style_markup_mode(
|
||||||
|
get_string(obj, "fields_style_markup", default="disabled"),
|
||||||
|
),
|
||||||
style_tags=match obj.get("style_tags") {
|
style_tags=match obj.get("style_tags") {
|
||||||
None => {}
|
None => {}
|
||||||
Some(inner) => parse_style_tags_config(inner)
|
Some(inner) => parse_style_tags_config(inner)
|
||||||
@@ -316,6 +356,7 @@ fn parse_text_formatter_config(value : @json_parser.JsonValue) -> TextFormatterC
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn parse_text_style_config(
|
fn parse_text_style_config(
|
||||||
value : @json_parser.JsonValue,
|
value : @json_parser.JsonValue,
|
||||||
context : String,
|
context : String,
|
||||||
@@ -331,16 +372,25 @@ fn parse_text_style_config(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_style_tags_config(value : @json_parser.JsonValue) -> Map[String, TextStyle] raise ConfigError {
|
///|
|
||||||
|
fn parse_style_tags_config(
|
||||||
|
value : @json_parser.JsonValue,
|
||||||
|
) -> Map[String, TextStyle] raise ConfigError {
|
||||||
let obj = expect_object(value, "text_formatter.style_tags")
|
let obj = expect_object(value, "text_formatter.style_tags")
|
||||||
let style_tags : Map[String, TextStyle] = {}
|
let style_tags : Map[String, TextStyle] = {}
|
||||||
for name, item in obj {
|
for name, item in obj {
|
||||||
style_tags[name] = parse_text_style_config(item, "text_formatter.style_tags." + name)
|
style_tags[name] = parse_text_style_config(
|
||||||
|
item,
|
||||||
|
"text_formatter.style_tags." + name,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
style_tags
|
style_tags
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_queue_config(value : @json_parser.JsonValue) -> QueueConfig raise ConfigError {
|
///|
|
||||||
|
fn parse_queue_config(
|
||||||
|
value : @json_parser.JsonValue,
|
||||||
|
) -> QueueConfig raise ConfigError {
|
||||||
let obj = expect_object(value, "queue")
|
let obj = expect_object(value, "queue")
|
||||||
QueueConfig::new(
|
QueueConfig::new(
|
||||||
get_int(obj, "max_pending", default=0),
|
get_int(obj, "max_pending", default=0),
|
||||||
@@ -348,7 +398,10 @@ fn parse_queue_config(value : @json_parser.JsonValue) -> QueueConfig raise Confi
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_file_rotation_config(value : @json_parser.JsonValue) -> FileRotation raise ConfigError {
|
///|
|
||||||
|
fn parse_file_rotation_config(
|
||||||
|
value : @json_parser.JsonValue,
|
||||||
|
) -> FileRotation raise ConfigError {
|
||||||
let obj = expect_object(value, "sink.rotation")
|
let obj = expect_object(value, "sink.rotation")
|
||||||
file_rotation(
|
file_rotation(
|
||||||
get_int(obj, "max_bytes", default=1),
|
get_int(obj, "max_bytes", default=1),
|
||||||
@@ -356,7 +409,10 @@ fn parse_file_rotation_config(value : @json_parser.JsonValue) -> FileRotation ra
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_sink_config(value : @json_parser.JsonValue) -> SinkConfig raise ConfigError {
|
///|
|
||||||
|
fn parse_sink_config(
|
||||||
|
value : @json_parser.JsonValue,
|
||||||
|
) -> SinkConfig raise ConfigError {
|
||||||
let obj = expect_object(value, "sink")
|
let obj = expect_object(value, "sink")
|
||||||
let kind = parse_sink_kind(get_string(obj, "kind", default="console"))
|
let kind = parse_sink_kind(get_string(obj, "kind", default="console"))
|
||||||
let formatter = match obj.get("text_formatter") {
|
let formatter = match obj.get("text_formatter") {
|
||||||
@@ -365,14 +421,15 @@ fn parse_sink_config(value : @json_parser.JsonValue) -> SinkConfig raise ConfigE
|
|||||||
}
|
}
|
||||||
let path = get_string(obj, "path", default="")
|
let path = get_string(obj, "path", default="")
|
||||||
match kind {
|
match kind {
|
||||||
SinkKind::File => if path == "" {
|
SinkKind::File =>
|
||||||
|
if path == "" {
|
||||||
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
SinkConfig::new(
|
SinkConfig::new(
|
||||||
kind=kind,
|
kind~,
|
||||||
path=path,
|
path~,
|
||||||
append=get_bool(obj, "append", default=true),
|
append=get_bool(obj, "append", default=true),
|
||||||
auto_flush=get_bool(obj, "auto_flush", default=true),
|
auto_flush=get_bool(obj, "auto_flush", default=true),
|
||||||
rotation=match obj.get("rotation") {
|
rotation=match obj.get("rotation") {
|
||||||
@@ -383,7 +440,10 @@ fn parse_sink_config(value : @json_parser.JsonValue) -> SinkConfig raise ConfigE
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_logger_config_text(input : String) -> LoggerConfig raise ConfigError {
|
///|
|
||||||
|
pub fn parse_logger_config_text(
|
||||||
|
input : String,
|
||||||
|
) -> LoggerConfig raise ConfigError {
|
||||||
let root = @json_parser.parse(input) catch {
|
let root = @json_parser.parse(input) catch {
|
||||||
e => raise ConfigError::InvalidConfig("Invalid JSON: " + e.to_string())
|
e => raise ConfigError::InvalidConfig("Invalid JSON: " + e.to_string())
|
||||||
}
|
}
|
||||||
@@ -403,17 +463,24 @@ pub fn parse_logger_config_text(input : String) -> LoggerConfig raise ConfigErro
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
||||||
@json_parser.JsonValue::Object({
|
@json_parser.JsonValue::Object({
|
||||||
"max_pending": @json_parser.JsonValue::Number(queue.max_pending.to_double()),
|
"max_pending": @json_parser.JsonValue::Number(queue.max_pending.to_double()),
|
||||||
"overflow": @json_parser.JsonValue::String(match queue.overflow {
|
"overflow": @json_parser.JsonValue::String(
|
||||||
|
match queue.overflow {
|
||||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_queue_config(
|
||||||
|
queue : QueueConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = queue_config_to_json(queue)
|
let value = queue_config_to_json(queue)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
@@ -422,7 +489,10 @@ pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> St
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn text_formatter_config_to_json(
|
||||||
|
config : TextFormatterConfig,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {
|
let obj : Map[String, @json_parser.JsonValue] = {
|
||||||
"show_timestamp": @json_parser.JsonValue::Bool(config.show_timestamp),
|
"show_timestamp": @json_parser.JsonValue::Bool(config.show_timestamp),
|
||||||
"show_level": @json_parser.JsonValue::Bool(config.show_level),
|
"show_level": @json_parser.JsonValue::Bool(config.show_level),
|
||||||
@@ -431,11 +501,21 @@ pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_pars
|
|||||||
"separator": @json_parser.JsonValue::String(config.separator),
|
"separator": @json_parser.JsonValue::String(config.separator),
|
||||||
"field_separator": @json_parser.JsonValue::String(config.field_separator),
|
"field_separator": @json_parser.JsonValue::String(config.field_separator),
|
||||||
"template": @json_parser.JsonValue::String(config.template),
|
"template": @json_parser.JsonValue::String(config.template),
|
||||||
"color_mode": @json_parser.JsonValue::String(color_mode_label(config.color_mode)),
|
"color_mode": @json_parser.JsonValue::String(
|
||||||
"color_support": @json_parser.JsonValue::String(color_support_label(config.color_support)),
|
color_mode_label(config.color_mode),
|
||||||
"style_markup": @json_parser.JsonValue::String(style_markup_mode_label(config.style_markup)),
|
),
|
||||||
"target_style_markup": @json_parser.JsonValue::String(style_markup_mode_label(config.target_style_markup)),
|
"color_support": @json_parser.JsonValue::String(
|
||||||
"fields_style_markup": @json_parser.JsonValue::String(style_markup_mode_label(config.fields_style_markup)),
|
color_support_label(config.color_support),
|
||||||
|
),
|
||||||
|
"style_markup": @json_parser.JsonValue::String(
|
||||||
|
style_markup_mode_label(config.style_markup),
|
||||||
|
),
|
||||||
|
"target_style_markup": @json_parser.JsonValue::String(
|
||||||
|
style_markup_mode_label(config.target_style_markup),
|
||||||
|
),
|
||||||
|
"fields_style_markup": @json_parser.JsonValue::String(
|
||||||
|
style_markup_mode_label(config.fields_style_markup),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
if config.style_tags.length() != 0 {
|
if config.style_tags.length() != 0 {
|
||||||
obj["style_tags"] = style_tags_config_to_json(config.style_tags)
|
obj["style_tags"] = style_tags_config_to_json(config.style_tags)
|
||||||
@@ -443,6 +523,7 @@ pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_pars
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {
|
let obj : Map[String, @json_parser.JsonValue] = {
|
||||||
"bold": @json_parser.JsonValue::Bool(style.bold),
|
"bold": @json_parser.JsonValue::Bool(style.bold),
|
||||||
@@ -461,7 +542,10 @@ fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn style_tags_config_to_json(style_tags : Map[String, TextStyle]) -> @json_parser.JsonValue {
|
///|
|
||||||
|
fn style_tags_config_to_json(
|
||||||
|
style_tags : Map[String, TextStyle],
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {}
|
let obj : Map[String, @json_parser.JsonValue] = {}
|
||||||
for name, style in style_tags {
|
for name, style in style_tags {
|
||||||
obj[name] = text_style_config_to_json(style)
|
obj[name] = text_style_config_to_json(style)
|
||||||
@@ -469,9 +553,10 @@ fn style_tags_config_to_json(style_tags : Map[String, TextStyle]) -> @json_parse
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn stringify_text_formatter_config(
|
pub fn stringify_text_formatter_config(
|
||||||
config : TextFormatterConfig,
|
config : TextFormatterConfig,
|
||||||
pretty~ : Bool = false,
|
pretty? : Bool = false,
|
||||||
) -> String {
|
) -> String {
|
||||||
let value = text_formatter_config_to_json(config)
|
let value = text_formatter_config_to_json(config)
|
||||||
if pretty {
|
if pretty {
|
||||||
@@ -481,13 +566,19 @@ pub fn stringify_text_formatter_config(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_rotation_config_to_json(config : FileRotation) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn file_rotation_config_to_json(
|
||||||
|
config : FileRotation,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@json_parser.JsonValue::Object({
|
@json_parser.JsonValue::Object({
|
||||||
"max_bytes": @json_parser.JsonValue::Number(config.max_bytes.to_double()),
|
"max_bytes": @json_parser.JsonValue::Number(config.max_bytes.to_double()),
|
||||||
"max_backups": @json_parser.JsonValue::Number(config.max_backups.to_double()),
|
"max_backups": @json_parser.JsonValue::Number(
|
||||||
|
config.max_backups.to_double(),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {
|
let obj : Map[String, @json_parser.JsonValue] = {
|
||||||
"kind": @json_parser.JsonValue::String(sink_kind_label(config.kind)),
|
"kind": @json_parser.JsonValue::String(sink_kind_label(config.kind)),
|
||||||
@@ -503,7 +594,11 @@ pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_sink_config(
|
||||||
|
config : SinkConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = sink_config_to_json(config)
|
let value = sink_config_to_json(config)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
@@ -512,6 +607,7 @@ pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> Str
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {
|
let obj : Map[String, @json_parser.JsonValue] = {
|
||||||
"min_level": @json_parser.JsonValue::String(config.min_level.label()),
|
"min_level": @json_parser.JsonValue::String(config.min_level.label()),
|
||||||
@@ -526,7 +622,11 @@ pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_logger_config(config : LoggerConfig, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_logger_config(
|
||||||
|
config : LoggerConfig,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = logger_config_to_json(config)
|
let value = logger_config_to_json(config)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
fn string_to_c_bytes(str : String) -> Bytes {
|
fn string_to_c_bytes(str : String) -> Bytes {
|
||||||
let res : Array[Byte] = []
|
let res : Array[Byte] = []
|
||||||
let len = str.length()
|
let len = str.length()
|
||||||
@@ -31,14 +32,18 @@ fn string_to_c_bytes(str : String) -> Bytes {
|
|||||||
Bytes::from_array(res)
|
Bytes::from_array(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
#external
|
#external
|
||||||
type NativeFileHandle
|
type NativeFileHandle
|
||||||
|
|
||||||
|
///|
|
||||||
#borrow(path, mode)
|
#borrow(path, mode)
|
||||||
extern "C" fn file_open_ffi(path : Bytes, mode : Bytes) -> NativeFileHandle = "bitlogger_file_open"
|
extern "C" fn file_open_ffi(path : Bytes, mode : Bytes) -> NativeFileHandle = "bitlogger_file_open"
|
||||||
|
|
||||||
|
///|
|
||||||
extern "C" fn file_is_null_ffi(handle : NativeFileHandle) -> Bool = "bitlogger_pointer_is_null"
|
extern "C" fn file_is_null_ffi(handle : NativeFileHandle) -> Bool = "bitlogger_pointer_is_null"
|
||||||
|
|
||||||
|
///|
|
||||||
#borrow(buffer)
|
#borrow(buffer)
|
||||||
extern "C" fn file_write_ffi(
|
extern "C" fn file_write_ffi(
|
||||||
buffer : Bytes,
|
buffer : Bytes,
|
||||||
@@ -47,32 +52,37 @@ extern "C" fn file_write_ffi(
|
|||||||
handle : NativeFileHandle,
|
handle : NativeFileHandle,
|
||||||
) -> Int = "bitlogger_file_write"
|
) -> Int = "bitlogger_file_write"
|
||||||
|
|
||||||
|
///|
|
||||||
extern "C" fn file_flush_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_flush"
|
extern "C" fn file_flush_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_flush"
|
||||||
|
|
||||||
|
///|
|
||||||
extern "C" fn file_close_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_close"
|
extern "C" fn file_close_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_close"
|
||||||
|
|
||||||
|
///|
|
||||||
extern "C" fn file_seek_ffi(
|
extern "C" fn file_seek_ffi(
|
||||||
handle : NativeFileHandle,
|
handle : NativeFileHandle,
|
||||||
offset : Int,
|
offset : Int,
|
||||||
origin : Int,
|
origin : Int,
|
||||||
) -> Int = "bitlogger_file_seek"
|
) -> Int = "bitlogger_file_seek"
|
||||||
|
|
||||||
|
///|
|
||||||
extern "C" fn file_tell_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_tell"
|
extern "C" fn file_tell_ffi(handle : NativeFileHandle) -> Int = "bitlogger_file_tell"
|
||||||
|
|
||||||
|
///|
|
||||||
#borrow(from_path, to_path)
|
#borrow(from_path, to_path)
|
||||||
extern "C" fn file_rename_ffi(
|
extern "C" fn file_rename_ffi(from_path : Bytes, to_path : Bytes) -> Int = "bitlogger_file_rename"
|
||||||
from_path : Bytes,
|
|
||||||
to_path : Bytes,
|
|
||||||
) -> Int = "bitlogger_file_rename"
|
|
||||||
|
|
||||||
|
///|
|
||||||
#borrow(path)
|
#borrow(path)
|
||||||
extern "C" fn file_remove_ffi(path : Bytes) -> Int = "bitlogger_file_remove"
|
extern "C" fn file_remove_ffi(path : Bytes) -> Int = "bitlogger_file_remove"
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FileHandle {
|
pub struct FileHandle {
|
||||||
path : String
|
path : String
|
||||||
raw : NativeFileHandle
|
raw : NativeFileHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||||
let mode = if append { "ab" } else { "wb" }
|
let mode = if append { "ab" } else { "wb" }
|
||||||
let raw = file_open_ffi(string_to_c_bytes(path), string_to_c_bytes(mode))
|
let raw = file_open_ffi(string_to_c_bytes(path), string_to_c_bytes(mode))
|
||||||
@@ -83,20 +93,27 @@ pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
///|
|
||||||
|
pub fn write_file_handle_internal(
|
||||||
|
handle : FileHandle,
|
||||||
|
content : String,
|
||||||
|
) -> Bool {
|
||||||
let bytes = string_to_c_bytes(content)
|
let bytes = string_to_c_bytes(content)
|
||||||
let written = file_write_ffi(bytes, 1, bytes.length() - 1, handle.raw)
|
let written = file_write_ffi(bytes, 1, bytes.length() - 1, handle.raw)
|
||||||
written == bytes.length() - 1
|
written == bytes.length() - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
file_flush_ffi(handle.raw) == 0
|
file_flush_ffi(handle.raw) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
file_close_ffi(handle.raw) == 0
|
file_close_ffi(handle.raw) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn file_size_internal(handle : FileHandle) -> Int {
|
pub fn file_size_internal(handle : FileHandle) -> Int {
|
||||||
ignore(file_seek_ffi(handle.raw, 0, 2))
|
ignore(file_seek_ffi(handle.raw, 0, 2))
|
||||||
let size = file_tell_ffi(handle.raw)
|
let size = file_tell_ffi(handle.raw)
|
||||||
@@ -107,18 +124,22 @@ pub fn file_size_internal(handle : FileHandle) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||||
file_rename_ffi(string_to_c_bytes(from_path), string_to_c_bytes(to_path)) == 0
|
file_rename_ffi(string_to_c_bytes(from_path), string_to_c_bytes(to_path)) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn remove_file_internal(path : String) -> Bool {
|
pub fn remove_file_internal(path : String) -> Bool {
|
||||||
file_remove_ffi(string_to_c_bytes(path)) == 0
|
file_remove_ffi(string_to_c_bytes(path)) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn string_byte_length_internal(content : String) -> Int {
|
pub fn string_byte_length_internal(content : String) -> Int {
|
||||||
string_to_c_bytes(content).length() - 1
|
string_to_c_bytes(content).length() - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn native_files_supported_internal() -> Bool {
|
pub fn native_files_supported_internal() -> Bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
///|
|
||||||
pub struct FileHandle {
|
pub struct FileHandle {
|
||||||
path : String
|
path : String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||||
ignore(append)
|
ignore(append)
|
||||||
ignore(path)
|
ignore(path)
|
||||||
@@ -10,42 +12,53 @@ pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
///|
|
||||||
|
pub fn write_file_handle_internal(
|
||||||
|
handle : FileHandle,
|
||||||
|
content : String,
|
||||||
|
) -> Bool {
|
||||||
ignore(handle)
|
ignore(handle)
|
||||||
ignore(content)
|
ignore(content)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
pub fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
ignore(handle)
|
ignore(handle)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
pub fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||||
ignore(handle)
|
ignore(handle)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn file_size_internal(handle : FileHandle) -> Int {
|
pub fn file_size_internal(handle : FileHandle) -> Int {
|
||||||
ignore(handle)
|
ignore(handle)
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
pub fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||||
ignore(from_path)
|
ignore(from_path)
|
||||||
ignore(to_path)
|
ignore(to_path)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn remove_file_internal(path : String) -> Bool {
|
pub fn remove_file_internal(path : String) -> Bool {
|
||||||
ignore(path)
|
ignore(path)
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn string_byte_length_internal(content : String) -> Int {
|
pub fn string_byte_length_internal(content : String) -> Int {
|
||||||
content.length()
|
content.length()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn native_files_supported_internal() -> Bool {
|
pub fn native_files_supported_internal() -> Bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-16
@@ -1,29 +1,27 @@
|
|||||||
|
///|
|
||||||
pub type RecordPredicate = (@core.Record) -> Bool
|
pub type RecordPredicate = (@core.Record) -> Bool
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn level_at_least(min_level : @core.Level) -> RecordPredicate {
|
pub fn level_at_least(min_level : @core.Level) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) { rec.level.priority() >= min_level.priority() }
|
||||||
rec.level.priority() >= min_level.priority()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn target_is(target : String) -> RecordPredicate {
|
pub fn target_is(target : String) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) { rec.target == target }
|
||||||
rec.target == target
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) { rec.target.has_prefix(prefix) }
|
||||||
rec.target.has_prefix(prefix)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn message_contains(fragment : String) -> RecordPredicate {
|
pub fn message_contains(fragment : String) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) { rec.message.contains(fragment) }
|
||||||
rec.message.contains(fragment)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn has_field(key : String) -> RecordPredicate {
|
pub fn has_field(key : String) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
for field in rec.fields {
|
for field in rec.fields {
|
||||||
@@ -35,6 +33,7 @@ pub fn has_field(key : String) -> RecordPredicate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
for field in rec.fields {
|
for field in rec.fields {
|
||||||
@@ -46,16 +45,16 @@ pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) { !predicate(rec) }
|
||||||
!(predicate(rec))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
for predicate in predicates {
|
for predicate in predicates {
|
||||||
if !(predicate(rec)) {
|
if !predicate(rec) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,6 +62,7 @@ pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
for predicate in predicates {
|
for predicate in predicates {
|
||||||
|
|||||||
+249
-77
@@ -1,22 +1,27 @@
|
|||||||
|
///|
|
||||||
pub type RecordFormatter = (@core.Record) -> String
|
pub type RecordFormatter = (@core.Record) -> String
|
||||||
|
|
||||||
|
///|
|
||||||
pub(all) enum ColorMode {
|
pub(all) enum ColorMode {
|
||||||
Never
|
Never
|
||||||
Auto
|
Auto
|
||||||
Always
|
Always
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub(all) enum ColorSupport {
|
pub(all) enum ColorSupport {
|
||||||
Basic
|
Basic
|
||||||
TrueColor
|
TrueColor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub(all) enum StyleMarkupMode {
|
pub(all) enum StyleMarkupMode {
|
||||||
Disabled
|
Disabled
|
||||||
Builtin
|
Builtin
|
||||||
Full
|
Full
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct TextStyle {
|
pub struct TextStyle {
|
||||||
fg : String?
|
fg : String?
|
||||||
bg : String?
|
bg : String?
|
||||||
@@ -26,29 +31,34 @@ pub struct TextStyle {
|
|||||||
underline : Bool
|
underline : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_style(
|
pub fn text_style(
|
||||||
fg~ : String? = None,
|
fg? : String? = None,
|
||||||
bg~ : String? = None,
|
bg? : String? = None,
|
||||||
bold~ : Bool = false,
|
bold? : Bool = false,
|
||||||
dim~ : Bool = false,
|
dim? : Bool = false,
|
||||||
italic~ : Bool = false,
|
italic? : Bool = false,
|
||||||
underline~ : Bool = false,
|
underline? : Bool = false,
|
||||||
) -> TextStyle {
|
) -> TextStyle {
|
||||||
{ fg, bg, bold, dim, italic, underline }
|
{ fg, bg, bold, dim, italic, underline }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct StyleTagRegistry {
|
pub struct StyleTagRegistry {
|
||||||
entries : Map[String, TextStyle]
|
entries : Map[String, TextStyle]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn normalize_style_tag_name(name : String) -> String {
|
fn normalize_style_tag_name(name : String) -> String {
|
||||||
name.trim().to_lower().to_owned()
|
name.trim().to_lower().to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn style_tag_registry() -> StyleTagRegistry {
|
pub fn style_tag_registry() -> StyleTagRegistry {
|
||||||
{ entries: {} }
|
{ entries: {} }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn merge_text_style(base : TextStyle, overlay : TextStyle) -> TextStyle {
|
fn merge_text_style(base : TextStyle, overlay : TextStyle) -> TextStyle {
|
||||||
{
|
{
|
||||||
fg: match overlay.fg {
|
fg: match overlay.fg {
|
||||||
@@ -66,47 +76,62 @@ fn merge_text_style(base : TextStyle, overlay : TextStyle) -> TextStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn StyleTagRegistry::set_tag(
|
pub fn StyleTagRegistry::set_tag(
|
||||||
self : StyleTagRegistry,
|
self : StyleTagRegistry,
|
||||||
name : String,
|
name : String,
|
||||||
style~ : TextStyle = text_style(),
|
style? : TextStyle = text_style(),
|
||||||
fg~ : String? = None,
|
fg? : String? = None,
|
||||||
bg~ : String? = None,
|
bg? : String? = None,
|
||||||
bold~ : Bool = false,
|
bold? : Bool = false,
|
||||||
dim~ : Bool = false,
|
dim? : Bool = false,
|
||||||
italic~ : Bool = false,
|
italic? : Bool = false,
|
||||||
underline~ : Bool = false,
|
underline? : Bool = false,
|
||||||
) -> StyleTagRegistry {
|
) -> StyleTagRegistry {
|
||||||
let overlay = text_style(fg=fg, bg=bg, bold=bold, dim=dim, italic=italic, underline=underline)
|
let overlay = text_style(fg~, bg~, bold~, dim~, italic~, underline~)
|
||||||
self.entries[normalize_style_tag_name(name)] = merge_text_style(style, overlay)
|
self.entries[normalize_style_tag_name(name)] = merge_text_style(
|
||||||
|
style, overlay,
|
||||||
|
)
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn StyleTagRegistry::get(self : StyleTagRegistry, name : String) -> TextStyle? {
|
///|
|
||||||
|
pub fn StyleTagRegistry::get(
|
||||||
|
self : StyleTagRegistry,
|
||||||
|
name : String,
|
||||||
|
) -> TextStyle? {
|
||||||
self.entries.get(normalize_style_tag_name(name))
|
self.entries.get(normalize_style_tag_name(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn StyleTagRegistry::contains(self : StyleTagRegistry, name : String) -> Bool {
|
///|
|
||||||
|
pub fn StyleTagRegistry::contains(
|
||||||
|
self : StyleTagRegistry,
|
||||||
|
name : String,
|
||||||
|
) -> Bool {
|
||||||
self.entries.contains(normalize_style_tag_name(name))
|
self.entries.contains(normalize_style_tag_name(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn StyleTagRegistry::define_alias(
|
pub fn StyleTagRegistry::define_alias(
|
||||||
self : StyleTagRegistry,
|
self : StyleTagRegistry,
|
||||||
name : String,
|
name : String,
|
||||||
target : String,
|
target : String,
|
||||||
) -> StyleTagRegistry {
|
) -> StyleTagRegistry {
|
||||||
match self.get(target) {
|
match self.get(target) {
|
||||||
Some(style) => self.set_tag(name, style=style)
|
Some(style) => self.set_tag(name, style~)
|
||||||
None => match global_style_tag_registry().get(target) {
|
None =>
|
||||||
Some(style) => self.set_tag(name, style=style)
|
match global_style_tag_registry().get(target) {
|
||||||
None => match builtin_text_style_for_tag(normalize_style_tag_name(target)) {
|
Some(style) => self.set_tag(name, style~)
|
||||||
Some(style) => self.set_tag(name, style=style)
|
None =>
|
||||||
|
match builtin_text_style_for_tag(normalize_style_tag_name(target)) {
|
||||||
|
Some(style) => self.set_tag(name, style~)
|
||||||
None => self
|
None => self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
||||||
style_tag_registry()
|
style_tag_registry()
|
||||||
.set_tag("black", fg=Some("black"))
|
.set_tag("black", fg=Some("black"))
|
||||||
@@ -137,20 +162,27 @@ pub fn default_style_tag_registry() -> StyleTagRegistry {
|
|||||||
.set_tag("u", underline=true)
|
.set_tag("u", underline=true)
|
||||||
}
|
}
|
||||||
|
|
||||||
let global_style_tag_registry_ref : Ref[StyleTagRegistry] = Ref(style_tag_registry())
|
///|
|
||||||
|
let global_style_tag_registry_ref : Ref[StyleTagRegistry] = Ref(
|
||||||
|
style_tag_registry(),
|
||||||
|
)
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
||||||
global_style_tag_registry_ref.val
|
global_style_tag_registry_ref.val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
||||||
global_style_tag_registry_ref.val = registry
|
global_style_tag_registry_ref.val = registry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn reset_global_style_tag_registry() -> Unit {
|
pub fn reset_global_style_tag_registry() -> Unit {
|
||||||
global_style_tag_registry_ref.val = style_tag_registry()
|
global_style_tag_registry_ref.val = style_tag_registry()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
priv struct InlineStyle {
|
priv struct InlineStyle {
|
||||||
fg_code : String?
|
fg_code : String?
|
||||||
bg_code : String?
|
bg_code : String?
|
||||||
@@ -162,24 +194,29 @@ priv struct InlineStyle {
|
|||||||
underline : Bool
|
underline : Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
priv struct StyledSegment {
|
priv struct StyledSegment {
|
||||||
text : String
|
text : String
|
||||||
style : InlineStyle
|
style : InlineStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
priv struct StyleFrame {
|
priv struct StyleFrame {
|
||||||
tag : String
|
tag : String
|
||||||
style : InlineStyle
|
style : InlineStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn code_unit(ch : Char) -> Int {
|
fn code_unit(ch : Char) -> Int {
|
||||||
ch.to_int()
|
ch.to_int()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn code_unit16(ch : UInt16) -> Int {
|
fn code_unit16(ch : UInt16) -> Int {
|
||||||
ch.to_int()
|
ch.to_int()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct TextFormatter {
|
pub struct TextFormatter {
|
||||||
show_timestamp : Bool
|
show_timestamp : Bool
|
||||||
show_level : Bool
|
show_level : Bool
|
||||||
@@ -196,20 +233,21 @@ pub struct TextFormatter {
|
|||||||
style_tags : StyleTagRegistry?
|
style_tags : StyleTagRegistry?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn text_formatter(
|
pub fn text_formatter(
|
||||||
show_timestamp~ : Bool = true,
|
show_timestamp? : Bool = true,
|
||||||
show_level~ : Bool = true,
|
show_level? : Bool = true,
|
||||||
show_target~ : Bool = true,
|
show_target? : Bool = true,
|
||||||
show_fields~ : Bool = true,
|
show_fields? : Bool = true,
|
||||||
separator~ : String = " ",
|
separator? : String = " ",
|
||||||
field_separator~ : String = " ",
|
field_separator? : String = " ",
|
||||||
template~ : String = "",
|
template? : String = "",
|
||||||
color_mode~ : ColorMode = ColorMode::Never,
|
color_mode? : ColorMode = ColorMode::Never,
|
||||||
color_support~ : ColorSupport = ColorSupport::TrueColor,
|
color_support? : ColorSupport = ColorSupport::TrueColor,
|
||||||
style_markup~ : StyleMarkupMode = StyleMarkupMode::Full,
|
style_markup? : StyleMarkupMode = StyleMarkupMode::Full,
|
||||||
target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
target_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||||
fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled,
|
fields_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||||
style_tags~ : StyleTagRegistry? = None,
|
style_tags? : StyleTagRegistry? = None,
|
||||||
) -> TextFormatter {
|
) -> TextFormatter {
|
||||||
{
|
{
|
||||||
show_timestamp,
|
show_timestamp,
|
||||||
@@ -228,6 +266,7 @@ pub fn text_formatter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn color_support_label(support : ColorSupport) -> String {
|
pub fn color_support_label(support : ColorSupport) -> String {
|
||||||
match support {
|
match support {
|
||||||
ColorSupport::Basic => "basic"
|
ColorSupport::Basic => "basic"
|
||||||
@@ -235,7 +274,11 @@ pub fn color_support_label(support : ColorSupport) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TextFormatter::with_color_support(self : TextFormatter, color_support : ColorSupport) -> TextFormatter {
|
///|
|
||||||
|
pub fn TextFormatter::with_color_support(
|
||||||
|
self : TextFormatter,
|
||||||
|
color_support : ColorSupport,
|
||||||
|
) -> TextFormatter {
|
||||||
text_formatter(
|
text_formatter(
|
||||||
show_timestamp=self.show_timestamp,
|
show_timestamp=self.show_timestamp,
|
||||||
show_level=self.show_level,
|
show_level=self.show_level,
|
||||||
@@ -245,7 +288,7 @@ pub fn TextFormatter::with_color_support(self : TextFormatter, color_support : C
|
|||||||
field_separator=self.field_separator,
|
field_separator=self.field_separator,
|
||||||
template=self.template,
|
template=self.template,
|
||||||
color_mode=self.color_mode,
|
color_mode=self.color_mode,
|
||||||
color_support=color_support,
|
color_support~,
|
||||||
style_markup=self.style_markup,
|
style_markup=self.style_markup,
|
||||||
target_style_markup=self.target_style_markup,
|
target_style_markup=self.target_style_markup,
|
||||||
fields_style_markup=self.fields_style_markup,
|
fields_style_markup=self.fields_style_markup,
|
||||||
@@ -253,6 +296,7 @@ pub fn TextFormatter::with_color_support(self : TextFormatter, color_support : C
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
||||||
match mode {
|
match mode {
|
||||||
StyleMarkupMode::Disabled => "disabled"
|
StyleMarkupMode::Disabled => "disabled"
|
||||||
@@ -261,7 +305,11 @@ pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TextFormatter::with_style_markup(self : TextFormatter, style_markup : StyleMarkupMode) -> TextFormatter {
|
///|
|
||||||
|
pub fn TextFormatter::with_style_markup(
|
||||||
|
self : TextFormatter,
|
||||||
|
style_markup : StyleMarkupMode,
|
||||||
|
) -> TextFormatter {
|
||||||
text_formatter(
|
text_formatter(
|
||||||
show_timestamp=self.show_timestamp,
|
show_timestamp=self.show_timestamp,
|
||||||
show_level=self.show_level,
|
show_level=self.show_level,
|
||||||
@@ -272,17 +320,21 @@ pub fn TextFormatter::with_style_markup(self : TextFormatter, style_markup : Sty
|
|||||||
template=self.template,
|
template=self.template,
|
||||||
color_mode=self.color_mode,
|
color_mode=self.color_mode,
|
||||||
color_support=self.color_support,
|
color_support=self.color_support,
|
||||||
style_markup=style_markup,
|
style_markup~,
|
||||||
target_style_markup=self.target_style_markup,
|
target_style_markup=self.target_style_markup,
|
||||||
fields_style_markup=self.fields_style_markup,
|
fields_style_markup=self.fields_style_markup,
|
||||||
style_tags=self.style_tags,
|
style_tags=self.style_tags,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TextFormatter::without_style_markup(self : TextFormatter) -> TextFormatter {
|
///|
|
||||||
|
pub fn TextFormatter::without_style_markup(
|
||||||
|
self : TextFormatter,
|
||||||
|
) -> TextFormatter {
|
||||||
self.with_style_markup(StyleMarkupMode::Disabled)
|
self.with_style_markup(StyleMarkupMode::Disabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn TextFormatter::with_target_style_markup(
|
pub fn TextFormatter::with_target_style_markup(
|
||||||
self : TextFormatter,
|
self : TextFormatter,
|
||||||
style_markup : StyleMarkupMode,
|
style_markup : StyleMarkupMode,
|
||||||
@@ -304,6 +356,7 @@ pub fn TextFormatter::with_target_style_markup(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn TextFormatter::with_fields_style_markup(
|
pub fn TextFormatter::with_fields_style_markup(
|
||||||
self : TextFormatter,
|
self : TextFormatter,
|
||||||
style_markup : StyleMarkupMode,
|
style_markup : StyleMarkupMode,
|
||||||
@@ -325,7 +378,11 @@ pub fn TextFormatter::with_fields_style_markup(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn TextFormatter::with_style_tags(self : TextFormatter, style_tags : StyleTagRegistry) -> TextFormatter {
|
///|
|
||||||
|
pub fn TextFormatter::with_style_tags(
|
||||||
|
self : TextFormatter,
|
||||||
|
style_tags : StyleTagRegistry,
|
||||||
|
) -> TextFormatter {
|
||||||
text_formatter(
|
text_formatter(
|
||||||
show_timestamp=self.show_timestamp,
|
show_timestamp=self.show_timestamp,
|
||||||
show_level=self.show_level,
|
show_level=self.show_level,
|
||||||
@@ -343,6 +400,7 @@ pub fn TextFormatter::with_style_tags(self : TextFormatter, style_tags : StyleTa
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn color_mode_label(mode : ColorMode) -> String {
|
pub fn color_mode_label(mode : ColorMode) -> String {
|
||||||
match mode {
|
match mode {
|
||||||
ColorMode::Never => "never"
|
ColorMode::Never => "never"
|
||||||
@@ -351,17 +409,20 @@ pub fn color_mode_label(mode : ColorMode) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn use_ansi_color(mode : ColorMode) -> Bool {
|
fn use_ansi_color(mode : ColorMode) -> Bool {
|
||||||
match mode {
|
match mode {
|
||||||
ColorMode::Never => false
|
ColorMode::Never => false
|
||||||
ColorMode::Always => true
|
ColorMode::Always => true
|
||||||
ColorMode::Auto => match @env.get_env_var("NO_COLOR") {
|
ColorMode::Auto =>
|
||||||
|
match @env.get_env_var("NO_COLOR") {
|
||||||
Some(_) => false
|
Some(_) => false
|
||||||
None => true
|
None => true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn ansi_wrap(text : String, code : String, enabled : Bool) -> String {
|
fn ansi_wrap(text : String, code : String, enabled : Bool) -> String {
|
||||||
if !enabled || text == "" {
|
if !enabled || text == "" {
|
||||||
text
|
text
|
||||||
@@ -370,7 +431,12 @@ fn ansi_wrap(text : String, code : String, enabled : Bool) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ansi_wrap_with_style(text : String, style : InlineStyle, enabled : Bool) -> String {
|
///|
|
||||||
|
fn ansi_wrap_with_style(
|
||||||
|
text : String,
|
||||||
|
style : InlineStyle,
|
||||||
|
enabled : Bool,
|
||||||
|
) -> String {
|
||||||
if !enabled || text == "" {
|
if !enabled || text == "" {
|
||||||
text
|
text
|
||||||
} else {
|
} else {
|
||||||
@@ -404,6 +470,7 @@ fn ansi_wrap_with_style(text : String, style : InlineStyle, enabled : Bool) -> S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn default_inline_style() -> InlineStyle {
|
fn default_inline_style() -> InlineStyle {
|
||||||
{
|
{
|
||||||
fg_code: None,
|
fg_code: None,
|
||||||
@@ -417,6 +484,7 @@ fn default_inline_style() -> InlineStyle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn named_color_code(tag : String) -> String? {
|
fn named_color_code(tag : String) -> String? {
|
||||||
match tag {
|
match tag {
|
||||||
"black" => Some("30")
|
"black" => Some("30")
|
||||||
@@ -439,6 +507,7 @@ fn named_color_code(tag : String) -> String? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn named_bg_color_code(tag : String) -> String? {
|
fn named_bg_color_code(tag : String) -> String? {
|
||||||
match tag {
|
match tag {
|
||||||
"black" => Some("40")
|
"black" => Some("40")
|
||||||
@@ -461,6 +530,7 @@ fn named_bg_color_code(tag : String) -> String? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn basic_name_from_hex(value : String) -> String {
|
fn basic_name_from_hex(value : String) -> String {
|
||||||
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||||
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||||
@@ -495,8 +565,7 @@ fn basic_name_from_hex(value : String) -> String {
|
|||||||
} else {
|
} else {
|
||||||
"green"
|
"green"
|
||||||
}
|
}
|
||||||
} else {
|
} else if r > 96 && g < 96 {
|
||||||
if r > 96 && g < 96 {
|
|
||||||
"magenta"
|
"magenta"
|
||||||
} else if g > 96 && r < 96 {
|
} else if g > 96 && r < 96 {
|
||||||
"cyan"
|
"cyan"
|
||||||
@@ -504,9 +573,9 @@ fn basic_name_from_hex(value : String) -> String {
|
|||||||
"blue"
|
"blue"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn resolve_inline_color_code(
|
fn resolve_inline_color_code(
|
||||||
formatter : TextFormatter,
|
formatter : TextFormatter,
|
||||||
basic_name : String?,
|
basic_name : String?,
|
||||||
@@ -514,21 +583,25 @@ fn resolve_inline_color_code(
|
|||||||
) -> String {
|
) -> String {
|
||||||
match formatter.color_support {
|
match formatter.color_support {
|
||||||
ColorSupport::TrueColor => truecolor_code
|
ColorSupport::TrueColor => truecolor_code
|
||||||
ColorSupport::Basic => match basic_name {
|
ColorSupport::Basic =>
|
||||||
|
match basic_name {
|
||||||
Some(name) => named_code_from_basic_name(name).unwrap_or(truecolor_code)
|
Some(name) => named_code_from_basic_name(name).unwrap_or(truecolor_code)
|
||||||
None => truecolor_code
|
None => truecolor_code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn named_code_from_basic_name(name : String) -> String? {
|
fn named_code_from_basic_name(name : String) -> String? {
|
||||||
named_color_code(name)
|
named_color_code(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn named_bg_code_from_basic_name(name : String) -> String? {
|
fn named_bg_code_from_basic_name(name : String) -> String? {
|
||||||
named_bg_color_code(name)
|
named_bg_color_code(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn resolve_inline_bg_code(
|
fn resolve_inline_bg_code(
|
||||||
formatter : TextFormatter,
|
formatter : TextFormatter,
|
||||||
basic_name : String?,
|
basic_name : String?,
|
||||||
@@ -536,13 +609,16 @@ fn resolve_inline_bg_code(
|
|||||||
) -> String {
|
) -> String {
|
||||||
match formatter.color_support {
|
match formatter.color_support {
|
||||||
ColorSupport::TrueColor => truecolor_code
|
ColorSupport::TrueColor => truecolor_code
|
||||||
ColorSupport::Basic => match basic_name {
|
ColorSupport::Basic =>
|
||||||
Some(name) => named_bg_code_from_basic_name(name).unwrap_or(truecolor_code)
|
match basic_name {
|
||||||
|
Some(name) =>
|
||||||
|
named_bg_code_from_basic_name(name).unwrap_or(truecolor_code)
|
||||||
None => truecolor_code
|
None => truecolor_code
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn is_hex_color(value : String) -> Bool {
|
fn is_hex_color(value : String) -> Bool {
|
||||||
if value.length() != 7 {
|
if value.length() != 7 {
|
||||||
return false
|
return false
|
||||||
@@ -562,6 +638,7 @@ fn is_hex_color(value : String) -> Bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn hex_to_int(ch : UInt16) -> Int {
|
fn hex_to_int(ch : UInt16) -> Int {
|
||||||
let code = code_unit16(ch)
|
let code = code_unit16(ch)
|
||||||
if code >= code_unit('0') && code <= code_unit('9') {
|
if code >= code_unit('0') && code <= code_unit('9') {
|
||||||
@@ -573,10 +650,12 @@ fn hex_to_int(ch : UInt16) -> Int {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn hex_pair_to_int(high : UInt16, low : UInt16) -> Int {
|
fn hex_pair_to_int(high : UInt16, low : UInt16) -> Int {
|
||||||
hex_to_int(high) * 16 + hex_to_int(low)
|
hex_to_int(high) * 16 + hex_to_int(low)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rgb_fg_code(value : String) -> String {
|
fn rgb_fg_code(value : String) -> String {
|
||||||
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||||
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||||
@@ -584,6 +663,7 @@ fn rgb_fg_code(value : String) -> String {
|
|||||||
"38;2;\{r};\{g};\{b}"
|
"38;2;\{r};\{g};\{b}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rgb_bg_code(value : String) -> String {
|
fn rgb_bg_code(value : String) -> String {
|
||||||
let r = hex_pair_to_int(value.unsafe_get(4), value.unsafe_get(5))
|
let r = hex_pair_to_int(value.unsafe_get(4), value.unsafe_get(5))
|
||||||
let g = hex_pair_to_int(value.unsafe_get(6), value.unsafe_get(7))
|
let g = hex_pair_to_int(value.unsafe_get(6), value.unsafe_get(7))
|
||||||
@@ -591,6 +671,7 @@ fn rgb_bg_code(value : String) -> String {
|
|||||||
"48;2;\{r};\{g};\{b}"
|
"48;2;\{r};\{g};\{b}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn rgb_bg_code_from_hex(value : String) -> String {
|
fn rgb_bg_code_from_hex(value : String) -> String {
|
||||||
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
let r = hex_pair_to_int(value.unsafe_get(1), value.unsafe_get(2))
|
||||||
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
let g = hex_pair_to_int(value.unsafe_get(3), value.unsafe_get(4))
|
||||||
@@ -598,6 +679,7 @@ fn rgb_bg_code_from_hex(value : String) -> String {
|
|||||||
"48;2;\{r};\{g};\{b}"
|
"48;2;\{r};\{g};\{b}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn inline_style_from_text_style(
|
fn inline_style_from_text_style(
|
||||||
base : InlineStyle,
|
base : InlineStyle,
|
||||||
style : TextStyle,
|
style : TextStyle,
|
||||||
@@ -609,12 +691,21 @@ fn inline_style_from_text_style(
|
|||||||
let normalized = normalize_style_tag_name(value)
|
let normalized = normalize_style_tag_name(value)
|
||||||
match named_color_code(normalized) {
|
match named_color_code(normalized) {
|
||||||
Some(code) => Some((Some(code), Some(normalized)))
|
Some(code) => Some((Some(code), Some(normalized)))
|
||||||
None => if is_hex_color(value) {
|
None =>
|
||||||
|
if is_hex_color(value) {
|
||||||
let basic_name = basic_name_from_hex(value)
|
let basic_name = basic_name_from_hex(value)
|
||||||
Some((
|
Some(
|
||||||
Some(resolve_inline_color_code(formatter, Some(basic_name), rgb_fg_code(value))),
|
(
|
||||||
|
Some(
|
||||||
|
resolve_inline_color_code(
|
||||||
|
formatter,
|
||||||
Some(basic_name),
|
Some(basic_name),
|
||||||
))
|
rgb_fg_code(value),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Some(basic_name),
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -634,12 +725,21 @@ fn inline_style_from_text_style(
|
|||||||
}
|
}
|
||||||
Some((Some(code), Some(bg_name)))
|
Some((Some(code), Some(bg_name)))
|
||||||
}
|
}
|
||||||
None => if is_hex_color(value) {
|
None =>
|
||||||
|
if is_hex_color(value) {
|
||||||
let basic_name = basic_name_from_hex(value)
|
let basic_name = basic_name_from_hex(value)
|
||||||
Some((
|
Some(
|
||||||
Some(resolve_inline_bg_code(formatter, Some(basic_name), rgb_bg_code_from_hex(value))),
|
(
|
||||||
|
Some(
|
||||||
|
resolve_inline_bg_code(
|
||||||
|
formatter,
|
||||||
Some(basic_name),
|
Some(basic_name),
|
||||||
))
|
rgb_bg_code_from_hex(value),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Some(basic_name),
|
||||||
|
),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -647,8 +747,10 @@ fn inline_style_from_text_style(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
match fg {
|
match fg {
|
||||||
Some((next_fg_code, next_fg_name)) => match bg {
|
Some((next_fg_code, next_fg_name)) =>
|
||||||
Some((next_bg_code, next_bg_name)) => Some({
|
match bg {
|
||||||
|
Some((next_bg_code, next_bg_name)) =>
|
||||||
|
Some({
|
||||||
fg_code: next_fg_code,
|
fg_code: next_fg_code,
|
||||||
bg_code: next_bg_code,
|
bg_code: next_bg_code,
|
||||||
fg_basic_name: next_fg_name,
|
fg_basic_name: next_fg_name,
|
||||||
@@ -664,6 +766,7 @@ fn inline_style_from_text_style(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn builtin_text_style_for_tag(tag : String) -> TextStyle? {
|
fn builtin_text_style_for_tag(tag : String) -> TextStyle? {
|
||||||
match normalize_style_tag_name(tag) {
|
match normalize_style_tag_name(tag) {
|
||||||
"black" => Some(text_style(fg=Some("black")))
|
"black" => Some(text_style(fg=Some("black")))
|
||||||
@@ -696,41 +799,63 @@ fn builtin_text_style_for_tag(tag : String) -> TextStyle? {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_registered_text_style(tag : String, formatter : TextFormatter) -> TextStyle? {
|
///|
|
||||||
|
fn resolve_registered_text_style(
|
||||||
|
tag : String,
|
||||||
|
formatter : TextFormatter,
|
||||||
|
) -> TextStyle? {
|
||||||
let normalized = normalize_style_tag_name(tag)
|
let normalized = normalize_style_tag_name(tag)
|
||||||
match formatter.style_markup {
|
match formatter.style_markup {
|
||||||
StyleMarkupMode::Builtin => return builtin_text_style_for_tag(normalized)
|
StyleMarkupMode::Builtin => return builtin_text_style_for_tag(normalized)
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
match formatter.style_tags {
|
match formatter.style_tags {
|
||||||
Some(registry) => match registry.get(normalized) {
|
Some(registry) =>
|
||||||
|
match registry.get(normalized) {
|
||||||
Some(style) => Some(style)
|
Some(style) => Some(style)
|
||||||
None => match global_style_tag_registry().get(normalized) {
|
None =>
|
||||||
|
match global_style_tag_registry().get(normalized) {
|
||||||
Some(style) => Some(style)
|
Some(style) => Some(style)
|
||||||
None => builtin_text_style_for_tag(normalized)
|
None => builtin_text_style_for_tag(normalized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => match global_style_tag_registry().get(normalized) {
|
None =>
|
||||||
|
match global_style_tag_registry().get(normalized) {
|
||||||
Some(style) => Some(style)
|
Some(style) => Some(style)
|
||||||
None => builtin_text_style_for_tag(normalized)
|
None => builtin_text_style_for_tag(normalized)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_inline_tag(style : InlineStyle, tag : String, formatter : TextFormatter) -> InlineStyle? {
|
///|
|
||||||
|
fn apply_inline_tag(
|
||||||
|
style : InlineStyle,
|
||||||
|
tag : String,
|
||||||
|
formatter : TextFormatter,
|
||||||
|
) -> InlineStyle? {
|
||||||
let normalized = normalize_style_tag_name(tag)
|
let normalized = normalize_style_tag_name(tag)
|
||||||
if is_hex_color(tag) {
|
if is_hex_color(tag) {
|
||||||
let basic_name = basic_name_from_hex(tag)
|
let basic_name = basic_name_from_hex(tag)
|
||||||
Some({
|
Some({
|
||||||
..style,
|
..style,
|
||||||
fg_code: Some(resolve_inline_color_code(formatter, Some(basic_name), rgb_fg_code(tag))),
|
fg_code: Some(
|
||||||
|
resolve_inline_color_code(formatter, Some(basic_name), rgb_fg_code(tag)),
|
||||||
|
),
|
||||||
fg_basic_name: Some(basic_name),
|
fg_basic_name: Some(basic_name),
|
||||||
})
|
})
|
||||||
} else if normalized.length() == 10 && normalized.has_prefix("bg:") && is_hex_color(normalized[3:].to_owned()) {
|
} else if normalized.length() == 10 &&
|
||||||
|
normalized.has_prefix("bg:") &&
|
||||||
|
is_hex_color(normalized[3:].to_owned()) {
|
||||||
let basic_name = basic_name_from_hex(normalized[3:].to_owned())
|
let basic_name = basic_name_from_hex(normalized[3:].to_owned())
|
||||||
Some({
|
Some({
|
||||||
..style,
|
..style,
|
||||||
bg_code: Some(resolve_inline_bg_code(formatter, Some(basic_name), rgb_bg_code(normalized))),
|
bg_code: Some(
|
||||||
|
resolve_inline_bg_code(
|
||||||
|
formatter,
|
||||||
|
Some(basic_name),
|
||||||
|
rgb_bg_code(normalized),
|
||||||
|
),
|
||||||
|
),
|
||||||
bg_basic_name: Some(basic_name),
|
bg_basic_name: Some(basic_name),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -741,6 +866,7 @@ fn apply_inline_tag(style : InlineStyle, tag : String, formatter : TextFormatter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn push_plain_segment(
|
fn push_plain_segment(
|
||||||
segments : Array[StyledSegment],
|
segments : Array[StyledSegment],
|
||||||
buffer : StringBuilder,
|
buffer : StringBuilder,
|
||||||
@@ -753,6 +879,7 @@ fn push_plain_segment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn pop_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
fn pop_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
||||||
let normalized = normalize_style_tag_name(tag)
|
let normalized = normalize_style_tag_name(tag)
|
||||||
if stack.length() <= 1 {
|
if stack.length() <= 1 {
|
||||||
@@ -769,6 +896,7 @@ fn pop_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn has_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
fn has_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
||||||
let normalized = normalize_style_tag_name(tag)
|
let normalized = normalize_style_tag_name(tag)
|
||||||
if stack.length() <= 1 {
|
if stack.length() <= 1 {
|
||||||
@@ -782,7 +910,11 @@ fn has_named_style_frame(stack : Array[StyleFrame], tag : String) -> Bool {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_inline_markup(input : String, formatter : TextFormatter) -> Array[StyledSegment] {
|
///|
|
||||||
|
fn parse_inline_markup(
|
||||||
|
input : String,
|
||||||
|
formatter : TextFormatter,
|
||||||
|
) -> Array[StyledSegment] {
|
||||||
let segments : Array[StyledSegment] = []
|
let segments : Array[StyledSegment] = []
|
||||||
let buffer = StringBuilder::new()
|
let buffer = StringBuilder::new()
|
||||||
let stack : Array[StyleFrame] = [{ tag: "", style: default_inline_style() }]
|
let stack : Array[StyleFrame] = [{ tag: "", style: default_inline_style() }]
|
||||||
@@ -845,7 +977,12 @@ fn parse_inline_markup(input : String, formatter : TextFormatter) -> Array[Style
|
|||||||
segments
|
segments
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_styled_text(text : String, formatter : TextFormatter, mode : StyleMarkupMode) -> String {
|
///|
|
||||||
|
fn render_styled_text(
|
||||||
|
text : String,
|
||||||
|
formatter : TextFormatter,
|
||||||
|
mode : StyleMarkupMode,
|
||||||
|
) -> String {
|
||||||
match mode {
|
match mode {
|
||||||
StyleMarkupMode::Disabled => return text
|
StyleMarkupMode::Disabled => return text
|
||||||
_ => ()
|
_ => ()
|
||||||
@@ -860,10 +997,12 @@ fn render_styled_text(text : String, formatter : TextFormatter, mode : StyleMark
|
|||||||
out.to_string()
|
out.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn render_inline_markup(message : String, formatter : TextFormatter) -> String {
|
fn render_inline_markup(message : String, formatter : TextFormatter) -> String {
|
||||||
render_styled_text(message, formatter, formatter.style_markup)
|
render_styled_text(message, formatter, formatter.style_markup)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn level_ansi_code(level : @core.Level) -> String {
|
fn level_ansi_code(level : @core.Level) -> String {
|
||||||
match level {
|
match level {
|
||||||
@core.Level::Trace => "90"
|
@core.Level::Trace => "90"
|
||||||
@@ -874,6 +1013,7 @@ fn level_ansi_code(level : @core.Level) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn fields_to_json(fields : Array[@core.Field]) -> Json {
|
fn fields_to_json(fields : Array[@core.Field]) -> Json {
|
||||||
let obj : Map[String, Json] = {}
|
let obj : Map[String, Json] = {}
|
||||||
for item in fields {
|
for item in fields {
|
||||||
@@ -882,58 +1022,89 @@ fn fields_to_json(fields : Array[@core.Field]) -> Json {
|
|||||||
Json::object(obj)
|
Json::object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn timestamp_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
fn timestamp_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||||
if formatter.show_timestamp && rec.timestamp_ms != 0UL {
|
if formatter.show_timestamp && rec.timestamp_ms != 0UL {
|
||||||
ansi_wrap(rec.timestamp_ms.to_string(), "90", use_ansi_color(formatter.color_mode))
|
ansi_wrap(
|
||||||
|
rec.timestamp_ms.to_string(),
|
||||||
|
"90",
|
||||||
|
use_ansi_color(formatter.color_mode),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn level_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
fn level_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||||
if formatter.show_level {
|
if formatter.show_level {
|
||||||
ansi_wrap(rec.level.label(), level_ansi_code(rec.level), use_ansi_color(formatter.color_mode))
|
ansi_wrap(
|
||||||
|
rec.level.label(),
|
||||||
|
level_ansi_code(rec.level),
|
||||||
|
use_ansi_color(formatter.color_mode),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn target_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
fn target_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||||
if formatter.show_target && rec.target != "" {
|
if formatter.show_target && rec.target != "" {
|
||||||
let rendered = render_styled_text(rec.target, formatter, formatter.target_style_markup)
|
let rendered = render_styled_text(
|
||||||
|
rec.target,
|
||||||
|
formatter,
|
||||||
|
formatter.target_style_markup,
|
||||||
|
)
|
||||||
ansi_wrap(rendered, "34", use_ansi_color(formatter.color_mode))
|
ansi_wrap(rendered, "34", use_ansi_color(formatter.color_mode))
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn format_field_text(field : @core.Field, formatter : TextFormatter) -> String {
|
fn format_field_text(field : @core.Field, formatter : TextFormatter) -> String {
|
||||||
let value = render_styled_text(field.value, formatter, formatter.fields_style_markup)
|
let value = render_styled_text(
|
||||||
|
field.value,
|
||||||
|
formatter,
|
||||||
|
formatter.fields_style_markup,
|
||||||
|
)
|
||||||
"\{field.key}=\{value}"
|
"\{field.key}=\{value}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn fields_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
fn fields_text(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||||
if formatter.show_fields && rec.fields.length() != 0 {
|
if formatter.show_fields && rec.fields.length() != 0 {
|
||||||
let content = rec.fields.map(fn(field) { format_field_text(field, formatter) }).join(formatter.field_separator)
|
let content = rec.fields
|
||||||
|
.map(fn(field) { format_field_text(field, formatter) })
|
||||||
|
.join(formatter.field_separator)
|
||||||
ansi_wrap(content, "35", use_ansi_color(formatter.color_mode))
|
ansi_wrap(content, "35", use_ansi_color(formatter.color_mode))
|
||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
fn render_template(rec : @core.Record, formatter : TextFormatter) -> String {
|
fn render_template(rec : @core.Record, formatter : TextFormatter) -> String {
|
||||||
formatter.template
|
formatter.template
|
||||||
.replace_all(old="{timestamp}", new=timestamp_text(rec, formatter))
|
.replace_all(old="{timestamp}", new=timestamp_text(rec, formatter))
|
||||||
.replace_all(old="{timestamp_ms}", new=timestamp_text(rec, formatter))
|
.replace_all(old="{timestamp_ms}", new=timestamp_text(rec, formatter))
|
||||||
.replace_all(old="{level}", new=level_text(rec, formatter))
|
.replace_all(old="{level}", new=level_text(rec, formatter))
|
||||||
.replace_all(old="{target}", new=target_text(rec, formatter))
|
.replace_all(old="{target}", new=target_text(rec, formatter))
|
||||||
.replace_all(old="{message}", new=render_inline_markup(rec.message, formatter))
|
.replace_all(
|
||||||
|
old="{message}",
|
||||||
|
new=render_inline_markup(rec.message, formatter),
|
||||||
|
)
|
||||||
.replace_all(old="{fields}", new=fields_text(rec, formatter))
|
.replace_all(old="{fields}", new=fields_text(rec, formatter))
|
||||||
.trim()
|
.trim()
|
||||||
.to_owned()
|
.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_text(rec : @core.Record, formatter~ : TextFormatter = text_formatter()) -> String {
|
///|
|
||||||
|
pub fn format_text(
|
||||||
|
rec : @core.Record,
|
||||||
|
formatter? : TextFormatter = text_formatter(),
|
||||||
|
) -> String {
|
||||||
if formatter.template != "" {
|
if formatter.template != "" {
|
||||||
return render_template(rec, formatter)
|
return render_template(rec, formatter)
|
||||||
}
|
}
|
||||||
@@ -957,6 +1128,7 @@ pub fn format_text(rec : @core.Record, formatter~ : TextFormatter = text_formatt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn format_json(rec : @core.Record) -> String {
|
pub fn format_json(rec : @core.Record) -> String {
|
||||||
let obj : Map[String, Json] = {
|
let obj : Map[String, Json] = {
|
||||||
"level": Json::string(rec.level.label()),
|
"level": Json::string(rec.level.label()),
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
"Nanaloveyuki/BitLogger/src/core" @core,
|
"Nanaloveyuki/BitLogger/src/core",
|
||||||
"maria/json_parser" @json_parser,
|
"maria/json_parser",
|
||||||
"moonbitlang/core/env" @env,
|
"moonbitlang/core/env",
|
||||||
"moonbitlang/core/json",
|
"moonbitlang/core/json",
|
||||||
"moonbitlang/core/ref",
|
"moonbitlang/core/ref",
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-12
@@ -1,21 +1,22 @@
|
|||||||
|
///|
|
||||||
pub type RecordPatch = (@core.Record) -> @core.Record
|
pub type RecordPatch = (@core.Record) -> @core.Record
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn identity_patch() -> RecordPatch {
|
pub fn identity_patch() -> RecordPatch {
|
||||||
fn(rec) { rec }
|
fn(rec) { rec }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn set_target(target : String) -> RecordPatch {
|
pub fn set_target(target : String) -> RecordPatch {
|
||||||
fn(rec) {
|
fn(rec) { rec.with_target(target) }
|
||||||
rec.with_target(target)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn prefix_message(prefix : String) -> RecordPatch {
|
pub fn prefix_message(prefix : String) -> RecordPatch {
|
||||||
fn(rec) {
|
fn(rec) { rec.with_message("\{prefix}\{rec.message}") }
|
||||||
rec.with_message("\{prefix}\{rec.message}")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch {
|
pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
if extra_fields.length() == 0 {
|
if extra_fields.length() == 0 {
|
||||||
@@ -28,30 +29,40 @@ pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redact_field(key : String, placeholder~ : String = "***") -> RecordPatch {
|
///|
|
||||||
|
pub fn redact_field(key : String, placeholder? : String = "***") -> RecordPatch {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
rec.with_fields(rec.fields.map(fn(field) {
|
rec.with_fields(
|
||||||
|
rec.fields.map(fn(field) {
|
||||||
if field.key == key {
|
if field.key == key {
|
||||||
field.with_value(placeholder)
|
field.with_value(placeholder)
|
||||||
} else {
|
} else {
|
||||||
field
|
field
|
||||||
}
|
}
|
||||||
}))
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn redact_fields(keys : Array[String], placeholder~ : String = "***") -> RecordPatch {
|
///|
|
||||||
|
pub fn redact_fields(
|
||||||
|
keys : Array[String],
|
||||||
|
placeholder? : String = "***",
|
||||||
|
) -> RecordPatch {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
rec.with_fields(rec.fields.map(fn(field) {
|
rec.with_fields(
|
||||||
|
rec.fields.map(fn(field) {
|
||||||
if keys.contains(field.key) {
|
if keys.contains(field.key) {
|
||||||
field.with_value(placeholder)
|
field.with_value(placeholder)
|
||||||
} else {
|
} else {
|
||||||
field
|
field
|
||||||
}
|
}
|
||||||
}))
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
||||||
fn(rec) {
|
fn(rec) {
|
||||||
let mut current = rec
|
let mut current = rec
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
///|
|
||||||
pub struct RuntimeFileState {
|
pub struct RuntimeFileState {
|
||||||
file : FileSinkState
|
file : FileSinkState
|
||||||
queued : Bool
|
queued : Bool
|
||||||
@@ -5,16 +6,20 @@ pub struct RuntimeFileState {
|
|||||||
dropped_count : Int
|
dropped_count : Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn RuntimeFileState::new(
|
pub fn RuntimeFileState::new(
|
||||||
file : FileSinkState,
|
file : FileSinkState,
|
||||||
queued~ : Bool = false,
|
queued? : Bool = false,
|
||||||
pending_count~ : Int = 0,
|
pending_count? : Int = 0,
|
||||||
dropped_count~ : Int = 0,
|
dropped_count? : Int = 0,
|
||||||
) -> RuntimeFileState {
|
) -> RuntimeFileState {
|
||||||
{ file, queued, pending_count, dropped_count }
|
{ file, queued, pending_count, dropped_count }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_sink_policy_to_json_value(policy : FileSinkPolicy) -> @json_parser.JsonValue {
|
///|
|
||||||
|
fn file_sink_policy_to_json_value(
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {
|
let obj : Map[String, @json_parser.JsonValue] = {
|
||||||
"append": @json_parser.JsonValue::Bool(policy.append),
|
"append": @json_parser.JsonValue::Bool(policy.append),
|
||||||
"auto_flush": @json_parser.JsonValue::Bool(policy.auto_flush),
|
"auto_flush": @json_parser.JsonValue::Bool(policy.auto_flush),
|
||||||
@@ -26,11 +31,18 @@ fn file_sink_policy_to_json_value(policy : FileSinkPolicy) -> @json_parser.JsonV
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_sink_policy_to_json(policy : FileSinkPolicy) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn file_sink_policy_to_json(
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
file_sink_policy_to_json_value(policy)
|
file_sink_policy_to_json_value(policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_file_sink_policy(policy : FileSinkPolicy, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_file_sink_policy(
|
||||||
|
policy : FileSinkPolicy,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = file_sink_policy_to_json_value(policy)
|
let value = file_sink_policy_to_json_value(policy)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
@@ -39,16 +51,27 @@ pub fn stringify_file_sink_policy(policy : FileSinkPolicy, pretty~ : Bool = fals
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_sink_state_to_json_value(state : FileSinkState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
fn file_sink_state_to_json_value(
|
||||||
|
state : FileSinkState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
let obj : Map[String, @json_parser.JsonValue] = {
|
let obj : Map[String, @json_parser.JsonValue] = {
|
||||||
"path": @json_parser.JsonValue::String(state.path),
|
"path": @json_parser.JsonValue::String(state.path),
|
||||||
"available": @json_parser.JsonValue::Bool(state.available),
|
"available": @json_parser.JsonValue::Bool(state.available),
|
||||||
"append": @json_parser.JsonValue::Bool(state.append),
|
"append": @json_parser.JsonValue::Bool(state.append),
|
||||||
"auto_flush": @json_parser.JsonValue::Bool(state.auto_flush),
|
"auto_flush": @json_parser.JsonValue::Bool(state.auto_flush),
|
||||||
"open_failures": @json_parser.JsonValue::Number(state.open_failures.to_double()),
|
"open_failures": @json_parser.JsonValue::Number(
|
||||||
"write_failures": @json_parser.JsonValue::Number(state.write_failures.to_double()),
|
state.open_failures.to_double(),
|
||||||
"flush_failures": @json_parser.JsonValue::Number(state.flush_failures.to_double()),
|
),
|
||||||
"rotation_failures": @json_parser.JsonValue::Number(state.rotation_failures.to_double()),
|
"write_failures": @json_parser.JsonValue::Number(
|
||||||
|
state.write_failures.to_double(),
|
||||||
|
),
|
||||||
|
"flush_failures": @json_parser.JsonValue::Number(
|
||||||
|
state.flush_failures.to_double(),
|
||||||
|
),
|
||||||
|
"rotation_failures": @json_parser.JsonValue::Number(
|
||||||
|
state.rotation_failures.to_double(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
match state.rotation {
|
match state.rotation {
|
||||||
None => obj["rotation"] = @json_parser.JsonValue::Null
|
None => obj["rotation"] = @json_parser.JsonValue::Null
|
||||||
@@ -57,11 +80,16 @@ fn file_sink_state_to_json_value(state : FileSinkState) -> @json_parser.JsonValu
|
|||||||
@json_parser.JsonValue::Object(obj)
|
@json_parser.JsonValue::Object(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||||
file_sink_state_to_json_value(state)
|
file_sink_state_to_json_value(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_file_sink_state(state : FileSinkState, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_file_sink_state(
|
||||||
|
state : FileSinkState,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = file_sink_state_to_json_value(state)
|
let value = file_sink_state_to_json_value(state)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
@@ -70,16 +98,27 @@ pub fn stringify_file_sink_state(state : FileSinkState, pretty~ : Bool = false)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn runtime_file_state_to_json(state : RuntimeFileState) -> @json_parser.JsonValue {
|
///|
|
||||||
|
pub fn runtime_file_state_to_json(
|
||||||
|
state : RuntimeFileState,
|
||||||
|
) -> @json_parser.JsonValue {
|
||||||
@json_parser.JsonValue::Object({
|
@json_parser.JsonValue::Object({
|
||||||
"file": file_sink_state_to_json_value(state.file),
|
"file": file_sink_state_to_json_value(state.file),
|
||||||
"queued": @json_parser.JsonValue::Bool(state.queued),
|
"queued": @json_parser.JsonValue::Bool(state.queued),
|
||||||
"pending_count": @json_parser.JsonValue::Number(state.pending_count.to_double()),
|
"pending_count": @json_parser.JsonValue::Number(
|
||||||
"dropped_count": @json_parser.JsonValue::Number(state.dropped_count.to_double()),
|
state.pending_count.to_double(),
|
||||||
|
),
|
||||||
|
"dropped_count": @json_parser.JsonValue::Number(
|
||||||
|
state.dropped_count.to_double(),
|
||||||
|
),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stringify_runtime_file_state(state : RuntimeFileState, pretty~ : Bool = false) -> String {
|
///|
|
||||||
|
pub fn stringify_runtime_file_state(
|
||||||
|
state : RuntimeFileState,
|
||||||
|
pretty? : Bool = false,
|
||||||
|
) -> String {
|
||||||
let value = runtime_file_state_to_json(state)
|
let value = runtime_file_state_to_json(state)
|
||||||
if pretty {
|
if pretty {
|
||||||
@json_parser.stringify_pretty(value, 2)
|
@json_parser.stringify_pretty(value, 2)
|
||||||
|
|||||||
+29
-14
@@ -1,8 +1,10 @@
|
|||||||
|
///|
|
||||||
pub struct FileRotation {
|
pub struct FileRotation {
|
||||||
max_bytes : Int
|
max_bytes : Int
|
||||||
max_backups : Int
|
max_backups : Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FileSinkState {
|
pub struct FileSinkState {
|
||||||
path : String
|
path : String
|
||||||
available : Bool
|
available : Bool
|
||||||
@@ -15,30 +17,33 @@ pub struct FileSinkState {
|
|||||||
rotation_failures : Int
|
rotation_failures : Int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub struct FileSinkPolicy {
|
pub struct FileSinkPolicy {
|
||||||
append : Bool
|
append : Bool
|
||||||
auto_flush : Bool
|
auto_flush : Bool
|
||||||
rotation : FileRotation?
|
rotation : FileRotation?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSinkPolicy::new(
|
pub fn FileSinkPolicy::new(
|
||||||
append~ : Bool = true,
|
append? : Bool = true,
|
||||||
auto_flush~ : Bool = true,
|
auto_flush? : Bool = true,
|
||||||
rotation~ : FileRotation? = None,
|
rotation? : FileRotation? = None,
|
||||||
) -> FileSinkPolicy {
|
) -> FileSinkPolicy {
|
||||||
{ append, auto_flush, rotation }
|
{ append, auto_flush, rotation }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub fn FileSinkState::new(
|
pub fn FileSinkState::new(
|
||||||
path : String,
|
path : String,
|
||||||
available~ : Bool = false,
|
available? : Bool = false,
|
||||||
append~ : Bool = true,
|
append? : Bool = true,
|
||||||
auto_flush~ : Bool = true,
|
auto_flush? : Bool = true,
|
||||||
rotation~ : FileRotation? = None,
|
rotation? : FileRotation? = None,
|
||||||
open_failures~ : Int = 0,
|
open_failures? : Int = 0,
|
||||||
write_failures~ : Int = 0,
|
write_failures? : Int = 0,
|
||||||
flush_failures~ : Int = 0,
|
flush_failures? : Int = 0,
|
||||||
rotation_failures~ : Int = 0,
|
rotation_failures? : Int = 0,
|
||||||
) -> FileSinkState {
|
) -> FileSinkState {
|
||||||
{
|
{
|
||||||
path,
|
path,
|
||||||
@@ -53,13 +58,23 @@ pub fn FileSinkState::new(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_rotation(max_bytes : Int, max_backups~ : Int = 1) -> FileRotation {
|
///|
|
||||||
|
pub fn file_rotation(max_bytes : Int, max_backups? : Int = 1) -> FileRotation {
|
||||||
{
|
{
|
||||||
max_bytes: if max_bytes <= 0 { 1 } else { max_bytes },
|
max_bytes: if max_bytes <= 0 {
|
||||||
max_backups: if max_backups <= 0 { 1 } else { max_backups },
|
1
|
||||||
|
} else {
|
||||||
|
max_bytes
|
||||||
|
},
|
||||||
|
max_backups: if max_backups <= 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
max_backups
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
pub(all) enum QueueOverflowPolicy {
|
pub(all) enum QueueOverflowPolicy {
|
||||||
DropNewest
|
DropNewest
|
||||||
DropOldest
|
DropOldest
|
||||||
|
|||||||
Reference in New Issue
Block a user