diff --git a/docs/api/.example.md b/docs/api/.example.md new file mode 100644 index 0000000..9768e9b --- /dev/null +++ b/docs/api/.example.md @@ -0,0 +1,152 @@ +--- +name: example-api +group: dev +category: example-group +update-time: 20260512 +description: An example API file to show how to write API doc. +key-word: + - example + - async + - sync + - public + - doc +--- + +**ONE API ONE FILE** + +## Example-api-name + +long discription. + +### Interface + +```moonbit +pub fn function_name(input) -> output {} +``` + +#### input + +- `args : type` - Explain + +#### output + +- `output : type` - Explain + +--- + +> `---` Just when interface has double or more write. Used to separate two different APIs. + + + +> Usedoes not actually need to be written in the official document, it is only used as an example for reference. + +It is not necessary to write the complete function implementation. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- ... + +### How to Use + +Here are some specific examples provided. + +e.g.: + +#### + +> title like: `#### When Need Colorful Formatter` + +When sometime ...: +```moonbit +impl +``` + +In this example, will . + +And . + +#### + +... + +### Error Case + +e.g.: +- If `target` is empty, returns a predicate that always evaluates to false. + +- ... + +... + +### Notes + +Notes are here. + +1. ... + +2. ... + +3. ... + +4. ... + +... + +--- + +## API MARKDOWN YAML HEADER + +> This just is an example, `---` in fact has yaml grammer error. +```yaml +--- +name: example-api +group: dev +category: example-group +update-time: 20260512 +description: An example API file to show how to write API doc. +key-word: + - example + - async + - sync + - public + - doc +--- +``` + +It has 6 key: +- `name` - short and clear api name +- `group` - in static doc template site will use this key to render how to fold and group +- `category` - fastly search category in repo and will be used in template site +- `update-time` - full number use YYYYMMdd(year, month, day) +- `discription` - short discription +- `key-word` - use 2~5 key-words to help user fastly search + +## Title Capitalization Standards + +NO `# ...` + +- `## ...` use `Abcd` +- `### ...` use `Abcd` +- `#### ...` use `abcd` + +NO `##### ...` + diff --git a/docs/api/async-logger-build-config-to-json.md b/docs/api/async-logger-build-config-to-json.md index 0bb1214..c36284c 100644 --- a/docs/api/async-logger-build-config-to-json.md +++ b/docs/api/async-logger-build-config-to-json.md @@ -31,23 +31,6 @@ pub fn async_logger_build_config_to_json( - `JsonValue` - Structured JSON representation of the full async build config. ---- - -e.g.: -```moonbit -pub fn async_logger_build_config_to_json(config : AsyncLoggerBuildConfig) -> @json_parser.JsonValue {} -``` - -#### input - -- `config : AsyncLoggerBuildConfig` - Combined logger and async config. - -#### output - -- `JsonValue` - JSON-exportable build payload. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/async-logger-config-to-json.md b/docs/api/async-logger-config-to-json.md index 0aa077b..7dc5c2e 100644 --- a/docs/api/async-logger-config-to-json.md +++ b/docs/api/async-logger-config-to-json.md @@ -29,23 +29,6 @@ pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.J - `JsonValue` - Structured JSON representation of the async config. ---- - -e.g.: -```moonbit -pub fn async_logger_config_to_json(config : AsyncLoggerConfig) -> @json_parser.JsonValue {} -``` - -#### input - -- `config : AsyncLoggerConfig` - Typed async config. - -#### output - -- `JsonValue` - JSON-exportable async configuration. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/async-logger-config.md b/docs/api/async-logger-config.md new file mode 100644 index 0000000..b04d78d --- /dev/null +++ b/docs/api/async-logger-config.md @@ -0,0 +1,96 @@ +--- +name: async-logger-config +group: api +category: async +update-time: 20260512 +description: Build the queue, batching, linger, and flush policy config used by async loggers. +key-word: + - async + - config + - queue + - public +--- + +## Async-logger-config + +Create an `AsyncLoggerConfig` value describing queue capacity, overflow behavior, batching size, linger timing, and flush policy for async logger construction. + +### Interface + +```moonbit +pub fn AsyncLoggerConfig::new( + max_pending~ : Int = 0, + overflow~ : AsyncOverflowPolicy = AsyncOverflowPolicy::Blocking, + max_batch~ : Int = 1, + linger_ms~ : Int = 0, + flush~ : AsyncFlushPolicy = AsyncFlushPolicy::Never, +) -> AsyncLoggerConfig {} +``` + +#### input + +- `max_pending : Int` - Maximum queued records. +- `overflow : AsyncOverflowPolicy` - Queue overflow strategy. +- `max_batch : Int` - Maximum records drained per batch. +- `linger_ms : Int` - Optional wait window for batch accumulation. +- `flush : AsyncFlushPolicy` - Flush behavior for batch/shutdown phases. + +#### output + +- `AsyncLoggerConfig` - Async runtime config object used by `async_logger(...)` or async build helpers. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `max_batch <= 1` is normalized to `1`. +- `linger_ms < 0` is normalized to `0`. +- `overflow` and `flush` define the most important queue/runtime behavior tradeoffs. +- This type is used directly by `async_logger(...)` and embedded in `AsyncLoggerBuildConfig`. + +### How to Use + +Here are some specific examples provided. + +#### When Tune Async Queue Backlog And Batch Size + +When async behavior should be explicit in code: +```moonbit +let config = AsyncLoggerConfig::new( + max_pending=128, + overflow=AsyncOverflowPolicy::DropOldest, + max_batch=8, + linger_ms=10, + flush=AsyncFlushPolicy::Batch, +) +``` + +In this example, queue pressure, batch size, and flush timing are configured together. + +#### When Export Async Config + +When async policy should be serialized or logged: +```moonbit +println(stringify_async_logger_config(AsyncLoggerConfig::new(max_pending=8))) +``` + +In this example, the config becomes a stable JSON payload. + +### Error Case + +e.g.: +- If `max_batch` is set to `0` or below, runtime config normalizes it to `1`. + +- If `linger_ms` is negative, it is normalized to `0`. + +### Notes + +Notes are here. + +1. This type controls async runtime behavior, not synchronous queue wrapping. + +2. Prefer explicit values for production services so overflow and flush semantics are visible. + +3. Use `stringify_async_logger_config(...)` when exporting diagnostics or generated config. + +4. This API is reused by `AsyncLoggerBuildConfig` rather than duplicated. diff --git a/docs/api/async-logger-state-to-json.md b/docs/api/async-logger-state-to-json.md index b87022c..8f64d08 100644 --- a/docs/api/async-logger-state-to-json.md +++ b/docs/api/async-logger-state-to-json.md @@ -29,23 +29,6 @@ pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.Json - `JsonValue` - Structured JSON representation of the async logger snapshot. ---- - -e.g.: -```moonbit -pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.JsonValue {} -``` - -#### input - -- `state : AsyncLoggerState` - Async logger runtime snapshot. - -#### output - -- `JsonValue` - JSON-exportable state value. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/async-logger-state.md b/docs/api/async-logger-state.md new file mode 100644 index 0000000..849182d --- /dev/null +++ b/docs/api/async-logger-state.md @@ -0,0 +1,86 @@ +--- +name: async-logger-state +group: api +category: async +update-time: 20260512 +description: Read and serialize a full async logger runtime snapshot including queue counters, lifecycle flags, and runtime mode. +key-word: + - async + - state + - diagnostics + - public +--- + +## Async-logger-state + +Read a complete async logger runtime snapshot and serialize it for diagnostics. This API is the preferred way to export queue backlog, dropped counts, lifecycle status, and runtime mode in startup logs, health endpoints, or failure reports. + +### Interface + +```moonbit +pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {} +``` + +#### input + +- `self : AsyncLogger[S]` - The async logger whose runtime snapshot should be read. + +#### output + +- `AsyncLoggerState` - A snapshot containing runtime mode, worker support, queue counts, lifecycle flags, last error, and flush policy. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `AsyncLoggerState` includes `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`. +- `state()` returns a point-in-time snapshot rather than a live handle. +- `async_logger_state_to_json(...)` and `stringify_async_logger_state(...)` convert the snapshot to stable diagnostic output. +- `runtime` embeds the result of `async_runtime_state()` so callers do not need to join separate helpers manually. + +### How to Use + +Here are some specific examples provided. + +#### When Need Startup Diagnostics + +When you want to expose current async logger mode and queue state at startup: +```moonbit +let logger = build_async_logger(config) +println(stringify_async_logger_state(logger.state(), pretty=true)) +``` + +In this example, the snapshot can be printed directly without extra manual formatting. + +And downstream operators can see both runtime mode and queue-related status together. + +#### When Need Failure Investigation Data + +When diagnosing async delivery issues: +```moonbit +let state = logger.state() +if state.has_failed { + println(stringify_async_logger_state(state, pretty=true)) +} +``` + +In this example, the same snapshot object works for conditional diagnostics and serialization. + +### Error Case + +e.g.: +- If no error has occurred, `last_error` is just an empty string. + +- If the queue is empty, `pending_count` is `0`; this is normal and not a special error condition. + +### Notes + +Notes are here. + +1. Prefer this API over manually combining `pending_count()`, `dropped_count()`, and runtime-mode helpers. + +2. Use `pretty=true` when emitting logs for humans and the compact form for machine-oriented payloads. + +3. This snapshot is especially useful in cross-target deployments where async behavior differs by backend. + +4. `AsyncLoggerState` is diagnostics-oriented and does not control the logger. diff --git a/docs/api/async-logger.md b/docs/api/async-logger.md new file mode 100644 index 0000000..6271f6a --- /dev/null +++ b/docs/api/async-logger.md @@ -0,0 +1,105 @@ +--- +name: async-logger +group: api +category: async +update-time: 20260512 +description: Create an async logger with bounded queueing, overflow policy, lifecycle helpers, and background run control. +key-word: + - async + - logger + - queue + - public +--- + +## Async-logger + +Create an `AsyncLogger[S]` on top of a sink and async queue configuration. This API is the main entry for queue-backed async logging, including overflow policy, batching, lifecycle control, and runtime observability. + +### Interface + +```moonbit +pub fn[S] async_logger( + sink : S, + config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(), + min_level~ : @bitlogger.Level = @bitlogger.Level::Info, + target~ : String = "", + flush~ : (S) -> Int = fn(_) { 0 }, +) -> AsyncLogger[S] {} +``` + +#### input + +- `sink : S` - Underlying sink used after queue drain. +- `config : AsyncLoggerConfig` - Queue size, overflow behavior, batching, linger, and flush policy. +- `min_level : Level` - Level gate applied before enqueue. +- `target : String` - Default target for emitted records. +- `flush : (S) -> Int` - Flush callback used by batch/shutdown flush policies. + +#### output + +- `AsyncLogger[S]` - A queue-backed async logger with lifecycle and state helpers. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `async_logger(...)` only builds the logger. Actual background draining is started by `run()`. +- In non-native targets, the implementation uses compatibility behavior while keeping the same public surface. +- `flush` is used only when batch or shutdown policy wants explicit flushing. +- Queue overflow behavior depends on `AsyncOverflowPolicy`. + +### How to Use + +Here are some specific examples provided. + +#### When Need Background Queue Drain + +When your sink should not be written directly on the caller path: +```moonbit +let logger = async_logger(callback_sink(fn(rec) { println(rec.message) })) +@async.with_task_group(group => { + group.spawn_bg(() => logger.run()) + logger.info("hello") + logger.shutdown() +}) +``` + +In this example, the worker drains queued records in the background and `shutdown()` waits for completion. + +And the logging call path stays queue-oriented rather than direct-sink oriented. + +#### When Need Configurable Overflow And Flush Behavior + +When queue semantics matter for service durability and load: +```moonbit +let logger = async_logger( + console_sink(), + config=AsyncLoggerConfig::new( + max_pending=128, + overflow=AsyncOverflowPolicy::DropOldest, + max_batch=8, + flush=AsyncFlushPolicy::Batch, + ), +) +``` + +In this example, queue pressure and flush timing are both explicit. + +### Error Case + +e.g.: +- If the logger is closed, further enqueue attempts stop being normal active logging operations. + +- If queue drain fails internally, runtime state can reflect that through `has_failed()` and `last_error()`. + +### Notes + +Notes are here. + +1. `async_logger(...)` is the async counterpart to `Logger::new(...)`. + +2. Use `state()`, `pending_count()`, and `dropped_count()` for runtime diagnostics. + +3. Prefer `shutdown()` over raw `close()` in normal graceful shutdown paths. + +4. On cross-target code paths, pair this API with `async_runtime_mode()` or `async_runtime_state()` when behavior differences matter. diff --git a/docs/api/async-runtime-mode-label.md b/docs/api/async-runtime-mode-label.md new file mode 100644 index 0000000..f6f17c5 --- /dev/null +++ b/docs/api/async-runtime-mode-label.md @@ -0,0 +1,80 @@ +--- +name: async-runtime-mode-label +group: api +category: async +update-time: 20260512 +description: Convert AsyncRuntimeMode into a stable string label for logs, JSON, and diagnostics. +key-word: + - async + - runtime + - label + - public +--- + +## Async-runtime-mode-label + +Convert `AsyncRuntimeMode` into a stable string label. This helper is useful when runtime mode should be logged, serialized, or exposed through human-readable diagnostics. + +### Interface + +```moonbit +pub fn async_runtime_mode_label(mode : AsyncRuntimeMode) -> String {} +``` + +#### input + +- `mode : AsyncRuntimeMode` - Runtime mode enum value. + +#### output + +- `String` - Stable mode label such as `native_worker` or `compatibility`. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- The returned value is intended for diagnostics and stable output, not just debugging prints. +- It keeps mode serialization logic in one place. +- This helper is used by async runtime JSON helpers. +- Labels are more stable for telemetry and docs than ad hoc manual matching at call sites. + +### How to Use + +Here are some specific examples provided. + +#### When Need A Stable Log Label + +When the mode should be included in structured or plain logs: +```moonbit +println(async_runtime_mode_label(async_runtime_mode())) +``` + +In this example, the label is directly usable in diagnostics. + +#### When Build Custom Serialization + +When callers want to embed the mode into their own payloads: +```moonbit +let label = async_runtime_mode_label(async_runtime_mode()) +``` + +In this example, code gets a stable string without duplicating enum matching logic. + +### Error Case + +e.g.: +- This API assumes a valid `AsyncRuntimeMode` input and does not expose a normal runtime error path. + +- If callers need the whole runtime object rather than a string label, use `async_runtime_state()`. + +### Notes + +Notes are here. + +1. Prefer this helper over repeated manual `match` blocks when only a label is needed. + +2. The label format is especially useful for JSON and telemetry. + +3. This API complements `async_runtime_mode()` and `async_runtime_state()`. + +4. Keep downstream consumers aligned with these stable labels rather than inventing local variants. diff --git a/docs/api/async-runtime-mode.md b/docs/api/async-runtime-mode.md new file mode 100644 index 0000000..eba90d7 --- /dev/null +++ b/docs/api/async-runtime-mode.md @@ -0,0 +1,83 @@ +--- +name: async-runtime-mode +group: api +category: async +update-time: 20260512 +description: Read the current async runtime mode and distinguish native worker behavior from compatibility behavior. +key-word: + - async + - runtime + - mode + - public +--- + +## Async-runtime-mode + +Read the current backend-specific async runtime mode. This API is the narrowest capability probe when you only care whether the current build is running native worker semantics or compatibility behavior. + +### Interface + +```moonbit +pub fn async_runtime_mode() -> AsyncRuntimeMode {} +``` + +#### input + +- `none` - No arguments are required. + +#### output + +- `AsyncRuntimeMode` - Either `NativeWorker` or `Compatibility`. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- The return value is determined by the active backend implementation. +- `async_runtime_mode_label(...)` converts the enum into a stable string value. +- `async_runtime_supports_background_worker()` is a narrower boolean probe built on the same idea. +- This API is intentionally small and useful for lightweight branching. + +### How to Use + +Here are some specific examples provided. + +#### When Need A Small Capability Branch + +When behavior should differ between native worker mode and compatibility mode: +```moonbit +match async_runtime_mode() { + AsyncRuntimeMode::NativeWorker => println("native worker") + AsyncRuntimeMode::Compatibility => println("compat") +} +``` + +In this example, the branch is explicit and readable. + +#### When Need Stable String Output + +When the mode should be included in logs or telemetry labels: +```moonbit +println(async_runtime_mode_label(async_runtime_mode())) +``` + +In this example, the output becomes a stable string instead of an enum pattern-match requirement. + +### Error Case + +e.g.: +- This API does not have a normal runtime failure mode; it reflects the compiled backend behavior. + +- If you need worker support as a direct boolean, use `async_runtime_supports_background_worker()` instead. + +### Notes + +Notes are here. + +1. Use this API for minimal mode branching. + +2. Use `async_runtime_state()` when you also want worker support packaged into one object. + +3. Use `AsyncLogger::state()` when you need logger instance counters and lifecycle flags too. + +4. The enum is intentionally small to keep capability branching simple. diff --git a/docs/api/async-runtime-state-to-json.md b/docs/api/async-runtime-state-to-json.md index 10d7745..9336ce3 100644 --- a/docs/api/async-runtime-state-to-json.md +++ b/docs/api/async-runtime-state-to-json.md @@ -29,23 +29,6 @@ pub fn async_runtime_state_to_json(state : AsyncRuntimeState) -> @json_parser.Js - `JsonValue` - Structured JSON representation of the runtime state. ---- - -e.g.: -```moonbit -pub fn async_runtime_state_to_json(state : AsyncRuntimeState) -> @json_parser.JsonValue {} -``` - -#### input - -- `state : AsyncRuntimeState` - Runtime snapshot to export. - -#### output - -- `JsonValue` - JSON-exportable state object. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/async-runtime-state.md b/docs/api/async-runtime-state.md new file mode 100644 index 0000000..77fd26a --- /dev/null +++ b/docs/api/async-runtime-state.md @@ -0,0 +1,83 @@ +--- +name: async-runtime-state +group: api +category: async +update-time: 20260512 +description: Read and serialize the current backend-specific async runtime mode and worker capability. +key-word: + - async + - runtime + - diagnostics + - public +--- + +## Async-runtime-state + +Read the current backend-specific async runtime state and serialize it for diagnostics. This API focuses on the environment-level async mode rather than any one logger instance. + +### Interface + +```moonbit +pub fn async_runtime_state() -> AsyncRuntimeState {} +``` + +#### input + +- `none` - This API reads the current backend mode and does not require logger input. + +#### output + +- `AsyncRuntimeState` - Runtime snapshot containing `mode` and `background_worker` capability. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `mode` is derived from the active backend implementation. +- `background_worker` tells callers whether native worker semantics are available. +- `async_runtime_state_to_json(...)` and `stringify_async_runtime_state(...)` serialize this state. +- This API is environment-scoped and does not depend on a particular `AsyncLogger` instance. + +### How to Use + +Here are some specific examples provided. + +#### When Need Startup Diagnostics + +When startup logs should reveal async backend behavior: +```moonbit +println(stringify_async_runtime_state(async_runtime_state(), pretty=true)) +``` + +In this example, backend mode is exposed before any logger is started. + +#### When Branch Behavior By Runtime Capability + +When code should react differently depending on worker support: +```moonbit +let runtime = async_runtime_state() +if runtime.background_worker { + println("native worker path") +} +``` + +In this example, branch decisions are based on actual runtime capability instead of assumptions. + +### Error Case + +e.g.: +- This API does not normally expose a dynamic error path; it reports the currently compiled backend behavior. + +- If callers need richer runtime state, they should use `AsyncLogger::state()` on a logger instance instead. + +### Notes + +Notes are here. + +1. Use this API for environment-level diagnostics. + +2. Use `AsyncLogger::state()` for logger-instance diagnostics. + +3. Serialization helpers make this API suitable for health output and startup logs. + +4. This API is especially valuable in cross-target deployments. diff --git a/docs/api/async-runtime-supports-background-worker.md b/docs/api/async-runtime-supports-background-worker.md new file mode 100644 index 0000000..d1dd591 --- /dev/null +++ b/docs/api/async-runtime-supports-background-worker.md @@ -0,0 +1,82 @@ +--- +name: async-runtime-supports-background-worker +group: api +category: async +update-time: 20260512 +description: Return whether the current backend provides native async background worker support. +key-word: + - async + - runtime + - worker + - public +--- + +## Async-runtime-supports-background-worker + +Return a boolean telling callers whether the current backend provides native background worker semantics for `bitlogger_async`. This is the narrowest capability probe when only worker support matters. + +### Interface + +```moonbit +pub fn async_runtime_supports_background_worker() -> Bool {} +``` + +#### input + +- `none` - No explicit arguments are required. + +#### output + +- `Bool` - `true` when native background worker semantics are available, otherwise `false`. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `true` indicates native worker capability. +- `false` indicates compatibility-mode behavior. +- This helper is derived from backend-specific async runtime implementation choice. +- Use it when an enum branch is unnecessary and a boolean capability check is enough. + +### How to Use + +Here are some specific examples provided. + +#### When Need A Simple Capability Branch + +When logic only depends on worker availability: +```moonbit +if async_runtime_supports_background_worker() { + println("native worker available") +} +``` + +In this example, callers avoid a more verbose mode match. + +#### When Add Diagnostics Labels + +When capability should be surfaced in diagnostics: +```moonbit +println(if async_runtime_supports_background_worker() { "worker" } else { "compat" }) +``` + +In this example, a simple boolean can drive compact status output. + +### Error Case + +e.g.: +- This API does not normally fail at runtime; it reflects compiled backend behavior. + +- If you need the exact mode name rather than a boolean, use `async_runtime_mode()` or `async_runtime_state()`. + +### Notes + +Notes are here. + +1. Use this helper for minimal capability checks. + +2. Prefer `async_runtime_state()` when you want the same information in a richer object. + +3. Prefer `AsyncLogger::state()` when logger-instance counters matter too. + +4. This helper is intentionally small and should stay cheap to call. diff --git a/docs/api/build-async-logger.md b/docs/api/build-async-logger.md new file mode 100644 index 0000000..d8ceec6 --- /dev/null +++ b/docs/api/build-async-logger.md @@ -0,0 +1,86 @@ +--- +name: build-async-logger +group: api +category: async +update-time: 20260512 +description: Build an async logger from combined logger and async config without manually wiring the runtime sink. +key-word: + - async + - config + - builder + - public +--- + +## Build-async-logger + +Build an async logger directly from `AsyncLoggerBuildConfig`. This is the config-driven async entry point that bridges synchronous logger config, sink creation, and async queue setup in one call. + +### Interface + +```moonbit +pub fn build_async_logger(config : AsyncLoggerBuildConfig) -> AsyncLogger[@bitlogger.RuntimeSink] {} +``` + +#### input + +- `config : AsyncLoggerBuildConfig` - Combined synchronous logger config plus async queue/flush config. + +#### output + +- `AsyncLogger[RuntimeSink]` - A config-built async logger with runtime sink control preserved. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- The `logger` section is built through the same config machinery used by synchronous configured loggers. +- The resulting async logger inherits `min_level`, `target`, and timestamp behavior from the built synchronous logger. +- File, queue, and formatter choices all come from config rather than direct code-side sink wiring. +- The returned sink type is `RuntimeSink`, which keeps configured control helpers available where relevant. + +### How to Use + +Here are some specific examples provided. + +#### When Need Fully Config-driven Async Bootstrapping + +When your application should build async logging entirely from configuration: +```moonbit +let config = parse_async_logger_build_config_text(raw) catch { + err => return +} +let logger = build_async_logger(config) +``` + +In this example, parsing and async runtime wiring are separated cleanly. + +And the returned logger can immediately be started with `run()`. + +#### When Need Runtime Sink Features After Async Build + +When the sink shape is configured but runtime features still matter: +```moonbit +let logger = build_async_logger(config) +println(stringify_async_logger_state(logger.state(), pretty=true)) +``` + +In this example, the built async logger remains introspectable even though construction was config-driven. + +### Error Case + +e.g.: +- If the config text was invalid, error handling should happen earlier in `parse_async_logger_build_config_text(...)`. + +- If the configured sink shape is unsupported for a specific capability, the resulting runtime behavior follows the existing sink/runtime rules rather than inventing a separate builder-only failure model. + +### Notes + +Notes are here. + +1. Prefer this API when applications externalize both sync sink choice and async queue behavior. + +2. Use `async_logger(...)` directly when you want explicit code-defined sink wiring. + +3. This API is the async counterpart to `build_logger(...)`. + +4. The runtime diagnostics surface remains useful after config-built construction. diff --git a/docs/api/build-logger.md b/docs/api/build-logger.md new file mode 100644 index 0000000..b74487b --- /dev/null +++ b/docs/api/build-logger.md @@ -0,0 +1,90 @@ +--- +name: build-logger +group: api +category: config +update-time: 20260512 +description: Build a configured runtime logger from a LoggerConfig while preserving queue and file control helpers. +key-word: + - logger + - config + - runtime + - public +--- + +## Build-logger + +Build a `ConfiguredLogger` from `LoggerConfig`. This is the main config-to-runtime bridge for synchronous logging and is the builder used before async wrapping in config-driven async flows. + +### Interface + +```moonbit +pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {} +``` + +#### input + +- `config : LoggerConfig` - Fully assembled logger config including level, target, timestamp, sink, and optional queue wrapper. + +#### output + +- `ConfiguredLogger` - A runtime logger backed by `RuntimeSink`, with queue and file control helpers preserved. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `build_logger(...)` constructs the runtime sink shape based on `SinkConfig` and optional queue wrapper. +- The returned logger still supports normal logging methods because `ConfiguredLogger` is `Logger[RuntimeSink]`. +- Queue metrics and file controls remain available through forwarding helpers on the configured logger. +- This API is deterministic and data-driven, making it suitable for bootstrapping from parsed config. + +### How to Use + +Here are some specific examples provided. + +#### When Need Structured Config-first Bootstrapping + +When config is already assembled as typed values: +```moonbit +let logger = build_logger( + LoggerConfig::new( + min_level=Level::Info, + target="svc", + sink=SinkConfig::new(kind=SinkKind::TextConsole), + ), +) +``` + +In this example, no JSON parsing is required because config objects were built directly. + +And the runtime logger is ready immediately. + +#### When Need Config-built Queue Or File Runtime Helpers + +When the sink shape comes from config but runtime controls still matter: +```moonbit +let logger = build_logger(config) +ignore(logger.pending_count()) +ignore(logger.file_runtime_state()) +``` + +In this example, config-driven construction does not remove observability or control helpers. + +### Error Case + +e.g.: +- If config contains a file sink on a non-native backend, callers must still respect backend capability behavior. + +- If queue is not configured, queue-related counters simply reflect the non-queued runtime shape. + +### Notes + +Notes are here. + +1. Use this API when config is already typed as `LoggerConfig`. + +2. Use `parse_and_build_logger(...)` when the starting point is raw JSON text. + +3. `ConfiguredLogger` is still a logger, not a separate opaque runtime object. + +4. This API is the sync runtime builder paired with `build_async_logger(...)` for async use cases. diff --git a/docs/api/fields.md b/docs/api/fields.md new file mode 100644 index 0000000..18a68bb --- /dev/null +++ b/docs/api/fields.md @@ -0,0 +1,81 @@ +--- +name: fields +group: api +category: record +update-time: 20260512 +description: Build structured field arrays ergonomically from key-value tuples. +key-word: + - fields + - record + - helper + - public +--- + +## Fields + +Create an `Array[Field]` from an array of `(String, String)` tuples. This helper reduces repetitive `field(...)` calls when binding context or constructing event fields. + +### Interface + +```moonbit +pub fn fields(entries : Array[(String, String)]) -> Array[Field] {} +``` + +#### input + +- `entries : Array[(String, String)]` - Tuple entries where `.0` is the field key and `.1` is the field value. + +#### output + +- `Array[Field]` - Structured field array ready for logger APIs. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- Each tuple becomes one `Field` value. +- Order is preserved. +- This helper is purely ergonomic and does not add validation beyond normal string handling. +- It is commonly used with `bind(...)`, `with_context_fields(...)`, and per-event field arguments. + +### How to Use + +Here are some specific examples provided. + +#### When Build Reusable Context Fields + +When binding stable metadata to a logger: +```moonbit +let logger = Logger::new(console_sink(), target="audit") + .bind(fields([("service", "billing"), ("scope", "login")])) +``` + +In this example, tuple syntax is shorter and easier to scan than repeated `field(...)` calls. + +#### When Build Small Per-event Field Arrays + +When logging a few fields inline: +```moonbit +logger.info("accepted", fields=fields([("user", "alice"), ("status", "ok")])) +``` + +In this example, the helper keeps call sites compact. + +### Error Case + +e.g.: +- If `entries` is empty, the result is just an empty field array. + +- Duplicate keys are preserved rather than collapsed. + +### Notes + +Notes are here. + +1. Use `field(...)` when only one field is needed. + +2. Use `fields(...)` when tuple syntax improves readability. + +3. This helper preserves order. + +4. No special deduplication or normalization is performed. diff --git a/docs/api/file-rotation.md b/docs/api/file-rotation.md new file mode 100644 index 0000000..5299b3c --- /dev/null +++ b/docs/api/file-rotation.md @@ -0,0 +1,86 @@ +--- +name: file-rotation +group: api +category: sink +update-time: 20260512 +description: Create a size-based file rotation policy for native file sinks. +key-word: + - file + - rotation + - policy + - public +--- + +## File-rotation + +Create a size-based file rotation policy for `file_sink(...)`. This helper defines how large a file may grow before rotation and how many historical backups should be retained. + +### Interface + +```moonbit +pub fn file_rotation(max_bytes : Int, max_backups~ : Int = 1) -> FileRotation {} +``` + +#### input + +- `max_bytes : Int` - Maximum active file size threshold before rotation. +- `max_backups : Int` - Number of retained backup files. + +#### output + +- `FileRotation` - Rotation policy usable by direct file sinks or config-driven sink state. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `max_bytes <= 0` is normalized to `1`. +- `max_backups <= 0` is normalized to `1`. +- Rotation is size-based only. +- This policy is consumed by `file_sink(...)`, file policy helpers, and config-driven file sink assembly. + +### How to Use + +Here are some specific examples provided. + +#### When Need Bounded Local Log Files + +When a file should not grow without limit: +```moonbit +let sink = file_sink( + "app.log", + rotation=Some(file_rotation(1024 * 1024, max_backups=3)), +) +``` + +In this example, the file rotates after the configured size threshold. + +And up to three backup files are retained. + +#### When Need Runtime Policy Composition + +When file sink policy is assembled explicitly: +```moonbit +let policy = FileSinkPolicy::new(rotation=Some(file_rotation(4096, max_backups=2))) +``` + +In this example, rotation can be bundled with append and auto-flush settings. + +### Error Case + +e.g.: +- If `max_bytes` is non-positive, it is clamped to `1`. + +- If `max_backups` is non-positive, it is clamped to `1`. + +### Notes + +Notes are here. + +1. This API defines policy only; it does not open files by itself. + +2. Rotation currently focuses on size thresholds rather than time schedules or compression. + +3. Use with `file_sink(...)` on native-capable backends only. + +4. Policy values can later be inspected through file sink state helpers. diff --git a/docs/api/file-sink.md b/docs/api/file-sink.md new file mode 100644 index 0000000..c920571 --- /dev/null +++ b/docs/api/file-sink.md @@ -0,0 +1,98 @@ +--- +name: file-sink +group: api +category: sink +update-time: 20260512 +description: Create a native file sink with append, auto-flush, rotation, reopen, and runtime observability helpers. +key-word: + - file + - sink + - native + - public +--- + +## File-sink + +Create a native file sink for text-oriented or custom-formatted file logging. This API includes lifecycle controls, rotation configuration, reopen behavior, policy inspection, and failure counters. + +### Interface + +```moonbit +pub fn file_sink( + path : String, + append~ : Bool = true, + auto_flush~ : Bool = true, + rotation~ : FileRotation? = None, + formatter~ : RecordFormatter = fn(rec) { format_text(rec) }, +) -> FileSink {} +``` + +#### input + +- `path : String` - Destination file path. +- `append : Bool` - Whether opening/reopening should append rather than truncate. +- `auto_flush : Bool` - Whether flush is attempted after each write. +- `rotation : FileRotation?` - Optional size-based rotation policy. +- `formatter : RecordFormatter` - Formatter used to render each record before writing. + +#### output + +- `FileSink` - A native-only sink with write, flush, close, reopen, policy, and state helpers. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- This sink is only available on `native/llvm`; use `native_files_supported()` for capability detection. +- `append` is persistent policy state and also affects later reopen behavior. +- `auto_flush` trades durability for more flush work per record. +- Rotation is currently size-based and rename-retention-oriented, not time-based. + +### How to Use + +Here are some specific examples provided. + +#### When Need Persistent Local Logs + +When logs should be written to a host filesystem: +```moonbit +if native_files_supported() { + let sink = file_sink("app.log") + let logger = Logger::new(sink, target="file") + logger.info("started") + ignore(sink.flush()) +} +``` + +In this example, the sink writes normal text-formatted records to `app.log`. + +And capability detection prevents non-native misuse. + +#### When Need Rotation And Runtime Inspection + +When you want bounded local log retention plus observability: +```moonbit +let sink = file_sink("app.log", rotation=Some(file_rotation(1024, max_backups=3))) +let state = sink.state() +``` + +In this example, rotation policy and sink health can both be read through runtime helpers. + +### Error Case + +e.g.: +- If the backend is non-native, file availability is not provided and callers should not expect writes to succeed. + +- If open, write, flush, or rotation fails, the sink records failure counters instead of exposing a large exception surface. + +### Notes + +Notes are here. + +1. Always pair this API with `native_files_supported()` in cross-target code. + +2. Prefer `state()`, `policy()`, and failure counters when integrating diagnostics. + +3. Use `reopen_append()` and `reopen_truncate()` for common recovery flows instead of raw `reopen(...)` where possible. + +4. For config-driven file logging, the mirrored control surface is exposed through `ConfiguredLogger` and `RuntimeSink`. diff --git a/docs/api/logger-child.md b/docs/api/logger-child.md index 3a615b3..cd5c9c0 100644 --- a/docs/api/logger-child.md +++ b/docs/api/logger-child.md @@ -30,24 +30,6 @@ pub fn[S] Logger::child(self : Logger[S], target : String) -> Logger[S] {} - `Logger[S]` - A new logger whose default target is the composed child path. ---- - -e.g.: -```moonbit -pub fn[S] Logger::child(self : Logger[S], target : String) -> Logger[S] {} -``` - -#### input - -- `self : Logger[S]` - Parent logger. -- `target : String` - Child suffix. - -#### output - -- `Logger[S]` - Logger with combined target. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-config-to-json.md b/docs/api/logger-config-to-json.md index 81cc431..b6b5fa1 100644 --- a/docs/api/logger-config-to-json.md +++ b/docs/api/logger-config-to-json.md @@ -29,23 +29,6 @@ pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {} - `JsonValue` - JSON representation of the logger config. ---- - -e.g.: -```moonbit -pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {} -``` - -#### input - -- `config : LoggerConfig` - Config to export. - -#### output - -- `JsonValue` - Structured JSON value. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-config.md b/docs/api/logger-config.md new file mode 100644 index 0000000..e1e9509 --- /dev/null +++ b/docs/api/logger-config.md @@ -0,0 +1,96 @@ +--- +name: logger-config +group: api +category: config +update-time: 20260512 +description: Build the main logger configuration object used by config-driven runtime logger assembly. +key-word: + - logger + - config + - runtime + - public +--- + +## Logger-config + +Create a `LoggerConfig` value describing level, target, timestamp behavior, sink shape, and optional queue wrapping. This is the main typed configuration object consumed by `build_logger(...)` and async build helpers. + +### Interface + +```moonbit +pub fn LoggerConfig::new( + min_level~ : Level = Level::Info, + target~ : String = "", + timestamp~ : Bool = false, + sink~ : SinkConfig = default_sink_config(), + queue~ : QueueConfig? = None, +) -> LoggerConfig {} +``` + +#### input + +- `min_level : Level` - Global level gate. +- `target : String` - Default target namespace. +- `timestamp : Bool` - Whether the built logger should emit timestamps. +- `sink : SinkConfig` - Configured sink shape. +- `queue : QueueConfig?` - Optional synchronous queue wrapper. + +#### output + +- `LoggerConfig` - Main logger configuration object. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `LoggerConfig` is the top-level typed representation for synchronous config-driven logging. +- `sink` describes the final sink shape before optional queue wrapping. +- `queue=None` means no configured synchronous queue layer. +- This same type is embedded into async build config as the synchronous sink/runtime portion. + +### How to Use + +Here are some specific examples provided. + +#### When Build Config In Code Instead Of JSON + +When application bootstrapping prefers typed config values: +```moonbit +let config = LoggerConfig::new( + min_level=Level::Warn, + target="svc", + timestamp=true, + sink=SinkConfig::new(kind=SinkKind::TextConsole), +) +``` + +In this example, the logger configuration is explicit and strongly typed. + +#### When Prepare Config For A Later Builder + +When config is assembled in one place and built later: +```moonbit +let config = LoggerConfig::new(queue=Some(QueueConfig::new(16))) +let logger = build_logger(config) +``` + +In this example, the config object becomes the handoff boundary between assembly and runtime construction. + +### Error Case + +e.g.: +- If `sink` describes a capability-limited backend shape such as native file output on a non-native target, later runtime behavior still follows backend support rules. + +- If `target` is empty, the configuration is still valid. + +### Notes + +Notes are here. + +1. This is the core typed config object for sync logger assembly. + +2. Prefer this API when config is generated in code rather than parsed from text. + +3. Use `logger_config_to_json(...)` and `stringify_logger_config(...)` for export. + +4. `AsyncLoggerBuildConfig` reuses this type rather than inventing a second sync logger schema. diff --git a/docs/api/logger-new.md b/docs/api/logger-new.md new file mode 100644 index 0000000..a21edcb --- /dev/null +++ b/docs/api/logger-new.md @@ -0,0 +1,87 @@ +--- +name: logger-new +group: api +category: logging +update-time: 20260512 +description: Create a typed logger with level filtering, target binding, and optional later composition. +key-word: + - logger + - sync + - public + - target +--- + +## Logger-new + +Create a `Logger[S]` from any sink implementation. This is the main entry for synchronous logging pipelines and the base object used by most chainable helpers such as `with_context_fields(...)`, `with_filter(...)`, `with_patch(...)`, and `with_queue(...)`. + +### Interface + +```moonbit +pub fn[S] Logger::new(sink : S, min_level~ : Level = Level::Info, target~ : String = "") -> Logger[S] {} +``` + +#### input + +- `sink : S` - Any sink value implementing the `Sink` trait, such as `console_sink()`, `json_console_sink()`, `file_sink(...)`, or a composed sink. +- `min_level : Level` - Minimum enabled level. Messages below this threshold are ignored. +- `target : String` - Default target attached to emitted records when `log(...)` does not override it. + +#### output + +- `Logger[S]` - A typed logger that keeps the original sink type and can be further composed. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- `Logger::new(...)` does not mutate the sink. It stores the sink value as part of the returned logger. +- `min_level` applies before any sink write occurs. +- `target` is just a default value. Later calls may override it with `with_target(...)`, `child(...)`, or `log(..., target=...)`. +- `timestamp` is disabled by default and is only enabled through `with_timestamp()`. + +### How to Use + +Here are some specific examples provided. + +#### When Create Basic Application Logger + +When you need a simple typed logger with a default target: +```moonbit +let logger = Logger::new(console_sink(), min_level=Level::Info, target="app") +logger.info("started") +``` + +In this example, `logger` will emit `INFO` and above to the console with target `app`. + +And later composition still preserves the typed logger workflow. + +#### When Start A Composed Logging Pipeline + +When you want to build a richer logging chain from a single root logger: +```moonbit +let logger = Logger::new(text_console_sink(text_formatter()), target="service") + .with_timestamp() + .with_context_fields([field("service", "billing")]) +``` + +In this example, the root logger becomes the stable base for additional context and formatting features. + +### Error Case + +e.g.: +- If `min_level` is set too high, lower-severity records are intentionally dropped. + +- If `target` is empty, records are still valid and simply omit the target unless later overridden. + +### Notes + +Notes are here. + +1. This API is synchronous and does not create buffering or background execution by itself. + +2. The returned sink type stays visible in `Logger[S]`, which is useful for typed composition. + +3. Prefer `Logger::new(...)` over global helpers when you want explicit control over sink, target, and level. + +4. `Logger::new(...)` is the correct starting point for both public app logging and internal composed sink pipelines. diff --git a/docs/api/logger-with-context-fields.md b/docs/api/logger-with-context-fields.md new file mode 100644 index 0000000..cdb3ca8 --- /dev/null +++ b/docs/api/logger-with-context-fields.md @@ -0,0 +1,88 @@ +--- +name: logger-with-context-fields +group: api +category: logging +update-time: 20260512 +description: Attach reusable structured fields to a logger so every emitted record inherits them. +key-word: + - logger + - fields + - context + - public +--- + +## Logger-with-context-fields + +Bind shared structured fields to a logger. This is the standard way to attach stable metadata such as service name, component, region, request scope, or subsystem identity without repeating them for every log call. + +### Interface + +```moonbit +pub fn[S] Logger::with_context_fields(self : Logger[S], fields : Array[Field]) -> Logger[ContextSink[S]] {} +``` + +#### input + +- `self : Logger[S]` - The base logger that should gain shared fields. +- `fields : Array[Field]` - Structured fields that will be prepended to each emitted record. + +#### output + +- `Logger[ContextSink[S]]` - A new logger wrapping the original sink with context-field merging behavior. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- Context fields are merged at write time, not by mutating previously created records. +- When a log call also passes per-record fields, the context fields are placed before those per-call fields. +- This API returns a new typed logger wrapper; it does not mutate the original logger variable. +- `bind(...)` is an ergonomic alias for this same behavior. + +### How to Use + +Here are some specific examples provided. + +#### When Need Stable Service Metadata + +When every record from a logger should carry service-level metadata: +```moonbit +let logger = Logger::new(console_sink(), target="billing") + .with_context_fields([field("service", "billing"), field("region", "cn")]) + +logger.info("started") +``` + +In this example, both `service` and `region` are automatically included on every record. + +And callers only need to provide fields that actually vary per event. + +#### When Build Child Loggers For Subsystems + +When a subsystem has both a target and fixed fields: +```moonbit +let worker = Logger::new(console_sink(), target="app") + .child("worker") + .with_context_fields([field("component", "worker")]) +``` + +In this example, target composition and field binding stay separate but work together cleanly. + +### Error Case + +e.g.: +- If `fields` is empty, the logger remains valid and just adds no extra metadata. + +- If duplicate field keys are provided, all fields are still emitted; conflict handling is left to the consumer/formatter side. + +### Notes + +Notes are here. + +1. Use this for stable metadata, not highly dynamic event-specific values. + +2. Prefer `fields([("k", "v")])` when you want a more ergonomic call site. + +3. This API composes naturally with `with_filter(...)`, `with_patch(...)`, and `with_queue(...)`. + +4. If you want an alias with the same semantics, use `bind(...)`. diff --git a/docs/api/logger-with-filter.md b/docs/api/logger-with-filter.md index 671c115..6b8763e 100644 --- a/docs/api/logger-with-filter.md +++ b/docs/api/logger-with-filter.md @@ -30,24 +30,6 @@ pub fn[S] Logger::with_filter(self : Logger[S], predicate : (Record) -> Bool) -> - `Logger[FilterSink[S]]` - A new logger that only forwards matching records. ---- - -e.g.: -```moonbit -pub fn[S] Logger::with_filter(self : Logger[S], predicate : (Record) -> Bool) -> Logger[FilterSink[S]] {} -``` - -#### input - -- `self : Logger[S]` - Logger to filter. -- `predicate : (Record) -> Bool` - Acceptance rule. - -#### output - -- `Logger[FilterSink[S]]` - Logger with predicate filtering. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-with-min-level.md b/docs/api/logger-with-min-level.md index a9c19b4..7b8a542 100644 --- a/docs/api/logger-with-min-level.md +++ b/docs/api/logger-with-min-level.md @@ -30,24 +30,6 @@ pub fn[S] Logger::with_min_level(self : Logger[S], min_level : Level) -> Logger[ - `Logger[S]` - A new logger value carrying the updated threshold. ---- - -e.g.: -```moonbit -pub fn[S] Logger::with_min_level(self : Logger[S], min_level : Level) -> Logger[S] {} -``` - -#### input - -- `self : Logger[S]` - Current logger. -- `min_level : Level` - New threshold. - -#### output - -- `Logger[S]` - Level-updated logger. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-with-patch.md b/docs/api/logger-with-patch.md index 2e9bcc1..7f26ddf 100644 --- a/docs/api/logger-with-patch.md +++ b/docs/api/logger-with-patch.md @@ -30,24 +30,6 @@ pub fn[S] Logger::with_patch(self : Logger[S], patch : RecordPatch) -> Logger[Pa - `Logger[PatchSink[S]]` - A new logger that rewrites emitted records. ---- - -e.g.: -```moonbit -pub fn[S] Logger::with_patch(self : Logger[S], patch : RecordPatch) -> Logger[PatchSink[S]] {} -``` - -#### input - -- `self : Logger[S]` - Logger to transform. -- `patch : RecordPatch` - Rewrite logic. - -#### output - -- `Logger[PatchSink[S]]` - Logger with transformation behavior. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-with-queue.md b/docs/api/logger-with-queue.md index 052fd76..5dfe58b 100644 --- a/docs/api/logger-with-queue.md +++ b/docs/api/logger-with-queue.md @@ -35,24 +35,6 @@ pub fn[S] Logger::with_queue( - `Logger[QueuedSink[S]]` - A logger using an explicit synchronous queue wrapper. ---- - -e.g.: -```moonbit -pub fn[S] Logger::with_queue(self : Logger[S], max_pending~ : Int = 0, overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest) -> Logger[QueuedSink[S]] {} -``` - -#### input - -- `max_pending : Int` - Queue bound. -- `overflow : QueueOverflowPolicy` - Backlog overflow behavior. - -#### output - -- `Logger[QueuedSink[S]]` - Queue-wrapped logger. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-with-target.md b/docs/api/logger-with-target.md index 52928dc..29dfa1c 100644 --- a/docs/api/logger-with-target.md +++ b/docs/api/logger-with-target.md @@ -30,24 +30,6 @@ pub fn[S] Logger::with_target(self : Logger[S], target : String) -> Logger[S] {} - `Logger[S]` - A new logger value carrying the updated target. ---- - -e.g.: -```moonbit -pub fn[S] Logger::with_target(self : Logger[S], target : String) -> Logger[S] {} -``` - -#### input - -- `self : Logger[S]` - Current logger. -- `target : String` - Replacement target. - -#### output - -- `Logger[S]` - Retargeted logger. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/logger-with-timestamp.md b/docs/api/logger-with-timestamp.md index ecdc14d..894f6aa 100644 --- a/docs/api/logger-with-timestamp.md +++ b/docs/api/logger-with-timestamp.md @@ -30,24 +30,6 @@ pub fn[S] Logger::with_timestamp(self : Logger[S], enabled~ : Bool = true) -> Lo - `Logger[S]` - A new logger value with updated timestamp behavior. ---- - -e.g.: -```moonbit -pub fn[S] Logger::with_timestamp(self : Logger[S], enabled~ : Bool = true) -> Logger[S] {} -``` - -#### input - -- `self : Logger[S]` - Current logger. -- `enabled : Bool` - Timestamp toggle. - -#### output - -- `Logger[S]` - Logger with updated timestamp behavior. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/parse-and-build-logger.md b/docs/api/parse-and-build-logger.md new file mode 100644 index 0000000..bf0aafb --- /dev/null +++ b/docs/api/parse-and-build-logger.md @@ -0,0 +1,93 @@ +--- +name: parse-and-build-logger +group: api +category: config +update-time: 20260512 +description: Parse logger JSON config and immediately build a runtime logger with a stable control surface. +key-word: + - config + - logger + - json + - public +--- + +## Parse-and-build-logger + +Parse a JSON logger definition and build a ready-to-use `ConfiguredLogger`. This is the most direct API when configuration is loaded from files, environment-derived JSON, or external settings systems. + +### Interface + +```moonbit +pub fn parse_and_build_logger(input : String) -> ConfiguredLogger raise ConfigError {} +``` + +#### input + +- `input : String` - JSON text following the supported `LoggerConfig` schema. + +#### output + +- `ConfiguredLogger` - A runtime logger with normal logging methods plus queue/file control helpers. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- Parsing and building are done in one step, which is useful when you do not need to inspect the intermediate `LoggerConfig`. +- The returned `ConfiguredLogger` is just `Logger[RuntimeSink]`, so it still supports regular logging calls. +- Queue wrapping and file control helpers remain available after config assembly. +- Errors are surfaced as `ConfigError` rather than silent fallback. + +### How to Use + +Here are some specific examples provided. + +#### When Load Logger From JSON Text + +When configuration comes from a file, environment variable, or settings service: +```moonbit +let logger = parse_and_build_logger( + "{\"min_level\":\"info\",\"target\":\"api\",\"sink\":{\"kind\":\"text_console\"}}", +) catch { + err => { + ignore(err) + return + } +} +``` + +In this example, config parsing and logger construction happen in one place. + +And the resulting value can immediately emit logs. + +#### When Need Config-built File Or Queue Controls + +When the sink shape is chosen by config but runtime introspection is still required: +```moonbit +let logger = parse_and_build_logger(raw) catch { + err => return +} +ignore(logger.pending_count()) +ignore(logger.file_runtime_state()) +``` + +In this example, the configured runtime surface is still operational after building. + +### Error Case + +e.g.: +- If `input` is not valid JSON, a `ConfigError` is raised. + +- If supported keys have wrong types or unsupported enum text, a `ConfigError` is raised. + +### Notes + +Notes are here. + +1. Use `parse_logger_config_text(...)` first if you want to validate and inspect config separately. + +2. Prefer this API for app bootstrapping paths that read config once and then construct the runtime logger. + +3. `ConfiguredLogger` keeps queue and file helper methods, so config-driven logging does not lose control surface. + +4. Keep the JSON schema limited to supported built-in sink shapes when designing external config files. diff --git a/docs/api/parse-async-logger-build-config-text.md b/docs/api/parse-async-logger-build-config-text.md new file mode 100644 index 0000000..2eacdd6 --- /dev/null +++ b/docs/api/parse-async-logger-build-config-text.md @@ -0,0 +1,86 @@ +--- +name: parse-async-logger-build-config-text +group: api +category: async +update-time: 20260512 +description: Parse combined sync logger and async runtime JSON into a typed async build configuration. +key-word: + - async + - parse + - config + - public +--- + +## Parse-async-logger-build-config-text + +Parse JSON text into `AsyncLoggerBuildConfig`. This API validates both the synchronous logger portion and the async queue/runtime portion before any async logger is built. + +### Interface + +```moonbit +pub fn parse_async_logger_build_config_text(input : String) -> AsyncLoggerBuildConfig raise {} +``` + +#### input + +- `input : String` - JSON text containing `logger` and `async_config` sections. + +#### output + +- `AsyncLoggerBuildConfig` - Typed build config ready for `build_async_logger(...)` or `build_async_text_logger(...)`. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- The JSON root is split into `logger` and `async_config`. +- `logger` reuses the same synchronous config schema parsed by `parse_logger_config_text(...)`. +- `async_config` is parsed through `parse_async_logger_config_text(...)`. +- This API separates validation from actual async runtime construction. + +### How to Use + +Here are some specific examples provided. + +#### When Need Config-driven Async Bootstrapping + +When both sink config and async runtime config come from JSON: +```moonbit +let config = parse_async_logger_build_config_text(raw) catch { + err => return +} +let logger = build_async_logger(config) +``` + +In this example, parsing and runtime construction remain separate and testable. + +#### When Need To Inspect Async Build Config Before Use + +When config should be validated or reviewed before build: +```moonbit +let config = parse_async_logger_build_config_text(raw) catch { + err => return +} +println(config.logger.target) +``` + +In this example, parsed sync and async sections can be inspected independently. + +### Error Case + +e.g.: +- If the root is not an object, parsing fails. + +- If either `logger` or `async_config` contains invalid schema values, parsing fails through the underlying config parsers. + +### Notes + +Notes are here. + +1. Use this API when async build config is stored as JSON. + +2. Use `AsyncLoggerBuildConfig::new(...)` when assembling config directly in code. + +3. Pair this API with `build_async_logger(...)` after validation. + +4. The split `logger` plus `async_config` shape keeps sync and async concerns explicit. diff --git a/docs/api/parse-logger-config-text.md b/docs/api/parse-logger-config-text.md new file mode 100644 index 0000000..82dfb80 --- /dev/null +++ b/docs/api/parse-logger-config-text.md @@ -0,0 +1,86 @@ +--- +name: parse-logger-config-text +group: api +category: config +update-time: 20260512 +description: Parse raw JSON text into a typed LoggerConfig without building the runtime logger yet. +key-word: + - parse + - config + - json + - public +--- + +## Parse-logger-config-text + +Parse JSON text into a typed `LoggerConfig`. This API is useful when you want validation and inspection of config data before turning it into a runtime logger. + +### Interface + +```moonbit +pub fn parse_logger_config_text(input : String) -> LoggerConfig raise ConfigError {} +``` + +#### input + +- `input : String` - Raw JSON text matching the supported logger config schema. + +#### output + +- `LoggerConfig` - Parsed typed configuration value. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- Parsing is separated from runtime construction. +- This API is ideal for validating, editing, or inspecting config values before calling `build_logger(...)`. +- Supported keys are intentionally constrained to stable built-in sink shapes and formatter options. +- The error surface is `ConfigError` rather than silent fallback behavior. + +### How to Use + +Here are some specific examples provided. + +#### When Need Validation Before Runtime Build + +When config should be reviewed before creating the logger: +```moonbit +let config = parse_logger_config_text(raw) catch { + err => return +} +let logger = build_logger(config) +``` + +In this example, parsing and building remain separate phases. + +#### When Need To Inspect Parsed Values + +When config should be normalized into typed values first: +```moonbit +let config = parse_logger_config_text(raw) catch { + err => return +} +println(config.target) +``` + +In this example, the parsed object can be inspected or rewritten before runtime use. + +### Error Case + +e.g.: +- If `input` is invalid JSON, parsing raises `ConfigError`. + +- If supported fields have wrong types or unsupported enum text, parsing raises `ConfigError`. + +### Notes + +Notes are here. + +1. Prefer this API when you need typed config inspection before building. + +2. Prefer `parse_and_build_logger(...)` when one-step bootstrapping is enough. + +3. Keep external config files aligned with the supported stable schema. + +4. Parsed config remains reusable across multiple runtime builders if needed. diff --git a/docs/api/queue-config-to-json.md b/docs/api/queue-config-to-json.md index 6168e06..ddb3c27 100644 --- a/docs/api/queue-config-to-json.md +++ b/docs/api/queue-config-to-json.md @@ -29,23 +29,6 @@ pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {} - `JsonValue` - Structured JSON representation of the queue config. ---- - -e.g.: -```moonbit -pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {} -``` - -#### input - -- `queue : QueueConfig` - Queue settings to export. - -#### output - -- `JsonValue` - JSON-exportable queue object. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/queue-config.md b/docs/api/queue-config.md new file mode 100644 index 0000000..e2722ac --- /dev/null +++ b/docs/api/queue-config.md @@ -0,0 +1,85 @@ +--- +name: queue-config +group: api +category: config +update-time: 20260512 +description: Build a serializable queue wrapper config for configured synchronous loggers. +key-word: + - queue + - config + - json + - public +--- + +## Queue-config + +Create a `QueueConfig` value for config-driven synchronous queue wrapping. This API is used inside `LoggerConfig` when the final runtime sink should be wrapped by a bounded synchronous queue. + +### Interface + +```moonbit +pub fn QueueConfig::new( + max_pending : Int, + overflow~ : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest, +) -> QueueConfig {} +``` + +#### input + +- `max_pending : Int` - Queue capacity used by the configured queue wrapper. +- `overflow : QueueOverflowPolicy` - Overflow strategy for full queues. + +#### output + +- `QueueConfig` - Queue configuration value suitable for `LoggerConfig` or JSON serialization helpers. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- This config is used by `build_logger(...)` and `parse_and_build_logger(...)` when `queue` is present in `LoggerConfig`. +- It configures the synchronous `QueuedSink`, not the async adapter package. +- The queue remains explicit and drain-based. +- Overflow behavior is limited to the supported queue policies. + +### How to Use + +Here are some specific examples provided. + +#### When Need Config-driven Bounded Queueing + +When runtime queue wrapping should be described as config: +```moonbit +let queue = QueueConfig::new(32, overflow=QueueOverflowPolicy::DropOldest) +let config = LoggerConfig::new(queue=Some(queue)) +``` + +In this example, the queue policy is expressed as data and later consumed by the runtime builder. + +#### When Need JSON Export For Tooling + +When queue policy should be exported or persisted: +```moonbit +println(stringify_queue_config(QueueConfig::new(8))) +``` + +In this example, the queue config is converted into a stable JSON representation. + +### Error Case + +e.g.: +- If `max_pending` is too small, configured runtime drops may happen frequently under bursty load. + +- If queue config is omitted from `LoggerConfig`, no synchronous queue wrapper is added. + +### Notes + +Notes are here. + +1. This API is for config-driven queue wrapping, not `bitlogger_async`. + +2. Use `Logger::with_queue(...)` when you want code-side queue composition instead of config. + +3. Pair with `stringify_queue_config(...)` when inspecting generated config output. + +4. Queue capacity policy should be chosen based on expected burst size and acceptable loss behavior. diff --git a/docs/api/sink-config-to-json.md b/docs/api/sink-config-to-json.md index edae084..5d4d2c6 100644 --- a/docs/api/sink-config-to-json.md +++ b/docs/api/sink-config-to-json.md @@ -29,23 +29,6 @@ pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {} - `JsonValue` - JSON representation of the sink configuration. ---- - -e.g.: -```moonbit -pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {} -``` - -#### input - -- `config : SinkConfig` - Sink definition. - -#### output - -- `JsonValue` - Structured JSON sink value. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/sink-config.md b/docs/api/sink-config.md new file mode 100644 index 0000000..e578d37 --- /dev/null +++ b/docs/api/sink-config.md @@ -0,0 +1,99 @@ +--- +name: sink-config +group: api +category: config +update-time: 20260512 +description: Build a typed sink configuration for config-driven logger assembly. +key-word: + - sink + - config + - file + - public +--- + +## Sink-config + +Create a `SinkConfig` value describing the concrete sink shape used by config-driven logger builders. This API selects between console, JSON console, text console, and file-based sink assembly while also carrying sink-specific settings. + +### Interface + +```moonbit +pub fn SinkConfig::new( + kind~ : SinkKind = SinkKind::Console, + path~ : String = "", + append~ : Bool = true, + auto_flush~ : Bool = true, + rotation~ : FileRotation? = None, + text_formatter~ : TextFormatterConfig = default_text_formatter_config(), +) -> SinkConfig {} +``` + +#### input + +- `kind : SinkKind` - Sink variant such as `Console`, `JsonConsole`, `TextConsole`, or `File`. +- `path : String` - File path used when `kind=File`. +- `append : Bool` - File append policy. +- `auto_flush : Bool` - File auto-flush policy. +- `rotation : FileRotation?` - Optional file rotation policy. +- `text_formatter : TextFormatterConfig` - Formatter config used by text console or file text rendering. + +#### output + +- `SinkConfig` - Typed sink configuration used by `LoggerConfig`. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- One config type is used for all supported built-in sink shapes. +- File-only options are stored even though only `kind=File` actually consumes them. +- Text formatter config is always present, making text-driven sink configuration simpler and stable. +- This type is consumed by `build_logger(...)` and `parse_and_build_logger(...)`. + +### How to Use + +Here are some specific examples provided. + +#### When Build A Text Console Config + +When runtime output should be text-formatted through config: +```moonbit +let sink = SinkConfig::new( + kind=SinkKind::TextConsole, + text_formatter=TextFormatterConfig::new(show_timestamp=false), +) +``` + +In this example, the formatter choice is embedded directly into sink config. + +#### When Build A File Sink Config + +When file behavior should be data-driven: +```moonbit +let sink = SinkConfig::new( + kind=SinkKind::File, + path="app.log", + rotation=Some(file_rotation(1024, max_backups=2)), +) +``` + +In this example, file location and retention policy are part of the same sink definition. + +### Error Case + +e.g.: +- If `kind=File` but `path` is empty, the config object is still constructible, but runtime usage should be evaluated carefully. + +- If `kind` is non-file, file-specific options may simply be unused by the runtime builder. + +### Notes + +Notes are here. + +1. This type is sink-shape configuration, not the runtime sink itself. + +2. Use `sink_config_to_json(...)` and `stringify_sink_config(...)` for export. + +3. Prefer `SinkConfig::new(...)` over raw JSON when config is assembled programmatically. + +4. `LoggerConfig` embeds exactly one `SinkConfig` plus an optional outer queue config. diff --git a/docs/api/stringify-async-logger-build-config.md b/docs/api/stringify-async-logger-build-config.md index 04823e2..b10962f 100644 --- a/docs/api/stringify-async-logger-build-config.md +++ b/docs/api/stringify-async-logger-build-config.md @@ -33,24 +33,6 @@ pub fn stringify_async_logger_build_config( - `String` - Serialized JSON text for the full build config. ---- - -e.g.: -```moonbit -pub fn stringify_async_logger_build_config(config : AsyncLoggerBuildConfig, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `config : AsyncLoggerBuildConfig` - Build config to stringify. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - JSON text. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-async-logger-config.md b/docs/api/stringify-async-logger-config.md index 0e9aa69..d902eea 100644 --- a/docs/api/stringify-async-logger-config.md +++ b/docs/api/stringify-async-logger-config.md @@ -30,24 +30,6 @@ pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool - `String` - Serialized JSON text for the async config. ---- - -e.g.: -```moonbit -pub fn stringify_async_logger_config(config : AsyncLoggerConfig, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `config : AsyncLoggerConfig` - Config to stringify. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - JSON text. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-async-logger-state.md b/docs/api/stringify-async-logger-state.md index 61e8d6c..b6c128a 100644 --- a/docs/api/stringify-async-logger-state.md +++ b/docs/api/stringify-async-logger-state.md @@ -33,24 +33,6 @@ pub fn stringify_async_logger_state( - `String` - JSON text for the async logger snapshot. ---- - -e.g.: -```moonbit -pub fn stringify_async_logger_state(state : AsyncLoggerState, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `state : AsyncLoggerState` - Snapshot to serialize. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - Serialized JSON text. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-async-runtime-state.md b/docs/api/stringify-async-runtime-state.md index 001f377..2e10254 100644 --- a/docs/api/stringify-async-runtime-state.md +++ b/docs/api/stringify-async-runtime-state.md @@ -33,24 +33,6 @@ pub fn stringify_async_runtime_state( - `String` - Serialized JSON text for the runtime state. ---- - -e.g.: -```moonbit -pub fn stringify_async_runtime_state(state : AsyncRuntimeState, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `state : AsyncRuntimeState` - State to stringify. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - JSON text. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-logger-config.md b/docs/api/stringify-logger-config.md index fc6f3a2..6fcb42a 100644 --- a/docs/api/stringify-logger-config.md +++ b/docs/api/stringify-logger-config.md @@ -30,24 +30,6 @@ pub fn stringify_logger_config(config : LoggerConfig, pretty~ : Bool = false) -> - `String` - Serialized logger config JSON. ---- - -e.g.: -```moonbit -pub fn stringify_logger_config(config : LoggerConfig, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `config : LoggerConfig` - Logger config value. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - JSON string. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-queue-config.md b/docs/api/stringify-queue-config.md index aaf3e84..1aa43b2 100644 --- a/docs/api/stringify-queue-config.md +++ b/docs/api/stringify-queue-config.md @@ -30,24 +30,6 @@ pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> St - `String` - Serialized JSON text for the queue config. ---- - -e.g.: -```moonbit -pub fn stringify_queue_config(queue : QueueConfig, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `queue : QueueConfig` - Config to stringify. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - JSON text. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-sink-config.md b/docs/api/stringify-sink-config.md index f865762..37bc661 100644 --- a/docs/api/stringify-sink-config.md +++ b/docs/api/stringify-sink-config.md @@ -30,24 +30,6 @@ pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> Str - `String` - Serialized sink config JSON. ---- - -e.g.: -```moonbit -pub fn stringify_sink_config(config : SinkConfig, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `config : SinkConfig` - Sink config value. -- `pretty : Bool` - Pretty-print option. - -#### output - -- `String` - JSON string. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/stringify-text-formatter-config.md b/docs/api/stringify-text-formatter-config.md index adde7c8..d96b830 100644 --- a/docs/api/stringify-text-formatter-config.md +++ b/docs/api/stringify-text-formatter-config.md @@ -33,24 +33,6 @@ pub fn stringify_text_formatter_config( - `String` - Serialized JSON text for the formatter config. ---- - -e.g.: -```moonbit -pub fn stringify_text_formatter_config(config : TextFormatterConfig, pretty~ : Bool = false) -> String {} -``` - -#### input - -- `config : TextFormatterConfig` - Config to stringify. -- `pretty : Bool` - Pretty-print flag. - -#### output - -- `String` - JSON text. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/target-has-prefix.md b/docs/api/target-has-prefix.md new file mode 100644 index 0000000..827c4ca --- /dev/null +++ b/docs/api/target-has-prefix.md @@ -0,0 +1,86 @@ +--- +name: target-has-prefix +group: api +category: filtering +update-time: 20260512 +description: Create a reusable record predicate that matches records by target prefix. +key-word: + - target + - filter + - predicate + - public +--- + +## Target-has-prefix + +Create a `RecordPredicate` that returns `true` when a record target starts with a given prefix. This helper is commonly used with `with_filter(...)`, `filter_sink(...)`, `all_of(...)`, and routing logic. + +### Interface + +```moonbit +pub fn target_has_prefix(prefix : String) -> RecordPredicate {} +``` + +#### input + +- `prefix : String` - Prefix expected at the start of `rec.target`. + +#### output + +- `RecordPredicate` - Predicate that matches records whose target starts with the given prefix. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- Matching is based on `String::has_prefix(...)` over the full target string. +- This helper does not modify records; it only returns a reusable predicate. +- Prefix-based matching is especially useful when using hierarchical targets such as `app.worker.job`. +- It composes cleanly with `all_of(...)`, `any_of(...)`, and `not_(...)`. + +### How to Use + +Here are some specific examples provided. + +#### When Filter A Target Namespace + +When a logger should keep one target subtree: +```moonbit +let logger = Logger::new(console_sink(), target="app") + .with_filter(target_has_prefix("app.worker")) +``` + +In this example, only records under `app.worker...` remain visible. + +And child targets continue to compose naturally. + +#### When Combine With Level Rules + +When both namespace and severity matter: +```moonbit +let predicate = all_of([ + target_has_prefix("service.api"), + level_at_least(Level::Warn), +]) +``` + +In this example, the predicate stays reusable across multiple loggers or sinks. + +### Error Case + +e.g.: +- If `prefix` is empty, the predicate effectively matches every target because every string starts with an empty prefix. + +- If no target matches the prefix, the predicate simply returns `false` for those records. + +### Notes + +Notes are here. + +1. This helper is most useful when targets are structured hierarchically. + +2. Prefer this helper over ad hoc inline prefix logic for readability. + +3. Use `target_is(...)` instead when exact equality is required. + +4. Combine with `message_contains(...)` or field predicates for narrower routing rules. diff --git a/docs/api/text-formatter-config-to-json.md b/docs/api/text-formatter-config-to-json.md index 4b09c07..56d6162 100644 --- a/docs/api/text-formatter-config-to-json.md +++ b/docs/api/text-formatter-config-to-json.md @@ -29,23 +29,6 @@ pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_pars - `JsonValue` - Structured JSON representation of the formatter config. ---- - -e.g.: -```moonbit -pub fn text_formatter_config_to_json(config : TextFormatterConfig) -> @json_parser.JsonValue {} -``` - -#### input - -- `config : TextFormatterConfig` - Typed formatter config. - -#### output - -- `JsonValue` - JSON-exportable formatter object. - ---- - ### Explanation Detailed rules explaining key parameters and behaviors diff --git a/docs/api/text-formatter-config.md b/docs/api/text-formatter-config.md new file mode 100644 index 0000000..440e3c8 --- /dev/null +++ b/docs/api/text-formatter-config.md @@ -0,0 +1,101 @@ +--- +name: text-formatter-config +group: api +category: config +update-time: 20260512 +description: Build a serializable formatter config object that bridges JSON config and runtime text formatting. +key-word: + - formatter + - config + - json + - public +--- + +## Text-formatter-config + +Create a `TextFormatterConfig` object for config-driven text rendering. This is the serializable counterpart to `text_formatter(...)` and is the main bridge between JSON config parsing and runtime formatter construction. + +### Interface + +```moonbit +pub fn TextFormatterConfig::new( + show_timestamp~ : Bool = true, + show_level~ : Bool = true, + show_target~ : Bool = true, + show_fields~ : Bool = true, + separator~ : String = " ", + field_separator~ : String = " ", + template~ : String = "", + color_mode~ : ColorMode = ColorMode::Never, + color_support~ : ColorSupport = ColorSupport::TrueColor, + style_markup~ : StyleMarkupMode = StyleMarkupMode::Full, + target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled, + fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled, + style_tags~ : Map[String, TextStyle] = {}, +) -> TextFormatterConfig {} +``` + +#### input + +- Parameters mirror `text_formatter(...)` but are stored in a serializable config object. +- `style_tags : Map[String, TextStyle]` - Local tag definitions stored as plain config data. + +#### output + +- `TextFormatterConfig` - Config object that can later be serialized or converted to a runtime formatter. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- This type is data-oriented and suitable for JSON parse/stringify workflows. +- `to_formatter()` converts config into a runtime `TextFormatter`. +- `style_tags` are stored as concrete style objects instead of alias-style runtime behavior. +- This config type is used by `SinkConfig`, `LoggerConfig`, and config-driven sink assembly. + +### How to Use + +Here are some specific examples provided. + +#### When Need Config-built Text Output + +When text formatting should be configured rather than hard-coded: +```moonbit +let formatter = TextFormatterConfig::new( + show_timestamp=false, + template="[{level}] {message}", + color_mode=ColorMode::Always, +) +``` + +In this example, the formatter settings are stored as config rather than a runtime-only formatter. + +And the same value can be serialized or embedded in larger logger config objects. + +#### When Need Runtime Bridge After Parsing + +When config has already been parsed from JSON: +```moonbit +let runtime_formatter = config.sink.text_formatter.to_formatter() +``` + +In this example, JSON-driven settings become a real runtime formatter only when needed. + +### Error Case + +e.g.: +- If `template` is empty, runtime formatting falls back to the normal part-assembly path. + +- If `style_tags` is empty, no local formatter tag registry is created. + +### Notes + +Notes are here. + +1. Prefer this API when formatter behavior must be stored, parsed, or serialized. + +2. Prefer `text_formatter(...)` when writing direct runtime code without config. + +3. `to_formatter()` is the key bridge from config to runtime behavior. + +4. This type is central to config-driven text sink assembly. diff --git a/docs/api/text-formatter.md b/docs/api/text-formatter.md new file mode 100644 index 0000000..7abf4c1 --- /dev/null +++ b/docs/api/text-formatter.md @@ -0,0 +1,113 @@ +--- +name: text-formatter +group: api +category: formatter +update-time: 20260512 +description: Create a configurable text formatter for console, callback, and file-oriented text logging output. +key-word: + - formatter + - text + - color + - public +--- + +## Text-formatter + +Create a `TextFormatter` that controls timestamp, level, target, field rendering, template substitution, color behavior, and style markup behavior. This is the main API for readable text output in `BitLogger`. + +### Interface + +```moonbit +pub fn text_formatter( + show_timestamp~ : Bool = true, + show_level~ : Bool = true, + show_target~ : Bool = true, + show_fields~ : Bool = true, + separator~ : String = " ", + field_separator~ : String = " ", + template~ : String = "", + color_mode~ : ColorMode = ColorMode::Never, + color_support~ : ColorSupport = ColorSupport::TrueColor, + style_markup~ : StyleMarkupMode = StyleMarkupMode::Full, + target_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled, + fields_style_markup~ : StyleMarkupMode = StyleMarkupMode::Disabled, + style_tags~ : StyleTagRegistry? = None, +) -> TextFormatter {} +``` + +#### input + +- `show_timestamp : Bool` - Whether timestamp text is rendered when the record carries a timestamp. +- `show_level : Bool` - Whether the level label is rendered. +- `show_target : Bool` - Whether the target is rendered. +- `show_fields : Bool` - Whether structured fields are rendered. +- `separator : String` - Separator between major rendered parts. +- `field_separator : String` - Separator used between field values in text output. +- `template : String` - Optional template using tokens such as `{level}`, `{target}`, `{message}`, `{timestamp}`, `{timestamp_ms}`, and `{fields}`. +- `color_mode : ColorMode` - `Never`, `Auto`, or `Always`. +- `color_support : ColorSupport` - `Basic` or `TrueColor`. +- `style_markup : StyleMarkupMode` - Controls whether message style tags are parsed. +- `target_style_markup : StyleMarkupMode` - Controls whether target style tags are parsed. +- `fields_style_markup : StyleMarkupMode` - Controls whether field-value style tags are parsed. +- `style_tags : StyleTagRegistry?` - Optional local tag registry. + +#### output + +- `TextFormatter` - A reusable text formatter instance for text sinks or direct formatting. + +### Explanation + +Detailed rules explaining key parameters and behaviors + +- If `template` is empty, the formatter uses built-in part assembly. +- `color_mode=Auto` currently follows a conservative rule based on `NO_COLOR`. +- `style_markup`, `target_style_markup`, and `fields_style_markup` are independent scopes. +- Local `style_tags` override global tag registry lookup, which overrides builtin tags. + +### How to Use + +Here are some specific examples provided. + +#### When Need Human-readable Console Output + +When logs should stay readable in terminals: +```moonbit +let formatter = text_formatter( + show_timestamp=false, + template="[{level}] {target} {message} :: {fields}", +) +let logger = Logger::new(text_console_sink(formatter), target="demo") +``` + +In this example, the formatter produces predictable text output without timestamps. + +And the same formatter can be reused by multiple sinks. + +#### When Need Styled ANSI Output + +When you want visible severity or semantic tags in terminal output: +```moonbit +let formatter = text_formatter(color_mode=ColorMode::Always) + .with_style_tags(default_style_tag_registry().set_tag("accent", fg=Some("#4cc9f0"), bold=true)) +``` + +In this example, message text can use inline tags such as `...`. + +### Error Case + +e.g.: +- If `template` contains unknown text, the formatter keeps it as plain text. + +- If a style tag is unknown or invalid, current behavior falls back to plain text rather than raising an error. + +### Notes + +Notes are here. + +1. Prefer `text_formatter(...)` when you want explicit control over readable text output. + +2. `TextFormatter` is reusable and should usually be constructed once, then shared. + +3. `fields_style_markup` currently affects field values only, not field keys. + +4. Use `TextFormatterConfig` when the formatter must be driven by JSON config rather than code.