mirror of
https://github.com/Nanaloveyuki/BitLogger.git
synced 2026-07-24 00:42:18 +00:00
♻️ sync owner migration and facade thinning
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
name: async-logger-close
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Close the async logger queue immediately and optionally convert current pending backlog into dropped records before queue closure.
|
||||
key-word:
|
||||
- async
|
||||
@@ -35,13 +35,14 @@ pub fn[S] AsyncLogger::close(self : AsyncLogger[S], clear? : Bool = false) -> Un
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `close(...)` marks the logger as closed immediately.
|
||||
- If a worker is still active when `close(...)` runs, the lifecycle phase moves into the closing path first and only settles into a terminal closed phase after worker exit.
|
||||
- `clear=false` closes the queue without explicitly abandoning pending records in the helper itself.
|
||||
- `clear=true` counts pending records as dropped and resets `pending_count` to `0` before closing the queue.
|
||||
- This helper does not itself wait for the worker to finish.
|
||||
- `close(...)` also does not change `has_failed()` or `last_error()`; it is a closure primitive, not a failure reset API.
|
||||
- Because this is a low-level close primitive, it does not first run `wait_idle()` or apply the runtime-dependent fallback logic used by `shutdown()`.
|
||||
- After closure, later log attempts do not add new pending or dropped counts, but backend behavior can still differ before the closed queue rejects the record.
|
||||
- In the current direct coverage, compatibility runtimes short-circuit before patch-path work on late log attempts, while native-worker runtimes may still build and patch the record before the closed queue rejects it.
|
||||
- After closure, later log attempts are rejected in the shared async log path before record build, patch, or filter work starts.
|
||||
- That means post-close late logs no longer add pending or dropped counts, and they no longer trigger patch/filter side effects on one backend but not another.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -72,7 +73,7 @@ e.g.:
|
||||
|
||||
- If `clear=false`, pending records may still exist after closure until worker drain or later cleanup resolves them.
|
||||
|
||||
- If callers perform late log attempts after closure, backlog counters still stay unchanged, but patch-path side effects are runtime-dependent and should not be treated as a portable post-close contract.
|
||||
- If callers perform late log attempts after closure, backlog counters still stay unchanged and patch/filter side effects stay skipped.
|
||||
|
||||
- If callers need graceful waiting for drain completion, `shutdown()` is usually the better API.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-flush-policy
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Read the async logger flush policy currently governing batch-end and shutdown-end flushing behavior.
|
||||
update-time: 20260707
|
||||
description: Read the async logger flush policy currently governing batch-end and shutdown-end flush-callback timing.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -37,8 +37,10 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `Batch` means the worker invokes the stored async flush callback after each completed drained batch, not after every individual record write.
|
||||
- `Shutdown` means the worker invokes the stored async flush callback once after the worker loop exits.
|
||||
- `Never` leaves that explicit callback path unused and relies entirely on sink behavior or external control.
|
||||
- This helper reports callback timing policy, not a guarantee that a particular sink type has a meaningful built-in flush effect on every constructor path.
|
||||
- In particular, text-specific async builder paths keep the default no-op flush callback even when the visible policy is `Batch` or `Shutdown`, so the reported policy can describe when the callback would run without implying extra sink work actually happens on that path.
|
||||
- This helper reports callback timing policy, not a progress count contract.
|
||||
- The callback is now treated as an attempted flush action with optional failure, not as a meaningful returned item count.
|
||||
- Builder routes that wrap `RuntimeSink` align with the sync/runtime facade by calling `RuntimeSink::flush_progress()` inside that callback and discarding the returned progress details.
|
||||
- Text-specific async builder paths still keep the default no-op flush callback even when the visible policy is `Batch` or `Shutdown`, so the reported policy can describe when the callback would run without implying extra sink work actually happens on that path.
|
||||
|
||||
### How to Use
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-has-failed
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Read whether the async logger worker has recorded a runtime failure after run() startup reset and drain execution.
|
||||
key-word:
|
||||
- async
|
||||
@@ -35,7 +35,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `run()` clears previous failure state at startup.
|
||||
- `run()` also clears the stored `last_error()` string at startup before drain work begins.
|
||||
- If the worker loop raises an error, the logger records that failure and exposes it through this flag.
|
||||
- If the worker loop raises an error, the logger transitions its lifecycle phase to `failed` or `closed_failed` and exposes that failure through this flag.
|
||||
- Once set by a failed run, the flag stays `true` until a later `run()` invocation actually starts and resets it.
|
||||
- Failure-driven shutdown does not clear this flag by itself, so `has_failed()` can remain `true` even after the logger is already closed.
|
||||
- This helper is intentionally compact and should usually be paired with `last_error()` for details.
|
||||
@@ -71,9 +71,9 @@ e.g.:
|
||||
- If `has_failed()` is `false`, queue pressure or dropped records may still exist for non-failure reasons.
|
||||
|
||||
- If `has_failed()` becomes `true`, `wait_idle()` may stop early while pending records still remain until a later close or clear path handles them.
|
||||
- In the current regression coverage, that later handling can be an explicit `close(clear=true)` that resets pending backlog immediately or a runtime-dependent `shutdown(...)` path that either clears pending into dropped records or leaves the closed-queue remainder visible.
|
||||
- In the current regression coverage, that later handling can be an explicit `close(clear=true)` that resets pending backlog immediately or a `shutdown(...)` path that clears retained pending backlog into dropped records before returning.
|
||||
|
||||
- If `has_failed()` is still `true` after shutdown, that does not by itself mean cleanup failed; the logger may already be `is_closed=true` while the remaining pending-versus-dropped outcome still reflects the active runtime's shutdown path.
|
||||
- If `has_failed()` is still `true` after shutdown, that does not by itself mean cleanup failed; the logger may already be `phase=closed_failed` and `terminal=true` while the retained failure record is still intentionally visible.
|
||||
|
||||
- If `has_failed()` is `true`, callers should inspect `last_error()` or `state()` for more context.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-is-closed
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Read whether the async logger has entered closed lifecycle state and should no longer be treated as a normal active enqueue target.
|
||||
key-word:
|
||||
- async
|
||||
@@ -36,11 +36,11 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `close(...)` sets the closed state immediately.
|
||||
- `shutdown(...)` also results in a closed logger by the end of its lifecycle flow.
|
||||
- A closed logger should no longer be treated as a normal active enqueue target.
|
||||
- This helper is only a direct read of the current `is_closed` ref; it does not wait for drain completion or clear any other state.
|
||||
- This helper is derived from the current lifecycle phase rather than from an independent closed flag ref.
|
||||
- This helper reflects lifecycle state only and does not indicate whether the worker is still draining.
|
||||
- `is_closed()` becoming `true` does not imply the logger reached a clean success state. Failure flags, retained `last_error()`, and remaining backlog-related counters can still reflect the earlier worker outcome.
|
||||
- After shutdown on a worker-failure path, `is_closed()` can therefore be `true` while backlog cleanup remains runtime-dependent: native-worker runtimes can convert leftover pending records into dropped ones, while compatibility runtimes can still report the remaining queue entries as pending.
|
||||
- Exact post-close logging behavior is runtime-dependent: compatibility runtimes can short-circuit before patch and enqueue work, while native-worker runtimes may still build and patch a record before the closed queue rejects it, so `is_closed()` should be read as a lifecycle signal rather than a full enqueue-policy contract.
|
||||
- After shutdown on a worker-failure path, `is_closed()` can therefore be `true` while retained failure state still remains visible under `phase=closed_failed`.
|
||||
- Late log attempts are rejected in the shared async log path after closure, so `is_closed()` now aligns with a stable post-close enqueue rejection contract.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -74,7 +74,7 @@ e.g.:
|
||||
|
||||
- If callers need to know whether the worker is still active, they should also inspect `is_running()`.
|
||||
|
||||
- If callers need to know whether closure also prevented later log attempts on the current backend, they must interpret this together with the active runtime behavior rather than this flag alone.
|
||||
- If callers need to know whether the logger is also terminal or rerunnable, they should inspect `state().terminal` or `state().can_rerun`.
|
||||
|
||||
- Closing a logger does not by itself reset `has_failed()` or `last_error()`.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-is-running
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Read whether the async logger worker loop is currently running, regardless of queue backlog or recorded failure state.
|
||||
key-word:
|
||||
- async
|
||||
@@ -36,8 +36,8 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `run()` sets the running state while the worker loop is active.
|
||||
- The flag is cleared when the worker exits normally or after failure handling finishes.
|
||||
- A logger may be closed while still running briefly during final drain or shutdown processing.
|
||||
- After a worker failure, the logger can already be `is_running=false` while still retaining `has_failed=true`, the recorded `last_error()`, and runtime-dependent leftover backlog or dropped-count cleanup.
|
||||
- This helper is only a direct read of the current `is_running` ref; it does not wait, synchronize, or infer why the value is what it is.
|
||||
- After a worker failure, the logger can already be `is_running=false` while still retaining `has_failed=true`, the recorded `last_error()`, and leftover dropped-count cleanup.
|
||||
- This helper is derived from the current lifecycle phase rather than from an independent running flag ref; it does not wait, synchronize, or infer why the value is what it is.
|
||||
- This helper focuses on worker activity rather than queue size or failure details.
|
||||
- `is_running()` can be `false` even when `pending_count()` is still nonzero, for example if the worker was never started or if it exited after a recorded failure.
|
||||
- A later `run()` attempt can flip `is_running()` back to `true` before that retained failure/backlog state has been fully drained, because the restarted worker clears stale failure state only once the new run has actually started.
|
||||
@@ -71,7 +71,7 @@ In this example, callers watch the worker lifecycle directly.
|
||||
e.g.:
|
||||
- If `is_running()` is `false`, pending records may still exist if the worker was never started or has already failed.
|
||||
|
||||
- If `is_running()` is `false`, the logger may also already be closed while still retaining the previous failure record and a runtime-dependent pending-versus-dropped cleanup result from shutdown.
|
||||
- If `is_running()` is `false`, the logger may also already be closed while still retaining the previous failure record and the cleanup result from shutdown.
|
||||
|
||||
- If callers need a one-shot lifecycle flow, `shutdown()` is usually better than manual polling.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-last-error
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Read the last error string recorded by the async logger worker after run() resets and runtime failure capture.
|
||||
key-word:
|
||||
- async
|
||||
@@ -76,7 +76,7 @@ e.g.:
|
||||
|
||||
- `close()` or `shutdown()` do not clear a previously recorded error string by themselves; the reset happens only after a later `run()` has already started.
|
||||
|
||||
- If the same error string is still present after shutdown, that does not by itself mean cleanup was skipped; the logger may already be `is_closed=true` while the remaining pending-versus-dropped outcome still reflects the active runtime's shutdown path.
|
||||
- If the same error string is still present after shutdown, that does not by itself mean cleanup was skipped; the logger may already be `phase=closed_failed` and `terminal=true` while the retained failure record is still intentionally visible.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-run
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Start the async logger worker loop so queued records are drained to the underlying sink while lifecycle and failure state are reset and updated around execution.
|
||||
key-word:
|
||||
- async
|
||||
@@ -34,13 +34,15 @@ pub async fn[S : @bitlogger.Sink] AsyncLogger::run(self : AsyncLogger[S]) -> Uni
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `run()` sets `is_running` to `true` before worker execution begins.
|
||||
- `run()` moves the logger lifecycle phase from `ready` or `failed` into `running`.
|
||||
- `run()` now enforces a single-worker contract. If the same logger already has a running worker, the later call raises `AsyncLoggerAlreadyRunning` instead of silently starting another drain loop.
|
||||
- If the logger is already closed, `run()` raises `AsyncLoggerClosed` instead of trying to restart a terminal logger.
|
||||
- Every invocation clears previous failure state first by setting `has_failed=false` and `last_error()` to an empty string once that `run()` call has actually started executing.
|
||||
- The method then keeps draining records until `queue.get()` stops with `AsyncLoggerClosed` or a worker error escapes.
|
||||
- On a normal queue-close exit, `run()` clears `is_running` and returns normally.
|
||||
- On failure, the logger records `has_failed=true`, stores the error text in `last_error`, clears `is_running`, and then raises the error back out of `run()`.
|
||||
- On a normal queue-close exit, `run()` leaves the logger in `closed` if shutdown/close had already started, otherwise it returns to `ready`.
|
||||
- On failure, the logger records `last_error`, transitions to `failed` or `closed_failed`, and then raises the error back out of `run()`.
|
||||
- A worker failure does not guarantee the async backlog was fully drained first. If the failure happens after some records were already written, later queued records can remain pending when `run()` exits.
|
||||
- A later `run()` invocation can resume draining that retained backlog, but the stale failure flag and stale `last_error()` value are only cleared after the new worker call actually begins running.
|
||||
- This helper does not enforce a single-worker guard by itself, so the public contract should be treated as application-controlled worker startup rather than an API that deduplicates repeated `run()` calls.
|
||||
|
||||
### How to Use
|
||||
|
||||
@@ -80,7 +82,9 @@ e.g.:
|
||||
|
||||
- A later `run()` attempt starts from a fresh failure flag and empty `last_error()` string once that retrying worker has actually started, even if an earlier run failed.
|
||||
|
||||
- Starting more than one `run()` task for the same logger is not prevented by this method and can produce application-level worker coordination bugs.
|
||||
- Starting more than one `run()` task for the same logger raises `AsyncLoggerAlreadyRunning` on the later attempt.
|
||||
|
||||
- Starting `run()` after a terminal close path raises `AsyncLoggerClosed`.
|
||||
|
||||
### Notes
|
||||
|
||||
@@ -90,4 +94,4 @@ e.g.:
|
||||
|
||||
3. Pair it with `has_failed()`, `last_error()`, or `state()` when tests need to inspect how a worker exit affected logger health.
|
||||
|
||||
4. Start one deliberate worker task per logger unless your own code is intentionally coordinating a different pattern.
|
||||
4. Start one deliberate worker task per logger. A concurrent second startup now fails explicitly with `AsyncLoggerAlreadyRunning`.
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-shutdown
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Gracefully stop an async logger by waiting for idle or clearing queued work, with worker-wait behavior depending on the active async runtime.
|
||||
update-time: 20260707
|
||||
description: Gracefully stop an async logger by waiting for idle or clearing queued work, then waiting for any active worker to finish.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -35,12 +35,10 @@ pub async fn[S] AsyncLogger::shutdown(self : AsyncLogger[S], clear? : Bool = fal
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `clear=false` first waits for idle, then closes the logger.
|
||||
- In runtimes where shutdown clearing after idle is enabled, remaining backlog after `wait_idle()` triggers a fallback `close(clear=true)`.
|
||||
- If `wait_idle()` returned early because a worker failure left backlog behind, shutdown now converts that retained pending backlog into dropped records with `close(clear=true)` before returning.
|
||||
- `clear=true` immediately closes and abandons pending records, even if no worker was ever started for that logger.
|
||||
- In runtimes where shutdown waits for workers, the method then waits until `is_running()` becomes `false` before returning.
|
||||
- In the current backend split, native-worker runtimes enable both the post-`wait_idle()` clear fallback and the final wait-for-worker phase, while compatibility runtimes skip both extra steps.
|
||||
- That means a failure-short-circuited `wait_idle()` can still be followed by forced pending-to-dropped cleanup on native-worker runtimes, while compatibility runtimes close without that extra forced clear step.
|
||||
- In the current tested failure path, native-worker shutdown turns the leftover pending item into one more dropped record, while compatibility shutdown leaves that leftover closed-queue count in `pending_count()` instead.
|
||||
- After either shutdown branch starts closing, the helper waits until `is_running()` becomes `false` before returning.
|
||||
- In lifecycle-phase terms, shutdown drives the logger into `closing` while a worker is still active, then settles into `closed` or `closed_failed` once that worker has exited.
|
||||
- Shutdown itself does not clear retained worker failure state. If a previous `run()` already recorded `has_failed=true` and a non-empty `last_error()`, those diagnostics can remain visible after shutdown completes.
|
||||
- Because `clear=false` delegates to `wait_idle()` first, shutdown can also wait indefinitely when pending records exist but no worker is making progress and no failure flag is raised.
|
||||
|
||||
@@ -71,15 +69,10 @@ In this example, pending work is abandoned intentionally so shutdown can complet
|
||||
e.g.:
|
||||
- If `clear=true`, pending records are intentionally dropped rather than drained.
|
||||
|
||||
- If `wait_idle()` returns early because the worker failed, shutdown behavior after that point still depends on the active runtime's fallback and worker-wait rules.
|
||||
|
||||
- After a worker failure, native-worker shutdown may convert the remaining backlog into dropped records, while compatibility shutdown can leave the pending counter reflecting that leftover closed queue state.
|
||||
- In the current direct regression coverage, that split appears as `pending_count() == 0` and `dropped_count()` increasing on native-worker runtimes, versus `pending_count() > 0` and no extra dropped cleanup on compatibility runtimes.
|
||||
- If `wait_idle()` returns early because the worker failed, shutdown still finishes by converting retained pending backlog into dropped records before it returns.
|
||||
|
||||
- Even after shutdown finishes with `is_closed=true`, callers can still observe retained `has_failed()` and `last_error()` from an earlier worker failure.
|
||||
|
||||
- In compatibility-style runtimes without background-worker waiting, shutdown still closes the logger but may not perform the extra wait-for-worker phase described for native-worker runtimes.
|
||||
|
||||
- If pending work exists but no worker was started, `shutdown(clear=false)` may never reach its later close step because it is still waiting inside `wait_idle()`.
|
||||
|
||||
- If callers skip `shutdown()` and only inspect flags manually, it is easier to leave the worker lifecycle in an unclear state.
|
||||
@@ -88,7 +81,7 @@ e.g.:
|
||||
|
||||
1. Prefer this API over raw `close()` in normal application shutdown paths.
|
||||
|
||||
2. Exact post-close waiting behavior depends on the active async runtime mode.
|
||||
2. `shutdown()` now always waits for an already-running worker to leave `is_running=true` before returning.
|
||||
|
||||
3. Choose `clear=true` only when loss of queued records is acceptable.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-state-new
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Construct an AsyncLoggerState snapshot from explicit runtime, queue, lifecycle, failure, and flush-policy values without probing a live logger.
|
||||
update-time: 20260707
|
||||
description: Construct an AsyncLoggerState snapshot from explicit runtime, lifecycle phase, queue, failure text, and flush-policy values without probing a live logger.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -20,11 +20,9 @@ Construct an `AsyncLoggerState` snapshot from explicit runtime, queue, lifecycle
|
||||
```moonbit
|
||||
pub fn AsyncLoggerState::new(
|
||||
runtime : AsyncRuntimeState,
|
||||
phase : AsyncLifecyclePhase,
|
||||
pending_count : Int,
|
||||
dropped_count : Int,
|
||||
is_closed : Bool,
|
||||
is_running : Bool,
|
||||
has_failed : Bool,
|
||||
last_error : String,
|
||||
flush_policy : AsyncFlushPolicy,
|
||||
) -> AsyncLoggerState {
|
||||
@@ -33,11 +31,9 @@ pub fn AsyncLoggerState::new(
|
||||
#### input
|
||||
|
||||
- `runtime : AsyncRuntimeState` - Embedded backend-level runtime snapshot.
|
||||
- `phase : AsyncLifecyclePhase` - Primary lifecycle conclusion for the snapshot.
|
||||
- `pending_count : Int` - Current async queue backlog.
|
||||
- `dropped_count : Int` - Current dropped-record count.
|
||||
- `is_closed : Bool` - Whether the logger has been closed.
|
||||
- `is_running : Bool` - Whether the logger worker loop is currently running.
|
||||
- `has_failed : Bool` - Whether the logger has recorded a runtime failure state.
|
||||
- `last_error : String` - Latest error text, or an empty string when no failure has been recorded.
|
||||
- `flush_policy : AsyncFlushPolicy` - Active async flush policy for the logger.
|
||||
|
||||
@@ -49,11 +45,12 @@ pub fn AsyncLoggerState::new(
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This constructor simply packages the supplied fields into one public snapshot value.
|
||||
- This constructor packages the supplied runtime, phase, counters, last error, and flush policy into one public snapshot value.
|
||||
- It does not inspect a live logger instance by itself.
|
||||
- `AsyncLogger::state()` is the higher-level API that reads these values from a concrete logger.
|
||||
- It also does not validate whether the supplied fields represent a combination that could come from one real logger instant.
|
||||
- The supplied `runtime : AsyncRuntimeState` is stored exactly as provided; this constructor does not recompute `mode` or `background_worker` from the active backend.
|
||||
- The constructor derives `is_closed`, `is_running`, `has_failed`, `backlog_retained`, `can_rerun`, and `terminal` from the supplied `phase` and `pending_count`.
|
||||
- The constructed value matches the same public shape used by async logger serializers.
|
||||
- Because `AsyncLoggerState` is only a data snapshot type, this constructor is mainly useful for tests, adapters, and synthetic diagnostics rather than ordinary logger inspection.
|
||||
- Serialization helpers accept any `AsyncLoggerState` value, including hand-built ones from this constructor.
|
||||
@@ -69,11 +66,9 @@ When tests or adapters should construct a full async logger state explicitly:
|
||||
```moonbit
|
||||
let state = AsyncLoggerState::new(
|
||||
runtime=AsyncRuntimeState::new(AsyncRuntimeMode::Compatibility, false),
|
||||
phase=AsyncLifecyclePhase::Running,
|
||||
pending_count=0,
|
||||
dropped_count=0,
|
||||
is_closed=false,
|
||||
is_running=true,
|
||||
has_failed=false,
|
||||
last_error="",
|
||||
flush_policy=AsyncFlushPolicy::Never,
|
||||
)
|
||||
@@ -87,11 +82,9 @@ When code should prepare a typed logger state value for later export:
|
||||
```moonbit
|
||||
let state = AsyncLoggerState::new(
|
||||
runtime=async_runtime_state(),
|
||||
phase=logger.phase(),
|
||||
pending_count=logger.pending_count(),
|
||||
dropped_count=logger.dropped_count(),
|
||||
is_closed=logger.is_closed(),
|
||||
is_running=logger.is_running(),
|
||||
has_failed=logger.has_failed(),
|
||||
last_error=logger.last_error(),
|
||||
flush_policy=logger.flush_policy(),
|
||||
)
|
||||
@@ -110,7 +103,7 @@ e.g.:
|
||||
|
||||
- If callers want the current backend-derived runtime pair instead of a synthetic one, they must pass `async_runtime_state()` explicitly or use `AsyncLogger::state()`.
|
||||
|
||||
- This constructor does not apply cleanup semantics such as clearing `last_error` on restart or draining pending records; callers must provide those fields exactly as they want them represented.
|
||||
- This constructor does not apply cleanup semantics such as clearing `last_error` on restart or draining pending records; callers must provide the phase and counters exactly as they want them represented.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-state-to-json
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Convert an AsyncLoggerState snapshot into a JSON value for diagnostics and transport using the canonical nested runtime shape and flush-policy labels.
|
||||
key-word:
|
||||
- async
|
||||
@@ -33,14 +33,14 @@ pub fn async_logger_state_to_json(state : AsyncLoggerState) -> @json_parser.Json
|
||||
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- The JSON includes runtime mode, worker support, queue counters, lifecycle flags, last error, and flush policy.
|
||||
- The top-level fields are `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`.
|
||||
- The JSON includes runtime mode, lifecycle phase, derived lifecycle conclusions, queue counters, last error, and flush policy.
|
||||
- The top-level fields are `runtime`, `phase`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `backlog_retained`, `can_rerun`, `terminal`, `last_error`, and `flush_policy`.
|
||||
- The nested `runtime` field reuses `async_runtime_state_to_json(...)`, and `flush_policy` is serialized with the canonical labels `Never`, `Batch`, or `Shutdown`.
|
||||
- The public helper returns the same internal JSON snapshot shape used by `stringify_async_logger_state(...)`, so both export paths stay aligned without duplicate field assembly logic.
|
||||
- This helper is suitable for health endpoints, diagnostics payloads, and custom serialization flows.
|
||||
- It shares the same stable field names used by `stringify_async_logger_state(...)`.
|
||||
- The state must already have been captured or constructed before serialization.
|
||||
- Serialization preserves whatever snapshot combination it receives, including failure flags together with remaining backlog counts.
|
||||
- Serialization preserves whatever snapshot combination it receives, including lifecycle phase and failure/backlog combinations together with remaining backlog counts.
|
||||
- This helper never rereads a logger instance by itself. If callers pass an older or manually constructed `AsyncLoggerState`, the JSON reflects that provided value exactly rather than refreshing fields from live runtime state.
|
||||
- It also does not normalize mixed diagnostic combinations. If the provided snapshot says `is_closed=true` together with retained `has_failed=true`, `last_error`, or non-zero backlog counters, those exact combinations are emitted unchanged.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-state-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Public async logger state alias used for queue, lifecycle, runtime, and flush-policy diagnostics.
|
||||
update-time: 20260707
|
||||
description: Public async logger state alias used for queue, lifecycle phase, derived lifecycle conclusions, runtime, and flush-policy diagnostics.
|
||||
key-word:
|
||||
- async
|
||||
- logger
|
||||
@@ -23,7 +23,7 @@ pub type AsyncLoggerState = @utils.AsyncLoggerState
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerState` - Public async logger snapshot containing `runtime`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `last_error`, and `flush_policy`.
|
||||
- `AsyncLoggerState` - Public async logger snapshot containing `runtime`, `phase`, queue counters, derived lifecycle conclusions, `last_error`, and `flush_policy`.
|
||||
|
||||
### Explanation
|
||||
|
||||
@@ -31,13 +31,14 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a type alias, not a live logger handle.
|
||||
- The `runtime` field embeds an `AsyncRuntimeState` snapshot.
|
||||
- The remaining fields capture queue counts, lifecycle status, failure state, last error text, and active flush policy.
|
||||
- The remaining fields capture queue counts, lifecycle phase, derived lifecycle conclusions, failure state, last error text, and active flush policy.
|
||||
- `AsyncLogger::state()` returns this type directly, while `async_logger_state_to_json(...)` and `stringify_async_logger_state(...)` export the same data shape for diagnostics.
|
||||
- `AsyncLogger::state()` currently builds this snapshot from `async_runtime_state()` plus the logger's current counters, lifecycle flags, last error, and flush policy.
|
||||
- `AsyncLogger::state()` currently builds this snapshot from `async_runtime_state()` plus the logger's current counters, lifecycle phase, last error, and flush policy.
|
||||
- When the value comes from `AsyncLogger::state()`, the fields are read one by one rather than through a transactional snapshot primitive.
|
||||
- `AsyncLoggerState::new(...)` can also construct this type manually, but manual construction is synthetic snapshot data and does not read one live logger instant by itself.
|
||||
- The type itself does not distinguish live logger snapshots from hand-built ones; callers must track whether a given `AsyncLoggerState` value came from `AsyncLogger::state()` or from manual construction.
|
||||
- When a live snapshot is taken after worker failure, `has_failed=true`, a retained `last_error`, and non-zero `pending_count` may legitimately coexist until later cleanup or restart.
|
||||
- `phase` is the strongest lifecycle conclusion in the snapshot, while `is_closed`, `is_running`, `has_failed`, `backlog_retained`, `can_rerun`, and `terminal` are the main derived convenience reads.
|
||||
- When a live snapshot is taken after worker failure, `phase=failed`, a retained `last_error`, `backlog_retained=true`, and non-zero `pending_count` may legitimately coexist until later cleanup or restart.
|
||||
|
||||
### How to Use
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: async-logger-state
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
description: Read a full async logger runtime snapshot including the embedded runtime snapshot, queue counters, lifecycle flags, last error, and flush policy.
|
||||
update-time: 20260707
|
||||
description: Read a full async logger runtime snapshot including runtime, lifecycle phase, derived lifecycle conclusions, queue counters, last error, and flush policy.
|
||||
key-word:
|
||||
- async
|
||||
- state
|
||||
@@ -27,22 +27,26 @@ pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {}
|
||||
|
||||
#### output
|
||||
|
||||
- `AsyncLoggerState` - A snapshot containing runtime mode, worker support, queue counts, lifecycle flags, last error, and flush policy.
|
||||
- `AsyncLoggerState` - A snapshot containing runtime mode, lifecycle phase, derived lifecycle conclusions, queue counts, 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`.
|
||||
- `AsyncLoggerState` includes `runtime`, `phase`, `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, `backlog_retained`, `can_rerun`, `terminal`, `last_error`, and `flush_policy`.
|
||||
- `state()` returns a value snapshot rather than a live handle.
|
||||
- This helper is equivalent to `AsyncLoggerState::new(async_runtime_state(), self.pending_count(), self.dropped_count(), self.is_closed(), self.is_running(), self.has_failed(), self.last_error(), self.flush_policy())`.
|
||||
- This helper is equivalent to `AsyncLoggerState::new(async_runtime_state(), self.phase(), self.pending_count(), self.dropped_count(), self.last_error(), self.flush_policy())`.
|
||||
- `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()` from the moment `state()` is called, so callers do not need to join separate helpers manually.
|
||||
- The runtime portion is therefore recomputed from the active backend helper on each call, while the remaining fields come from the logger's current counters, flags, and flush policy at that same general moment.
|
||||
- The runtime portion is therefore recomputed from the active backend helper on each call, while the remaining fields come from the logger's current counters, lifecycle phase, derived lifecycle conclusions, and flush policy at that same general moment.
|
||||
- Because the snapshot is assembled field by field when `state()` is called, later logger changes require calling `state()` again rather than reusing an older `AsyncLoggerState` value as if it refreshed itself.
|
||||
- That field-by-field assembly also means this helper is not an atomic freeze across all refs; under concurrent logger activity, neighboring fields can reflect slightly different instants.
|
||||
- After a worker failure, `has_failed=true`, a non-empty `last_error`, and `pending_count>0` can legitimately appear together in one snapshot until later cleanup or a later started `run()` changes them.
|
||||
- After shutdown cleanup on an already failed logger, snapshots can also legitimately show `is_closed=true` together with retained `has_failed=true` and the same `last_error()`, while `pending_count` versus `dropped_count` still reflects the active runtime's cleanup path.
|
||||
- `phase` is the primary lifecycle conclusion. The current public phases are `ready`, `running`, `failed`, `closing`, `closed`, and `closed_failed`.
|
||||
- `backlog_retained=true` means pending backlog still exists while the logger is no longer actively draining it.
|
||||
- `can_rerun=true` means the current phase still allows a future `run()` call to restart drain work.
|
||||
- `terminal=true` means the logger is closed, no worker is active, and no pending backlog remains.
|
||||
- After a worker failure, snapshots can legitimately report `phase=failed`, `has_failed=true`, `backlog_retained=true`, a non-empty `last_error`, and `pending_count>0` together until later cleanup or restart changes them.
|
||||
- After shutdown cleanup on an already failed logger, snapshots can also legitimately report `phase=closed_failed`, `is_closed=true`, `terminal=true`, retained `has_failed=true`, and the same `last_error()`.
|
||||
- `state()` only reports the current field values; it does not clear failure state, drain backlog, or synchronize pending work by itself.
|
||||
|
||||
### How to Use
|
||||
@@ -90,7 +94,7 @@ e.g.:
|
||||
|
||||
- A snapshot showing `has_failed=true` does not imply `pending_count` is already `0`; remaining queued records may still be visible until later cleanup or restart.
|
||||
|
||||
- A snapshot showing `is_closed=true` also does not imply failure state was cleared; after failure-driven shutdown, `has_failed=true` and the recorded `last_error` can still remain visible until a later `run()` actually restarts the logger.
|
||||
- A snapshot showing `is_closed=true` also does not imply failure state was cleared; after failure-driven shutdown, `phase=closed_failed`, `has_failed=true`, and the recorded `last_error` can still remain visible until a later `run()` actually restarts the logger.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-to-library-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Convert a full async logger into the narrower library-facing async facade without rebuilding or detaching the underlying async state.
|
||||
key-word:
|
||||
- async
|
||||
@@ -38,8 +38,8 @@ Detailed rules explaining key parameters and behaviors
|
||||
- The original `AsyncLogger[S]` handle remains the same live logger. If caller code keeps that original value, later facade calls and later unwraps still observe the same shared queue, counters, sink helpers, and lifecycle mutations.
|
||||
- The returned facade keeps library-facing async operations including `log(...)`, `run()`, and `shutdown(...)`.
|
||||
- Async inspection helpers and broader composition APIs remain on the underlying `AsyncLogger[S]` and are intentionally hidden until `to_async_logger()` is used again.
|
||||
- If later facade-level `run()` or `shutdown()` calls record worker failure, leave backlog behind, or follow runtime-dependent shutdown cleanup rules, unwrapping later still exposes that same post-call state instead of a translated facade copy.
|
||||
- That includes states where delegated shutdown already finished with `is_closed=true` while retained `has_failed()` and `last_error()` remain on the wrapped logger, together with the same runtime-dependent pending-versus-dropped cleanup outcome.
|
||||
- If later facade-level `run()` or `shutdown()` calls record worker failure or perform shutdown cleanup, unwrapping later still exposes that same post-call state instead of a translated facade copy.
|
||||
- That includes states where delegated shutdown already finished with `is_closed=true` while retained `has_failed()` and `last_error()` remain on the wrapped logger, together with the same retained dropped-count cleanup outcome.
|
||||
- When `S` itself exposes richer runtime helpers, projecting to the library facade does not strip those capabilities from the wrapped logger; they are still reachable after `to_async_logger()`.
|
||||
- When `S` is `RuntimeSink`, projection also preserves queued runtime state and file-backed runtime helper behavior behind the facade instead of replacing them with a library-specific copy.
|
||||
- Unwrapping later with `to_async_logger()` therefore exposes the same queue counters, failure snapshots, file state, and runtime file controls that the original async logger already carried.
|
||||
@@ -83,7 +83,7 @@ e.g.:
|
||||
|
||||
- Projection does not normalize failure snapshots; a later unwrap can still show combinations such as retained `last_error()` with remaining `pending_count()` when the wrapped async logger really ended up in that state.
|
||||
|
||||
- Projection also does not normalize delegated shutdown results; a later unwrap can still show `is_closed=true` together with retained `has_failed()`, the same `last_error()`, and the same runtime-dependent leftover backlog or dropped-count cleanup that accumulated behind the facade.
|
||||
- Projection also does not normalize delegated shutdown results; a later unwrap can still show `is_closed=true` together with retained `has_failed()`, the same `last_error()`, and the same retained dropped-count cleanup that accumulated behind the facade.
|
||||
|
||||
- Projection also does not normalize richer runtime sink state; if the original async logger already carried queued runtime data or file-backed helper state, a later unwrap still exposes that same live state.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-type
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Public asynchronous logger root type used for queue-backed sink-preserving logging pipelines with explicit lifecycle, failure, and flush-callback state.
|
||||
key-word:
|
||||
- async
|
||||
@@ -13,7 +13,7 @@ key-word:
|
||||
|
||||
## Async-logger-type
|
||||
|
||||
`AsyncLogger[S]` is the public asynchronous root logger type. It stores a concrete sink type `S` together with queue policy, runtime state counters, and lifecycle flags, then serves as the base value for async composition, worker control, and async write APIs.
|
||||
`AsyncLogger[S]` is the public asynchronous root logger type. It stores a concrete sink type `S` together with queue policy, runtime state counters, and lifecycle state, then serves as the base value for async composition, worker control, and async write APIs.
|
||||
|
||||
### Interface
|
||||
|
||||
@@ -27,16 +27,14 @@ pub struct AsyncLogger[S] {
|
||||
linger_ms : Int
|
||||
flush_policy : AsyncFlushPolicy
|
||||
sink : S
|
||||
flush_sink : (S) -> Int raise
|
||||
flush_callback : (S) -> Unit raise
|
||||
context_fields : Array[@bitlogger.Field]
|
||||
filter : (@bitlogger.Record) -> Bool
|
||||
patch : @bitlogger.RecordPatch
|
||||
queue : @async.Queue[@bitlogger.Record]
|
||||
pending_count : Ref[Int]
|
||||
dropped_count : Ref[Int]
|
||||
is_closed : Ref[Bool]
|
||||
is_running : Ref[Bool]
|
||||
has_failed : Ref[Bool]
|
||||
phase : Ref[AsyncLifecyclePhase]
|
||||
last_error : Ref[String]
|
||||
}
|
||||
```
|
||||
@@ -50,9 +48,10 @@ pub struct AsyncLogger[S] {
|
||||
Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This is a public root struct, not a type alias.
|
||||
- The current fields cover targeting, overflow policy, batching, linger timing, flush policy, the wrapped sink, context/filter/patch behavior, queue state, and worker lifecycle flags.
|
||||
- `flush_sink : (S) -> Int raise` stores the raising flush callback used by batch and shutdown flush policies.
|
||||
- `pending_count`, `dropped_count`, `is_closed`, `is_running`, `has_failed`, and `last_error` are mutable runtime refs that power the higher-level lifecycle and diagnostics helpers.
|
||||
- The current fields cover targeting, overflow policy, batching, linger timing, flush policy, the wrapped sink, context/filter/patch behavior, queue state, and the internal lifecycle phase model.
|
||||
- `flush_callback : (S) -> Unit raise` stores the raising flush callback used by batch and shutdown flush policies.
|
||||
- `pending_count`, `dropped_count`, `phase`, and `last_error` are the mutable runtime refs that power the higher-level lifecycle and diagnostics helpers.
|
||||
- `phase` is the stronger internal lifecycle source of truth; helper reads such as `is_closed()`, `is_running()`, `has_failed()`, and the richer `state()` snapshot are derived from it.
|
||||
- The sink type parameter is preserved across async composition, which is why helpers such as `with_target(...)`, `with_context_fields(...)`, `with_filter(...)`, and `with_patch(...)` keep returning `AsyncLogger[S]`.
|
||||
- `async_logger(...)` constructs this type as the main asynchronous entry point.
|
||||
- This root type is also what sits underneath both async facade families: `ApplicationAsyncLogger` is a direct alias over the runtime-sink line, while `LibraryAsyncLogger[S]` is a narrowing wrapper around an `AsyncLogger[S]` value.
|
||||
@@ -88,7 +87,7 @@ e.g.:
|
||||
|
||||
- Actual enqueue, worker, and flush behavior still depends on the wrapped sink `S`, async runtime support, and the configured queue policy.
|
||||
|
||||
- Post-close logging behavior is not a property of the struct shape alone; it also depends on the active runtime implementation.
|
||||
- Post-close logging behavior now follows the shared close contract rather than backend-specific divergence, but lifecycle interpretation should still prefer `state()` over manual field reasoning.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger-wait-idle
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Wait until the async logger backlog drains to zero or a worker failure interrupts normal progress, using the repo's direct async call style.
|
||||
key-word:
|
||||
- async
|
||||
@@ -37,6 +37,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
- If `has_failed()` becomes `true`, waiting stops early instead of continuing to spin.
|
||||
- This API does not close the logger or stop the worker.
|
||||
- A return from `wait_idle()` therefore means either backlog reached `0` or failure interrupted normal drain progress.
|
||||
- In the stronger lifecycle model, the common post-failure interpretation is `phase=failed` together with `backlog_retained=true` while `pending_count() > 0` remains visible.
|
||||
- `wait_idle()` does not clear retained failure state by itself, so if pending records remain after a worker failure, later `wait_idle()` calls also short-circuit until another path changes that state.
|
||||
- A later `run()` can make `wait_idle()` meaningful again for the retained backlog, but only after that new worker invocation has actually started and reset the stale failure flag.
|
||||
- If no worker is draining the queue and no failure flag is raised, `wait_idle()` can wait indefinitely.
|
||||
@@ -73,7 +74,7 @@ e.g.:
|
||||
- If the worker was never started, or if nothing is making pending records decrease, `wait_idle()` can block indefinitely.
|
||||
|
||||
- If callers need backlog cleanup after a failure-short-circuit, they still need a later `close(clear=true)` or `shutdown(...)` path.
|
||||
- In the current direct coverage, `wait_idle()` can return with `pending_count() > 0` after a worker failure, and the later cleanup path may either clear that backlog explicitly or follow the runtime-dependent shutdown split documented on `shutdown(...)`.
|
||||
- In the current direct coverage, `wait_idle()` can return with `pending_count() > 0` after a worker failure, and a later `shutdown(...)` call will convert that retained backlog into dropped records before returning.
|
||||
|
||||
- If callers retry `wait_idle()` immediately after such a failure without restarting the worker or forcing cleanup first, the call can return again with the same retained pending backlog.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: async-logger
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Create an async logger with bounded queueing, overflow policy, lifecycle helpers, background run control, and a raising flush callback.
|
||||
key-word:
|
||||
- async
|
||||
@@ -23,7 +23,7 @@ pub fn[S] async_logger(
|
||||
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
||||
target~ : String = "",
|
||||
flush~ : (S) -> Int raise = fn(_) { 0 },
|
||||
flush~ : (S) -> Unit raise = fn(_) { () },
|
||||
) -> AsyncLogger[S] {}
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn[S] async_logger(
|
||||
- `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 raise` - Flush callback used by batch/shutdown flush policies and allowed to raise if sink flushing fails.
|
||||
- `flush : (S) -> Unit raise` - Flush callback used by batch/shutdown flush policies and allowed to raise if sink flushing fails.
|
||||
|
||||
#### output
|
||||
|
||||
@@ -45,7 +45,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- `async_logger(...)` only builds the logger. Actual background draining is started by `run()`.
|
||||
- `async_logger(...)` returns the full `AsyncLogger[S]` surface directly. It is therefore the underlying constructor used by both application-facing async aliases and the narrower `LibraryAsyncLogger[S]` wrapper line.
|
||||
- The constructed logger starts with `is_closed=false`, `is_running=false`, `has_failed=false`, `last_error=""`, and zeroed pending/dropped counters.
|
||||
- The constructed logger starts in lifecycle phase `ready`, with `last_error=""` and zeroed pending/dropped counters.
|
||||
- The constructed logger also keeps the core async target contract unchanged: `log(..., target=...)` can override the target for one call, while fixed-level helpers such as `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless code derives another logger first with `with_target(...)` or `child(...)`.
|
||||
- Unlike synchronous `Logger`, async `with_context_fields(...)` and `bind(...)` preserve the visible `AsyncLogger[S]` type because shared fields are stored directly on the async logger value instead of being modeled as a separate sink wrapper.
|
||||
- `ApplicationAsyncLogger` and `ApplicationTextAsyncLogger` are only alias names over concrete `AsyncLogger[...]` shapes, so they keep the same lifecycle, queue, failure, and state helpers without adding a wrapper layer.
|
||||
@@ -54,10 +54,15 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `src-async` is designed for `native / llvm / js / wasm / wasm-gc`, but current release-facing local verification is stronger for `native / js / wasm / wasm-gc` than for `llvm`.
|
||||
- `llvm` should currently be read as experimental and locally unverified in this environment rather than as a stable checked target.
|
||||
- `flush` is used only when batch or shutdown policy wants explicit flushing.
|
||||
- The callback expresses attempted flush timing and failure, not a returned progress count contract.
|
||||
- If the supplied flush callback raises, worker failure state is recorded through `has_failed()` and `last_error()`.
|
||||
- `wait_idle()` is failure-aware rather than a pure backlog-to-zero guarantee. If a worker failure sets `has_failed=true`, waiting stops early and the logger can still report `pending_count() > 0` until later cleanup or restart work happens.
|
||||
- A later `run()` attempt starts by clearing stale failure state back to `has_failed=false` and `last_error=""` before it resumes draining any backlog still left in the queue.
|
||||
- The exact behavior of late log attempts after closure is runtime-dependent, so callers should use lifecycle helpers like `is_closed()` and `shutdown()` instead of assuming identical post-close enqueue semantics everywhere.
|
||||
- `state()` exposes the stronger lifecycle conclusion through `phase`, plus derived reads such as `backlog_retained`, `can_rerun`, and `terminal` so callers do not have to infer these states from raw flag combinations.
|
||||
- Late log attempts after closure are rejected in the shared async log path before patch/filter work runs, so post-close side effects no longer vary by backend.
|
||||
- `run()` now enforces a single-worker contract and raises `AsyncLoggerAlreadyRunning` when a second worker startup is attempted for the same live logger.
|
||||
- `run()` also rejects already-closed loggers with `AsyncLoggerClosed`, which keeps rerun semantics aligned with the stronger lifecycle model: rerun is for retained `failed` backlog, not for terminal closed phases.
|
||||
- `shutdown()` now always waits for any active worker to finish and converts retained post-failure backlog into dropped records before returning.
|
||||
- Queue overflow behavior depends on `AsyncOverflowPolicy`.
|
||||
|
||||
### How to Use
|
||||
@@ -125,6 +130,7 @@ 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()`.
|
||||
- If a second worker startup is attempted while `is_running()` is already true, `run()` raises `AsyncLoggerAlreadyRunning`.
|
||||
|
||||
### Notes
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: library-async-logger-new
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260613
|
||||
update-time: 20260707
|
||||
description: Create a narrower library-facing async logger facade by building a regular async logger and wrapping the same underlying state.
|
||||
key-word:
|
||||
- async
|
||||
@@ -23,7 +23,7 @@ pub fn[S] LibraryAsyncLogger::new(
|
||||
config~ : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||
min_level~ : @bitlogger.Level = @bitlogger.Level::Info,
|
||||
target~ : String = "",
|
||||
flush~ : (S) -> Int raise = fn(_) { 0 },
|
||||
flush~ : (S) -> Unit raise = fn(_) { () },
|
||||
) -> LibraryAsyncLogger[S] {
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn[S] LibraryAsyncLogger::new(
|
||||
- `config : AsyncLoggerConfig` - Queue size, overflow behavior, batching, linger, and flush policy.
|
||||
- `min_level : Level` - Minimum enabled level. Messages below this threshold are ignored before enqueue.
|
||||
- `target : String` - Default target attached to emitted records unless later overridden.
|
||||
- `flush : (S) -> Int raise` - Flush callback used when async batch or shutdown policy needs explicit flushing, and allowed to raise if flushing fails.
|
||||
- `flush : (S) -> Unit raise` - Flush callback used when async batch or shutdown policy needs explicit flushing, and allowed to raise if flushing fails.
|
||||
|
||||
#### output
|
||||
|
||||
@@ -73,7 +73,7 @@ When the sink requires a flush callback for batch or shutdown policy:
|
||||
```moonbit
|
||||
let logger = LibraryAsyncLogger::new(
|
||||
@bitlogger.console_sink(),
|
||||
flush=fn(sink) { 0 },
|
||||
flush=fn(sink) { () },
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: library-async-logger-run
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260613
|
||||
update-time: 20260707
|
||||
description: Start the LibraryAsyncLogger worker loop by delegating to the wrapped async logger's run behavior.
|
||||
key-word:
|
||||
- async
|
||||
@@ -35,6 +35,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This method delegates directly to the wrapped async logger's `run()` behavior.
|
||||
- It starts the worker loop that makes accepted queued records reach the underlying sink.
|
||||
- The delegated `run()` call now preserves the wrapped logger's single-worker guard, so a second concurrent facade-level startup raises `AsyncLoggerAlreadyRunning`.
|
||||
- Failure and lifecycle state are still tracked by the wrapped async logger.
|
||||
- Once a delegated `run()` call has actually started, it clears any previous `has_failed()` flag and stored `last_error()` string on that same wrapped logger before draining resumes.
|
||||
- The narrower library facade does not hide the need to explicitly activate queue draining.
|
||||
@@ -78,6 +79,7 @@ e.g.:
|
||||
- If `run()` is never started, accepted records may remain queued and not reach the sink.
|
||||
|
||||
- A later delegated `run()` attempt starts from a fresh failure flag and empty `last_error()` string on the same wrapped logger, even if an earlier facade-level run failed.
|
||||
- A concurrent delegated `run()` attempt while the wrapped logger is already active fails explicitly with `AsyncLoggerAlreadyRunning`.
|
||||
|
||||
- If callers need to inspect `is_running()`, `has_failed()`, or `last_error()` directly, they must unwrap first with `to_async_logger()`.
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
name: library-async-logger-shutdown
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
description: Gracefully stop a LibraryAsyncLogger by delegating to the wrapped async logger's shutdown behavior, including runtime-dependent drain and worker-wait rules.
|
||||
update-time: 20260707
|
||||
description: Gracefully stop a LibraryAsyncLogger by delegating to the wrapped async logger's shutdown behavior, including drain and worker-wait rules.
|
||||
key-word:
|
||||
- async
|
||||
- library
|
||||
@@ -39,13 +39,12 @@ Detailed rules explaining key parameters and behaviors
|
||||
|
||||
- This method delegates directly to the wrapped async logger's `shutdown(...)` behavior.
|
||||
- `clear=false` first waits for idle, then closes the logger.
|
||||
- If the active async runtime uses shutdown clearing after idle and backlog still remains, the wrapped logger falls back to `close(clear=true)`.
|
||||
- If backlog still remains after `wait_idle()` because failure stopped progress early, the wrapped logger falls back to `close(clear=true)`.
|
||||
- `clear=true` immediately closes and abandons pending records, even if the facade never started a drain worker for the wrapped logger.
|
||||
- In runtimes where shutdown waits for workers, the method then waits until the worker is no longer running before returning.
|
||||
- After a worker-failure short-circuit, native-worker backends can still convert remaining backlog into dropped records, while compatibility backends skip that extra forced-clear step.
|
||||
- In the current direct facade coverage, the wrapped logger ends that path with `pending_count() == 0` and one more dropped item on native-worker runtimes, versus a still-nonzero pending count and no extra dropped cleanup on compatibility runtimes.
|
||||
- The method then waits until the worker is no longer running before returning.
|
||||
- After a worker-failure short-circuit, delegated shutdown converts remaining backlog into dropped records before it returns.
|
||||
- Delegated shutdown also does not clear retained worker failure state by itself. If the wrapped logger had already recorded a worker error, later inspection through `to_async_logger()` can still show `has_failed=true` and the same `last_error()` string after shutdown completes.
|
||||
- The narrower library facade does not change any of these runtime-dependent shutdown rules; it only keeps the broader inspection helpers out of the direct public surface.
|
||||
- The narrower library facade does not change any of these shutdown rules; it only keeps the broader inspection helpers out of the direct public surface.
|
||||
- Inspecting the logger later through `to_async_logger()` reveals the same delegated shutdown result rather than a rebuilt or translated lifecycle snapshot.
|
||||
|
||||
### How to Use
|
||||
@@ -79,8 +78,6 @@ e.g.:
|
||||
|
||||
- `clear=true` can therefore be used as the facade-level no-worker cleanup path when queued records were accepted but no `run()` task was ever started.
|
||||
|
||||
- In compatibility-style runtimes without background-worker waiting, shutdown still closes the logger but may not perform the extra wait-for-worker phase described for native-worker runtimes.
|
||||
|
||||
- Even when delegated shutdown finishes with `is_closed=true`, callers can still observe retained `has_failed()` and `last_error()` on the unwrapped logger if the worker had already failed before shutdown cleanup completed.
|
||||
|
||||
- If callers skip `shutdown()` and only inspect flags manually, it is easier to leave the worker lifecycle in an unclear state.
|
||||
@@ -91,7 +88,7 @@ e.g.:
|
||||
|
||||
1. Prefer this API over low-level closure control in normal library shutdown paths.
|
||||
|
||||
2. Exact post-close waiting behavior depends on the active async runtime mode.
|
||||
2. Delegated shutdown waits for an already-running worker to finish before returning.
|
||||
|
||||
3. Choose `clear=true` only when loss of queued records is acceptable.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: library-async-logger-to-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Recover the underlying full async logger from the library-facing async facade without rebuilding, copying, or detaching the wrapped async state.
|
||||
key-word:
|
||||
- async
|
||||
@@ -40,9 +40,9 @@ Detailed rules explaining key parameters and behaviors
|
||||
- Use this when code needs wider async logger APIs outside the library facade.
|
||||
- This is the step required for helpers such as `pending_count()`, `dropped_count()`, `state()`, `wait_idle()`, `has_failed()`, `last_error()`, or broader composition methods that are intentionally hidden by `LibraryAsyncLogger[S]`.
|
||||
- It is also the step that exposes the real post-run or post-shutdown state after facade-level lifecycle calls, because those calls delegated to this same wrapped logger all along.
|
||||
- That includes failure/backlog combinations and runtime-dependent shutdown results exactly as they accumulated behind the facade.
|
||||
- That includes failure/backlog combinations and shutdown results exactly as they accumulated behind the facade.
|
||||
- Because the same live value is shared, code can unwrap once, keep that `AsyncLogger[S]` handle, and then observe `pending_count()`, `state()`, `is_closed()`, or failure fields changing as later facade-level `info(...)`, `log(...)`, `run()`, or `shutdown(...)` calls execute.
|
||||
- That also means the unwrapped logger can already be both `is_closed=true` and `has_failed=true`, with the same retained `last_error()` string and the same runtime-dependent pending-versus-dropped cleanup outcome that delegated shutdown left behind.
|
||||
- That also means the unwrapped logger can already be both `is_closed=true` and `has_failed=true`, with the same retained `last_error()` string and the same dropped-count cleanup outcome that delegated shutdown left behind.
|
||||
- If the wrapped sink type has richer helper APIs, unwrapping also restores access to that same sink helper surface through the original `AsyncLogger[S]` value.
|
||||
- When the wrapped sink is `RuntimeSink`, that same unwrap also preserves queued runtime state and file-backed helper behavior exactly as they existed behind the facade, including runtime file state snapshots and file control methods.
|
||||
- Runtime sink helper mutations are still live too. Changing file append mode, auto-flush, rotation, reopen state, or related helper-managed file state through the unwrapped logger changes the same wrapped runtime sink that later facade writes and shutdown behavior continue using.
|
||||
@@ -87,7 +87,7 @@ e.g.:
|
||||
|
||||
- Unwrapping does not convert facade lifecycle history into a simplified snapshot; any retained `last_error()`, pending backlog, dropped counts, or sink runtime details stay exactly as they were on the wrapped logger.
|
||||
|
||||
- If facade-level `run()` or `shutdown()` already ended in a failure-retaining state, unwrapping can therefore expose combinations such as `is_closed=true` together with `has_failed=true`, the same `last_error()`, and runtime-dependent leftover backlog or dropped-count cleanup.
|
||||
- If facade-level `run()` or `shutdown()` already ended in a failure-retaining state, unwrapping can therefore expose combinations such as `is_closed=true` together with `has_failed=true`, the same `last_error()`, and the same leftover dropped-count cleanup.
|
||||
|
||||
- Recovering the full async logger also does not translate runtime sink helper state into a simpler snapshot; queue counters, file availability, file failure counters, and runtime file controls stay exactly as they were on the wrapped logger.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: library-async-logger
|
||||
group: api
|
||||
category: facade
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Public library-facing async logger facade type used to expose a narrower surface than AsyncLogger while preserving sink typing.
|
||||
key-word:
|
||||
- library
|
||||
@@ -34,13 +34,13 @@ Detailed rules explaining key parameters and behaviors
|
||||
- This is a public facade struct, not a type alias.
|
||||
- The wrapped sink type `S` is preserved, so sink-specific typing remains available through the facade type parameter.
|
||||
- The facade keeps common library-safe async operations such as `new(...)`, `with_target(...)`, `child(...)`, `bind(...)`, `is_enabled(...)`, `run()`, `shutdown()`, and the main async write methods `log(...)`, `info(...)`, `warn(...)`, and `error(...)`.
|
||||
- `LibraryAsyncLogger::new(...)` delegates to `async_logger(...)`, so the same async queue, raising flush callback, and runtime-dependent lifecycle behavior still exist behind the narrower facade.
|
||||
- `LibraryAsyncLogger::new(...)` delegates to `async_logger(...)`, so the same async queue, raising flush callback, and lifecycle behavior still exist behind the narrower facade.
|
||||
- Because `new(...)` delegates directly, `AsyncLoggerConfig` values such as pending limits, overflow mode, batch sizing, linger timing, and flush policy are preserved exactly rather than being translated into facade-specific defaults.
|
||||
- The facade also preserves the wrapped async logger's target rules on its exposed write methods: `log(..., target=...)` can override the target for one call, while `info(...)`, `warn(...)`, and `error(...)` continue using the stored logger target unless the facade first derives another logger with `with_target(...)` or `child(...)`.
|
||||
- Most facade reshaping helpers keep the same visible sink type, and unlike synchronous `LibraryLogger`, async `with_context_fields(...)` and `bind(...)` also preserve the visible `LibraryAsyncLogger[S]` type because they update stored async context metadata instead of changing the exposed sink wrapper.
|
||||
- It does not expose the wider `AsyncLogger[S]` composition surface or the async state and lifecycle inspection helpers directly.
|
||||
- Call `to_async_logger()` when later code must recover the full underlying `AsyncLogger[S]` surface.
|
||||
- That recovered logger is the same live async value, so queue counters, retained failure state, runtime-dependent shutdown outcomes, and sink helper access are preserved rather than recomputed.
|
||||
- That recovered logger is the same live async value, so queue counters, retained failure state, shutdown outcomes, and sink helper access are preserved rather than recomputed.
|
||||
- If the delegated async flush callback fails, the facade preserves the same `has_failed()`, `last_error()`, `is_running()`, pending-backlog, and shutdown-cleanup semantics that the underlying `AsyncLogger[S]` would have exposed directly.
|
||||
- If `S` is `RuntimeSink`, queued runtime state and file-backed helper behavior also stay on that same wrapped logger value; the facade only hides direct access until `to_async_logger()` is used.
|
||||
- If `S` is `RuntimeSink` and the value came from `build_library_async_logger(...)` or `parse_and_build_library_async_logger(...)`, the wrapped logger also keeps that sync-first builder route unchanged: any optional `LoggerConfig.queue` was already applied before async wrapping, and `logger.sink.kind` had already decided the concrete `RuntimeSink` variant before the facade narrowed the surface.
|
||||
@@ -111,7 +111,7 @@ e.g.:
|
||||
|
||||
- If the wrapped async logger later ends in a mixed diagnostic state such as `has_failed=true` with retained backlog, unwrapping exposes that exact state instead of a library-specific translation.
|
||||
|
||||
- Shutdown through the facade keeps the wrapped logger's runtime-dependent failure cleanup behavior: after a worker-side failure, unwrapped pending versus dropped cleanup can still differ between native-worker and compatibility runtimes.
|
||||
- Shutdown through the facade keeps the wrapped logger's failure cleanup behavior: after a worker-side failure, unwrapped retained pending backlog is converted into dropped records before shutdown returns.
|
||||
|
||||
- Helpers such as `pending_count()`, `dropped_count()`, `is_closed()`, `is_running()`, `has_failed()`, `last_error()`, `flush_policy()`, `state()`, and `wait_idle()` remain on the underlying `AsyncLogger[S]` and require `to_async_logger()` first.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
name: stringify-async-logger-state
|
||||
group: api
|
||||
category: async
|
||||
update-time: 20260614
|
||||
update-time: 20260707
|
||||
description: Serialize AsyncLoggerState into compact or pretty JSON text for logs and diagnostics using the canonical nested runtime snapshot shape.
|
||||
key-word:
|
||||
- async
|
||||
@@ -41,7 +41,7 @@ Detailed rules explaining key parameters and behaviors
|
||||
- `pretty=true` returns indented JSON suitable for human diagnostics.
|
||||
- This helper is built on top of `async_logger_state_to_json(...)`.
|
||||
- Internally it stringifies the same JSON snapshot shape returned by the public export helper, using `@json_parser.stringify(...)` or `@json_parser.stringify_pretty(value, 2)`.
|
||||
- The compact form matches snapshots such as `{"runtime":{"mode":"native_worker","background_worker":true},"pending_count":0,...}`.
|
||||
- The compact form matches snapshots such as `{"runtime":{"mode":"native_worker","background_worker":true},"phase":"ready","pending_count":0,...}`.
|
||||
- String output is convenient for logs, CLI output, and startup diagnostics.
|
||||
- The serializer does not care whether the input came from a live logger read or a synthetic `AsyncLoggerState::new(...)` call.
|
||||
- It also preserves mixed diagnostic states exactly as provided, such as a failure flag together with non-zero backlog.
|
||||
|
||||
@@ -25,7 +25,7 @@ async test "shutdown drains pending records" {
|
||||
target="async.test",
|
||||
flush=fn(_) {
|
||||
flushes.val += 1
|
||||
1
|
||||
()
|
||||
},
|
||||
)
|
||||
|
||||
@@ -141,14 +141,84 @@ async test "closed logger runtime determines whether later log reaches patch pat
|
||||
inspect(logger.dropped_count(), content="1")
|
||||
|
||||
logger.info("late")
|
||||
inspect(
|
||||
patched.val,
|
||||
content=if async_runtime_supports_background_worker() { "2" } else { "1" },
|
||||
)
|
||||
inspect(patched.val, content="1")
|
||||
inspect(logger.pending_count(), content="0")
|
||||
inspect(logger.dropped_count(), content="1")
|
||||
}
|
||||
|
||||
///|
|
||||
async test "closed logger does not enter filter path on later log attempts" {
|
||||
let filtered : Ref[Int] = Ref(0)
|
||||
let logger = async_logger(
|
||||
@bitlogger.callback_sink(fn(_) { }),
|
||||
config=AsyncLoggerConfig::new(
|
||||
max_pending=2,
|
||||
overflow=AsyncOverflowPolicy::Blocking,
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.closed.filter",
|
||||
).with_filter(fn(_) {
|
||||
filtered.val += 1
|
||||
true
|
||||
})
|
||||
|
||||
logger.info("one")
|
||||
inspect(filtered.val, content="1")
|
||||
logger.close(clear=true)
|
||||
|
||||
logger.info("late")
|
||||
inspect(filtered.val, content="1")
|
||||
inspect(logger.pending_count(), content="0")
|
||||
inspect(logger.dropped_count(), content="1")
|
||||
}
|
||||
|
||||
///|
|
||||
async test "run rejects duplicate worker startup for same logger" {
|
||||
let logger = async_logger(
|
||||
@bitlogger.callback_sink(fn(_) { }),
|
||||
config=AsyncLoggerConfig::new(
|
||||
max_pending=2,
|
||||
overflow=AsyncOverflowPolicy::Blocking,
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.run.duplicate",
|
||||
)
|
||||
|
||||
@async.with_task_group(group => {
|
||||
group.spawn_bg(() => logger.run())
|
||||
while !logger.is_running() {
|
||||
@async.pause()
|
||||
}
|
||||
|
||||
let second_error = (async fn() -> String raise {
|
||||
logger.run()
|
||||
"no error"
|
||||
})() catch {
|
||||
err => err.to_string()
|
||||
}
|
||||
|
||||
inspect(second_error.contains("AsyncLoggerAlreadyRunning"), content="true")
|
||||
let state = logger.state()
|
||||
inspect(
|
||||
match state.phase {
|
||||
AsyncLifecyclePhase::Running => "running"
|
||||
_ => "other"
|
||||
},
|
||||
content="running",
|
||||
)
|
||||
inspect(logger.has_failed(), content="false")
|
||||
inspect(logger.last_error(), content="")
|
||||
inspect(state.can_rerun, content="false")
|
||||
inspect(state.terminal, content="false")
|
||||
logger.shutdown(clear=true)
|
||||
})
|
||||
|
||||
inspect(logger.is_closed(), content="true")
|
||||
inspect(logger.is_running(), content="false")
|
||||
inspect(logger.has_failed(), content="false")
|
||||
inspect(logger.last_error(), content="")
|
||||
}
|
||||
|
||||
///|
|
||||
async test "async logger with_filter composes and leaves base logger unchanged" {
|
||||
let written_targets : Ref[Array[String]] = Ref([])
|
||||
@@ -1128,9 +1198,23 @@ test "async logger state snapshot reflects current counters and runtime" {
|
||||
)
|
||||
inspect(state.pending_count, content="0")
|
||||
inspect(state.dropped_count, content="0")
|
||||
inspect(
|
||||
match state.phase {
|
||||
AsyncLifecyclePhase::Ready => "ready"
|
||||
AsyncLifecyclePhase::Running => "running"
|
||||
AsyncLifecyclePhase::Failed => "failed"
|
||||
AsyncLifecyclePhase::Closing => "closing"
|
||||
AsyncLifecyclePhase::Closed => "closed"
|
||||
AsyncLifecyclePhase::ClosedFailed => "closed_failed"
|
||||
},
|
||||
content="ready",
|
||||
)
|
||||
inspect(state.is_closed, content="false")
|
||||
inspect(state.is_running, content="false")
|
||||
inspect(state.has_failed, content="false")
|
||||
inspect(state.backlog_retained, content="false")
|
||||
inspect(state.can_rerun, content="true")
|
||||
inspect(state.terminal, content="false")
|
||||
inspect(state.last_error, content="")
|
||||
inspect(
|
||||
match state.flush_policy {
|
||||
@@ -1143,21 +1227,54 @@ test "async logger state snapshot reflects current counters and runtime" {
|
||||
inspect(
|
||||
@json_parser.stringify(async_logger_state_to_json(state)),
|
||||
content=if async_runtime_supports_background_worker() {
|
||||
"{\"runtime\":{\"mode\":\"native_worker\",\"background_worker\":true},\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
"{\"runtime\":{\"mode\":\"native_worker\",\"background_worker\":true},\"phase\":\"ready\",\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"backlog_retained\":false,\"can_rerun\":true,\"terminal\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
} else {
|
||||
"{\"runtime\":{\"mode\":\"compatibility\",\"background_worker\":false},\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
"{\"runtime\":{\"mode\":\"compatibility\",\"background_worker\":false},\"phase\":\"ready\",\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"backlog_retained\":false,\"can_rerun\":true,\"terminal\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
},
|
||||
)
|
||||
inspect(
|
||||
stringify_async_logger_state(state),
|
||||
content=if async_runtime_supports_background_worker() {
|
||||
"{\"runtime\":{\"mode\":\"native_worker\",\"background_worker\":true},\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
"{\"runtime\":{\"mode\":\"native_worker\",\"background_worker\":true},\"phase\":\"ready\",\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"backlog_retained\":false,\"can_rerun\":true,\"terminal\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
} else {
|
||||
"{\"runtime\":{\"mode\":\"compatibility\",\"background_worker\":false},\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
"{\"runtime\":{\"mode\":\"compatibility\",\"background_worker\":false},\"phase\":\"ready\",\"pending_count\":0,\"dropped_count\":0,\"is_closed\":false,\"is_running\":false,\"has_failed\":false,\"backlog_retained\":false,\"can_rerun\":true,\"terminal\":false,\"last_error\":\"\",\"flush_policy\":\"Shutdown\"}"
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
async test "async logger state enters running phase while worker is active" {
|
||||
let logger = async_logger(
|
||||
@bitlogger.callback_sink(fn(_) { }),
|
||||
config=AsyncLoggerConfig::new(max_pending=2),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.state.running",
|
||||
)
|
||||
|
||||
@async.with_task_group(group => {
|
||||
group.spawn_bg(() => logger.run())
|
||||
while !logger.is_running() {
|
||||
@async.pause()
|
||||
}
|
||||
|
||||
let state = logger.state()
|
||||
inspect(
|
||||
match state.phase {
|
||||
AsyncLifecyclePhase::Running => "running"
|
||||
_ => "other"
|
||||
},
|
||||
content="running",
|
||||
)
|
||||
inspect(state.is_closed, content="false")
|
||||
inspect(state.is_running, content="true")
|
||||
inspect(state.has_failed, content="false")
|
||||
inspect(state.backlog_retained, content="false")
|
||||
inspect(state.can_rerun, content="false")
|
||||
inspect(state.terminal, content="false")
|
||||
logger.shutdown(clear=true)
|
||||
})
|
||||
}
|
||||
|
||||
///|
|
||||
async test "run drains queued records in compatibility backends too" {
|
||||
let written : Ref[Array[String]] = Ref([])
|
||||
@@ -1201,7 +1318,7 @@ async test "async logger records worker failures and wait_idle stops early" {
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.failure",
|
||||
flush=fn(_) -> Int raise { raise TestFlushError("flush exploded") },
|
||||
flush=fn(_) -> Unit raise { raise TestFlushError("flush exploded") },
|
||||
)
|
||||
|
||||
@async.with_task_group(group => {
|
||||
@@ -1219,6 +1336,18 @@ async test "async logger records worker failures and wait_idle stops early" {
|
||||
inspect(logger.last_error().contains("TestFlushError"), content="true")
|
||||
inspect(logger.is_running(), content="false")
|
||||
inspect(logger.pending_count(), content="0")
|
||||
|
||||
let state = logger.state()
|
||||
inspect(
|
||||
match state.phase {
|
||||
AsyncLifecyclePhase::ClosedFailed => "closed_failed"
|
||||
_ => "other"
|
||||
},
|
||||
content="closed_failed",
|
||||
)
|
||||
inspect(state.backlog_retained, content="false")
|
||||
inspect(state.can_rerun, content="false")
|
||||
inspect(state.terminal, content="true")
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -1234,12 +1363,12 @@ async test "later started run resets async failure state before draining remaini
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.retry",
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
flushes.val += 1
|
||||
if flushes.val == 1 {
|
||||
raise TestFlushError("flush exploded once")
|
||||
}
|
||||
1
|
||||
()
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1253,12 +1382,33 @@ async test "later started run resets async failure state before draining remaini
|
||||
inspect(logger.is_running(), content="false")
|
||||
inspect(logger.pending_count(), content="1")
|
||||
|
||||
let failed_state = logger.state()
|
||||
inspect(
|
||||
match failed_state.phase {
|
||||
AsyncLifecyclePhase::Failed => "failed"
|
||||
_ => "other"
|
||||
},
|
||||
content="failed",
|
||||
)
|
||||
inspect(failed_state.backlog_retained, content="true")
|
||||
inspect(failed_state.can_rerun, content="true")
|
||||
inspect(failed_state.terminal, content="false")
|
||||
|
||||
group.spawn_bg(() => logger.run())
|
||||
while !logger.is_running() {
|
||||
@async.pause()
|
||||
}
|
||||
inspect(logger.has_failed(), content="false")
|
||||
inspect(logger.last_error(), content="")
|
||||
|
||||
let running_state = logger.state()
|
||||
inspect(
|
||||
match running_state.phase {
|
||||
AsyncLifecyclePhase::Running => "running"
|
||||
_ => "other"
|
||||
},
|
||||
content="running",
|
||||
)
|
||||
logger.shutdown()
|
||||
})
|
||||
|
||||
@@ -1272,7 +1422,7 @@ async test "later started run resets async failure state before draining remaini
|
||||
}
|
||||
|
||||
///|
|
||||
async test "shutdown after worker failure uses runtime-specific pending cleanup" {
|
||||
async test "shutdown after worker failure clears remaining pending backlog" {
|
||||
let writes : Ref[Int] = Ref(0)
|
||||
let logger = async_logger(
|
||||
@bitlogger.callback_sink(fn(_) { writes.val += 1 }),
|
||||
@@ -1283,7 +1433,7 @@ async test "shutdown after worker failure uses runtime-specific pending cleanup"
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.failure.shutdown",
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
raise TestFlushError("flush exploded on shutdown path")
|
||||
},
|
||||
)
|
||||
@@ -1303,14 +1453,58 @@ async test "shutdown after worker failure uses runtime-specific pending cleanup"
|
||||
inspect(logger.last_error().contains("TestFlushError"), content="true")
|
||||
inspect(logger.is_running(), content="false")
|
||||
inspect(writes.val, content="1")
|
||||
inspect(logger.pending_count(), content="0")
|
||||
inspect(logger.dropped_count(), content="1")
|
||||
|
||||
let state = logger.state()
|
||||
inspect(
|
||||
logger.pending_count(),
|
||||
content=if async_runtime_supports_background_worker() { "0" } else { "1" },
|
||||
match state.phase {
|
||||
AsyncLifecyclePhase::ClosedFailed => "closed_failed"
|
||||
_ => "other"
|
||||
},
|
||||
content="closed_failed",
|
||||
)
|
||||
inspect(state.is_closed, content="true")
|
||||
inspect(state.is_running, content="false")
|
||||
inspect(state.has_failed, content="true")
|
||||
inspect(state.pending_count, content="0")
|
||||
inspect(state.dropped_count, content="1")
|
||||
inspect(state.backlog_retained, content="false")
|
||||
inspect(state.can_rerun, content="false")
|
||||
inspect(state.terminal, content="true")
|
||||
}
|
||||
|
||||
///|
|
||||
async test "shutdown clear reaches terminal closed phase without worker startup" {
|
||||
let logger = async_logger(
|
||||
@bitlogger.callback_sink(fn(_) { }),
|
||||
config=AsyncLoggerConfig::new(
|
||||
max_pending=2,
|
||||
overflow=AsyncOverflowPolicy::Blocking,
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.shutdown.clear.state",
|
||||
)
|
||||
|
||||
logger.info("one")
|
||||
logger.shutdown(clear=true)
|
||||
|
||||
let state = logger.state()
|
||||
inspect(
|
||||
logger.dropped_count(),
|
||||
content=if async_runtime_supports_background_worker() { "1" } else { "0" },
|
||||
match state.phase {
|
||||
AsyncLifecyclePhase::Closed => "closed"
|
||||
_ => "other"
|
||||
},
|
||||
content="closed",
|
||||
)
|
||||
inspect(state.is_closed, content="true")
|
||||
inspect(state.is_running, content="false")
|
||||
inspect(state.has_failed, content="false")
|
||||
inspect(state.pending_count, content="0")
|
||||
inspect(state.dropped_count, content="1")
|
||||
inspect(state.backlog_retained, content="false")
|
||||
inspect(state.can_rerun, content="false")
|
||||
inspect(state.terminal, content="true")
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -1358,7 +1552,7 @@ async test "library async new preserves config and flush failure contract" {
|
||||
),
|
||||
min_level=@bitlogger.Level::Warn,
|
||||
target="async.lib.new",
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
flushes.val += 1
|
||||
raise TestFlushError("library new flush exploded")
|
||||
},
|
||||
@@ -1687,7 +1881,7 @@ async test "library async shutdown preserves wrapped failure cleanup semantics"
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.lib.failure",
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
raise TestFlushError("library facade flush exploded")
|
||||
},
|
||||
)
|
||||
@@ -2847,6 +3041,47 @@ async test "build async logger keeps direct helper surface and runtime sink path
|
||||
inspect(logger.dropped_count(), content="1")
|
||||
inspect(logger.has_failed(), content="false")
|
||||
inspect(logger.last_error(), content="")
|
||||
inspect(logger.sink.pending_count(), content="0")
|
||||
}
|
||||
|
||||
///|
|
||||
async test "build async logger batch flush policy drains queued runtime sink work at batch boundary" {
|
||||
let logger = build_async_logger(
|
||||
AsyncLoggerBuildConfig::new(
|
||||
logger=@bitlogger.LoggerConfig::new(
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.direct.batch.flush.runtime",
|
||||
queue=Some(
|
||||
@bitlogger.QueueConfig::new(
|
||||
4,
|
||||
overflow=@bitlogger.QueueOverflowPolicy::DropNewest,
|
||||
),
|
||||
),
|
||||
sink=@bitlogger.SinkConfig::new(kind=@bitlogger.SinkKind::Console),
|
||||
),
|
||||
async_config=AsyncLoggerConfig::new(
|
||||
max_pending=4,
|
||||
overflow=AsyncOverflowPolicy::Blocking,
|
||||
max_batch=2,
|
||||
flush=AsyncFlushPolicy::Batch,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@async.with_task_group(group => {
|
||||
group.spawn_bg(() => logger.run())
|
||||
logger.info("one")
|
||||
logger.info("two")
|
||||
logger.wait_idle()
|
||||
inspect(logger.pending_count(), content="0")
|
||||
inspect(logger.sink.pending_count(), content="0")
|
||||
inspect(logger.has_failed(), content="false")
|
||||
logger.shutdown()
|
||||
})
|
||||
|
||||
inspect(logger.is_closed(), content="true")
|
||||
inspect(logger.is_running(), content="false")
|
||||
inspect(logger.sink.pending_count(), content="0")
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -2959,7 +3194,7 @@ async test "async logger projection preserves async queue and failure state" {
|
||||
),
|
||||
min_level=@bitlogger.Level::Info,
|
||||
target="async.projected.state",
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
raise TestFlushError("projected facade flush exploded")
|
||||
},
|
||||
).to_library_async_logger()
|
||||
@@ -4471,7 +4706,7 @@ async test "build async text logger batch flush policy keeps default no-op flush
|
||||
config=config.async_config,
|
||||
min_level=config.logger.min_level,
|
||||
target=config.logger.target,
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
raise TestFlushError("text batch flush exploded")
|
||||
},
|
||||
).with_timestamp(enabled=config.logger.timestamp)
|
||||
@@ -4556,7 +4791,7 @@ async test "build async text logger shutdown flush policy keeps default no-op fl
|
||||
config=config.async_config,
|
||||
min_level=config.logger.min_level,
|
||||
target=config.logger.target,
|
||||
flush=fn(_) -> Int raise {
|
||||
flush=fn(_) -> Unit raise {
|
||||
raise TestFlushError("text shutdown flush exploded")
|
||||
},
|
||||
).with_timestamp(enabled=config.logger.timestamp)
|
||||
|
||||
@@ -8,18 +8,3 @@ pub fn async_runtime_supports_background_worker() -> Bool {
|
||||
ignore(all_async_runtime_modes())
|
||||
true
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_runtime_guard_closed_on_log() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_runtime_shutdown_clears_pending_after_wait_idle() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_runtime_shutdown_waits_for_worker() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ pub(all) suberror AsyncLoggerClosed {
|
||||
AsyncLoggerClosed
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) suberror AsyncLoggerAlreadyRunning {
|
||||
AsyncLoggerAlreadyRunning
|
||||
}
|
||||
|
||||
///|
|
||||
pub type AsyncOverflowPolicy = @utils.AsyncOverflowPolicy
|
||||
|
||||
@@ -23,6 +28,9 @@ fn all_async_runtime_modes() -> Array[AsyncRuntimeMode] {
|
||||
///|
|
||||
pub type AsyncRuntimeState = @utils.AsyncRuntimeState
|
||||
|
||||
///|
|
||||
pub type AsyncLifecyclePhase = @utils.AsyncLifecyclePhase
|
||||
|
||||
///|
|
||||
pub type AsyncLoggerState = @utils.AsyncLoggerState
|
||||
|
||||
@@ -129,16 +137,14 @@ pub struct AsyncLogger[S] {
|
||||
linger_ms : Int
|
||||
flush_policy : AsyncFlushPolicy
|
||||
sink : S
|
||||
flush_sink : (S) -> Int raise
|
||||
flush_callback : (S) -> Unit raise
|
||||
context_fields : Array[@bitlogger.Field]
|
||||
filter : (@bitlogger.Record) -> Bool
|
||||
patch : @bitlogger.RecordPatch
|
||||
queue : @async.Queue[@bitlogger.Record]
|
||||
pending_count : Ref[Int]
|
||||
dropped_count : Ref[Int]
|
||||
is_closed : Ref[Bool]
|
||||
is_running : Ref[Bool]
|
||||
has_failed : Ref[Bool]
|
||||
phase : Ref[AsyncLifecyclePhase]
|
||||
last_error : Ref[String]
|
||||
}
|
||||
|
||||
@@ -148,7 +154,7 @@ pub fn[S] async_logger(
|
||||
config? : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||
min_level? : @bitlogger.Level = @bitlogger.Level::Info,
|
||||
target? : String = "",
|
||||
flush? : (S) -> Int raise = fn(_) { 0 },
|
||||
flush? : (S) -> Unit raise = fn(_) { () },
|
||||
) -> AsyncLogger[S] {
|
||||
{
|
||||
min_level,
|
||||
@@ -159,20 +165,87 @@ pub fn[S] async_logger(
|
||||
linger_ms: config.linger_ms,
|
||||
flush_policy: config.flush,
|
||||
sink,
|
||||
flush_sink: flush,
|
||||
flush_callback: flush,
|
||||
context_fields: [],
|
||||
filter: fn(_) { true },
|
||||
patch: @bitlogger.identity_patch(),
|
||||
queue: @async.Queue(kind=queue_kind_of(config)),
|
||||
pending_count: Ref(0),
|
||||
dropped_count: Ref(0),
|
||||
is_closed: Ref(false),
|
||||
is_running: Ref(false),
|
||||
has_failed: Ref(false),
|
||||
phase: Ref(AsyncLifecyclePhase::Ready),
|
||||
last_error: Ref(""),
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_logger_phase_is_closed(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Closing |
|
||||
AsyncLifecyclePhase::Closed |
|
||||
AsyncLifecyclePhase::ClosedFailed => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_logger_phase_is_running(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Running | AsyncLifecyclePhase::Closing => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_logger_phase_has_failed(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Failed | AsyncLifecyclePhase::ClosedFailed => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_logger_phase_after_close(
|
||||
phase : AsyncLifecyclePhase,
|
||||
) -> AsyncLifecyclePhase {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Running | AsyncLifecyclePhase::Closing =>
|
||||
AsyncLifecyclePhase::Closing
|
||||
AsyncLifecyclePhase::Failed | AsyncLifecyclePhase::ClosedFailed =>
|
||||
AsyncLifecyclePhase::ClosedFailed
|
||||
AsyncLifecyclePhase::Closed => AsyncLifecyclePhase::Closed
|
||||
AsyncLifecyclePhase::Ready => AsyncLifecyclePhase::Closed
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_logger_phase_after_run_exit(
|
||||
phase : AsyncLifecyclePhase,
|
||||
) -> AsyncLifecyclePhase {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Closing => AsyncLifecyclePhase::Closed
|
||||
AsyncLifecyclePhase::Running => AsyncLifecyclePhase::Ready
|
||||
AsyncLifecyclePhase::Closed | AsyncLifecyclePhase::ClosedFailed => phase
|
||||
_ => phase
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_logger_phase_after_run_failure(
|
||||
phase : AsyncLifecyclePhase,
|
||||
) -> AsyncLifecyclePhase {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Closing => AsyncLifecyclePhase::ClosedFailed
|
||||
AsyncLifecyclePhase::Closed | AsyncLifecyclePhase::ClosedFailed =>
|
||||
AsyncLifecyclePhase::ClosedFailed
|
||||
_ => AsyncLifecyclePhase::Failed
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] AsyncLogger::phase(self : AsyncLogger[S]) -> AsyncLifecyclePhase {
|
||||
self.phase.val
|
||||
}
|
||||
|
||||
///|
|
||||
fn queue_kind_of(config : AsyncLoggerConfig) -> @aqueue.Kind {
|
||||
let limit = if config.max_pending < 0 { 0 } else { config.max_pending }
|
||||
@@ -282,7 +355,7 @@ pub async fn[S] AsyncLogger::log(
|
||||
fields? : Array[@bitlogger.Field] = [],
|
||||
target? : String = "",
|
||||
) -> Unit {
|
||||
guard !(async_runtime_guard_closed_on_log() && self.is_closed()) else { () }
|
||||
guard !self.is_closed() else { () }
|
||||
guard self.is_enabled(level) else { () }
|
||||
let actual_target = if target == "" { self.target } else { target }
|
||||
let timestamp_ms = if self.timestamp { @env.now() } else { 0UL }
|
||||
@@ -378,17 +451,17 @@ pub fn[S] AsyncLogger::dropped_count(self : AsyncLogger[S]) -> Int {
|
||||
|
||||
///|
|
||||
pub fn[S] AsyncLogger::is_closed(self : AsyncLogger[S]) -> Bool {
|
||||
self.is_closed.val
|
||||
async_logger_phase_is_closed(self.phase())
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] AsyncLogger::is_running(self : AsyncLogger[S]) -> Bool {
|
||||
self.is_running.val
|
||||
async_logger_phase_is_running(self.phase())
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] AsyncLogger::has_failed(self : AsyncLogger[S]) -> Bool {
|
||||
self.has_failed.val
|
||||
async_logger_phase_has_failed(self.phase())
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -405,11 +478,9 @@ pub fn[S] AsyncLogger::flush_policy(self : AsyncLogger[S]) -> AsyncFlushPolicy {
|
||||
pub fn[S] AsyncLogger::state(self : AsyncLogger[S]) -> AsyncLoggerState {
|
||||
AsyncLoggerState::new(
|
||||
async_runtime_state(),
|
||||
self.phase(),
|
||||
self.pending_count(),
|
||||
self.dropped_count(),
|
||||
self.is_closed(),
|
||||
self.is_running(),
|
||||
self.has_failed(),
|
||||
self.last_error(),
|
||||
self.flush_policy(),
|
||||
)
|
||||
@@ -420,7 +491,7 @@ pub fn[S] AsyncLogger::close(
|
||||
self : AsyncLogger[S],
|
||||
clear? : Bool = false,
|
||||
) -> Unit {
|
||||
self.is_closed.val = true
|
||||
self.phase.val = async_logger_phase_after_close(self.phase())
|
||||
if clear {
|
||||
let abandoned = self.pending_count()
|
||||
if abandoned > 0 {
|
||||
@@ -450,20 +521,22 @@ pub async fn[S] AsyncLogger::shutdown(
|
||||
self.close(clear=true)
|
||||
} else {
|
||||
self.wait_idle()
|
||||
if async_runtime_shutdown_clears_pending_after_wait_idle() &&
|
||||
self.pending_count() > 0 {
|
||||
if self.pending_count() > 0 {
|
||||
self.close(clear=true)
|
||||
} else {
|
||||
self.close()
|
||||
}
|
||||
}
|
||||
if async_runtime_shutdown_waits_for_worker() {
|
||||
while self.is_running() {
|
||||
@async.pause()
|
||||
}
|
||||
while self.is_running() {
|
||||
@async.pause()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn[S] run_flush_callback(logger : AsyncLogger[S]) -> Unit raise {
|
||||
(logger.flush_callback)(logger.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
||||
while true {
|
||||
@@ -512,12 +585,12 @@ async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
||||
}
|
||||
}
|
||||
match logger.flush_policy {
|
||||
AsyncFlushPolicy::Batch => ignore((logger.flush_sink)(logger.sink))
|
||||
AsyncFlushPolicy::Batch => run_flush_callback(logger)
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
match logger.flush_policy {
|
||||
AsyncFlushPolicy::Shutdown => ignore((logger.flush_sink)(logger.sink))
|
||||
AsyncFlushPolicy::Shutdown => run_flush_callback(logger)
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
@@ -526,18 +599,18 @@ async fn[S : @bitlogger.Sink] run_worker(logger : AsyncLogger[S]) -> Unit {
|
||||
pub async fn[S : @bitlogger.Sink] AsyncLogger::run(
|
||||
self : AsyncLogger[S],
|
||||
) -> Unit {
|
||||
self.is_running.val = true
|
||||
self.has_failed.val = false
|
||||
guard !self.is_closed() else { raise AsyncLoggerClosed }
|
||||
guard !self.is_running() else { raise AsyncLoggerAlreadyRunning }
|
||||
self.phase.val = AsyncLifecyclePhase::Running
|
||||
self.last_error.val = ""
|
||||
run_worker(self) catch {
|
||||
err => {
|
||||
self.has_failed.val = true
|
||||
self.phase.val = async_logger_phase_after_run_failure(self.phase())
|
||||
self.last_error.val = err.to_string()
|
||||
self.is_running.val = false
|
||||
raise err
|
||||
}
|
||||
}
|
||||
self.is_running.val = false
|
||||
self.phase.val = async_logger_phase_after_run_exit(self.phase())
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -550,7 +623,7 @@ pub fn build_async_logger(
|
||||
config=config.async_config,
|
||||
min_level=logger.min_level,
|
||||
target=logger.target,
|
||||
flush=fn(sink) { sink.flush() },
|
||||
flush=fn(sink) { ignore(sink.flush_progress()) },
|
||||
).with_timestamp(enabled=logger.timestamp)
|
||||
}
|
||||
|
||||
|
||||
@@ -8,18 +8,3 @@ pub fn async_runtime_supports_background_worker() -> Bool {
|
||||
ignore(all_async_runtime_modes())
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_runtime_guard_closed_on_log() -> Bool {
|
||||
true
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_runtime_shutdown_clears_pending_after_wait_idle() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_runtime_shutdown_waits_for_worker() -> Bool {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ pub fn[S] LibraryAsyncLogger::new(
|
||||
config? : AsyncLoggerConfig = AsyncLoggerConfig::new(),
|
||||
min_level? : @bitlogger.Level = @bitlogger.Level::Info,
|
||||
target? : String = "",
|
||||
flush? : (S) -> Int raise = fn(_) { 0 },
|
||||
flush? : (S) -> Unit raise = fn(_) { () },
|
||||
) -> LibraryAsyncLogger[S] {
|
||||
library_async_logger(async_logger(sink, config~, min_level~, target~, flush~))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src-async"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src",
|
||||
"Nanaloveyuki/BitLogger/src-async/utils",
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"maria/json_parser",
|
||||
"moonbitlang/async/aqueue",
|
||||
"moonbitlang/core/ref",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn[S] async_logger(S, config? : @utils.AsyncLoggerConfig, min_level? : @core.Level, target? : String, flush? : (S) -> Unit raise) -> AsyncLogger[S]
|
||||
|
||||
pub fn async_logger_build_config_to_json(@utils.AsyncLoggerBuildConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn async_logger_config_to_json(@utils.AsyncLoggerConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn async_logger_state_to_json(@utils.AsyncLoggerState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn async_runtime_mode() -> @utils.AsyncRuntimeMode
|
||||
|
||||
pub fn async_runtime_mode_label(@utils.AsyncRuntimeMode) -> String
|
||||
|
||||
pub fn async_runtime_state() -> @utils.AsyncRuntimeState
|
||||
|
||||
pub fn async_runtime_state_to_json(@utils.AsyncRuntimeState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn async_runtime_supports_background_worker() -> Bool
|
||||
|
||||
pub fn build_application_async_logger(@utils.AsyncLoggerBuildConfig) -> AsyncLogger[@src.RuntimeSink]
|
||||
|
||||
pub fn build_application_text_async_logger(@utils.AsyncLoggerBuildConfig) -> AsyncLogger[@src.FormattedConsoleSink]
|
||||
|
||||
pub fn build_async_logger(@utils.AsyncLoggerBuildConfig) -> AsyncLogger[@src.RuntimeSink]
|
||||
|
||||
pub fn build_async_text_logger(@utils.AsyncLoggerBuildConfig) -> AsyncLogger[@src.FormattedConsoleSink]
|
||||
|
||||
pub fn build_library_async_logger(@utils.AsyncLoggerBuildConfig) -> LibraryAsyncLogger[@src.RuntimeSink]
|
||||
|
||||
pub fn build_library_async_text_logger(@utils.AsyncLoggerBuildConfig) -> LibraryAsyncLogger[@src.FormattedConsoleSink]
|
||||
|
||||
pub fn parse_and_build_application_async_logger(String) -> AsyncLogger[@src.RuntimeSink] raise
|
||||
|
||||
pub fn parse_and_build_library_async_logger(String) -> LibraryAsyncLogger[@src.RuntimeSink] raise
|
||||
|
||||
pub fn parse_async_logger_build_config_text(String) -> @utils.AsyncLoggerBuildConfig raise
|
||||
|
||||
pub fn parse_async_logger_config_text(String) -> @utils.AsyncLoggerConfig raise
|
||||
|
||||
pub fn stringify_async_logger_build_config(@utils.AsyncLoggerBuildConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_async_logger_config(@utils.AsyncLoggerConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_async_logger_state(@utils.AsyncLoggerState, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_async_runtime_state(@utils.AsyncRuntimeState, pretty? : Bool) -> String
|
||||
|
||||
// Errors
|
||||
pub(all) suberror AsyncLoggerAlreadyRunning {
|
||||
AsyncLoggerAlreadyRunning
|
||||
}
|
||||
|
||||
pub(all) suberror AsyncLoggerClosed {
|
||||
AsyncLoggerClosed
|
||||
}
|
||||
|
||||
// Types and methods
|
||||
pub struct AsyncLogger[S] {
|
||||
min_level : @core.Level
|
||||
target : String
|
||||
timestamp : Bool
|
||||
overflow : @utils.AsyncOverflowPolicy
|
||||
max_batch : Int
|
||||
linger_ms : Int
|
||||
flush_policy : @utils.AsyncFlushPolicy
|
||||
sink : S
|
||||
flush_callback : (S) -> Unit raise
|
||||
context_fields : Array[@core.Field]
|
||||
filter : (@core.Record) -> Bool
|
||||
patch : (@core.Record) -> @core.Record
|
||||
queue : @aqueue.Queue[@core.Record]
|
||||
pending_count : @ref.Ref[Int]
|
||||
dropped_count : @ref.Ref[Int]
|
||||
phase : @ref.Ref[@utils.AsyncLifecyclePhase]
|
||||
last_error : @ref.Ref[String]
|
||||
}
|
||||
pub fn[S] AsyncLogger::child(Self[S], String) -> Self[S]
|
||||
pub fn[S] AsyncLogger::close(Self[S], clear? : Bool) -> Unit
|
||||
pub async fn[S] AsyncLogger::debug(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] AsyncLogger::dropped_count(Self[S]) -> Int
|
||||
pub async fn[S] AsyncLogger::error(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] AsyncLogger::flush_policy(Self[S]) -> @utils.AsyncFlushPolicy
|
||||
pub fn[S] AsyncLogger::has_failed(Self[S]) -> Bool
|
||||
pub async fn[S] AsyncLogger::info(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] AsyncLogger::is_closed(Self[S]) -> Bool
|
||||
pub fn[S] AsyncLogger::is_enabled(Self[S], @core.Level) -> Bool
|
||||
pub fn[S] AsyncLogger::is_running(Self[S]) -> Bool
|
||||
pub fn[S] AsyncLogger::last_error(Self[S]) -> String
|
||||
pub async fn[S] AsyncLogger::log(Self[S], @core.Level, String, fields? : Array[@core.Field], target? : String) -> Unit
|
||||
pub fn[S] AsyncLogger::pending_count(Self[S]) -> Int
|
||||
pub fn[S] AsyncLogger::phase(Self[S]) -> @utils.AsyncLifecyclePhase
|
||||
pub async fn[S : @src.Sink] AsyncLogger::run(Self[S]) -> Unit
|
||||
pub async fn[S] AsyncLogger::shutdown(Self[S], clear? : Bool) -> Unit
|
||||
pub fn[S] AsyncLogger::state(Self[S]) -> @utils.AsyncLoggerState
|
||||
pub fn[S] AsyncLogger::to_library_async_logger(Self[S]) -> LibraryAsyncLogger[S]
|
||||
pub async fn[S] AsyncLogger::trace(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub async fn[S] AsyncLogger::wait_idle(Self[S]) -> Unit
|
||||
pub async fn[S] AsyncLogger::warn(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] AsyncLogger::with_context_fields(Self[S], Array[@core.Field]) -> Self[S]
|
||||
pub fn[S] AsyncLogger::with_filter(Self[S], (@core.Record) -> Bool) -> Self[S]
|
||||
pub fn[S] AsyncLogger::with_min_level(Self[S], @core.Level) -> Self[S]
|
||||
pub fn[S] AsyncLogger::with_patch(Self[S], (@core.Record) -> @core.Record) -> Self[S]
|
||||
pub fn[S] AsyncLogger::with_target(Self[S], String) -> Self[S]
|
||||
pub fn[S] AsyncLogger::with_timestamp(Self[S], enabled? : Bool) -> Self[S]
|
||||
|
||||
pub struct LibraryAsyncLogger[S] {
|
||||
inner : AsyncLogger[S]
|
||||
}
|
||||
pub fn[S] LibraryAsyncLogger::bind(Self[S], Array[@core.Field]) -> Self[S]
|
||||
pub fn[S] LibraryAsyncLogger::child(Self[S], String) -> Self[S]
|
||||
pub async fn[S] LibraryAsyncLogger::error(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub async fn[S] LibraryAsyncLogger::info(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] LibraryAsyncLogger::is_enabled(Self[S], @core.Level) -> Bool
|
||||
pub async fn[S] LibraryAsyncLogger::log(Self[S], @core.Level, String, fields? : Array[@core.Field], target? : String) -> Unit
|
||||
pub fn[S] LibraryAsyncLogger::new(S, config? : @utils.AsyncLoggerConfig, min_level? : @core.Level, target? : String, flush? : (S) -> Unit raise) -> Self[S]
|
||||
pub async fn[S : @src.Sink] LibraryAsyncLogger::run(Self[S]) -> Unit
|
||||
pub async fn[S] LibraryAsyncLogger::shutdown(Self[S], clear? : Bool) -> Unit
|
||||
pub fn[S] LibraryAsyncLogger::to_async_logger(Self[S]) -> AsyncLogger[S]
|
||||
pub async fn[S] LibraryAsyncLogger::warn(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] LibraryAsyncLogger::with_context_fields(Self[S], Array[@core.Field]) -> Self[S]
|
||||
pub fn[S] LibraryAsyncLogger::with_target(Self[S], String) -> Self[S]
|
||||
|
||||
// Type aliases
|
||||
pub type ApplicationAsyncLogger = AsyncLogger[@src.RuntimeSink]
|
||||
|
||||
pub type ApplicationTextAsyncLogger = AsyncLogger[@src.FormattedConsoleSink]
|
||||
|
||||
pub using @utils {type AsyncFlushPolicy}
|
||||
|
||||
pub using @utils {type AsyncLifecyclePhase}
|
||||
|
||||
pub using @utils {type AsyncLoggerBuildConfig}
|
||||
|
||||
pub using @utils {type AsyncLoggerConfig}
|
||||
|
||||
pub using @utils {type AsyncLoggerState}
|
||||
|
||||
pub using @utils {type AsyncOverflowPolicy}
|
||||
|
||||
pub using @utils {type AsyncRuntimeMode}
|
||||
|
||||
pub using @utils {type AsyncRuntimeState}
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -50,14 +50,74 @@ pub fn AsyncRuntimeState::new(
|
||||
{ mode, background_worker }
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) enum AsyncLifecyclePhase {
|
||||
Ready
|
||||
Running
|
||||
Failed
|
||||
Closing
|
||||
Closed
|
||||
ClosedFailed
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_lifecycle_phase_label(phase : AsyncLifecyclePhase) -> String {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Ready => "ready"
|
||||
AsyncLifecyclePhase::Running => "running"
|
||||
AsyncLifecyclePhase::Failed => "failed"
|
||||
AsyncLifecyclePhase::Closing => "closing"
|
||||
AsyncLifecyclePhase::Closed => "closed"
|
||||
AsyncLifecyclePhase::ClosedFailed => "closed_failed"
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_lifecycle_phase_is_closed(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Closing |
|
||||
AsyncLifecyclePhase::Closed |
|
||||
AsyncLifecyclePhase::ClosedFailed => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_lifecycle_phase_is_running(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Running | AsyncLifecyclePhase::Closing => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_lifecycle_phase_has_failed(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Failed | AsyncLifecyclePhase::ClosedFailed => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn async_lifecycle_phase_can_rerun(phase : AsyncLifecyclePhase) -> Bool {
|
||||
match phase {
|
||||
AsyncLifecyclePhase::Ready | AsyncLifecyclePhase::Failed => true
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct AsyncLoggerState {
|
||||
runtime : AsyncRuntimeState
|
||||
phase : AsyncLifecyclePhase
|
||||
pending_count : Int
|
||||
dropped_count : Int
|
||||
is_closed : Bool
|
||||
is_running : Bool
|
||||
has_failed : Bool
|
||||
backlog_retained : Bool
|
||||
can_rerun : Bool
|
||||
terminal : Bool
|
||||
last_error : String
|
||||
flush_policy : AsyncFlushPolicy
|
||||
}
|
||||
@@ -65,21 +125,29 @@ pub struct AsyncLoggerState {
|
||||
///|
|
||||
pub fn AsyncLoggerState::new(
|
||||
runtime : AsyncRuntimeState,
|
||||
phase : AsyncLifecyclePhase,
|
||||
pending_count : Int,
|
||||
dropped_count : Int,
|
||||
is_closed : Bool,
|
||||
is_running : Bool,
|
||||
has_failed : Bool,
|
||||
last_error : String,
|
||||
flush_policy : AsyncFlushPolicy,
|
||||
) -> AsyncLoggerState {
|
||||
let is_closed = async_lifecycle_phase_is_closed(phase)
|
||||
let is_running = async_lifecycle_phase_is_running(phase)
|
||||
let has_failed = async_lifecycle_phase_has_failed(phase)
|
||||
let backlog_retained = pending_count > 0 && !is_running
|
||||
let can_rerun = async_lifecycle_phase_can_rerun(phase)
|
||||
let terminal = is_closed && !is_running && pending_count == 0
|
||||
{
|
||||
runtime,
|
||||
phase,
|
||||
pending_count,
|
||||
dropped_count,
|
||||
is_closed,
|
||||
is_running,
|
||||
has_failed,
|
||||
backlog_retained,
|
||||
can_rerun,
|
||||
terminal,
|
||||
last_error,
|
||||
flush_policy,
|
||||
}
|
||||
@@ -123,6 +191,9 @@ fn async_logger_state_to_json_value(
|
||||
) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object({
|
||||
"runtime": async_runtime_state_to_json(state.runtime),
|
||||
"phase": @json_parser.JsonValue::String(
|
||||
async_lifecycle_phase_label(state.phase),
|
||||
),
|
||||
"pending_count": @json_parser.JsonValue::Number(
|
||||
state.pending_count.to_double(),
|
||||
),
|
||||
@@ -132,6 +203,11 @@ fn async_logger_state_to_json_value(
|
||||
"is_closed": @json_parser.JsonValue::Bool(state.is_closed),
|
||||
"is_running": @json_parser.JsonValue::Bool(state.is_running),
|
||||
"has_failed": @json_parser.JsonValue::Bool(state.has_failed),
|
||||
"backlog_retained": @json_parser.JsonValue::Bool(
|
||||
state.backlog_retained,
|
||||
),
|
||||
"can_rerun": @json_parser.JsonValue::Bool(state.can_rerun),
|
||||
"terminal": @json_parser.JsonValue::Bool(state.terminal),
|
||||
"last_error": @json_parser.JsonValue::String(state.last_error),
|
||||
"flush_policy": @json_parser.JsonValue::String(
|
||||
async_flush_policy_label(state.flush_policy),
|
||||
|
||||
+19
-19
@@ -1,46 +1,46 @@
|
||||
///|
|
||||
pub type ConfigError = @utils.ConfigError
|
||||
pub type ConfigError = @config_model.ConfigError
|
||||
|
||||
///|
|
||||
pub type SinkKind = @utils.SinkKind
|
||||
pub type SinkKind = @config_model.SinkKind
|
||||
|
||||
///|
|
||||
pub type TextFormatterConfig = @utils.TextFormatterConfig
|
||||
pub type TextFormatterConfig = @config_model.TextFormatterConfig
|
||||
|
||||
///|
|
||||
pub type QueueConfig = @utils.QueueConfig
|
||||
pub type QueueConfig = @config_model.QueueConfig
|
||||
|
||||
///|
|
||||
pub type SinkConfig = @utils.SinkConfig
|
||||
pub type SinkConfig = @config_model.SinkConfig
|
||||
|
||||
///|
|
||||
pub type LoggerConfig = @utils.LoggerConfig
|
||||
pub type LoggerConfig = @config_model.LoggerConfig
|
||||
|
||||
///|
|
||||
pub fn default_text_formatter_config() -> TextFormatterConfig {
|
||||
@utils.default_text_formatter_config()
|
||||
@config_model.default_text_formatter_config()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_sink_config() -> SinkConfig {
|
||||
@utils.default_sink_config()
|
||||
@config_model.default_sink_config()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_logger_config() -> LoggerConfig {
|
||||
@utils.default_logger_config()
|
||||
@config_model.default_logger_config()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn parse_logger_config_text(
|
||||
input : String,
|
||||
) -> LoggerConfig raise ConfigError {
|
||||
@utils.parse_logger_config_text(input)
|
||||
@config_model.parse_logger_config_text(input)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
||||
@utils.queue_config_to_json(queue)
|
||||
@config_model.queue_config_to_json(queue)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -48,14 +48,14 @@ pub fn stringify_queue_config(
|
||||
queue : QueueConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@utils.stringify_queue_config(queue, pretty~)
|
||||
@config_model.stringify_queue_config(queue, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_formatter_config_to_json(
|
||||
config : TextFormatterConfig,
|
||||
) -> @json_parser.JsonValue {
|
||||
@utils.text_formatter_config_to_json(config)
|
||||
@config_model.text_formatter_config_to_json(config)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -63,19 +63,19 @@ pub fn stringify_text_formatter_config(
|
||||
config : TextFormatterConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@utils.stringify_text_formatter_config(config, pretty~)
|
||||
@config_model.stringify_text_formatter_config(config, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_rotation_config_to_json(
|
||||
config : FileRotation,
|
||||
) -> @json_parser.JsonValue {
|
||||
@utils.file_rotation_config_to_json(config)
|
||||
@file_model.file_rotation_config_to_json(config)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||
@utils.sink_config_to_json(config)
|
||||
@config_model.sink_config_to_json(config)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -83,12 +83,12 @@ pub fn stringify_sink_config(
|
||||
config : SinkConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@utils.stringify_sink_config(config, pretty~)
|
||||
@config_model.stringify_sink_config(config, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn logger_config_to_json(config : LoggerConfig) -> @json_parser.JsonValue {
|
||||
@utils.logger_config_to_json(config)
|
||||
@config_model.logger_config_to_json(config)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -96,5 +96,5 @@ pub fn stringify_logger_config(
|
||||
config : LoggerConfig,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@utils.stringify_logger_config(config, pretty~)
|
||||
@config_model.stringify_logger_config(config, pretty~)
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ pub struct TextFormatterConfig {
|
||||
separator : String
|
||||
field_separator : String
|
||||
template : String
|
||||
color_mode : ColorMode
|
||||
color_support : ColorSupport
|
||||
style_markup : StyleMarkupMode
|
||||
target_style_markup : StyleMarkupMode
|
||||
fields_style_markup : StyleMarkupMode
|
||||
style_tags : Map[String, TextStyle]
|
||||
color_mode : @formatting.ColorMode
|
||||
color_support : @formatting.ColorSupport
|
||||
style_markup : @formatting.StyleMarkupMode
|
||||
target_style_markup : @formatting.StyleMarkupMode
|
||||
fields_style_markup : @formatting.StyleMarkupMode
|
||||
style_tags : Map[String, @formatting.TextStyle]
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -37,12 +37,12 @@ pub fn TextFormatterConfig::new(
|
||||
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] = {},
|
||||
color_mode? : @formatting.ColorMode = @formatting.ColorMode::Never,
|
||||
color_support? : @formatting.ColorSupport = @formatting.ColorSupport::TrueColor,
|
||||
style_markup? : @formatting.StyleMarkupMode = @formatting.StyleMarkupMode::Full,
|
||||
target_style_markup? : @formatting.StyleMarkupMode = @formatting.StyleMarkupMode::Disabled,
|
||||
fields_style_markup? : @formatting.StyleMarkupMode = @formatting.StyleMarkupMode::Disabled,
|
||||
style_tags? : Map[String, @formatting.TextStyle] = {},
|
||||
) -> TextFormatterConfig {
|
||||
{
|
||||
show_timestamp,
|
||||
@@ -63,9 +63,9 @@ pub fn TextFormatterConfig::new(
|
||||
|
||||
///|
|
||||
fn style_tag_registry_from_config(
|
||||
style_tags : Map[String, TextStyle],
|
||||
) -> StyleTagRegistry {
|
||||
let registry = style_tag_registry()
|
||||
style_tags : Map[String, @formatting.TextStyle],
|
||||
) -> @formatting.StyleTagRegistry {
|
||||
let registry = @formatting.style_tag_registry()
|
||||
for name, style in style_tags {
|
||||
ignore(registry.set_tag(name, style~))
|
||||
}
|
||||
@@ -75,8 +75,8 @@ fn style_tag_registry_from_config(
|
||||
///|
|
||||
pub fn TextFormatterConfig::to_formatter(
|
||||
self : TextFormatterConfig,
|
||||
) -> TextFormatter {
|
||||
text_formatter(
|
||||
) -> @formatting.TextFormatter {
|
||||
@formatting.text_formatter(
|
||||
show_timestamp=self.show_timestamp,
|
||||
show_level=self.show_level,
|
||||
show_target=self.show_target,
|
||||
@@ -100,13 +100,13 @@ pub fn TextFormatterConfig::to_formatter(
|
||||
///|
|
||||
pub struct QueueConfig {
|
||||
max_pending : Int
|
||||
overflow : QueueOverflowPolicy
|
||||
overflow : @queue_model.QueueOverflowPolicy
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn QueueConfig::new(
|
||||
max_pending : Int,
|
||||
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||
overflow? : @queue_model.QueueOverflowPolicy = @queue_model.QueueOverflowPolicy::DropNewest,
|
||||
) -> QueueConfig {
|
||||
{ max_pending, overflow }
|
||||
}
|
||||
@@ -117,7 +117,7 @@ pub struct SinkConfig {
|
||||
path : String
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
rotation : @file_model.FileRotation?
|
||||
text_formatter : TextFormatterConfig
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ pub fn SinkConfig::new(
|
||||
path? : String = "",
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
rotation? : @file_model.FileRotation? = None,
|
||||
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||
) -> SinkConfig {
|
||||
{ kind, path, append, auto_flush, rotation, text_formatter }
|
||||
@@ -282,11 +282,13 @@ fn parse_level(name : String) -> @core.Level raise ConfigError {
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_overflow(name : String) -> QueueOverflowPolicy raise ConfigError {
|
||||
fn parse_overflow(
|
||||
name : String,
|
||||
) -> @queue_model.QueueOverflowPolicy raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"DROPNEWEST" => QueueOverflowPolicy::DropNewest
|
||||
"DROPPOLDEST" => QueueOverflowPolicy::DropOldest
|
||||
"DROPOLDEST" => QueueOverflowPolicy::DropOldest
|
||||
"DROPNEWEST" => @queue_model.QueueOverflowPolicy::DropNewest
|
||||
"DROPPOLDEST" => @queue_model.QueueOverflowPolicy::DropOldest
|
||||
"DROPOLDEST" => @queue_model.QueueOverflowPolicy::DropOldest
|
||||
_ =>
|
||||
raise ConfigError::InvalidConfig(
|
||||
"Unsupported queue overflow policy: " + name,
|
||||
@@ -308,30 +310,34 @@ fn parse_sink_kind(name : String) -> SinkKind raise ConfigError {
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_color_mode(name : String) -> ColorMode raise ConfigError {
|
||||
fn parse_color_mode(name : String) -> @formatting.ColorMode raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"NEVER" => ColorMode::Never
|
||||
"AUTO" => ColorMode::Auto
|
||||
"ALWAYS" => ColorMode::Always
|
||||
"NEVER" => @formatting.ColorMode::Never
|
||||
"AUTO" => @formatting.ColorMode::Auto
|
||||
"ALWAYS" => @formatting.ColorMode::Always
|
||||
_ => raise ConfigError::InvalidConfig("Unsupported color mode: " + name)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_color_support(name : String) -> ColorSupport raise ConfigError {
|
||||
fn parse_color_support(
|
||||
name : String,
|
||||
) -> @formatting.ColorSupport raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"BASIC" => ColorSupport::Basic
|
||||
"TRUECOLOR" => ColorSupport::TrueColor
|
||||
"BASIC" => @formatting.ColorSupport::Basic
|
||||
"TRUECOLOR" => @formatting.ColorSupport::TrueColor
|
||||
_ => raise ConfigError::InvalidConfig("Unsupported color support: " + name)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn parse_style_markup_mode(name : String) -> StyleMarkupMode raise ConfigError {
|
||||
fn parse_style_markup_mode(
|
||||
name : String,
|
||||
) -> @formatting.StyleMarkupMode raise ConfigError {
|
||||
match name.to_upper() {
|
||||
"DISABLED" => StyleMarkupMode::Disabled
|
||||
"BUILTIN" => StyleMarkupMode::Builtin
|
||||
"FULL" => StyleMarkupMode::Full
|
||||
"DISABLED" => @formatting.StyleMarkupMode::Disabled
|
||||
"BUILTIN" => @formatting.StyleMarkupMode::Builtin
|
||||
"FULL" => @formatting.StyleMarkupMode::Full
|
||||
_ =>
|
||||
raise ConfigError::InvalidConfig("Unsupported style markup mode: " + name)
|
||||
}
|
||||
@@ -384,9 +390,9 @@ fn parse_text_formatter_config(
|
||||
fn parse_text_style_config(
|
||||
value : @json_parser.JsonValue,
|
||||
context : String,
|
||||
) -> TextStyle raise ConfigError {
|
||||
) -> @formatting.TextStyle raise ConfigError {
|
||||
let obj = expect_object(value, context)
|
||||
text_style(
|
||||
@formatting.text_style(
|
||||
fg=get_optional_string(obj, "fg"),
|
||||
bg=get_optional_string(obj, "bg"),
|
||||
bold=get_bool(obj, "bold", default=false),
|
||||
@@ -399,9 +405,9 @@ fn parse_text_style_config(
|
||||
///|
|
||||
fn parse_style_tags_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> Map[String, TextStyle] raise ConfigError {
|
||||
) -> Map[String, @formatting.TextStyle] raise ConfigError {
|
||||
let obj = expect_object(value, "text_formatter.style_tags")
|
||||
let style_tags : Map[String, TextStyle] = {}
|
||||
let style_tags : Map[String, @formatting.TextStyle] = {}
|
||||
for name, item in obj {
|
||||
style_tags[name] = parse_text_style_config(
|
||||
item,
|
||||
@@ -425,12 +431,17 @@ fn parse_queue_config(
|
||||
///|
|
||||
fn parse_file_rotation_config(
|
||||
value : @json_parser.JsonValue,
|
||||
) -> FileRotation raise ConfigError {
|
||||
) -> @file_model.FileRotation raise ConfigError {
|
||||
let obj = expect_object(value, "sink.rotation")
|
||||
let max_backups = get_int(obj, "max_backups", default=1)
|
||||
match get_optional_int64_string(obj, "max_bytes_i64") {
|
||||
Some(max_bytes_i64) => file_rotation_i64(max_bytes_i64, max_backups~)
|
||||
None => file_rotation(get_int(obj, "max_bytes", default=1), max_backups~)
|
||||
Some(max_bytes_i64) =>
|
||||
@file_model.file_rotation_i64(max_bytes_i64, max_backups~)
|
||||
None =>
|
||||
@file_model.file_rotation(
|
||||
get_int(obj, "max_bytes", default=1),
|
||||
max_backups~,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,8 +505,8 @@ pub fn queue_config_to_json(queue : QueueConfig) -> @json_parser.JsonValue {
|
||||
"max_pending": @json_parser.JsonValue::Number(queue.max_pending.to_double()),
|
||||
"overflow": @json_parser.JsonValue::String(
|
||||
match queue.overflow {
|
||||
QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||
QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||
@queue_model.QueueOverflowPolicy::DropNewest => "DropNewest"
|
||||
@queue_model.QueueOverflowPolicy::DropOldest => "DropOldest"
|
||||
},
|
||||
),
|
||||
})
|
||||
@@ -527,19 +538,19 @@ pub fn text_formatter_config_to_json(
|
||||
"field_separator": @json_parser.JsonValue::String(config.field_separator),
|
||||
"template": @json_parser.JsonValue::String(config.template),
|
||||
"color_mode": @json_parser.JsonValue::String(
|
||||
color_mode_label(config.color_mode),
|
||||
@formatting.color_mode_label(config.color_mode),
|
||||
),
|
||||
"color_support": @json_parser.JsonValue::String(
|
||||
color_support_label(config.color_support),
|
||||
@formatting.color_support_label(config.color_support),
|
||||
),
|
||||
"style_markup": @json_parser.JsonValue::String(
|
||||
style_markup_mode_label(config.style_markup),
|
||||
@formatting.style_markup_mode_label(config.style_markup),
|
||||
),
|
||||
"target_style_markup": @json_parser.JsonValue::String(
|
||||
style_markup_mode_label(config.target_style_markup),
|
||||
@formatting.style_markup_mode_label(config.target_style_markup),
|
||||
),
|
||||
"fields_style_markup": @json_parser.JsonValue::String(
|
||||
style_markup_mode_label(config.fields_style_markup),
|
||||
@formatting.style_markup_mode_label(config.fields_style_markup),
|
||||
),
|
||||
}
|
||||
if config.style_tags.length() != 0 {
|
||||
@@ -549,7 +560,9 @@ pub fn text_formatter_config_to_json(
|
||||
}
|
||||
|
||||
///|
|
||||
fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
||||
fn text_style_config_to_json(
|
||||
style : @formatting.TextStyle,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"bold": @json_parser.JsonValue::Bool(style.bold),
|
||||
"dim": @json_parser.JsonValue::Bool(style.dim),
|
||||
@@ -569,7 +582,7 @@ fn text_style_config_to_json(style : TextStyle) -> @json_parser.JsonValue {
|
||||
|
||||
///|
|
||||
fn style_tags_config_to_json(
|
||||
style_tags : Map[String, TextStyle],
|
||||
style_tags : Map[String, @formatting.TextStyle],
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {}
|
||||
for name, style in style_tags {
|
||||
@@ -591,24 +604,6 @@ pub fn stringify_text_formatter_config(
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_rotation_config_to_json(
|
||||
config : FileRotation,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"max_bytes": @json_parser.JsonValue::Number(config.max_bytes.to_double()),
|
||||
"max_backups": @json_parser.JsonValue::Number(
|
||||
config.max_backups.to_double(),
|
||||
),
|
||||
}
|
||||
match config.native_wide_max_bytes {
|
||||
Some(value) =>
|
||||
obj["max_bytes_i64"] = @json_parser.JsonValue::String(value.to_string())
|
||||
None => ()
|
||||
}
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
@@ -620,7 +615,8 @@ pub fn sink_config_to_json(config : SinkConfig) -> @json_parser.JsonValue {
|
||||
}
|
||||
match config.rotation {
|
||||
None => ()
|
||||
Some(rotation) => obj["rotation"] = file_rotation_config_to_json(rotation)
|
||||
Some(rotation) =>
|
||||
obj["rotation"] = @file_model.file_rotation_config_to_json(rotation)
|
||||
}
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
"maria/json_parser",
|
||||
"moonbitlang/core/string",
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/config_model"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
"maria/json_parser",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn default_logger_config() -> LoggerConfig
|
||||
|
||||
pub fn default_sink_config() -> SinkConfig
|
||||
|
||||
pub fn default_text_formatter_config() -> TextFormatterConfig
|
||||
|
||||
pub fn logger_config_to_json(LoggerConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn parse_logger_config_text(String) -> LoggerConfig raise ConfigError
|
||||
|
||||
pub fn queue_config_to_json(QueueConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn sink_config_to_json(SinkConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn stringify_logger_config(LoggerConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_queue_config(QueueConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_sink_config(SinkConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_text_formatter_config(TextFormatterConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn text_formatter_config_to_json(TextFormatterConfig) -> @json_parser.JsonValue
|
||||
|
||||
// Errors
|
||||
pub(all) suberror ConfigError {
|
||||
InvalidConfig(String)
|
||||
}
|
||||
|
||||
// Types and methods
|
||||
pub struct LoggerConfig {
|
||||
min_level : @core.Level
|
||||
target : String
|
||||
timestamp : Bool
|
||||
sink : SinkConfig
|
||||
queue : QueueConfig?
|
||||
}
|
||||
pub fn LoggerConfig::new(min_level? : @core.Level, target? : String, timestamp? : Bool, sink? : SinkConfig, queue? : QueueConfig?) -> Self
|
||||
|
||||
pub struct QueueConfig {
|
||||
max_pending : Int
|
||||
overflow : @queue_model.QueueOverflowPolicy
|
||||
}
|
||||
pub fn QueueConfig::new(Int, overflow? : @queue_model.QueueOverflowPolicy) -> Self
|
||||
|
||||
pub struct SinkConfig {
|
||||
kind : SinkKind
|
||||
path : String
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : @file_model.FileRotation?
|
||||
text_formatter : TextFormatterConfig
|
||||
}
|
||||
pub fn SinkConfig::new(kind? : SinkKind, path? : String, append? : Bool, auto_flush? : Bool, rotation? : @file_model.FileRotation?, text_formatter? : TextFormatterConfig) -> Self
|
||||
|
||||
pub(all) enum SinkKind {
|
||||
Console
|
||||
JsonConsole
|
||||
TextConsole
|
||||
File
|
||||
}
|
||||
|
||||
pub struct TextFormatterConfig {
|
||||
show_timestamp : Bool
|
||||
show_level : Bool
|
||||
show_target : Bool
|
||||
show_fields : Bool
|
||||
separator : String
|
||||
field_separator : String
|
||||
template : String
|
||||
color_mode : @formatting.ColorMode
|
||||
color_support : @formatting.ColorSupport
|
||||
style_markup : @formatting.StyleMarkupMode
|
||||
target_style_markup : @formatting.StyleMarkupMode
|
||||
fields_style_markup : @formatting.StyleMarkupMode
|
||||
style_tags : Map[String, @formatting.TextStyle]
|
||||
}
|
||||
pub fn TextFormatterConfig::new(show_timestamp? : Bool, show_level? : Bool, show_target? : Bool, show_fields? : Bool, separator? : String, field_separator? : String, template? : String, color_mode? : @formatting.ColorMode, color_support? : @formatting.ColorSupport, style_markup? : @formatting.StyleMarkupMode, target_style_markup? : @formatting.StyleMarkupMode, fields_style_markup? : @formatting.StyleMarkupMode, style_tags? : Map[String, @formatting.TextStyle]) -> Self
|
||||
pub fn TextFormatterConfig::to_formatter(Self) -> @formatting.TextFormatter
|
||||
|
||||
// Type aliases
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
///|
|
||||
type FileHandle = @utils.FileHandle
|
||||
|
||||
///|
|
||||
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
@utils.open_file_handle_internal(path, append)
|
||||
}
|
||||
|
||||
///|
|
||||
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
||||
@utils.write_file_handle_internal(handle, content)
|
||||
}
|
||||
|
||||
///|
|
||||
fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
@utils.flush_file_handle_internal(handle)
|
||||
}
|
||||
|
||||
///|
|
||||
fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
@utils.close_file_handle_internal(handle)
|
||||
}
|
||||
|
||||
///|
|
||||
fn file_size_i64_internal(handle : FileHandle) -> Int64 {
|
||||
@utils.file_size_i64_internal(handle)
|
||||
}
|
||||
|
||||
///|
|
||||
fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||
@utils.rename_file_internal(from_path, to_path)
|
||||
}
|
||||
|
||||
///|
|
||||
fn remove_file_internal(path : String) -> Bool {
|
||||
@utils.remove_file_internal(path)
|
||||
}
|
||||
|
||||
///|
|
||||
fn string_byte_length_internal(content : String) -> Int {
|
||||
@utils.string_byte_length_internal(content)
|
||||
}
|
||||
|
||||
///|
|
||||
fn native_files_supported_internal() -> Bool {
|
||||
@utils.native_files_supported_internal()
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
///|
|
||||
type FileHandle = @utils.FileHandle
|
||||
|
||||
///|
|
||||
fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
@utils.open_file_handle_internal(path, append)
|
||||
}
|
||||
|
||||
///|
|
||||
fn write_file_handle_internal(handle : FileHandle, content : String) -> Bool {
|
||||
@utils.write_file_handle_internal(handle, content)
|
||||
}
|
||||
|
||||
///|
|
||||
fn flush_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
@utils.flush_file_handle_internal(handle)
|
||||
}
|
||||
|
||||
///|
|
||||
fn close_file_handle_internal(handle : FileHandle) -> Bool {
|
||||
@utils.close_file_handle_internal(handle)
|
||||
}
|
||||
|
||||
///|
|
||||
fn file_size_i64_internal(handle : FileHandle) -> Int64 {
|
||||
@utils.file_size_i64_internal(handle)
|
||||
}
|
||||
|
||||
///|
|
||||
fn rename_file_internal(from_path : String, to_path : String) -> Bool {
|
||||
@utils.rename_file_internal(from_path, to_path)
|
||||
}
|
||||
|
||||
///|
|
||||
fn remove_file_internal(path : String) -> Bool {
|
||||
@utils.remove_file_internal(path)
|
||||
}
|
||||
|
||||
///|
|
||||
fn string_byte_length_internal(content : String) -> Int {
|
||||
@utils.string_byte_length_internal(content)
|
||||
}
|
||||
|
||||
///|
|
||||
fn native_files_supported_internal() -> Bool {
|
||||
@utils.native_files_supported_internal()
|
||||
}
|
||||
@@ -1,23 +1,23 @@
|
||||
///|
|
||||
pub struct RuntimeFileState {
|
||||
file : FileSinkState
|
||||
queued : Bool
|
||||
pending_count : Int
|
||||
dropped_count : Int
|
||||
pub fn file_rotation_config_to_json(
|
||||
config : FileRotation,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"max_bytes": @json_parser.JsonValue::Number(config.max_bytes.to_double()),
|
||||
"max_backups": @json_parser.JsonValue::Number(
|
||||
config.max_backups.to_double(),
|
||||
),
|
||||
}
|
||||
match config.native_wide_max_bytes {
|
||||
Some(value) =>
|
||||
obj["max_bytes_i64"] = @json_parser.JsonValue::String(value.to_string())
|
||||
None => ()
|
||||
}
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeFileState::new(
|
||||
file : FileSinkState,
|
||||
queued? : Bool = false,
|
||||
pending_count? : Int = 0,
|
||||
dropped_count? : Int = 0,
|
||||
) -> RuntimeFileState {
|
||||
{ file, queued, pending_count, dropped_count }
|
||||
}
|
||||
|
||||
///|
|
||||
fn file_sink_policy_to_json_value(
|
||||
pub fn file_sink_policy_to_json(
|
||||
policy : FileSinkPolicy,
|
||||
) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
@@ -31,19 +31,12 @@ fn file_sink_policy_to_json_value(
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_policy_to_json(
|
||||
policy : FileSinkPolicy,
|
||||
) -> @json_parser.JsonValue {
|
||||
file_sink_policy_to_json_value(policy)
|
||||
}
|
||||
|
||||
///|
|
||||
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(policy)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
} else {
|
||||
@@ -52,9 +45,7 @@ pub fn stringify_file_sink_policy(
|
||||
}
|
||||
|
||||
///|
|
||||
fn file_sink_state_to_json_value(
|
||||
state : FileSinkState,
|
||||
) -> @json_parser.JsonValue {
|
||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||
let obj : Map[String, @json_parser.JsonValue] = {
|
||||
"path": @json_parser.JsonValue::String(state.path),
|
||||
"available": @json_parser.JsonValue::Bool(state.available),
|
||||
@@ -80,46 +71,12 @@ fn file_sink_state_to_json_value(
|
||||
@json_parser.JsonValue::Object(obj)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||
file_sink_state_to_json_value(state)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn stringify_file_sink_state(
|
||||
state : FileSinkState,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
let value = file_sink_state_to_json_value(state)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
} else {
|
||||
@json_parser.stringify(value)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn runtime_file_state_to_json(
|
||||
state : RuntimeFileState,
|
||||
) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object({
|
||||
"file": file_sink_state_to_json_value(state.file),
|
||||
"queued": @json_parser.JsonValue::Bool(state.queued),
|
||||
"pending_count": @json_parser.JsonValue::Number(
|
||||
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 {
|
||||
let value = runtime_file_state_to_json(state)
|
||||
let value = file_sink_state_to_json(state)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
} else {
|
||||
@@ -0,0 +1,99 @@
|
||||
///|
|
||||
pub struct FileRotation {
|
||||
max_bytes : Int
|
||||
max_backups : Int
|
||||
native_wide_max_bytes : Int64?
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FileSinkState {
|
||||
path : String
|
||||
available : Bool
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
open_failures : Int
|
||||
write_failures : Int
|
||||
flush_failures : Int
|
||||
rotation_failures : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FileSinkPolicy {
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSinkPolicy::new(
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
) -> FileSinkPolicy {
|
||||
{ append, auto_flush, rotation }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSinkState::new(
|
||||
path : String,
|
||||
available? : Bool = false,
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
open_failures? : Int = 0,
|
||||
write_failures? : Int = 0,
|
||||
flush_failures? : Int = 0,
|
||||
rotation_failures? : Int = 0,
|
||||
) -> FileSinkState {
|
||||
{
|
||||
path,
|
||||
available,
|
||||
append,
|
||||
auto_flush,
|
||||
rotation,
|
||||
open_failures,
|
||||
write_failures,
|
||||
flush_failures,
|
||||
rotation_failures,
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_rotation(max_bytes : Int, max_backups? : Int = 1) -> FileRotation {
|
||||
{
|
||||
max_bytes: if max_bytes <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_bytes
|
||||
},
|
||||
max_backups: if max_backups <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_backups
|
||||
},
|
||||
native_wide_max_bytes: None,
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_rotation_i64(
|
||||
max_bytes : Int64,
|
||||
max_backups? : Int = 1,
|
||||
) -> FileRotation {
|
||||
let normalized = if max_bytes <= 0L { 1L } else { max_bytes }
|
||||
let clamped_max_bytes = if normalized > 2147483647L {
|
||||
2147483647
|
||||
} else {
|
||||
normalized.to_int()
|
||||
}
|
||||
{
|
||||
max_bytes: clamped_max_bytes,
|
||||
max_backups: if max_backups <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_backups
|
||||
},
|
||||
native_wide_max_bytes: Some(normalized),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import {
|
||||
"maria/json_parser",
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/file_model"
|
||||
|
||||
import {
|
||||
"maria/json_parser",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn file_rotation(Int, max_backups? : Int) -> FileRotation
|
||||
|
||||
pub fn file_rotation_config_to_json(FileRotation) -> @json_parser.JsonValue
|
||||
|
||||
pub fn file_rotation_i64(Int64, max_backups? : Int) -> FileRotation
|
||||
|
||||
pub fn file_sink_policy_to_json(FileSinkPolicy) -> @json_parser.JsonValue
|
||||
|
||||
pub fn file_sink_state_to_json(FileSinkState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn runtime_file_state_to_json(RuntimeFileState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn stringify_file_sink_policy(FileSinkPolicy, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_file_sink_state(FileSinkState, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_runtime_file_state(RuntimeFileState, pretty? : Bool) -> String
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub struct FileRotation {
|
||||
max_bytes : Int
|
||||
max_backups : Int
|
||||
native_wide_max_bytes : Int64?
|
||||
}
|
||||
|
||||
pub struct FileSinkPolicy {
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
}
|
||||
pub fn FileSinkPolicy::new(append? : Bool, auto_flush? : Bool, rotation? : FileRotation?) -> Self
|
||||
|
||||
pub struct FileSinkState {
|
||||
path : String
|
||||
available : Bool
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
open_failures : Int
|
||||
write_failures : Int
|
||||
flush_failures : Int
|
||||
rotation_failures : Int
|
||||
}
|
||||
pub fn FileSinkState::new(String, available? : Bool, append? : Bool, auto_flush? : Bool, rotation? : FileRotation?, open_failures? : Int, write_failures? : Int, flush_failures? : Int, rotation_failures? : Int) -> Self
|
||||
|
||||
pub struct RuntimeFileState {
|
||||
file : FileSinkState
|
||||
queued : Bool
|
||||
pending_count : Int
|
||||
dropped_count : Int
|
||||
}
|
||||
pub fn RuntimeFileState::new(FileSinkState, queued? : Bool, pending_count? : Int, dropped_count? : Int) -> Self
|
||||
|
||||
// Type aliases
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
///|
|
||||
pub struct RuntimeFileState {
|
||||
file : FileSinkState
|
||||
queued : Bool
|
||||
pending_count : Int
|
||||
dropped_count : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeFileState::new(
|
||||
file : FileSinkState,
|
||||
queued? : Bool = false,
|
||||
pending_count? : Int = 0,
|
||||
dropped_count? : Int = 0,
|
||||
) -> RuntimeFileState {
|
||||
{ file, queued, pending_count, dropped_count }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn runtime_file_state_to_json(
|
||||
state : RuntimeFileState,
|
||||
) -> @json_parser.JsonValue {
|
||||
@json_parser.JsonValue::Object({
|
||||
"file": file_sink_state_to_json(state.file),
|
||||
"queued": @json_parser.JsonValue::Bool(state.queued),
|
||||
"pending_count": @json_parser.JsonValue::Number(
|
||||
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 {
|
||||
let value = runtime_file_state_to_json(state)
|
||||
if pretty {
|
||||
@json_parser.stringify_pretty(value, 2)
|
||||
} else {
|
||||
@json_parser.stringify(value)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
///|
|
||||
type FileHandle = @utils.FileHandle
|
||||
|
||||
///|
|
||||
type FileRotation = @file_model.FileRotation
|
||||
|
||||
///|
|
||||
type FileSinkState = @file_model.FileSinkState
|
||||
|
||||
///|
|
||||
type FileSinkPolicy = @file_model.FileSinkPolicy
|
||||
|
||||
///|
|
||||
type Record = @core.Record
|
||||
|
||||
///|
|
||||
type RecordFormatter = @formatting.RecordFormatter
|
||||
|
||||
///|
|
||||
pub struct FileSink {
|
||||
priv path : String
|
||||
priv append : Ref[Bool]
|
||||
priv default_append : Bool
|
||||
priv handle : Ref[FileHandle?]
|
||||
priv formatter : RecordFormatter
|
||||
priv auto_flush : Ref[Bool]
|
||||
priv default_auto_flush : Bool
|
||||
priv rotation : Ref[FileRotation?]
|
||||
priv default_rotation : FileRotation?
|
||||
priv open_failures : Ref[Int]
|
||||
priv write_failures : Ref[Int]
|
||||
priv flush_failures : Ref[Int]
|
||||
priv rotation_failures : Ref[Int]
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn native_files_supported() -> Bool {
|
||||
@utils.native_files_supported_internal()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink(
|
||||
path : String,
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
formatter? : RecordFormatter = fn(rec) { @formatting.format_text(rec) },
|
||||
) -> FileSink {
|
||||
let handle = @utils.open_file_handle_internal(path, append)
|
||||
{
|
||||
path,
|
||||
append: Ref(append),
|
||||
default_append: append,
|
||||
handle: Ref(handle),
|
||||
formatter,
|
||||
auto_flush: Ref(auto_flush),
|
||||
default_auto_flush: auto_flush,
|
||||
rotation: Ref(rotation),
|
||||
default_rotation: rotation,
|
||||
open_failures: Ref(if handle is Some(_) { 0 } else { 1 }),
|
||||
write_failures: Ref(0),
|
||||
flush_failures: Ref(0),
|
||||
rotation_failures: Ref(0),
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::is_available(self : FileSink) -> Bool {
|
||||
self.handle.val is Some(_)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::flush(self : FileSink) -> Bool {
|
||||
match self.handle.val {
|
||||
None => false
|
||||
Some(handle) => {
|
||||
let ok = @utils.flush_file_handle_internal(handle)
|
||||
if !ok {
|
||||
self.flush_failures.val += 1
|
||||
}
|
||||
ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::append_mode(self : FileSink) -> Bool {
|
||||
self.append.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_append_mode(self : FileSink, append : Bool) -> Unit {
|
||||
self.append.val = append
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::path(self : FileSink) -> String {
|
||||
self.path
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::auto_flush_enabled(self : FileSink) -> Bool {
|
||||
self.auto_flush.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::rotation_enabled(self : FileSink) -> Bool {
|
||||
self.rotation.val is Some(_)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::rotation_config(self : FileSink) -> FileRotation? {
|
||||
self.rotation.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_auto_flush(self : FileSink, enabled : Bool) -> Unit {
|
||||
self.auto_flush.val = enabled
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_policy(self : FileSink, policy : FileSinkPolicy) -> Unit {
|
||||
self.append.val = policy.append
|
||||
self.auto_flush.val = policy.auto_flush
|
||||
self.rotation.val = policy.rotation
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_rotation(
|
||||
self : FileSink,
|
||||
rotation : FileRotation?,
|
||||
) -> Unit {
|
||||
self.rotation.val = rotation
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::clear_rotation(self : FileSink) -> Unit {
|
||||
self.rotation.val = None
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::close(self : FileSink) -> Bool {
|
||||
match self.handle.val {
|
||||
None => false
|
||||
Some(handle) => {
|
||||
let ok = @utils.close_file_handle_internal(handle)
|
||||
self.handle.val = None
|
||||
ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::rotation_failures(self : FileSink) -> Int {
|
||||
self.rotation_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::open_failures(self : FileSink) -> Int {
|
||||
self.open_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::write_failures(self : FileSink) -> Int {
|
||||
self.write_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::flush_failures(self : FileSink) -> Int {
|
||||
self.flush_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reset_failure_counters(self : FileSink) -> Unit {
|
||||
self.open_failures.val = 0
|
||||
self.write_failures.val = 0
|
||||
self.flush_failures.val = 0
|
||||
self.rotation_failures.val = 0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reset_policy(self : FileSink) -> Unit {
|
||||
self.append.val = self.default_append
|
||||
self.auto_flush.val = self.default_auto_flush
|
||||
self.rotation.val = self.default_rotation
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::policy(self : FileSink) -> FileSinkPolicy {
|
||||
FileSinkPolicy::new(
|
||||
append=self.append.val,
|
||||
auto_flush=self.auto_flush.val,
|
||||
rotation=self.rotation.val,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::default_policy(self : FileSink) -> FileSinkPolicy {
|
||||
FileSinkPolicy::new(
|
||||
append=self.default_append,
|
||||
auto_flush=self.default_auto_flush,
|
||||
rotation=self.default_rotation,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::policy_matches_default(self : FileSink) -> Bool {
|
||||
let current = self.policy()
|
||||
let default = self.default_policy()
|
||||
current.append == default.append &&
|
||||
current.auto_flush == default.auto_flush &&
|
||||
policy_rotation_equals_internal(current.rotation, default.rotation)
|
||||
}
|
||||
|
||||
///|
|
||||
fn policy_rotation_equals_internal(
|
||||
left : FileRotation?,
|
||||
right : FileRotation?,
|
||||
) -> Bool {
|
||||
match (left, right) {
|
||||
(None, None) => true
|
||||
(Some(a), Some(b)) =>
|
||||
a.max_bytes == b.max_bytes &&
|
||||
a.max_backups == b.max_backups &&
|
||||
a.native_wide_max_bytes == b.native_wide_max_bytes
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotation_max_bytes_internal(rotation : FileRotation) -> Int64 {
|
||||
match rotation.native_wide_max_bytes {
|
||||
Some(value) => value
|
||||
None => rotation.max_bytes.to_int64()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::state(self : FileSink) -> FileSinkState {
|
||||
FileSinkState::new(
|
||||
self.path,
|
||||
available=self.is_available(),
|
||||
append=self.append.val,
|
||||
auto_flush=self.auto_flush.val,
|
||||
rotation=self.rotation.val,
|
||||
open_failures=self.open_failures.val,
|
||||
write_failures=self.write_failures.val,
|
||||
flush_failures=self.flush_failures.val,
|
||||
rotation_failures=self.rotation_failures.val,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen(self : FileSink, append? : Bool? = None) -> Bool {
|
||||
let append_mode = append.unwrap_or(self.append.val)
|
||||
self.append.val = append_mode
|
||||
match self.handle.val {
|
||||
None => ()
|
||||
Some(handle) => {
|
||||
ignore(@utils.close_file_handle_internal(handle))
|
||||
self.handle.val = None
|
||||
}
|
||||
}
|
||||
let reopened = @utils.open_file_handle_internal(self.path, append_mode)
|
||||
self.handle.val = reopened
|
||||
if reopened is Some(_) {
|
||||
true
|
||||
} else {
|
||||
self.open_failures.val += 1
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen_with_current_policy(self : FileSink) -> Bool {
|
||||
self.reopen()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen_append(self : FileSink) -> Bool {
|
||||
self.reopen(append=Some(true))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen_truncate(self : FileSink) -> Bool {
|
||||
self.reopen(append=Some(false))
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotated_file_path(path : String, index : Int) -> String {
|
||||
"\{path}.\{index}"
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotate_file_sink_internal(sink : FileSink, rotation : FileRotation) -> Bool {
|
||||
let closed = match sink.handle.val {
|
||||
None => true
|
||||
Some(handle) => {
|
||||
let ok = @utils.close_file_handle_internal(handle)
|
||||
sink.handle.val = None
|
||||
ok
|
||||
}
|
||||
}
|
||||
if !closed {
|
||||
return false
|
||||
}
|
||||
if rotation.max_backups > 0 {
|
||||
ignore(
|
||||
@utils.remove_file_internal(
|
||||
rotated_file_path(sink.path, rotation.max_backups),
|
||||
),
|
||||
)
|
||||
for index = rotation.max_backups - 1; index >= 1; {
|
||||
let from_path = rotated_file_path(sink.path, index)
|
||||
let to_path = rotated_file_path(sink.path, index + 1)
|
||||
ignore(@utils.rename_file_internal(from_path, to_path))
|
||||
continue index - 1
|
||||
}
|
||||
ignore(
|
||||
@utils.rename_file_internal(sink.path, rotated_file_path(sink.path, 1)),
|
||||
)
|
||||
} else {
|
||||
ignore(@utils.remove_file_internal(sink.path))
|
||||
}
|
||||
sink.handle.val = @utils.open_file_handle_internal(sink.path, false)
|
||||
sink.handle.val is Some(_)
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotate_if_needed_internal(sink : FileSink, next_line_bytes : Int) -> Bool {
|
||||
match sink.rotation.val {
|
||||
None => true
|
||||
Some(rotation) =>
|
||||
match sink.handle.val {
|
||||
None => false
|
||||
Some(handle) => {
|
||||
let size = @utils.file_size_i64_internal(handle)
|
||||
let next_line = next_line_bytes.to_int64()
|
||||
if size + next_line <= rotation_max_bytes_internal(rotation) {
|
||||
true
|
||||
} else {
|
||||
let rotated = rotate_file_sink_internal(sink, rotation)
|
||||
if !rotated {
|
||||
sink.rotation_failures.val += 1
|
||||
}
|
||||
rotated
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl @sink_graph.Sink for FileSink with fn write(self, rec : Record) {
|
||||
match self.handle.val {
|
||||
None => self.write_failures.val += 1
|
||||
Some(_) => {
|
||||
let line = "\{(self.formatter)(rec)}\n"
|
||||
let can_write = rotate_if_needed_internal(
|
||||
self,
|
||||
@utils.string_byte_length_internal(line),
|
||||
)
|
||||
if can_write {
|
||||
match self.handle.val {
|
||||
None => self.write_failures.val += 1
|
||||
Some(active) => {
|
||||
let wrote = @utils.write_file_handle_internal(active, line)
|
||||
if wrote {
|
||||
if self.auto_flush.val {
|
||||
let flushed = @utils.flush_file_handle_internal(active)
|
||||
if !flushed {
|
||||
self.flush_failures.val += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.write_failures.val += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.write_failures.val += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/sink_graph",
|
||||
"Nanaloveyuki/BitLogger/src/utils",
|
||||
"moonbitlang/core/ref",
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/file_runtime"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/sink_graph",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn file_sink(String, append? : Bool, auto_flush? : Bool, rotation? : @file_model.FileRotation?, formatter? : (@core.Record) -> String) -> FileSink
|
||||
|
||||
pub fn native_files_supported() -> Bool
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub struct FileSink {
|
||||
// private fields
|
||||
}
|
||||
pub fn FileSink::append_mode(Self) -> Bool
|
||||
pub fn FileSink::auto_flush_enabled(Self) -> Bool
|
||||
pub fn FileSink::clear_rotation(Self) -> Unit
|
||||
pub fn FileSink::close(Self) -> Bool
|
||||
pub fn FileSink::default_policy(Self) -> @file_model.FileSinkPolicy
|
||||
pub fn FileSink::flush(Self) -> Bool
|
||||
pub fn FileSink::flush_failures(Self) -> Int
|
||||
pub fn FileSink::is_available(Self) -> Bool
|
||||
pub fn FileSink::open_failures(Self) -> Int
|
||||
pub fn FileSink::path(Self) -> String
|
||||
pub fn FileSink::policy(Self) -> @file_model.FileSinkPolicy
|
||||
pub fn FileSink::policy_matches_default(Self) -> Bool
|
||||
pub fn FileSink::reopen(Self, append? : Bool?) -> Bool
|
||||
pub fn FileSink::reopen_append(Self) -> Bool
|
||||
pub fn FileSink::reopen_truncate(Self) -> Bool
|
||||
pub fn FileSink::reopen_with_current_policy(Self) -> Bool
|
||||
pub fn FileSink::reset_failure_counters(Self) -> Unit
|
||||
pub fn FileSink::reset_policy(Self) -> Unit
|
||||
pub fn FileSink::rotation_config(Self) -> @file_model.FileRotation?
|
||||
pub fn FileSink::rotation_enabled(Self) -> Bool
|
||||
pub fn FileSink::rotation_failures(Self) -> Int
|
||||
pub fn FileSink::set_append_mode(Self, Bool) -> Unit
|
||||
pub fn FileSink::set_auto_flush(Self, Bool) -> Unit
|
||||
pub fn FileSink::set_policy(Self, @file_model.FileSinkPolicy) -> Unit
|
||||
pub fn FileSink::set_rotation(Self, @file_model.FileRotation?) -> Unit
|
||||
pub fn FileSink::state(Self) -> @file_model.FileSinkState
|
||||
pub fn FileSink::write_failures(Self) -> Int
|
||||
pub impl @sink_graph.Sink for FileSink
|
||||
|
||||
// Type aliases
|
||||
|
||||
// Traits
|
||||
|
||||
+10
-10
@@ -1,47 +1,47 @@
|
||||
///|
|
||||
pub type RecordPredicate = @utils.RecordPredicate
|
||||
pub type RecordPredicate = @record_ops.RecordPredicate
|
||||
|
||||
///|
|
||||
pub fn level_at_least(min_level : Level) -> RecordPredicate {
|
||||
@utils.level_at_least(min_level)
|
||||
@record_ops.level_at_least(min_level)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_is(target : String) -> RecordPredicate {
|
||||
@utils.target_is(target)
|
||||
@record_ops.target_is(target)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
||||
@utils.target_has_prefix(prefix)
|
||||
@record_ops.target_has_prefix(prefix)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn message_contains(fragment : String) -> RecordPredicate {
|
||||
@utils.message_contains(fragment)
|
||||
@record_ops.message_contains(fragment)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn has_field(key : String) -> RecordPredicate {
|
||||
@utils.has_field(key)
|
||||
@record_ops.has_field(key)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||
@utils.field_equals(key, value)
|
||||
@record_ops.field_equals(key, value)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
||||
@utils.not_(predicate)
|
||||
@record_ops.not_(predicate)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
@utils.all_of(predicates)
|
||||
@record_ops.all_of(predicates)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
@utils.any_of(predicates)
|
||||
@record_ops.any_of(predicates)
|
||||
}
|
||||
|
||||
+19
-19
@@ -1,17 +1,17 @@
|
||||
///|
|
||||
pub type RecordFormatter = @utils.RecordFormatter
|
||||
pub type RecordFormatter = @formatting.RecordFormatter
|
||||
|
||||
///|
|
||||
pub type ColorMode = @utils.ColorMode
|
||||
pub type ColorMode = @formatting.ColorMode
|
||||
|
||||
///|
|
||||
pub type ColorSupport = @utils.ColorSupport
|
||||
pub type ColorSupport = @formatting.ColorSupport
|
||||
|
||||
///|
|
||||
pub type StyleMarkupMode = @utils.StyleMarkupMode
|
||||
pub type StyleMarkupMode = @formatting.StyleMarkupMode
|
||||
|
||||
///|
|
||||
pub type TextStyle = @utils.TextStyle
|
||||
pub type TextStyle = @formatting.TextStyle
|
||||
|
||||
///|
|
||||
pub fn text_style(
|
||||
@@ -22,39 +22,39 @@ pub fn text_style(
|
||||
italic? : Bool = false,
|
||||
underline? : Bool = false,
|
||||
) -> TextStyle {
|
||||
@utils.text_style(fg~, bg~, bold~, dim~, italic~, underline~)
|
||||
@formatting.text_style(fg~, bg~, bold~, dim~, italic~, underline~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub type StyleTagRegistry = @utils.StyleTagRegistry
|
||||
pub type StyleTagRegistry = @formatting.StyleTagRegistry
|
||||
|
||||
///|
|
||||
pub fn style_tag_registry() -> StyleTagRegistry {
|
||||
@utils.style_tag_registry()
|
||||
@formatting.style_tag_registry()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn default_style_tag_registry() -> StyleTagRegistry {
|
||||
@utils.default_style_tag_registry()
|
||||
@formatting.default_style_tag_registry()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn global_style_tag_registry() -> StyleTagRegistry {
|
||||
@utils.global_style_tag_registry()
|
||||
@formatting.global_style_tag_registry()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn set_global_style_tag_registry(registry : StyleTagRegistry) -> Unit {
|
||||
@utils.set_global_style_tag_registry(registry)
|
||||
@formatting.set_global_style_tag_registry(registry)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn reset_global_style_tag_registry() -> Unit {
|
||||
@utils.reset_global_style_tag_registry()
|
||||
@formatting.reset_global_style_tag_registry()
|
||||
}
|
||||
|
||||
///|
|
||||
pub type TextFormatter = @utils.TextFormatter
|
||||
pub type TextFormatter = @formatting.TextFormatter
|
||||
|
||||
///|
|
||||
pub fn text_formatter(
|
||||
@@ -72,7 +72,7 @@ pub fn text_formatter(
|
||||
fields_style_markup? : StyleMarkupMode = StyleMarkupMode::Disabled,
|
||||
style_tags? : StyleTagRegistry? = None,
|
||||
) -> TextFormatter {
|
||||
@utils.text_formatter(
|
||||
@formatting.text_formatter(
|
||||
show_timestamp~,
|
||||
show_level~,
|
||||
show_target~,
|
||||
@@ -91,17 +91,17 @@ pub fn text_formatter(
|
||||
|
||||
///|
|
||||
pub fn color_support_label(support : ColorSupport) -> String {
|
||||
@utils.color_support_label(support)
|
||||
@formatting.color_support_label(support)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn style_markup_mode_label(mode : StyleMarkupMode) -> String {
|
||||
@utils.style_markup_mode_label(mode)
|
||||
@formatting.style_markup_mode_label(mode)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn color_mode_label(mode : ColorMode) -> String {
|
||||
@utils.color_mode_label(mode)
|
||||
@formatting.color_mode_label(mode)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -109,10 +109,10 @@ pub fn format_text(
|
||||
rec : Record,
|
||||
formatter? : TextFormatter = text_formatter(),
|
||||
) -> String {
|
||||
@utils.format_text(rec, formatter~)
|
||||
@formatting.format_text(rec, formatter~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn format_json(rec : Record) -> String {
|
||||
@utils.format_json(rec)
|
||||
@formatting.format_json(rec)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"moonbitlang/core/env",
|
||||
"moonbitlang/core/json",
|
||||
"moonbitlang/core/ref",
|
||||
"moonbitlang/core/string",
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/formatting"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn color_mode_label(ColorMode) -> String
|
||||
|
||||
pub fn color_support_label(ColorSupport) -> String
|
||||
|
||||
pub fn default_style_tag_registry() -> StyleTagRegistry
|
||||
|
||||
pub fn format_json(@core.Record) -> String
|
||||
|
||||
pub fn format_text(@core.Record, formatter? : TextFormatter) -> String
|
||||
|
||||
pub fn global_style_tag_registry() -> StyleTagRegistry
|
||||
|
||||
pub fn reset_global_style_tag_registry() -> Unit
|
||||
|
||||
pub fn set_global_style_tag_registry(StyleTagRegistry) -> Unit
|
||||
|
||||
pub fn style_markup_mode_label(StyleMarkupMode) -> String
|
||||
|
||||
pub fn style_tag_registry() -> StyleTagRegistry
|
||||
|
||||
pub fn text_formatter(show_timestamp? : Bool, show_level? : Bool, show_target? : Bool, show_fields? : Bool, separator? : String, field_separator? : String, template? : String, color_mode? : ColorMode, color_support? : ColorSupport, style_markup? : StyleMarkupMode, target_style_markup? : StyleMarkupMode, fields_style_markup? : StyleMarkupMode, style_tags? : StyleTagRegistry?) -> TextFormatter
|
||||
|
||||
pub fn text_style(fg? : String?, bg? : String?, bold? : Bool, dim? : Bool, italic? : Bool, underline? : Bool) -> TextStyle
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub(all) enum ColorMode {
|
||||
Never
|
||||
Auto
|
||||
Always
|
||||
}
|
||||
|
||||
pub(all) enum ColorSupport {
|
||||
Basic
|
||||
TrueColor
|
||||
}
|
||||
|
||||
pub(all) enum StyleMarkupMode {
|
||||
Disabled
|
||||
Builtin
|
||||
Full
|
||||
}
|
||||
|
||||
pub struct StyleTagRegistry {
|
||||
entries : Map[String, TextStyle]
|
||||
}
|
||||
pub fn StyleTagRegistry::contains(Self, String) -> Bool
|
||||
pub fn StyleTagRegistry::define_alias(Self, String, String) -> Self
|
||||
pub fn StyleTagRegistry::get(Self, String) -> TextStyle?
|
||||
pub fn StyleTagRegistry::set_tag(Self, String, style? : TextStyle, fg? : String?, bg? : String?, bold? : Bool, dim? : Bool, italic? : Bool, underline? : Bool) -> Self
|
||||
|
||||
pub struct TextFormatter {
|
||||
show_timestamp : Bool
|
||||
show_level : Bool
|
||||
show_target : Bool
|
||||
show_fields : Bool
|
||||
separator : String
|
||||
field_separator : String
|
||||
template : String
|
||||
color_mode : ColorMode
|
||||
color_support : ColorSupport
|
||||
style_markup : StyleMarkupMode
|
||||
target_style_markup : StyleMarkupMode
|
||||
fields_style_markup : StyleMarkupMode
|
||||
style_tags : StyleTagRegistry?
|
||||
}
|
||||
pub fn TextFormatter::with_color_support(Self, ColorSupport) -> Self
|
||||
pub fn TextFormatter::with_fields_style_markup(Self, StyleMarkupMode) -> Self
|
||||
pub fn TextFormatter::with_style_markup(Self, StyleMarkupMode) -> Self
|
||||
pub fn TextFormatter::with_style_tags(Self, StyleTagRegistry) -> Self
|
||||
pub fn TextFormatter::with_target_style_markup(Self, StyleMarkupMode) -> Self
|
||||
pub fn TextFormatter::without_style_markup(Self) -> Self
|
||||
|
||||
pub struct TextStyle {
|
||||
fg : String?
|
||||
bg : String?
|
||||
bold : Bool
|
||||
dim : Bool
|
||||
italic : Bool
|
||||
underline : Bool
|
||||
}
|
||||
|
||||
// Type aliases
|
||||
pub type RecordFormatter = (@core.Record) -> String
|
||||
|
||||
// Traits
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ pub fn[S] Logger::with_context_fields(
|
||||
) -> Logger[ContextSink[S]] {
|
||||
{
|
||||
min_level: self.min_level,
|
||||
sink: ContextSink::{ sink: self.sink, context_fields: fields },
|
||||
sink: context_sink(self.sink, fields),
|
||||
target: self.target,
|
||||
timestamp: self.timestamp,
|
||||
}
|
||||
|
||||
+12
-9
@@ -1,6 +1,14 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/record_ops",
|
||||
"Nanaloveyuki/BitLogger/src/config_model",
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/utils",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/file_runtime",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/presets_pkg",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
"Nanaloveyuki/BitLogger/src/runtime",
|
||||
"Nanaloveyuki/BitLogger/src/sink_graph",
|
||||
"maria/json_parser",
|
||||
"moonbitlang/core/array",
|
||||
"moonbitlang/core/builtin",
|
||||
@@ -10,11 +18,6 @@ import {
|
||||
"moonbitlang/core/ref",
|
||||
}
|
||||
|
||||
options(
|
||||
targets: {
|
||||
"sinks_file.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
||||
"runtime_file_controls.mbt": [ "native", "llvm", "js", "wasm", "wasm-gc" ],
|
||||
"file_backend_native.mbt": [ "native", "llvm" ],
|
||||
"file_backend_stub.mbt": [ "js", "wasm", "wasm-gc" ],
|
||||
},
|
||||
)
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/utils",
|
||||
} for "wbtest"
|
||||
|
||||
+8
-8
@@ -1,29 +1,29 @@
|
||||
///|
|
||||
pub type RecordPatch = @utils.RecordPatch
|
||||
pub type RecordPatch = @record_ops.RecordPatch
|
||||
|
||||
///|
|
||||
pub fn identity_patch() -> RecordPatch {
|
||||
@utils.identity_patch()
|
||||
@record_ops.identity_patch()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn set_target(target : String) -> RecordPatch {
|
||||
@utils.set_target(target)
|
||||
@record_ops.set_target(target)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn prefix_message(prefix : String) -> RecordPatch {
|
||||
@utils.prefix_message(prefix)
|
||||
@record_ops.prefix_message(prefix)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn append_fields(extra_fields : Array[Field]) -> RecordPatch {
|
||||
@utils.append_fields(extra_fields)
|
||||
@record_ops.append_fields(extra_fields)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn redact_field(key : String, placeholder? : String = "***") -> RecordPatch {
|
||||
@utils.redact_field(key, placeholder~)
|
||||
@record_ops.redact_field(key, placeholder~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -31,10 +31,10 @@ pub fn redact_fields(
|
||||
keys : Array[String],
|
||||
placeholder? : String = "***",
|
||||
) -> RecordPatch {
|
||||
@utils.redact_fields(keys, placeholder~)
|
||||
@record_ops.redact_fields(keys, placeholder~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
||||
@utils.compose_patches(patches)
|
||||
@record_ops.compose_patches(patches)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,365 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/config_model",
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/file_runtime",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
"Nanaloveyuki/BitLogger/src/runtime",
|
||||
"Nanaloveyuki/BitLogger/src/sink_graph",
|
||||
"maria/json_parser",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn all_of(Array[(@core.Record) -> Bool]) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn any_of(Array[(@core.Record) -> Bool]) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn append_fields(Array[@core.Field]) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn[S] buffered_sink(S, flush_limit? : Int) -> @sink_graph.BufferedSink[S]
|
||||
|
||||
pub fn build_application_logger(@config_model.LoggerConfig) -> Logger[@runtime.RuntimeSink]
|
||||
|
||||
pub fn build_library_logger(@config_model.LoggerConfig) -> LibraryLogger[@runtime.RuntimeSink]
|
||||
|
||||
pub fn build_logger(@config_model.LoggerConfig) -> Logger[@runtime.RuntimeSink]
|
||||
|
||||
pub fn callback_sink((@core.Record) -> Unit) -> @sink_graph.CallbackSink
|
||||
|
||||
pub fn color_mode_label(@formatting.ColorMode) -> String
|
||||
|
||||
pub fn color_support_label(@formatting.ColorSupport) -> String
|
||||
|
||||
pub fn compose_patches(Array[(@core.Record) -> @core.Record]) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn console(min_level? : @core.Level, target? : String, timestamp? : Bool) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn console_sink() -> @sink_graph.ConsoleSink
|
||||
|
||||
pub fn[S] context_sink(S, Array[@core.Field]) -> @sink_graph.ContextSink[S]
|
||||
|
||||
pub fn debug(String, fields? : Array[@core.Field]) -> Unit
|
||||
|
||||
pub fn default_library_logger() -> LibraryLogger[@sink_graph.ConsoleSink]
|
||||
|
||||
pub fn default_logger() -> Logger[@sink_graph.ConsoleSink]
|
||||
|
||||
pub fn default_logger_config() -> @config_model.LoggerConfig
|
||||
|
||||
pub fn default_sink_config() -> @config_model.SinkConfig
|
||||
|
||||
pub fn default_style_tag_registry() -> @formatting.StyleTagRegistry
|
||||
|
||||
pub fn default_text_formatter_config() -> @config_model.TextFormatterConfig
|
||||
|
||||
pub fn error(String, fields? : Array[@core.Field]) -> Unit
|
||||
|
||||
pub fn[A, B] fanout_sink(A, B) -> @sink_graph.FanoutSink[A, B]
|
||||
|
||||
pub fn field(String, String) -> @core.Field
|
||||
|
||||
pub fn field_equals(String, String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn fields(Array[(String, String)]) -> Array[@core.Field]
|
||||
|
||||
pub fn file(String, min_level? : @core.Level, target? : String, timestamp? : Bool, append? : Bool, auto_flush? : Bool, rotation? : @file_model.FileRotation?, text_formatter? : @config_model.TextFormatterConfig) -> @config_model.LoggerConfig raise @config_model.ConfigError
|
||||
|
||||
pub fn file_rotation(Int, max_backups? : Int) -> @file_model.FileRotation
|
||||
|
||||
pub fn file_rotation_config_to_json(@file_model.FileRotation) -> @json_parser.JsonValue
|
||||
|
||||
pub fn file_rotation_i64(Int64, max_backups? : Int) -> @file_model.FileRotation
|
||||
|
||||
pub fn file_sink(String, append? : Bool, auto_flush? : Bool, rotation? : @file_model.FileRotation?, formatter? : (@core.Record) -> String) -> @file_runtime.FileSink
|
||||
|
||||
pub fn file_sink_policy_to_json(@file_model.FileSinkPolicy) -> @json_parser.JsonValue
|
||||
|
||||
pub fn file_sink_state_to_json(@file_model.FileSinkState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn[S] filter_sink(S, (@core.Record) -> Bool) -> @sink_graph.FilterSink[S]
|
||||
|
||||
pub fn format_json(@core.Record) -> String
|
||||
|
||||
pub fn format_text(@core.Record, formatter? : @formatting.TextFormatter) -> String
|
||||
|
||||
pub fn formatted_callback_sink((@core.Record) -> String, (String) -> Unit) -> @sink_graph.FormattedCallbackSink
|
||||
|
||||
pub fn formatted_console_sink((@core.Record) -> String) -> @sink_graph.FormattedConsoleSink
|
||||
|
||||
pub fn global_style_tag_registry() -> @formatting.StyleTagRegistry
|
||||
|
||||
pub fn has_field(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn identity_patch() -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn info(String, fields? : Array[@core.Field]) -> Unit
|
||||
|
||||
pub fn json_console(min_level? : @core.Level, target? : String, timestamp? : Bool) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn json_console_sink() -> @sink_graph.JsonConsoleSink
|
||||
|
||||
pub fn level_at_least(@core.Level) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn log(@core.Level, String, fields? : Array[@core.Field]) -> Unit
|
||||
|
||||
pub fn logger_config_to_json(@config_model.LoggerConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn message_contains(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn native_files_supported() -> Bool
|
||||
|
||||
pub fn not_((@core.Record) -> Bool) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn parse_and_build_application_logger(String) -> Logger[@runtime.RuntimeSink] raise @config_model.ConfigError
|
||||
|
||||
pub fn parse_and_build_library_logger(String) -> LibraryLogger[@runtime.RuntimeSink] raise @config_model.ConfigError
|
||||
|
||||
pub fn parse_and_build_logger(String) -> Logger[@runtime.RuntimeSink] raise @config_model.ConfigError
|
||||
|
||||
pub fn parse_logger_config_text(String) -> @config_model.LoggerConfig raise @config_model.ConfigError
|
||||
|
||||
pub fn[S] patch_sink(S, (@core.Record) -> @core.Record) -> @sink_graph.PatchSink[S]
|
||||
|
||||
pub fn prefix_message(String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn queue_config_to_json(@config_model.QueueConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn[S] queued_sink(S, max_pending? : Int, overflow? : @queue_model.QueueOverflowPolicy) -> @sink_graph.QueuedSink[S]
|
||||
|
||||
pub fn redact_field(String, placeholder? : String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn redact_fields(Array[String], placeholder? : String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn reset_global_style_tag_registry() -> Unit
|
||||
|
||||
pub fn runtime_file_state_to_json(@file_model.RuntimeFileState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn set_default_min_level(@core.Level) -> Unit
|
||||
|
||||
pub fn set_default_target(String) -> Unit
|
||||
|
||||
pub fn set_global_style_tag_registry(@formatting.StyleTagRegistry) -> Unit
|
||||
|
||||
pub fn set_target(String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn sink_config_to_json(@config_model.SinkConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn[A, B] split_by_level(A, B, min_level? : @core.Level) -> @sink_graph.SplitSink[A, B]
|
||||
|
||||
pub fn[A, B] split_sink(A, B, (@core.Record) -> Bool) -> @sink_graph.SplitSink[A, B]
|
||||
|
||||
pub fn stringify_file_sink_policy(@file_model.FileSinkPolicy, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_file_sink_state(@file_model.FileSinkState, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_logger_config(@config_model.LoggerConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_queue_config(@config_model.QueueConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_runtime_file_state(@file_model.RuntimeFileState, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_sink_config(@config_model.SinkConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn stringify_text_formatter_config(@config_model.TextFormatterConfig, pretty? : Bool) -> String
|
||||
|
||||
pub fn style_markup_mode_label(@formatting.StyleMarkupMode) -> String
|
||||
|
||||
pub fn style_tag_registry() -> @formatting.StyleTagRegistry
|
||||
|
||||
pub fn target_has_prefix(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn target_is(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn text_callback_sink(@formatting.TextFormatter, (String) -> Unit) -> @sink_graph.FormattedCallbackSink
|
||||
|
||||
pub fn text_console(min_level? : @core.Level, target? : String, timestamp? : Bool, text_formatter? : @config_model.TextFormatterConfig) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn text_console_sink(@formatting.TextFormatter) -> @sink_graph.FormattedConsoleSink
|
||||
|
||||
pub fn text_formatter(show_timestamp? : Bool, show_level? : Bool, show_target? : Bool, show_fields? : Bool, separator? : String, field_separator? : String, template? : String, color_mode? : @formatting.ColorMode, color_support? : @formatting.ColorSupport, style_markup? : @formatting.StyleMarkupMode, target_style_markup? : @formatting.StyleMarkupMode, fields_style_markup? : @formatting.StyleMarkupMode, style_tags? : @formatting.StyleTagRegistry?) -> @formatting.TextFormatter
|
||||
|
||||
pub fn text_formatter_config_to_json(@config_model.TextFormatterConfig) -> @json_parser.JsonValue
|
||||
|
||||
pub fn text_style(fg? : String?, bg? : String?, bold? : Bool, dim? : Bool, italic? : Bool, underline? : Bool) -> @formatting.TextStyle
|
||||
|
||||
pub fn trace(String, fields? : Array[@core.Field]) -> Unit
|
||||
|
||||
pub fn warn(String, fields? : Array[@core.Field]) -> Unit
|
||||
|
||||
pub fn with_file_rotation(@config_model.LoggerConfig, Int, max_backups? : Int) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn with_file_rotation_i64(@config_model.LoggerConfig, Int64, max_backups? : Int) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn with_queue(@config_model.LoggerConfig, max_pending? : Int, overflow? : @queue_model.QueueOverflowPolicy) -> @config_model.LoggerConfig
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub struct LibraryLogger[S] {
|
||||
inner : Logger[S]
|
||||
}
|
||||
pub fn[S] LibraryLogger::bind(Self[S], Array[@core.Field]) -> Self[@sink_graph.ContextSink[S]]
|
||||
pub fn[S] LibraryLogger::child(Self[S], String) -> Self[S]
|
||||
pub fn[S : @sink_graph.Sink] LibraryLogger::error(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S : @sink_graph.Sink] LibraryLogger::info(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] LibraryLogger::is_enabled(Self[S], @core.Level) -> Bool
|
||||
pub fn[S : @sink_graph.Sink] LibraryLogger::log(Self[S], @core.Level, String, fields? : Array[@core.Field], target? : String) -> Unit
|
||||
pub fn[S] LibraryLogger::new(S, min_level? : @core.Level, target? : String) -> Self[S]
|
||||
pub fn[S] LibraryLogger::to_logger(Self[S]) -> Logger[S]
|
||||
pub fn[S : @sink_graph.Sink] LibraryLogger::warn(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] LibraryLogger::with_context_fields(Self[S], Array[@core.Field]) -> Self[@sink_graph.ContextSink[S]]
|
||||
pub fn[S] LibraryLogger::with_target(Self[S], String) -> Self[S]
|
||||
|
||||
pub struct Logger[S] {
|
||||
min_level : @core.Level
|
||||
sink : S
|
||||
target : String
|
||||
timestamp : Bool
|
||||
}
|
||||
pub fn[S] Logger::bind(Self[S], Array[@core.Field]) -> Self[@sink_graph.ContextSink[S]]
|
||||
pub fn[S] Logger::child(Self[S], String) -> Self[S]
|
||||
pub fn Logger::close(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn[S : @sink_graph.Sink] Logger::debug(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn Logger::drain(Self[@runtime.RuntimeSink], max_items? : Int) -> Int
|
||||
pub fn Logger::drain_progress(Self[@runtime.RuntimeSink], max_items? : Int) -> @runtime.RuntimeSinkProgress
|
||||
pub fn Logger::dropped_count(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn[S : @sink_graph.Sink] Logger::error(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn Logger::file_append_mode(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_auto_flush(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_available(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_clear_rotation(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_close(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_default_policy(Self[@runtime.RuntimeSink]) -> @file_model.FileSinkPolicy
|
||||
pub fn Logger::file_default_policy_or_none(Self[@runtime.RuntimeSink]) -> @file_model.FileSinkPolicy?
|
||||
pub fn Logger::file_flush(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_flush_failures(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn Logger::file_open_failures(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn Logger::file_path(Self[@runtime.RuntimeSink]) -> String
|
||||
pub fn Logger::file_path_or_none(Self[@runtime.RuntimeSink]) -> String?
|
||||
pub fn Logger::file_policy(Self[@runtime.RuntimeSink]) -> @file_model.FileSinkPolicy
|
||||
pub fn Logger::file_policy_matches_default(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_policy_or_none(Self[@runtime.RuntimeSink]) -> @file_model.FileSinkPolicy?
|
||||
pub fn Logger::file_reopen(Self[@runtime.RuntimeSink], append? : Bool?) -> Bool
|
||||
pub fn Logger::file_reopen_append(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_reopen_truncate(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_reopen_with_current_policy(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_reset_failure_counters(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_reset_policy(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_rotation_config(Self[@runtime.RuntimeSink]) -> @file_model.FileRotation?
|
||||
pub fn Logger::file_rotation_enabled(Self[@runtime.RuntimeSink]) -> Bool
|
||||
pub fn Logger::file_rotation_failures(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn Logger::file_runtime_state(Self[@runtime.RuntimeSink]) -> @file_model.RuntimeFileState?
|
||||
pub fn Logger::file_set_append_mode(Self[@runtime.RuntimeSink], Bool) -> Bool
|
||||
pub fn Logger::file_set_auto_flush(Self[@runtime.RuntimeSink], Bool) -> Bool
|
||||
pub fn Logger::file_set_policy(Self[@runtime.RuntimeSink], @file_model.FileSinkPolicy) -> Bool
|
||||
pub fn Logger::file_set_rotation(Self[@runtime.RuntimeSink], @file_model.FileRotation?) -> Bool
|
||||
pub fn Logger::file_state(Self[@runtime.RuntimeSink]) -> @file_model.FileSinkState
|
||||
pub fn Logger::file_state_or_none(Self[@runtime.RuntimeSink]) -> @file_model.FileSinkState?
|
||||
pub fn Logger::file_write_failures(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn Logger::flush(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn Logger::flush_progress(Self[@runtime.RuntimeSink]) -> @runtime.RuntimeSinkProgress
|
||||
pub fn[S : @sink_graph.Sink] Logger::info(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] Logger::is_enabled(Self[S], @core.Level) -> Bool
|
||||
pub fn[S : @sink_graph.Sink] Logger::log(Self[S], @core.Level, String, fields? : Array[@core.Field], target? : String) -> Unit
|
||||
pub fn[S] Logger::new(S, min_level? : @core.Level, target? : String) -> Self[S]
|
||||
pub fn Logger::pending_count(Self[@runtime.RuntimeSink]) -> Int
|
||||
pub fn[S] Logger::to_library_logger(Self[S]) -> LibraryLogger[S]
|
||||
pub fn[S : @sink_graph.Sink] Logger::trace(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S : @sink_graph.Sink] Logger::warn(Self[S], String, fields? : Array[@core.Field]) -> Unit
|
||||
pub fn[S] Logger::with_context_fields(Self[S], Array[@core.Field]) -> Self[@sink_graph.ContextSink[S]]
|
||||
pub fn[S] Logger::with_filter(Self[S], (@core.Record) -> Bool) -> Self[@sink_graph.FilterSink[S]]
|
||||
pub fn[S] Logger::with_min_level(Self[S], @core.Level) -> Self[S]
|
||||
pub fn[S] Logger::with_patch(Self[S], (@core.Record) -> @core.Record) -> Self[@sink_graph.PatchSink[S]]
|
||||
pub fn[S] Logger::with_queue(Self[S], max_pending? : Int, overflow? : @queue_model.QueueOverflowPolicy) -> Self[@sink_graph.QueuedSink[S]]
|
||||
pub fn[S] Logger::with_target(Self[S], String) -> Self[S]
|
||||
pub fn[S] Logger::with_timestamp(Self[S], enabled? : Bool) -> Self[S]
|
||||
|
||||
// Type aliases
|
||||
pub type ApplicationLogger = Logger[@runtime.RuntimeSink]
|
||||
|
||||
pub using @sink_graph {type BufferedSink}
|
||||
|
||||
pub using @sink_graph {type CallbackSink}
|
||||
|
||||
pub using @formatting {type ColorMode}
|
||||
|
||||
pub using @formatting {type ColorSupport}
|
||||
|
||||
pub using @config_model {type ConfigError}
|
||||
|
||||
pub type ConfiguredLogger = Logger[@runtime.RuntimeSink]
|
||||
|
||||
pub using @sink_graph {type ConsoleSink}
|
||||
|
||||
pub using @sink_graph {type ContextSink}
|
||||
|
||||
pub using @sink_graph {type FanoutSink}
|
||||
|
||||
pub using @core {type Field}
|
||||
|
||||
pub using @file_model {type FileRotation}
|
||||
|
||||
pub using @file_runtime {type FileSink}
|
||||
|
||||
pub using @file_model {type FileSinkPolicy}
|
||||
|
||||
pub using @file_model {type FileSinkState}
|
||||
|
||||
pub using @sink_graph {type FilterSink}
|
||||
|
||||
pub using @sink_graph {type FormattedCallbackSink}
|
||||
|
||||
pub using @sink_graph {type FormattedConsoleSink}
|
||||
|
||||
pub using @sink_graph {type JsonConsoleSink}
|
||||
|
||||
pub using @core {type Level}
|
||||
|
||||
pub using @config_model {type LoggerConfig}
|
||||
|
||||
pub using @sink_graph {type PatchSink}
|
||||
|
||||
pub using @config_model {type QueueConfig}
|
||||
|
||||
pub using @queue_model {type QueueOverflowPolicy}
|
||||
|
||||
pub using @sink_graph {type QueuedSink}
|
||||
|
||||
pub using @core {type Record}
|
||||
|
||||
pub type RecordFormatter = (@core.Record) -> String
|
||||
|
||||
pub type RecordPatch = (@core.Record) -> @core.Record
|
||||
|
||||
pub type RecordPredicate = (@core.Record) -> Bool
|
||||
|
||||
pub using @file_model {type RuntimeFileState}
|
||||
|
||||
pub using @runtime {type RuntimeSink}
|
||||
|
||||
pub using @runtime {type RuntimeSinkProgress}
|
||||
|
||||
pub using @config_model {type SinkConfig}
|
||||
|
||||
pub using @config_model {type SinkKind}
|
||||
|
||||
pub using @sink_graph {type SplitSink}
|
||||
|
||||
pub using @formatting {type StyleMarkupMode}
|
||||
|
||||
pub using @formatting {type StyleTagRegistry}
|
||||
|
||||
pub using @formatting {type TextFormatter}
|
||||
|
||||
pub using @config_model {type TextFormatterConfig}
|
||||
|
||||
pub using @formatting {type TextStyle}
|
||||
|
||||
pub using @sink_graph {trait Sink}
|
||||
|
||||
// Traits
|
||||
|
||||
+12
-73
@@ -4,12 +4,7 @@ pub fn console(
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
) -> LoggerConfig {
|
||||
LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=SinkConfig::new(kind=SinkKind::Console),
|
||||
)
|
||||
@presets_pkg.console(min_level~, target~, timestamp~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -18,12 +13,7 @@ pub fn json_console(
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
) -> LoggerConfig {
|
||||
LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=SinkConfig::new(kind=SinkKind::JsonConsole),
|
||||
)
|
||||
@presets_pkg.json_console(min_level~, target~, timestamp~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -33,12 +23,7 @@ pub fn text_console(
|
||||
timestamp? : Bool = false,
|
||||
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||
) -> LoggerConfig {
|
||||
LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=SinkConfig::new(kind=SinkKind::TextConsole, text_formatter~),
|
||||
)
|
||||
@presets_pkg.text_console(min_level~, target~, timestamp~, text_formatter~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -52,21 +37,15 @@ pub fn file(
|
||||
rotation? : FileRotation? = None,
|
||||
text_formatter? : TextFormatterConfig = default_text_formatter_config(),
|
||||
) -> LoggerConfig raise ConfigError {
|
||||
if path == "" {
|
||||
raise ConfigError::InvalidConfig("File sink requires non-empty path")
|
||||
}
|
||||
LoggerConfig::new(
|
||||
@presets_pkg.file(
|
||||
path,
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=SinkConfig::new(
|
||||
kind=SinkKind::File,
|
||||
path~,
|
||||
append~,
|
||||
auto_flush~,
|
||||
rotation~,
|
||||
text_formatter~,
|
||||
),
|
||||
append~,
|
||||
auto_flush~,
|
||||
rotation~,
|
||||
text_formatter~,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -76,13 +55,7 @@ pub fn with_queue(
|
||||
max_pending? : Int = 0,
|
||||
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||
) -> LoggerConfig {
|
||||
LoggerConfig::new(
|
||||
min_level=config.min_level,
|
||||
target=config.target,
|
||||
timestamp=config.timestamp,
|
||||
sink=config.sink,
|
||||
queue=Some(QueueConfig::new(max_pending, overflow~)),
|
||||
)
|
||||
@presets_pkg.with_queue(config, max_pending~, overflow~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -91,24 +64,7 @@ pub fn with_file_rotation(
|
||||
max_bytes : Int,
|
||||
max_backups? : Int = 1,
|
||||
) -> LoggerConfig {
|
||||
match config.sink.kind {
|
||||
SinkKind::File =>
|
||||
LoggerConfig::new(
|
||||
min_level=config.min_level,
|
||||
target=config.target,
|
||||
timestamp=config.timestamp,
|
||||
sink=SinkConfig::new(
|
||||
kind=config.sink.kind,
|
||||
path=config.sink.path,
|
||||
append=config.sink.append,
|
||||
auto_flush=config.sink.auto_flush,
|
||||
rotation=Some(file_rotation(max_bytes, max_backups~)),
|
||||
text_formatter=config.sink.text_formatter,
|
||||
),
|
||||
queue=config.queue,
|
||||
)
|
||||
_ => config
|
||||
}
|
||||
@presets_pkg.with_file_rotation(config, max_bytes, max_backups~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -117,22 +73,5 @@ pub fn with_file_rotation_i64(
|
||||
max_bytes : Int64,
|
||||
max_backups? : Int = 1,
|
||||
) -> LoggerConfig {
|
||||
match config.sink.kind {
|
||||
SinkKind::File =>
|
||||
LoggerConfig::new(
|
||||
min_level=config.min_level,
|
||||
target=config.target,
|
||||
timestamp=config.timestamp,
|
||||
sink=SinkConfig::new(
|
||||
kind=config.sink.kind,
|
||||
path=config.sink.path,
|
||||
append=config.sink.append,
|
||||
auto_flush=config.sink.auto_flush,
|
||||
rotation=Some(file_rotation_i64(max_bytes, max_backups~)),
|
||||
text_formatter=config.sink.text_formatter,
|
||||
),
|
||||
queue=config.queue,
|
||||
)
|
||||
_ => config
|
||||
}
|
||||
@presets_pkg.with_file_rotation_i64(config, max_bytes, max_backups~)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/config_model",
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/presets_pkg"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/config_model",
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn console(min_level? : @core.Level, target? : String, timestamp? : Bool) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn file(String, min_level? : @core.Level, target? : String, timestamp? : Bool, append? : Bool, auto_flush? : Bool, rotation? : @file_model.FileRotation?, text_formatter? : @config_model.TextFormatterConfig) -> @config_model.LoggerConfig raise @config_model.ConfigError
|
||||
|
||||
pub fn json_console(min_level? : @core.Level, target? : String, timestamp? : Bool) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn text_console(min_level? : @core.Level, target? : String, timestamp? : Bool, text_formatter? : @config_model.TextFormatterConfig) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn with_file_rotation(@config_model.LoggerConfig, Int, max_backups? : Int) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn with_file_rotation_i64(@config_model.LoggerConfig, Int64, max_backups? : Int) -> @config_model.LoggerConfig
|
||||
|
||||
pub fn with_queue(@config_model.LoggerConfig, max_pending? : Int, overflow? : @queue_model.QueueOverflowPolicy) -> @config_model.LoggerConfig
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
|
||||
// Type aliases
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
///|
|
||||
pub fn console(
|
||||
min_level? : @core.Level = @core.Level::Info,
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
) -> @config_model.LoggerConfig {
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=@config_model.SinkConfig::new(kind=@config_model.SinkKind::Console),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn json_console(
|
||||
min_level? : @core.Level = @core.Level::Info,
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
) -> @config_model.LoggerConfig {
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=@config_model.SinkConfig::new(kind=@config_model.SinkKind::JsonConsole),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_console(
|
||||
min_level? : @core.Level = @core.Level::Info,
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
text_formatter? : @config_model.TextFormatterConfig = @config_model.default_text_formatter_config(),
|
||||
) -> @config_model.LoggerConfig {
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=@config_model.SinkConfig::new(
|
||||
kind=@config_model.SinkKind::TextConsole,
|
||||
text_formatter~,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file(
|
||||
path : String,
|
||||
min_level? : @core.Level = @core.Level::Info,
|
||||
target? : String = "",
|
||||
timestamp? : Bool = false,
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : @file_model.FileRotation? = None,
|
||||
text_formatter? : @config_model.TextFormatterConfig = @config_model.default_text_formatter_config(),
|
||||
) -> @config_model.LoggerConfig raise @config_model.ConfigError {
|
||||
if path == "" {
|
||||
raise @config_model.ConfigError::InvalidConfig(
|
||||
"File sink requires non-empty path",
|
||||
)
|
||||
}
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level~,
|
||||
target~,
|
||||
timestamp~,
|
||||
sink=@config_model.SinkConfig::new(
|
||||
kind=@config_model.SinkKind::File,
|
||||
path~,
|
||||
append~,
|
||||
auto_flush~,
|
||||
rotation~,
|
||||
text_formatter~,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn with_queue(
|
||||
config : @config_model.LoggerConfig,
|
||||
max_pending? : Int = 0,
|
||||
overflow? : @queue_model.QueueOverflowPolicy = @queue_model.QueueOverflowPolicy::DropNewest,
|
||||
) -> @config_model.LoggerConfig {
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level=config.min_level,
|
||||
target=config.target,
|
||||
timestamp=config.timestamp,
|
||||
sink=config.sink,
|
||||
queue=Some(@config_model.QueueConfig::new(max_pending, overflow~)),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn with_file_rotation(
|
||||
config : @config_model.LoggerConfig,
|
||||
max_bytes : Int,
|
||||
max_backups? : Int = 1,
|
||||
) -> @config_model.LoggerConfig {
|
||||
match config.sink.kind {
|
||||
@config_model.SinkKind::File =>
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level=config.min_level,
|
||||
target=config.target,
|
||||
timestamp=config.timestamp,
|
||||
sink=@config_model.SinkConfig::new(
|
||||
kind=config.sink.kind,
|
||||
path=config.sink.path,
|
||||
append=config.sink.append,
|
||||
auto_flush=config.sink.auto_flush,
|
||||
rotation=Some(@file_model.file_rotation(max_bytes, max_backups~)),
|
||||
text_formatter=config.sink.text_formatter,
|
||||
),
|
||||
queue=config.queue,
|
||||
)
|
||||
_ => config
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn with_file_rotation_i64(
|
||||
config : @config_model.LoggerConfig,
|
||||
max_bytes : Int64,
|
||||
max_backups? : Int = 1,
|
||||
) -> @config_model.LoggerConfig {
|
||||
match config.sink.kind {
|
||||
@config_model.SinkKind::File =>
|
||||
@config_model.LoggerConfig::new(
|
||||
min_level=config.min_level,
|
||||
target=config.target,
|
||||
timestamp=config.timestamp,
|
||||
sink=@config_model.SinkConfig::new(
|
||||
kind=config.sink.kind,
|
||||
path=config.sink.path,
|
||||
append=config.sink.append,
|
||||
auto_flush=config.sink.auto_flush,
|
||||
rotation=Some(@file_model.file_rotation_i64(max_bytes, max_backups~)),
|
||||
text_formatter=config.sink.text_formatter,
|
||||
),
|
||||
queue=config.queue,
|
||||
)
|
||||
_ => config
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
///|
|
||||
@@ -0,0 +1,17 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/queue_model"
|
||||
|
||||
// Values
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub(all) enum QueueOverflowPolicy {
|
||||
DropNewest
|
||||
DropOldest
|
||||
}
|
||||
|
||||
// Type aliases
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
///|
|
||||
pub(all) enum QueueOverflowPolicy {
|
||||
DropNewest
|
||||
DropOldest
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
///|
|
||||
pub type RecordPredicate = (@core.Record) -> Bool
|
||||
|
||||
///|
|
||||
pub fn level_at_least(min_level : @core.Level) -> RecordPredicate {
|
||||
fn(rec) { rec.level.priority() >= min_level.priority() }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_is(target : String) -> RecordPredicate {
|
||||
fn(rec) { rec.target == target }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
||||
fn(rec) { rec.target.has_prefix(prefix) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn message_contains(fragment : String) -> RecordPredicate {
|
||||
fn(rec) { rec.message.contains(fragment) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn has_field(key : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for field in rec.fields {
|
||||
if field.key == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for field in rec.fields {
|
||||
if field.key == key && field.value == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
||||
fn(rec) { !predicate(rec) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for predicate in predicates {
|
||||
if !predicate(rec) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for predicate in predicates {
|
||||
if predicate(rec) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"moonbitlang/core/string",
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
///|
|
||||
pub type RecordPatch = (@core.Record) -> @core.Record
|
||||
|
||||
///|
|
||||
pub fn identity_patch() -> RecordPatch {
|
||||
fn(rec) { rec }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn set_target(target : String) -> RecordPatch {
|
||||
fn(rec) { rec.with_target(target) }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn prefix_message(prefix : String) -> RecordPatch {
|
||||
fn(rec) { rec.with_message("\{prefix}\{rec.message}") }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch {
|
||||
fn(rec) {
|
||||
if extra_fields.length() == 0 {
|
||||
rec
|
||||
} else if rec.fields.length() == 0 {
|
||||
rec.with_fields(extra_fields)
|
||||
} else {
|
||||
rec.with_fields(rec.fields + extra_fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn redact_field(key : String, placeholder? : String = "***") -> RecordPatch {
|
||||
fn(rec) {
|
||||
rec.with_fields(
|
||||
rec.fields.map(fn(field) {
|
||||
if field.key == key {
|
||||
field.with_value(placeholder)
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn redact_fields(
|
||||
keys : Array[String],
|
||||
placeholder? : String = "***",
|
||||
) -> RecordPatch {
|
||||
fn(rec) {
|
||||
rec.with_fields(
|
||||
rec.fields.map(fn(field) {
|
||||
if keys.contains(field.key) {
|
||||
field.with_value(placeholder)
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
||||
fn(rec) {
|
||||
let mut current = rec
|
||||
for patch in patches {
|
||||
current = patch(current)
|
||||
}
|
||||
current
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/record_ops"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn all_of(Array[(@core.Record) -> Bool]) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn any_of(Array[(@core.Record) -> Bool]) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn append_fields(Array[@core.Field]) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn compose_patches(Array[(@core.Record) -> @core.Record]) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn field_equals(String, String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn has_field(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn identity_patch() -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn level_at_least(@core.Level) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn message_contains(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn not_((@core.Record) -> Bool) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn prefix_message(String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn redact_field(String, placeholder? : String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn redact_fields(Array[String], placeholder? : String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn set_target(String) -> (@core.Record) -> @core.Record
|
||||
|
||||
pub fn target_has_prefix(String) -> (@core.Record) -> Bool
|
||||
|
||||
pub fn target_is(String) -> (@core.Record) -> Bool
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
|
||||
// Type aliases
|
||||
pub type RecordPatch = (@core.Record) -> @core.Record
|
||||
|
||||
pub type RecordPredicate = (@core.Record) -> Bool
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/config_model",
|
||||
"Nanaloveyuki/BitLogger/src/file_runtime",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/sink_graph",
|
||||
"maria/json_parser",
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/runtime"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/config_model",
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/file_model",
|
||||
"Nanaloveyuki/BitLogger/src/file_runtime",
|
||||
"Nanaloveyuki/BitLogger/src/sink_graph",
|
||||
"maria/json_parser",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn apply_queue_config(RuntimeSink, @config_model.QueueConfig) -> RuntimeSink
|
||||
|
||||
pub fn build_runtime_sink(@config_model.SinkConfig) -> RuntimeSink
|
||||
|
||||
pub fn runtime_file_state_to_json(@file_model.RuntimeFileState) -> @json_parser.JsonValue
|
||||
|
||||
pub fn stringify_runtime_file_state(@file_model.RuntimeFileState, pretty? : Bool) -> String
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub(all) enum RuntimeSink {
|
||||
Console(@sink_graph.ConsoleSink)
|
||||
JsonConsole(@sink_graph.JsonConsoleSink)
|
||||
TextConsole(@sink_graph.FormattedConsoleSink)
|
||||
File(@file_runtime.FileSink)
|
||||
QueuedConsole(@sink_graph.QueuedSink[@sink_graph.ConsoleSink])
|
||||
QueuedJsonConsole(@sink_graph.QueuedSink[@sink_graph.JsonConsoleSink])
|
||||
QueuedTextConsole(@sink_graph.QueuedSink[@sink_graph.FormattedConsoleSink])
|
||||
QueuedFile(@sink_graph.QueuedSink[@file_runtime.FileSink])
|
||||
}
|
||||
pub fn RuntimeSink::close(Self) -> Bool
|
||||
pub fn RuntimeSink::drain(Self, max_items? : Int) -> Int
|
||||
pub fn RuntimeSink::drain_progress(Self, max_items? : Int) -> RuntimeSinkProgress
|
||||
pub fn RuntimeSink::dropped_count(Self) -> Int
|
||||
pub fn RuntimeSink::file_append_mode(Self) -> Bool
|
||||
pub fn RuntimeSink::file_auto_flush(Self) -> Bool
|
||||
pub fn RuntimeSink::file_available(Self) -> Bool
|
||||
pub fn RuntimeSink::file_clear_rotation(Self) -> Bool
|
||||
pub fn RuntimeSink::file_close(Self) -> Bool
|
||||
pub fn RuntimeSink::file_default_policy(Self) -> @file_model.FileSinkPolicy
|
||||
pub fn RuntimeSink::file_default_policy_or_none(Self) -> @file_model.FileSinkPolicy?
|
||||
pub fn RuntimeSink::file_flush(Self) -> Bool
|
||||
pub fn RuntimeSink::file_flush_failures(Self) -> Int
|
||||
pub fn RuntimeSink::file_open_failures(Self) -> Int
|
||||
pub fn RuntimeSink::file_path(Self) -> String
|
||||
pub fn RuntimeSink::file_path_or_none(Self) -> String?
|
||||
pub fn RuntimeSink::file_policy(Self) -> @file_model.FileSinkPolicy
|
||||
pub fn RuntimeSink::file_policy_matches_default(Self) -> Bool
|
||||
pub fn RuntimeSink::file_policy_or_none(Self) -> @file_model.FileSinkPolicy?
|
||||
pub fn RuntimeSink::file_reopen(Self, append? : Bool?) -> Bool
|
||||
pub fn RuntimeSink::file_reopen_append(Self) -> Bool
|
||||
pub fn RuntimeSink::file_reopen_truncate(Self) -> Bool
|
||||
pub fn RuntimeSink::file_reopen_with_current_policy(Self) -> Bool
|
||||
pub fn RuntimeSink::file_reset_failure_counters(Self) -> Bool
|
||||
pub fn RuntimeSink::file_reset_policy(Self) -> Bool
|
||||
pub fn RuntimeSink::file_rotation_config(Self) -> @file_model.FileRotation?
|
||||
pub fn RuntimeSink::file_rotation_enabled(Self) -> Bool
|
||||
pub fn RuntimeSink::file_rotation_failures(Self) -> Int
|
||||
pub fn RuntimeSink::file_runtime_state(Self) -> @file_model.RuntimeFileState?
|
||||
pub fn RuntimeSink::file_set_append_mode(Self, Bool) -> Bool
|
||||
pub fn RuntimeSink::file_set_auto_flush(Self, Bool) -> Bool
|
||||
pub fn RuntimeSink::file_set_policy(Self, @file_model.FileSinkPolicy) -> Bool
|
||||
pub fn RuntimeSink::file_set_rotation(Self, @file_model.FileRotation?) -> Bool
|
||||
pub fn RuntimeSink::file_state(Self) -> @file_model.FileSinkState
|
||||
pub fn RuntimeSink::file_state_or_none(Self) -> @file_model.FileSinkState?
|
||||
pub fn RuntimeSink::file_write_failures(Self) -> Int
|
||||
pub fn RuntimeSink::flush(Self) -> Int
|
||||
pub fn RuntimeSink::flush_progress(Self) -> RuntimeSinkProgress
|
||||
pub fn RuntimeSink::pending_count(Self) -> Int
|
||||
pub impl @sink_graph.Sink for RuntimeSink
|
||||
|
||||
pub struct RuntimeSinkProgress {
|
||||
queue_advanced_count : Int
|
||||
file_flush_step_count : Int
|
||||
queue_backed : Bool
|
||||
file_backed : Bool
|
||||
}
|
||||
|
||||
// Type aliases
|
||||
pub using @file_model {type RuntimeFileState}
|
||||
|
||||
// Traits
|
||||
|
||||
@@ -0,0 +1,746 @@
|
||||
///|
|
||||
type SinkConfig = @config_model.SinkConfig
|
||||
|
||||
///|
|
||||
type SinkKind = @config_model.SinkKind
|
||||
|
||||
///|
|
||||
type QueueConfig = @config_model.QueueConfig
|
||||
|
||||
///|
|
||||
type FileSink = @file_runtime.FileSink
|
||||
|
||||
///|
|
||||
type FileRotation = @file_model.FileRotation
|
||||
|
||||
///|
|
||||
type FileSinkState = @file_model.FileSinkState
|
||||
|
||||
///|
|
||||
type FileSinkPolicy = @file_model.FileSinkPolicy
|
||||
|
||||
///|
|
||||
type ConsoleSink = @sink_graph.ConsoleSink
|
||||
|
||||
///|
|
||||
type JsonConsoleSink = @sink_graph.JsonConsoleSink
|
||||
|
||||
///|
|
||||
type FormattedConsoleSink = @sink_graph.FormattedConsoleSink
|
||||
|
||||
///|
|
||||
type QueuedSink[S] = @sink_graph.QueuedSink[S]
|
||||
|
||||
///|
|
||||
pub(all) enum RuntimeSink {
|
||||
Console(ConsoleSink)
|
||||
JsonConsole(JsonConsoleSink)
|
||||
TextConsole(FormattedConsoleSink)
|
||||
File(FileSink)
|
||||
QueuedConsole(QueuedSink[ConsoleSink])
|
||||
QueuedJsonConsole(QueuedSink[JsonConsoleSink])
|
||||
QueuedTextConsole(QueuedSink[FormattedConsoleSink])
|
||||
QueuedFile(QueuedSink[FileSink])
|
||||
}
|
||||
|
||||
///|
|
||||
pub type RuntimeFileState = @file_model.RuntimeFileState
|
||||
|
||||
///|
|
||||
pub struct RuntimeSinkProgress {
|
||||
queue_advanced_count : Int
|
||||
file_flush_step_count : Int
|
||||
queue_backed : Bool
|
||||
file_backed : Bool
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn runtime_file_state_to_json(
|
||||
state : RuntimeFileState,
|
||||
) -> @json_parser.JsonValue {
|
||||
@file_model.runtime_file_state_to_json(state)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn stringify_runtime_file_state(
|
||||
state : RuntimeFileState,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@file_model.stringify_runtime_file_state(state, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl @sink_graph.Sink for RuntimeSink with fn write(self, rec) {
|
||||
match self {
|
||||
Console(sink) => sink.write(rec)
|
||||
JsonConsole(sink) => sink.write(rec)
|
||||
TextConsole(sink) => sink.write(rec)
|
||||
File(sink) => sink.write(rec)
|
||||
QueuedConsole(sink) => sink.write(rec)
|
||||
QueuedJsonConsole(sink) => sink.write(rec)
|
||||
QueuedTextConsole(sink) => sink.write(rec)
|
||||
QueuedFile(sink) => sink.write(rec)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn[S : @sink_graph.Sink] queued_sink_close_internal(
|
||||
sink : QueuedSink[S],
|
||||
) -> Bool {
|
||||
ignore(sink.flush())
|
||||
sink.pending_count() == 0
|
||||
}
|
||||
|
||||
///|
|
||||
fn runtime_file_sink_internal(sink : RuntimeSink) -> FileSink? {
|
||||
match sink {
|
||||
File(sink) => Some(sink)
|
||||
QueuedFile(sink) => Some(sink.sink)
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn queued_file_policy_mutation_allowed_internal(
|
||||
sink : QueuedSink[FileSink],
|
||||
) -> Bool {
|
||||
sink.pending_count() == 0
|
||||
}
|
||||
|
||||
///|
|
||||
fn queued_file_flush_internal(sink : QueuedSink[FileSink]) -> Bool {
|
||||
let before_write_failures = sink.sink.write_failures()
|
||||
let before_flush_failures = sink.sink.flush_failures()
|
||||
let before_rotation_failures = sink.sink.rotation_failures()
|
||||
ignore(sink.flush())
|
||||
let flushed = sink.sink.flush()
|
||||
sink.pending_count() == 0 &&
|
||||
flushed &&
|
||||
sink.sink.write_failures() == before_write_failures &&
|
||||
sink.sink.flush_failures() == before_flush_failures &&
|
||||
sink.sink.rotation_failures() == before_rotation_failures
|
||||
}
|
||||
|
||||
///|
|
||||
fn queued_file_close_internal(sink : QueuedSink[FileSink]) -> Bool {
|
||||
let flushed = queued_file_flush_internal(sink)
|
||||
let closed = sink.sink.close()
|
||||
flushed && closed
|
||||
}
|
||||
|
||||
///|
|
||||
fn runtime_sink_progress_compat_count(progress : RuntimeSinkProgress) -> Int {
|
||||
progress.queue_advanced_count + progress.file_flush_step_count
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::flush_progress(self : RuntimeSink) -> RuntimeSinkProgress {
|
||||
match self {
|
||||
Console(_) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
JsonConsole(_) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
TextConsole(_) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
File(sink) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: if sink.flush() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
queue_backed: false,
|
||||
file_backed: true,
|
||||
}
|
||||
QueuedConsole(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedJsonConsole(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedTextConsole(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::flush(self : RuntimeSink) -> Int {
|
||||
runtime_sink_progress_compat_count(self.flush_progress())
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::drain_progress(
|
||||
self : RuntimeSink,
|
||||
max_items? : Int = -1,
|
||||
) -> RuntimeSinkProgress {
|
||||
match self {
|
||||
Console(_) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
JsonConsole(_) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
TextConsole(_) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
File(sink) =>
|
||||
{
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: if sink.flush() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
},
|
||||
queue_backed: false,
|
||||
file_backed: true,
|
||||
}
|
||||
QueuedConsole(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedJsonConsole(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedTextConsole(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
{
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::drain(self : RuntimeSink, max_items? : Int = -1) -> Int {
|
||||
runtime_sink_progress_compat_count(self.drain_progress(max_items~))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::close(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
Console(_) => true
|
||||
JsonConsole(_) => true
|
||||
TextConsole(_) => true
|
||||
File(sink) => sink.close()
|
||||
QueuedConsole(sink) => queued_sink_close_internal(sink)
|
||||
QueuedJsonConsole(sink) => queued_sink_close_internal(sink)
|
||||
QueuedTextConsole(sink) => queued_sink_close_internal(sink)
|
||||
QueuedFile(sink) => queued_file_close_internal(sink)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::pending_count(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
Console(_) => 0
|
||||
JsonConsole(_) => 0
|
||||
TextConsole(_) => 0
|
||||
File(_) => 0
|
||||
QueuedConsole(sink) => sink.pending_count()
|
||||
QueuedJsonConsole(sink) => sink.pending_count()
|
||||
QueuedTextConsole(sink) => sink.pending_count()
|
||||
QueuedFile(sink) => sink.pending_count()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::dropped_count(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
Console(_) => 0
|
||||
JsonConsole(_) => 0
|
||||
TextConsole(_) => 0
|
||||
File(_) => 0
|
||||
QueuedConsole(sink) => sink.dropped_count()
|
||||
QueuedJsonConsole(sink) => sink.dropped_count()
|
||||
QueuedTextConsole(sink) => sink.dropped_count()
|
||||
QueuedFile(sink) => sink.dropped_count()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_available(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.is_available()
|
||||
QueuedFile(sink) => sink.sink.is_available()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen(
|
||||
self : RuntimeSink,
|
||||
append? : Bool? = None,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.reopen(append~)
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.reopen(append~)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen_with_current_policy(self : RuntimeSink) -> Bool {
|
||||
self.file_reopen()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen_append(self : RuntimeSink) -> Bool {
|
||||
self.file_reopen(append=Some(true))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen_truncate(self : RuntimeSink) -> Bool {
|
||||
self.file_reopen(append=Some(false))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_append_mode(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.append_mode()
|
||||
QueuedFile(sink) => sink.sink.append_mode()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_append_mode(
|
||||
self : RuntimeSink,
|
||||
append : Bool,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_append_mode(append)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_append_mode(append)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_path_or_none(self : RuntimeSink) -> String? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.path() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_path(self : RuntimeSink) -> String {
|
||||
self.file_path_or_none().unwrap_or("")
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_auto_flush(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.auto_flush_enabled()
|
||||
QueuedFile(sink) => sink.sink.auto_flush_enabled()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_rotation_enabled(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.rotation_enabled()
|
||||
QueuedFile(sink) => sink.sink.rotation_enabled()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_rotation_config(self : RuntimeSink) -> FileRotation? {
|
||||
match self {
|
||||
File(sink) => sink.rotation_config()
|
||||
QueuedFile(sink) => sink.sink.rotation_config()
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_auto_flush(
|
||||
self : RuntimeSink,
|
||||
enabled : Bool,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_auto_flush(enabled)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_auto_flush(enabled)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_policy(
|
||||
self : RuntimeSink,
|
||||
policy : FileSinkPolicy,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_policy(policy)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_policy(policy)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_rotation(
|
||||
self : RuntimeSink,
|
||||
rotation : FileRotation?,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_rotation(rotation)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_rotation(rotation)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_clear_rotation(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.clear_rotation()
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.clear_rotation()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_flush(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.flush()
|
||||
QueuedFile(sink) => queued_file_flush_internal(sink)
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_close(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.close()
|
||||
QueuedFile(sink) => queued_file_close_internal(sink)
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_open_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.open_failures()
|
||||
QueuedFile(sink) => sink.sink.open_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_write_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.write_failures()
|
||||
QueuedFile(sink) => sink.sink.write_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_flush_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.flush_failures()
|
||||
QueuedFile(sink) => sink.sink.flush_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_rotation_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.rotation_failures()
|
||||
QueuedFile(sink) => sink.sink.rotation_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reset_failure_counters(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.reset_failure_counters()
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
sink.sink.reset_failure_counters()
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reset_policy(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.reset_policy()
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.reset_policy()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_policy_or_none(self : RuntimeSink) -> FileSinkPolicy? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.policy() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_policy(self : RuntimeSink) -> FileSinkPolicy {
|
||||
self
|
||||
.file_policy_or_none()
|
||||
.unwrap_or(FileSinkPolicy::new(append=false, auto_flush=false, rotation=None))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_default_policy_or_none(
|
||||
self : RuntimeSink,
|
||||
) -> FileSinkPolicy? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.default_policy() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_default_policy(self : RuntimeSink) -> FileSinkPolicy {
|
||||
self
|
||||
.file_default_policy_or_none()
|
||||
.unwrap_or(FileSinkPolicy::new(append=false, auto_flush=false, rotation=None))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_policy_matches_default(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.policy_matches_default()
|
||||
QueuedFile(sink) => sink.sink.policy_matches_default()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_state_or_none(self : RuntimeSink) -> FileSinkState? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.state() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_state(self : RuntimeSink) -> FileSinkState {
|
||||
self
|
||||
.file_state_or_none()
|
||||
.unwrap_or(
|
||||
FileSinkState::new(
|
||||
"",
|
||||
available=false,
|
||||
append=false,
|
||||
auto_flush=false,
|
||||
rotation=None,
|
||||
open_failures=0,
|
||||
write_failures=0,
|
||||
flush_failures=0,
|
||||
rotation_failures=0,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_runtime_state(self : RuntimeSink) -> RuntimeFileState? {
|
||||
match self {
|
||||
File(sink) => Some(RuntimeFileState::new(sink.state()))
|
||||
QueuedFile(sink) =>
|
||||
Some(
|
||||
RuntimeFileState::new(
|
||||
sink.sink.state(),
|
||||
queued=true,
|
||||
pending_count=sink.pending_count(),
|
||||
dropped_count=sink.dropped_count(),
|
||||
),
|
||||
)
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn build_runtime_sink(config : SinkConfig) -> RuntimeSink {
|
||||
match config.kind {
|
||||
SinkKind::Console => RuntimeSink::Console(@sink_graph.console_sink())
|
||||
SinkKind::JsonConsole =>
|
||||
RuntimeSink::JsonConsole(@sink_graph.json_console_sink())
|
||||
SinkKind::TextConsole =>
|
||||
RuntimeSink::TextConsole(
|
||||
@sink_graph.text_console_sink(config.text_formatter.to_formatter()),
|
||||
)
|
||||
SinkKind::File =>
|
||||
RuntimeSink::File(
|
||||
@file_runtime.file_sink(
|
||||
config.path,
|
||||
append=config.append,
|
||||
auto_flush=config.auto_flush,
|
||||
rotation=config.rotation,
|
||||
formatter=fn(rec) {
|
||||
@formatting.format_text(
|
||||
rec,
|
||||
formatter=config.text_formatter.to_formatter(),
|
||||
)
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn apply_queue_config(
|
||||
sink : RuntimeSink,
|
||||
queue : QueueConfig,
|
||||
) -> RuntimeSink {
|
||||
match sink {
|
||||
Console(inner) =>
|
||||
RuntimeSink::QueuedConsole(
|
||||
@sink_graph.queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
JsonConsole(inner) =>
|
||||
RuntimeSink::QueuedJsonConsole(
|
||||
@sink_graph.queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
TextConsole(inner) =>
|
||||
RuntimeSink::QueuedTextConsole(
|
||||
@sink_graph.queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
File(inner) =>
|
||||
RuntimeSink::QueuedFile(
|
||||
@sink_graph.queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
QueuedConsole(_) => sink
|
||||
QueuedJsonConsole(_) => sink
|
||||
QueuedTextConsole(_) => sink
|
||||
QueuedFile(_) => sink
|
||||
}
|
||||
}
|
||||
+79
-472
@@ -1,585 +1,192 @@
|
||||
///|
|
||||
fn runtime_file_sink_internal(sink : RuntimeSink) -> FileSink? {
|
||||
match sink {
|
||||
File(sink) => Some(sink)
|
||||
QueuedFile(sink) => Some(sink.sink)
|
||||
_ => None
|
||||
}
|
||||
pub fn Logger::file_available(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_available(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
fn queued_file_policy_mutation_allowed_internal(
|
||||
sink : QueuedSink[FileSink],
|
||||
) -> Bool {
|
||||
sink.pending_count() == 0
|
||||
}
|
||||
|
||||
///|
|
||||
fn queued_file_flush_internal(sink : QueuedSink[FileSink]) -> Bool {
|
||||
let before_write_failures = sink.sink.write_failures()
|
||||
let before_flush_failures = sink.sink.flush_failures()
|
||||
let before_rotation_failures = sink.sink.rotation_failures()
|
||||
ignore(sink.flush())
|
||||
let flushed = sink.sink.flush()
|
||||
sink.pending_count() == 0 &&
|
||||
flushed &&
|
||||
sink.sink.write_failures() == before_write_failures &&
|
||||
sink.sink.flush_failures() == before_flush_failures &&
|
||||
sink.sink.rotation_failures() == before_rotation_failures
|
||||
}
|
||||
|
||||
///|
|
||||
fn queued_file_close_internal(sink : QueuedSink[FileSink]) -> Bool {
|
||||
let flushed = queued_file_flush_internal(sink)
|
||||
let closed = sink.sink.close()
|
||||
flushed && closed
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_available(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.is_available()
|
||||
QueuedFile(sink) => sink.sink.is_available()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen(
|
||||
self : RuntimeSink,
|
||||
pub fn Logger::file_reopen(
|
||||
self : Logger[RuntimeSink],
|
||||
append? : Bool? = None,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.reopen(append~)
|
||||
QueuedFile(sink) =>
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.reopen(append~)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
@runtime.RuntimeSink::file_reopen(self.sink, append~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen_with_current_policy(self : RuntimeSink) -> Bool {
|
||||
self.file_reopen()
|
||||
pub fn Logger::file_reopen_with_current_policy(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> Bool {
|
||||
@runtime.RuntimeSink::file_reopen_with_current_policy(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen_append(self : RuntimeSink) -> Bool {
|
||||
self.file_reopen(append=Some(true))
|
||||
pub fn Logger::file_reopen_append(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_reopen_append(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reopen_truncate(self : RuntimeSink) -> Bool {
|
||||
self.file_reopen(append=Some(false))
|
||||
pub fn Logger::file_reopen_truncate(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_reopen_truncate(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_append_mode(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.append_mode()
|
||||
QueuedFile(sink) => sink.sink.append_mode()
|
||||
_ => false
|
||||
}
|
||||
pub fn Logger::file_append_mode(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_append_mode(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_append_mode(
|
||||
self : RuntimeSink,
|
||||
pub fn Logger::file_set_append_mode(
|
||||
self : Logger[RuntimeSink],
|
||||
append : Bool,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_append_mode(append)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_append_mode(append)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
@runtime.RuntimeSink::file_set_append_mode(self.sink, append)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_path_or_none(self : RuntimeSink) -> String? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.path() })
|
||||
pub fn Logger::file_path_or_none(self : Logger[RuntimeSink]) -> String? {
|
||||
@runtime.RuntimeSink::file_path_or_none(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_path(self : RuntimeSink) -> String {
|
||||
self.file_path_or_none().unwrap_or("")
|
||||
pub fn Logger::file_path(self : Logger[RuntimeSink]) -> String {
|
||||
@runtime.RuntimeSink::file_path(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_auto_flush(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.auto_flush_enabled()
|
||||
QueuedFile(sink) => sink.sink.auto_flush_enabled()
|
||||
_ => false
|
||||
}
|
||||
pub fn Logger::file_auto_flush(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_auto_flush(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_rotation_enabled(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.rotation_enabled()
|
||||
QueuedFile(sink) => sink.sink.rotation_enabled()
|
||||
_ => false
|
||||
}
|
||||
pub fn Logger::file_rotation_enabled(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_rotation_enabled(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_rotation_config(self : RuntimeSink) -> FileRotation? {
|
||||
match self {
|
||||
File(sink) => sink.rotation_config()
|
||||
QueuedFile(sink) => sink.sink.rotation_config()
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_auto_flush(
|
||||
self : RuntimeSink,
|
||||
enabled : Bool,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_auto_flush(enabled)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_auto_flush(enabled)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_policy(
|
||||
self : RuntimeSink,
|
||||
policy : FileSinkPolicy,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_policy(policy)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_policy(policy)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_set_rotation(
|
||||
self : RuntimeSink,
|
||||
rotation : FileRotation?,
|
||||
) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.set_rotation(rotation)
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.set_rotation(rotation)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_clear_rotation(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.clear_rotation()
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.clear_rotation()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_flush(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.flush()
|
||||
QueuedFile(sink) => queued_file_flush_internal(sink)
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_close(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.close()
|
||||
QueuedFile(sink) => queued_file_close_internal(sink)
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_open_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.open_failures()
|
||||
QueuedFile(sink) => sink.sink.open_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_write_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.write_failures()
|
||||
QueuedFile(sink) => sink.sink.write_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_flush_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.flush_failures()
|
||||
QueuedFile(sink) => sink.sink.flush_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_rotation_failures(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
File(sink) => sink.rotation_failures()
|
||||
QueuedFile(sink) => sink.sink.rotation_failures()
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reset_failure_counters(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.reset_failure_counters()
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
sink.sink.reset_failure_counters()
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_reset_policy(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => {
|
||||
sink.reset_policy()
|
||||
true
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
if queued_file_policy_mutation_allowed_internal(sink) {
|
||||
sink.sink.reset_policy()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_policy_or_none(self : RuntimeSink) -> FileSinkPolicy? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.policy() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_policy(self : RuntimeSink) -> FileSinkPolicy {
|
||||
self.file_policy_or_none().unwrap_or(
|
||||
FileSinkPolicy::new(append=false, auto_flush=false, rotation=None),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_default_policy_or_none(
|
||||
self : RuntimeSink,
|
||||
) -> FileSinkPolicy? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.default_policy() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_default_policy(self : RuntimeSink) -> FileSinkPolicy {
|
||||
self.file_default_policy_or_none().unwrap_or(
|
||||
FileSinkPolicy::new(append=false, auto_flush=false, rotation=None),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_policy_matches_default(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
File(sink) => sink.policy_matches_default()
|
||||
QueuedFile(sink) => sink.sink.policy_matches_default()
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_state_or_none(self : RuntimeSink) -> FileSinkState? {
|
||||
runtime_file_sink_internal(self).map(fn(sink) { sink.state() })
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_state(self : RuntimeSink) -> FileSinkState {
|
||||
self.file_state_or_none().unwrap_or(
|
||||
FileSinkState::new(
|
||||
"",
|
||||
available=false,
|
||||
append=false,
|
||||
auto_flush=false,
|
||||
rotation=None,
|
||||
open_failures=0,
|
||||
write_failures=0,
|
||||
flush_failures=0,
|
||||
rotation_failures=0,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::file_runtime_state(self : RuntimeSink) -> RuntimeFileState? {
|
||||
match self {
|
||||
File(sink) => Some(RuntimeFileState::new(sink.state()))
|
||||
QueuedFile(sink) =>
|
||||
Some(
|
||||
RuntimeFileState::new(
|
||||
sink.sink.state(),
|
||||
queued=true,
|
||||
pending_count=sink.pending_count(),
|
||||
dropped_count=sink.dropped_count(),
|
||||
),
|
||||
)
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_available(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_available()
|
||||
}
|
||||
|
||||
///|
|
||||
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 {
|
||||
self.sink.file_reopen_with_current_policy()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_reopen_append(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_reopen_append()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_reopen_truncate(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_reopen_truncate()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_append_mode(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_append_mode()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_set_append_mode(
|
||||
self : ConfiguredLogger,
|
||||
append : Bool,
|
||||
) -> Bool {
|
||||
self.sink.file_set_append_mode(append)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_path_or_none(self : ConfiguredLogger) -> String? {
|
||||
self.sink.file_path_or_none()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_path(self : ConfiguredLogger) -> String {
|
||||
self.sink.file_path()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_auto_flush(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_auto_flush()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_rotation_enabled(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_rotation_enabled()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_rotation_config(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_rotation_config(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> FileRotation? {
|
||||
self.sink.file_rotation_config()
|
||||
@runtime.RuntimeSink::file_rotation_config(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_set_auto_flush(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_set_auto_flush(
|
||||
self : Logger[RuntimeSink],
|
||||
enabled : Bool,
|
||||
) -> Bool {
|
||||
self.sink.file_set_auto_flush(enabled)
|
||||
@runtime.RuntimeSink::file_set_auto_flush(self.sink, enabled)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_set_policy(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_set_policy(
|
||||
self : Logger[RuntimeSink],
|
||||
policy : FileSinkPolicy,
|
||||
) -> Bool {
|
||||
self.sink.file_set_policy(policy)
|
||||
@runtime.RuntimeSink::file_set_policy(self.sink, policy)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_set_rotation(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_set_rotation(
|
||||
self : Logger[RuntimeSink],
|
||||
rotation : FileRotation?,
|
||||
) -> Bool {
|
||||
self.sink.file_set_rotation(rotation)
|
||||
@runtime.RuntimeSink::file_set_rotation(self.sink, rotation)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_clear_rotation(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_clear_rotation()
|
||||
pub fn Logger::file_clear_rotation(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_clear_rotation(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_flush(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_flush()
|
||||
pub fn Logger::file_flush(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_flush(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_close(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_close()
|
||||
pub fn Logger::file_close(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_close(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_open_failures(self : ConfiguredLogger) -> Int {
|
||||
self.sink.file_open_failures()
|
||||
pub fn Logger::file_open_failures(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::file_open_failures(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_write_failures(self : ConfiguredLogger) -> Int {
|
||||
self.sink.file_write_failures()
|
||||
pub fn Logger::file_write_failures(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::file_write_failures(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_flush_failures(self : ConfiguredLogger) -> Int {
|
||||
self.sink.file_flush_failures()
|
||||
pub fn Logger::file_flush_failures(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::file_flush_failures(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_rotation_failures(self : ConfiguredLogger) -> Int {
|
||||
self.sink.file_rotation_failures()
|
||||
pub fn Logger::file_rotation_failures(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::file_rotation_failures(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_reset_failure_counters(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_reset_failure_counters(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> Bool {
|
||||
self.sink.file_reset_failure_counters()
|
||||
@runtime.RuntimeSink::file_reset_failure_counters(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_reset_policy(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.file_reset_policy()
|
||||
pub fn Logger::file_reset_policy(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::file_reset_policy(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_policy_or_none(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_policy_or_none(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> FileSinkPolicy? {
|
||||
self.sink.file_policy_or_none()
|
||||
@runtime.RuntimeSink::file_policy_or_none(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_policy(self : ConfiguredLogger) -> FileSinkPolicy {
|
||||
self.sink.file_policy()
|
||||
pub fn Logger::file_policy(self : Logger[RuntimeSink]) -> FileSinkPolicy {
|
||||
@runtime.RuntimeSink::file_policy(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_default_policy_or_none(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_default_policy_or_none(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> FileSinkPolicy? {
|
||||
self.sink.file_default_policy_or_none()
|
||||
@runtime.RuntimeSink::file_default_policy_or_none(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_default_policy(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_default_policy(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> FileSinkPolicy {
|
||||
self.sink.file_default_policy()
|
||||
@runtime.RuntimeSink::file_default_policy(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_policy_matches_default(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_policy_matches_default(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> Bool {
|
||||
self.sink.file_policy_matches_default()
|
||||
@runtime.RuntimeSink::file_policy_matches_default(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_state_or_none(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_state_or_none(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> FileSinkState? {
|
||||
self.sink.file_state_or_none()
|
||||
@runtime.RuntimeSink::file_state_or_none(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_state(self : ConfiguredLogger) -> FileSinkState {
|
||||
self.sink.file_state()
|
||||
pub fn Logger::file_state(self : Logger[RuntimeSink]) -> FileSinkState {
|
||||
@runtime.RuntimeSink::file_state(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::file_runtime_state(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::file_runtime_state(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> RuntimeFileState? {
|
||||
self.sink.file_runtime_state()
|
||||
@runtime.RuntimeSink::file_runtime_state(self.sink)
|
||||
}
|
||||
|
||||
+26
-322
@@ -1,59 +1,17 @@
|
||||
///|
|
||||
pub(all) enum RuntimeSink {
|
||||
Console(ConsoleSink)
|
||||
JsonConsole(JsonConsoleSink)
|
||||
TextConsole(FormattedConsoleSink)
|
||||
File(FileSink)
|
||||
QueuedConsole(QueuedSink[ConsoleSink])
|
||||
QueuedJsonConsole(QueuedSink[JsonConsoleSink])
|
||||
QueuedTextConsole(QueuedSink[FormattedConsoleSink])
|
||||
QueuedFile(QueuedSink[FileSink])
|
||||
}
|
||||
pub type RuntimeSink = @runtime.RuntimeSink
|
||||
|
||||
///|
|
||||
pub type RuntimeFileState = @utils.RuntimeFileState
|
||||
pub type RuntimeFileState = @file_model.RuntimeFileState
|
||||
|
||||
///|
|
||||
pub struct RuntimeSinkProgress {
|
||||
queue_advanced_count : Int
|
||||
file_flush_step_count : Int
|
||||
queue_backed : Bool
|
||||
file_backed : Bool
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_policy_to_json(
|
||||
policy : FileSinkPolicy,
|
||||
) -> @json_parser.JsonValue {
|
||||
@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~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||
@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~)
|
||||
}
|
||||
pub type RuntimeSinkProgress = @runtime.RuntimeSinkProgress
|
||||
|
||||
///|
|
||||
pub fn runtime_file_state_to_json(
|
||||
state : RuntimeFileState,
|
||||
) -> @json_parser.JsonValue {
|
||||
@utils.runtime_file_state_to_json(state)
|
||||
@file_model.runtime_file_state_to_json(state)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -61,315 +19,61 @@ 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 fn write(self, rec) {
|
||||
match self {
|
||||
Console(sink) => sink.write(rec)
|
||||
JsonConsole(sink) => sink.write(rec)
|
||||
TextConsole(sink) => sink.write(rec)
|
||||
File(sink) => sink.write(rec)
|
||||
QueuedConsole(sink) => sink.write(rec)
|
||||
QueuedJsonConsole(sink) => sink.write(rec)
|
||||
QueuedTextConsole(sink) => sink.write(rec)
|
||||
QueuedFile(sink) => sink.write(rec)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn[S : Sink] queued_sink_close_internal(sink : QueuedSink[S]) -> Bool {
|
||||
ignore(sink.flush())
|
||||
sink.pending_count() == 0
|
||||
}
|
||||
|
||||
///|
|
||||
fn runtime_sink_progress_compat_count(progress : RuntimeSinkProgress) -> Int {
|
||||
progress.queue_advanced_count + progress.file_flush_step_count
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::flush_progress(self : RuntimeSink) -> RuntimeSinkProgress {
|
||||
match self {
|
||||
Console(_) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
JsonConsole(_) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
TextConsole(_) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
File(sink) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: if sink.flush() { 1 } else { 0 },
|
||||
queue_backed: false,
|
||||
file_backed: true,
|
||||
}
|
||||
QueuedConsole(sink) => {
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedJsonConsole(sink) => {
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedTextConsole(sink) => {
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
queue_advanced_count: sink.flush(),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::flush(self : RuntimeSink) -> Int {
|
||||
runtime_sink_progress_compat_count(self.flush_progress())
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::drain_progress(
|
||||
self : RuntimeSink,
|
||||
max_items? : Int = -1,
|
||||
) -> RuntimeSinkProgress {
|
||||
match self {
|
||||
Console(_) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
JsonConsole(_) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
TextConsole(_) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: false,
|
||||
file_backed: false,
|
||||
}
|
||||
File(sink) => {
|
||||
queue_advanced_count: 0,
|
||||
file_flush_step_count: if sink.flush() { 1 } else { 0 },
|
||||
queue_backed: false,
|
||||
file_backed: true,
|
||||
}
|
||||
QueuedConsole(sink) => {
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedJsonConsole(sink) => {
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedTextConsole(sink) => {
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: false,
|
||||
}
|
||||
QueuedFile(sink) => {
|
||||
queue_advanced_count: sink.drain(max_items~),
|
||||
file_flush_step_count: 0,
|
||||
queue_backed: true,
|
||||
file_backed: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::drain(self : RuntimeSink, max_items? : Int = -1) -> Int {
|
||||
runtime_sink_progress_compat_count(self.drain_progress(max_items~))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::close(self : RuntimeSink) -> Bool {
|
||||
match self {
|
||||
Console(_) => true
|
||||
JsonConsole(_) => true
|
||||
TextConsole(_) => true
|
||||
File(sink) => sink.close()
|
||||
QueuedConsole(sink) => queued_sink_close_internal(sink)
|
||||
QueuedJsonConsole(sink) => queued_sink_close_internal(sink)
|
||||
QueuedTextConsole(sink) => queued_sink_close_internal(sink)
|
||||
QueuedFile(sink) => queued_file_close_internal(sink)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::pending_count(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
Console(_) => 0
|
||||
JsonConsole(_) => 0
|
||||
TextConsole(_) => 0
|
||||
File(_) => 0
|
||||
QueuedConsole(sink) => sink.pending_count()
|
||||
QueuedJsonConsole(sink) => sink.pending_count()
|
||||
QueuedTextConsole(sink) => sink.pending_count()
|
||||
QueuedFile(sink) => sink.pending_count()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn RuntimeSink::dropped_count(self : RuntimeSink) -> Int {
|
||||
match self {
|
||||
Console(_) => 0
|
||||
JsonConsole(_) => 0
|
||||
TextConsole(_) => 0
|
||||
File(_) => 0
|
||||
QueuedConsole(sink) => sink.dropped_count()
|
||||
QueuedJsonConsole(sink) => sink.dropped_count()
|
||||
QueuedTextConsole(sink) => sink.dropped_count()
|
||||
QueuedFile(sink) => sink.dropped_count()
|
||||
}
|
||||
@file_model.stringify_runtime_file_state(state, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub type ConfiguredLogger = Logger[RuntimeSink]
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::flush_progress(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::flush_progress(
|
||||
self : Logger[RuntimeSink],
|
||||
) -> RuntimeSinkProgress {
|
||||
self.sink.flush_progress()
|
||||
@runtime.RuntimeSink::flush_progress(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::flush(self : ConfiguredLogger) -> Int {
|
||||
self.sink.flush()
|
||||
pub fn Logger::flush(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::flush(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::drain_progress(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::drain_progress(
|
||||
self : Logger[RuntimeSink],
|
||||
max_items? : Int = -1,
|
||||
) -> RuntimeSinkProgress {
|
||||
self.sink.drain_progress(max_items~)
|
||||
@runtime.RuntimeSink::drain_progress(self.sink, max_items~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::drain(
|
||||
self : ConfiguredLogger,
|
||||
pub fn Logger::drain(
|
||||
self : Logger[RuntimeSink],
|
||||
max_items? : Int = -1,
|
||||
) -> Int {
|
||||
self.sink.drain(max_items~)
|
||||
@runtime.RuntimeSink::drain(self.sink, max_items~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::close(self : ConfiguredLogger) -> Bool {
|
||||
self.sink.close()
|
||||
pub fn Logger::close(self : Logger[RuntimeSink]) -> Bool {
|
||||
@runtime.RuntimeSink::close(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::pending_count(self : ConfiguredLogger) -> Int {
|
||||
self.sink.pending_count()
|
||||
pub fn Logger::pending_count(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::pending_count(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn ConfiguredLogger::dropped_count(self : ConfiguredLogger) -> Int {
|
||||
self.sink.dropped_count()
|
||||
pub fn Logger::dropped_count(self : Logger[RuntimeSink]) -> Int {
|
||||
@runtime.RuntimeSink::dropped_count(self.sink)
|
||||
}
|
||||
|
||||
///|
|
||||
fn build_runtime_sink(config : SinkConfig) -> RuntimeSink {
|
||||
match config.kind {
|
||||
SinkKind::Console => RuntimeSink::Console(console_sink())
|
||||
SinkKind::JsonConsole => RuntimeSink::JsonConsole(json_console_sink())
|
||||
SinkKind::TextConsole =>
|
||||
RuntimeSink::TextConsole(
|
||||
text_console_sink(config.text_formatter.to_formatter()),
|
||||
)
|
||||
SinkKind::File =>
|
||||
RuntimeSink::File(
|
||||
file_sink(
|
||||
config.path,
|
||||
append=config.append,
|
||||
auto_flush=config.auto_flush,
|
||||
rotation=config.rotation,
|
||||
formatter=fn(rec) {
|
||||
format_text(rec, formatter=config.text_formatter.to_formatter())
|
||||
},
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn apply_queue_config(sink : RuntimeSink, queue : QueueConfig) -> RuntimeSink {
|
||||
match sink {
|
||||
Console(inner) =>
|
||||
RuntimeSink::QueuedConsole(
|
||||
queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
JsonConsole(inner) =>
|
||||
RuntimeSink::QueuedJsonConsole(
|
||||
queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
TextConsole(inner) =>
|
||||
RuntimeSink::QueuedTextConsole(
|
||||
queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
File(inner) =>
|
||||
RuntimeSink::QueuedFile(
|
||||
queued_sink(
|
||||
inner,
|
||||
max_pending=queue.max_pending,
|
||||
overflow=queue.overflow,
|
||||
),
|
||||
)
|
||||
QueuedConsole(_) => sink
|
||||
QueuedJsonConsole(_) => sink
|
||||
QueuedTextConsole(_) => sink
|
||||
QueuedFile(_) => sink
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {
|
||||
let sink = build_runtime_sink(config.sink)
|
||||
pub fn build_logger(config : LoggerConfig) -> Logger[RuntimeSink] {
|
||||
let sink = @runtime.build_runtime_sink(config.sink)
|
||||
let actual_sink = match config.queue {
|
||||
None => sink
|
||||
Some(queue) => apply_queue_config(sink, queue)
|
||||
Some(queue) => @runtime.apply_queue_config(sink, queue)
|
||||
}
|
||||
Logger::new(actual_sink, min_level=config.min_level, target=config.target).with_timestamp(
|
||||
enabled=config.timestamp,
|
||||
@@ -379,6 +83,6 @@ pub fn build_logger(config : LoggerConfig) -> ConfiguredLogger {
|
||||
///|
|
||||
pub fn parse_and_build_logger(
|
||||
input : String,
|
||||
) -> ConfiguredLogger raise ConfigError {
|
||||
) -> Logger[RuntimeSink] raise ConfigError {
|
||||
build_logger(parse_logger_config_text(input))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
"Nanaloveyuki/BitLogger/src/record_ops",
|
||||
"moonbitlang/core/queue",
|
||||
"moonbitlang/core/ref",
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// Generated using `moon info`, DON'T EDIT IT
|
||||
package "Nanaloveyuki/BitLogger/src/sink_graph"
|
||||
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/queue_model",
|
||||
"moonbitlang/core/queue",
|
||||
"moonbitlang/core/ref",
|
||||
}
|
||||
|
||||
// Values
|
||||
pub fn[S] buffered_sink(S, flush_limit? : Int) -> BufferedSink[S]
|
||||
|
||||
pub fn callback_sink((@core.Record) -> Unit) -> CallbackSink
|
||||
|
||||
pub fn console_sink() -> ConsoleSink
|
||||
|
||||
pub fn[S] context_sink(S, Array[@core.Field]) -> ContextSink[S]
|
||||
|
||||
pub fn[A, B] fanout_sink(A, B) -> FanoutSink[A, B]
|
||||
|
||||
pub fn[S] filter_sink(S, (@core.Record) -> Bool) -> FilterSink[S]
|
||||
|
||||
pub fn formatted_callback_sink((@core.Record) -> String, (String) -> Unit) -> FormattedCallbackSink
|
||||
|
||||
pub fn formatted_console_sink((@core.Record) -> String) -> FormattedConsoleSink
|
||||
|
||||
pub fn json_console_sink() -> JsonConsoleSink
|
||||
|
||||
pub fn[S] patch_sink(S, (@core.Record) -> @core.Record) -> PatchSink[S]
|
||||
|
||||
pub fn[S] queued_sink(S, max_pending? : Int, overflow? : @queue_model.QueueOverflowPolicy) -> QueuedSink[S]
|
||||
|
||||
pub fn[A, B] split_by_level(A, B, min_level? : @core.Level) -> SplitSink[A, B]
|
||||
|
||||
pub fn[A, B] split_sink(A, B, (@core.Record) -> Bool) -> SplitSink[A, B]
|
||||
|
||||
pub fn text_callback_sink(@formatting.TextFormatter, (String) -> Unit) -> FormattedCallbackSink
|
||||
|
||||
pub fn text_console_sink(@formatting.TextFormatter) -> FormattedConsoleSink
|
||||
|
||||
// Errors
|
||||
|
||||
// Types and methods
|
||||
pub struct BufferedSink[S] {
|
||||
sink : S
|
||||
buffer : @ref.Ref[Array[@core.Record]]
|
||||
flush_limit : Int
|
||||
}
|
||||
pub fn[S : Sink] BufferedSink::flush(Self[S]) -> Unit
|
||||
pub fn[S] BufferedSink::pending_count(Self[S]) -> Int
|
||||
pub impl[S : Sink] Sink for BufferedSink[S]
|
||||
|
||||
pub struct CallbackSink {
|
||||
callback : (@core.Record) -> Unit
|
||||
}
|
||||
pub impl Sink for CallbackSink
|
||||
|
||||
pub struct ConsoleSink {
|
||||
_dummy : Unit
|
||||
}
|
||||
pub impl Sink for ConsoleSink
|
||||
|
||||
pub struct ContextSink[S] {
|
||||
sink : S
|
||||
context_fields : Array[@core.Field]
|
||||
}
|
||||
pub impl[S : Sink] Sink for ContextSink[S]
|
||||
|
||||
pub struct FanoutSink[A, B] {
|
||||
left : A
|
||||
right : B
|
||||
}
|
||||
pub impl[A : Sink, B : Sink] Sink for FanoutSink[A, B]
|
||||
|
||||
pub struct FilterSink[S] {
|
||||
sink : S
|
||||
predicate : (@core.Record) -> Bool
|
||||
}
|
||||
pub impl[S : Sink] Sink for FilterSink[S]
|
||||
|
||||
pub struct FormattedCallbackSink {
|
||||
formatter : (@core.Record) -> String
|
||||
callback : (String) -> Unit
|
||||
}
|
||||
pub impl Sink for FormattedCallbackSink
|
||||
|
||||
pub struct FormattedConsoleSink {
|
||||
formatter : (@core.Record) -> String
|
||||
}
|
||||
pub impl Sink for FormattedConsoleSink
|
||||
|
||||
pub struct JsonConsoleSink {
|
||||
_dummy : Unit
|
||||
}
|
||||
pub impl Sink for JsonConsoleSink
|
||||
|
||||
pub struct PatchSink[S] {
|
||||
sink : S
|
||||
patch : (@core.Record) -> @core.Record
|
||||
}
|
||||
pub impl[S : Sink] Sink for PatchSink[S]
|
||||
|
||||
pub struct QueuedSink[S] {
|
||||
sink : S
|
||||
queue : @queue.Queue[@core.Record]
|
||||
max_pending : Int
|
||||
overflow : @queue_model.QueueOverflowPolicy
|
||||
dropped_count : @ref.Ref[Int]
|
||||
}
|
||||
pub fn[S : Sink] QueuedSink::drain(Self[S], max_items? : Int) -> Int
|
||||
pub fn[S] QueuedSink::dropped_count(Self[S]) -> Int
|
||||
pub fn[S : Sink] QueuedSink::flush(Self[S]) -> Int
|
||||
pub fn[S] QueuedSink::pending_count(Self[S]) -> Int
|
||||
pub impl[S] Sink for QueuedSink[S]
|
||||
|
||||
pub struct SplitSink[A, B] {
|
||||
left : A
|
||||
right : B
|
||||
predicate : (@core.Record) -> Bool
|
||||
}
|
||||
pub impl[A : Sink, B : Sink] Sink for SplitSink[A, B]
|
||||
|
||||
// Type aliases
|
||||
pub using @queue_model {type QueueOverflowPolicy}
|
||||
|
||||
// Traits
|
||||
pub(open) trait Sink {
|
||||
fn write(Self, @core.Record) -> Unit
|
||||
}
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
///|
|
||||
type Record = @core.Record
|
||||
|
||||
///|
|
||||
type Field = @core.Field
|
||||
|
||||
///|
|
||||
type Level = @core.Level
|
||||
|
||||
///|
|
||||
type RecordFormatter = @formatting.RecordFormatter
|
||||
|
||||
///|
|
||||
type TextFormatter = @formatting.TextFormatter
|
||||
|
||||
///|
|
||||
type RecordPatch = @record_ops.RecordPatch
|
||||
|
||||
///|
|
||||
pub(open) trait Sink {
|
||||
fn write(Self, Record) -> Unit
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct ConsoleSink {
|
||||
_dummy : Unit
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn console_sink() -> ConsoleSink {
|
||||
{ _dummy: () }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for ConsoleSink with fn write(self, rec) {
|
||||
ignore(self)
|
||||
println(@formatting.format_text(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct ContextSink[S] {
|
||||
sink : S
|
||||
context_fields : Array[Field]
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] context_sink(
|
||||
sink : S,
|
||||
context_fields : Array[Field],
|
||||
) -> ContextSink[S] {
|
||||
{ sink, context_fields }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for ContextSink[S] with fn write(self, rec) {
|
||||
let merged = if self.context_fields.length() == 0 {
|
||||
rec.fields
|
||||
} else if rec.fields.length() == 0 {
|
||||
self.context_fields
|
||||
} else {
|
||||
self.context_fields + rec.fields
|
||||
}
|
||||
self.sink.write(rec.with_fields(merged))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct JsonConsoleSink {
|
||||
_dummy : Unit
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn json_console_sink() -> JsonConsoleSink {
|
||||
{ _dummy: () }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for JsonConsoleSink with fn write(self, rec) {
|
||||
ignore(self)
|
||||
println(@formatting.format_json(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FormattedConsoleSink {
|
||||
formatter : RecordFormatter
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn formatted_console_sink(
|
||||
formatter : RecordFormatter,
|
||||
) -> FormattedConsoleSink {
|
||||
{ formatter, }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_console_sink(formatter : TextFormatter) -> FormattedConsoleSink {
|
||||
formatted_console_sink(fn(rec) { @formatting.format_text(rec, formatter~) })
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for FormattedConsoleSink with fn write(self, rec) {
|
||||
println((self.formatter)(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FormattedCallbackSink {
|
||||
formatter : RecordFormatter
|
||||
callback : (String) -> Unit
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn formatted_callback_sink(
|
||||
formatter : RecordFormatter,
|
||||
callback : (String) -> Unit,
|
||||
) -> FormattedCallbackSink {
|
||||
{ formatter, callback }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_callback_sink(
|
||||
formatter : TextFormatter,
|
||||
callback : (String) -> Unit,
|
||||
) -> FormattedCallbackSink {
|
||||
formatted_callback_sink(
|
||||
fn(rec) { @formatting.format_text(rec, formatter~) },
|
||||
callback,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for FormattedCallbackSink with fn write(self, rec) {
|
||||
(self.callback)((self.formatter)(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FanoutSink[A, B] {
|
||||
left : A
|
||||
right : B
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[A, B] fanout_sink(left : A, right : B) -> FanoutSink[A, B] {
|
||||
{ left, right }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[A : Sink, B : Sink] Sink for FanoutSink[A, B] with fn write(self, rec) {
|
||||
self.left.write(rec)
|
||||
self.right.write(rec.copy())
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct SplitSink[A, B] {
|
||||
left : A
|
||||
right : B
|
||||
predicate : (Record) -> Bool
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[A, B] split_sink(
|
||||
left : A,
|
||||
right : B,
|
||||
predicate : (Record) -> Bool,
|
||||
) -> SplitSink[A, B] {
|
||||
{ left, right, predicate }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[A, B] split_by_level(
|
||||
left : A,
|
||||
right : B,
|
||||
min_level? : Level = Level::Warn,
|
||||
) -> SplitSink[A, B] {
|
||||
split_sink(left, right, fn(rec) { rec.level.enabled(min_level) })
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[A : Sink, B : Sink] Sink for SplitSink[A, B] with fn write(self, rec) {
|
||||
if (self.predicate)(rec) {
|
||||
self.left.write(rec)
|
||||
} else {
|
||||
self.right.write(rec)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct CallbackSink {
|
||||
callback : (Record) -> Unit
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn callback_sink(callback : (Record) -> Unit) -> CallbackSink {
|
||||
{ callback, }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for CallbackSink with fn write(self, rec) {
|
||||
(self.callback)(rec)
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct BufferedSink[S] {
|
||||
sink : S
|
||||
buffer : Ref[Array[Record]]
|
||||
flush_limit : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] buffered_sink(sink : S, flush_limit? : Int = 1) -> BufferedSink[S] {
|
||||
let actual_limit = if flush_limit <= 0 { 1 } else { flush_limit }
|
||||
{ sink, buffer: Ref([]), flush_limit: actual_limit }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] BufferedSink::pending_count(self : BufferedSink[S]) -> Int {
|
||||
self.buffer.val.length()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S : Sink] BufferedSink::flush(self : BufferedSink[S]) -> Unit {
|
||||
if self.buffer.val.length() == 0 {
|
||||
()
|
||||
} else {
|
||||
let pending = self.buffer.val
|
||||
self.buffer.val = []
|
||||
for rec in pending {
|
||||
self.sink.write(rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for BufferedSink[S] with fn write(self, rec) {
|
||||
self.buffer.val.push(rec)
|
||||
if self.buffer.val.length() >= self.flush_limit {
|
||||
self.flush()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub type QueueOverflowPolicy = @queue_model.QueueOverflowPolicy
|
||||
|
||||
///|
|
||||
pub struct QueuedSink[S] {
|
||||
sink : S
|
||||
queue : @queue.Queue[Record]
|
||||
max_pending : Int
|
||||
overflow : QueueOverflowPolicy
|
||||
dropped_count : Ref[Int]
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] queued_sink(
|
||||
sink : S,
|
||||
max_pending? : Int = 0,
|
||||
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||
) -> QueuedSink[S] {
|
||||
{
|
||||
sink,
|
||||
queue: @queue.Queue([]),
|
||||
max_pending,
|
||||
overflow,
|
||||
dropped_count: Ref(0),
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] QueuedSink::pending_count(self : QueuedSink[S]) -> Int {
|
||||
self.queue.length()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] QueuedSink::dropped_count(self : QueuedSink[S]) -> Int {
|
||||
self.dropped_count.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S : Sink] QueuedSink::drain(
|
||||
self : QueuedSink[S],
|
||||
max_items? : Int = -1,
|
||||
) -> Int {
|
||||
if max_items == 0 {
|
||||
return 0
|
||||
}
|
||||
let limit = if max_items < 0 { self.pending_count() } else { max_items }
|
||||
for drained = 0; drained < limit; {
|
||||
match self.queue.pop() {
|
||||
None => break drained
|
||||
Some(rec) => {
|
||||
self.sink.write(rec)
|
||||
continue drained + 1
|
||||
}
|
||||
}
|
||||
} nobreak {
|
||||
limit
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S : Sink] QueuedSink::flush(self : QueuedSink[S]) -> Int {
|
||||
self.drain()
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S] Sink for QueuedSink[S] with fn write(self, rec) {
|
||||
let full = self.max_pending > 0 && self.pending_count() >= self.max_pending
|
||||
if !full {
|
||||
self.queue.push(rec)
|
||||
} else {
|
||||
self.dropped_count.val += 1
|
||||
match self.overflow {
|
||||
QueueOverflowPolicy::DropNewest => ()
|
||||
QueueOverflowPolicy::DropOldest => {
|
||||
ignore(self.queue.pop())
|
||||
self.queue.push(rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FilterSink[S] {
|
||||
sink : S
|
||||
predicate : (Record) -> Bool
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] filter_sink(sink : S, predicate : (Record) -> Bool) -> FilterSink[S] {
|
||||
{ sink, predicate }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for FilterSink[S] with fn write(self, rec) {
|
||||
if (self.predicate)(rec) {
|
||||
self.sink.write(rec)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct PatchSink[S] {
|
||||
sink : S
|
||||
patch : RecordPatch
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] patch_sink(sink : S, patch : RecordPatch) -> PatchSink[S] {
|
||||
{ sink, patch }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for PatchSink[S] with fn write(self, rec) {
|
||||
self.sink.write((self.patch)(rec))
|
||||
}
|
||||
+35
-219
@@ -1,92 +1,57 @@
|
||||
///|
|
||||
pub trait Sink {
|
||||
fn write(Self, Record) -> Unit
|
||||
}
|
||||
pub using @sink_graph {trait Sink}
|
||||
|
||||
///|
|
||||
pub struct ConsoleSink {
|
||||
_dummy : Unit
|
||||
}
|
||||
pub type ConsoleSink = @sink_graph.ConsoleSink
|
||||
|
||||
///|
|
||||
pub fn console_sink() -> ConsoleSink {
|
||||
{ _dummy: () }
|
||||
@sink_graph.console_sink()
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for ConsoleSink with fn write(self, rec) {
|
||||
ignore(self)
|
||||
println(format_text(rec))
|
||||
pub type ContextSink[S] = @sink_graph.ContextSink[S]
|
||||
|
||||
///|
|
||||
pub fn[S] context_sink(
|
||||
sink : S,
|
||||
context_fields : Array[Field],
|
||||
) -> ContextSink[S] {
|
||||
@sink_graph.context_sink(sink, context_fields)
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct ContextSink[S] {
|
||||
sink : S
|
||||
context_fields : Array[Field]
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for ContextSink[S] with fn write(self, rec) {
|
||||
let merged = if self.context_fields.length() == 0 {
|
||||
rec.fields
|
||||
} else if rec.fields.length() == 0 {
|
||||
self.context_fields
|
||||
} else {
|
||||
self.context_fields + rec.fields
|
||||
}
|
||||
self.sink.write(rec.with_fields(merged))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct JsonConsoleSink {
|
||||
_dummy : Unit
|
||||
}
|
||||
pub type JsonConsoleSink = @sink_graph.JsonConsoleSink
|
||||
|
||||
///|
|
||||
pub fn json_console_sink() -> JsonConsoleSink {
|
||||
{ _dummy: () }
|
||||
@sink_graph.json_console_sink()
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for JsonConsoleSink with fn write(self, rec) {
|
||||
ignore(self)
|
||||
println(format_json(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FormattedConsoleSink {
|
||||
formatter : RecordFormatter
|
||||
}
|
||||
pub type FormattedConsoleSink = @sink_graph.FormattedConsoleSink
|
||||
|
||||
///|
|
||||
pub fn formatted_console_sink(
|
||||
formatter : RecordFormatter,
|
||||
) -> FormattedConsoleSink {
|
||||
{ formatter, }
|
||||
@sink_graph.formatted_console_sink(formatter)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn text_console_sink(formatter : TextFormatter) -> FormattedConsoleSink {
|
||||
formatted_console_sink(fn(rec) { format_text(rec, formatter~) })
|
||||
@sink_graph.text_console_sink(formatter)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for FormattedConsoleSink with fn write(self, rec) {
|
||||
println((self.formatter)(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FormattedCallbackSink {
|
||||
formatter : RecordFormatter
|
||||
callback : (String) -> Unit
|
||||
}
|
||||
pub type FormattedCallbackSink = @sink_graph.FormattedCallbackSink
|
||||
|
||||
///|
|
||||
pub fn formatted_callback_sink(
|
||||
formatter : RecordFormatter,
|
||||
callback : (String) -> Unit,
|
||||
) -> FormattedCallbackSink {
|
||||
{ formatter, callback }
|
||||
@sink_graph.formatted_callback_sink(formatter, callback)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -94,37 +59,19 @@ pub fn text_callback_sink(
|
||||
formatter : TextFormatter,
|
||||
callback : (String) -> Unit,
|
||||
) -> FormattedCallbackSink {
|
||||
formatted_callback_sink(fn(rec) { format_text(rec, formatter~) }, callback)
|
||||
@sink_graph.text_callback_sink(formatter, callback)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for FormattedCallbackSink with fn write(self, rec) {
|
||||
(self.callback)((self.formatter)(rec))
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FanoutSink[A, B] {
|
||||
left : A
|
||||
right : B
|
||||
}
|
||||
pub type FanoutSink[A, B] = @sink_graph.FanoutSink[A, B]
|
||||
|
||||
///|
|
||||
pub fn[A, B] fanout_sink(left : A, right : B) -> FanoutSink[A, B] {
|
||||
{ left, right }
|
||||
@sink_graph.fanout_sink(left, right)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[A : Sink, B : Sink] Sink for FanoutSink[A, B] with fn write(self, rec) {
|
||||
self.left.write(rec)
|
||||
self.right.write(rec.copy())
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct SplitSink[A, B] {
|
||||
left : A
|
||||
right : B
|
||||
predicate : (Record) -> Bool
|
||||
}
|
||||
pub type SplitSink[A, B] = @sink_graph.SplitSink[A, B]
|
||||
|
||||
///|
|
||||
pub fn[A, B] split_sink(
|
||||
@@ -132,7 +79,7 @@ pub fn[A, B] split_sink(
|
||||
right : B,
|
||||
predicate : (Record) -> Bool,
|
||||
) -> SplitSink[A, B] {
|
||||
{ left, right, predicate }
|
||||
@sink_graph.split_sink(left, right, predicate)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -141,83 +88,30 @@ pub fn[A, B] split_by_level(
|
||||
right : B,
|
||||
min_level? : Level = Level::Warn,
|
||||
) -> SplitSink[A, B] {
|
||||
split_sink(left, right, fn(rec) { rec.level.enabled(min_level) })
|
||||
@sink_graph.split_by_level(left, right, min_level~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[A : Sink, B : Sink] Sink for SplitSink[A, B] with fn write(self, rec) {
|
||||
if (self.predicate)(rec) {
|
||||
self.left.write(rec)
|
||||
} else {
|
||||
self.right.write(rec)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct CallbackSink {
|
||||
callback : (Record) -> Unit
|
||||
}
|
||||
pub type CallbackSink = @sink_graph.CallbackSink
|
||||
|
||||
///|
|
||||
pub fn callback_sink(callback : (Record) -> Unit) -> CallbackSink {
|
||||
{ callback, }
|
||||
@sink_graph.callback_sink(callback)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for CallbackSink with fn write(self, rec) {
|
||||
(self.callback)(rec)
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct BufferedSink[S] {
|
||||
sink : S
|
||||
buffer : Ref[Array[Record]]
|
||||
flush_limit : Int
|
||||
}
|
||||
pub type BufferedSink[S] = @sink_graph.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 }
|
||||
{ sink, buffer: Ref([]), flush_limit: actual_limit }
|
||||
@sink_graph.buffered_sink(sink, flush_limit~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] BufferedSink::pending_count(self : BufferedSink[S]) -> Int {
|
||||
self.buffer.val.length()
|
||||
}
|
||||
pub type QueueOverflowPolicy = @queue_model.QueueOverflowPolicy
|
||||
|
||||
///|
|
||||
pub fn[S : Sink] BufferedSink::flush(self : BufferedSink[S]) -> Unit {
|
||||
if self.buffer.val.length() == 0 {
|
||||
()
|
||||
} else {
|
||||
let pending = self.buffer.val
|
||||
self.buffer.val = []
|
||||
for rec in pending {
|
||||
self.sink.write(rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for BufferedSink[S] with fn write(self, rec) {
|
||||
self.buffer.val.push(rec)
|
||||
if self.buffer.val.length() >= self.flush_limit {
|
||||
self.flush()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub type QueueOverflowPolicy = @utils.QueueOverflowPolicy
|
||||
|
||||
///|
|
||||
pub struct QueuedSink[S] {
|
||||
sink : S
|
||||
queue : @queue.Queue[Record]
|
||||
max_pending : Int
|
||||
overflow : QueueOverflowPolicy
|
||||
dropped_count : Ref[Int]
|
||||
}
|
||||
pub type QueuedSink[S] = @sink_graph.QueuedSink[S]
|
||||
|
||||
///|
|
||||
pub fn[S] queued_sink(
|
||||
@@ -225,99 +119,21 @@ pub fn[S] queued_sink(
|
||||
max_pending? : Int = 0,
|
||||
overflow? : QueueOverflowPolicy = QueueOverflowPolicy::DropNewest,
|
||||
) -> QueuedSink[S] {
|
||||
{
|
||||
sink,
|
||||
queue: @queue.Queue([]),
|
||||
max_pending,
|
||||
overflow,
|
||||
dropped_count: Ref(0),
|
||||
}
|
||||
@sink_graph.queued_sink(sink, max_pending~, overflow~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] QueuedSink::pending_count(self : QueuedSink[S]) -> Int {
|
||||
self.queue.length()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S] QueuedSink::dropped_count(self : QueuedSink[S]) -> Int {
|
||||
self.dropped_count.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S : Sink] QueuedSink::drain(
|
||||
self : QueuedSink[S],
|
||||
max_items? : Int = -1,
|
||||
) -> Int {
|
||||
if max_items == 0 {
|
||||
return 0
|
||||
}
|
||||
let limit = if max_items < 0 { self.pending_count() } else { max_items }
|
||||
for drained = 0; drained < limit; {
|
||||
match self.queue.pop() {
|
||||
None => break drained
|
||||
Some(rec) => {
|
||||
self.sink.write(rec)
|
||||
continue drained + 1
|
||||
}
|
||||
}
|
||||
} nobreak {
|
||||
limit
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn[S : Sink] QueuedSink::flush(self : QueuedSink[S]) -> Int {
|
||||
self.drain()
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S] Sink for QueuedSink[S] with fn write(self, rec) {
|
||||
let full = self.max_pending > 0 && self.pending_count() >= self.max_pending
|
||||
if !full {
|
||||
self.queue.push(rec)
|
||||
} else {
|
||||
self.dropped_count.val += 1
|
||||
match self.overflow {
|
||||
QueueOverflowPolicy::DropNewest => ()
|
||||
QueueOverflowPolicy::DropOldest => {
|
||||
ignore(self.queue.pop())
|
||||
self.queue.push(rec)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FilterSink[S] {
|
||||
sink : S
|
||||
predicate : (Record) -> Bool
|
||||
}
|
||||
pub type FilterSink[S] = @sink_graph.FilterSink[S]
|
||||
|
||||
///|
|
||||
pub fn[S] filter_sink(sink : S, predicate : (Record) -> Bool) -> FilterSink[S] {
|
||||
{ sink, predicate }
|
||||
@sink_graph.filter_sink(sink, predicate)
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for FilterSink[S] with fn write(self, rec) {
|
||||
if (self.predicate)(rec) {
|
||||
self.sink.write(rec)
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct PatchSink[S] {
|
||||
sink : S
|
||||
patch : RecordPatch
|
||||
}
|
||||
pub type PatchSink[S] = @sink_graph.PatchSink[S]
|
||||
|
||||
///|
|
||||
pub fn[S] patch_sink(sink : S, patch : RecordPatch) -> PatchSink[S] {
|
||||
{ sink, patch }
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl[S : Sink] Sink for PatchSink[S] with fn write(self, rec) {
|
||||
self.sink.write((self.patch)(rec))
|
||||
@sink_graph.patch_sink(sink, patch)
|
||||
}
|
||||
|
||||
+36
-353
@@ -1,32 +1,18 @@
|
||||
///|
|
||||
pub struct FileSink {
|
||||
path : String
|
||||
append : Ref[Bool]
|
||||
default_append : Bool
|
||||
handle : Ref[FileHandle?]
|
||||
formatter : RecordFormatter
|
||||
auto_flush : Ref[Bool]
|
||||
default_auto_flush : Bool
|
||||
rotation : Ref[FileRotation?]
|
||||
default_rotation : FileRotation?
|
||||
open_failures : Ref[Int]
|
||||
write_failures : Ref[Int]
|
||||
flush_failures : Ref[Int]
|
||||
rotation_failures : Ref[Int]
|
||||
}
|
||||
pub type FileSink = @file_runtime.FileSink
|
||||
|
||||
///|
|
||||
pub type FileRotation = @utils.FileRotation
|
||||
pub type FileRotation = @file_model.FileRotation
|
||||
|
||||
///|
|
||||
pub type FileSinkState = @utils.FileSinkState
|
||||
pub type FileSinkState = @file_model.FileSinkState
|
||||
|
||||
///|
|
||||
pub type FileSinkPolicy = @utils.FileSinkPolicy
|
||||
pub type FileSinkPolicy = @file_model.FileSinkPolicy
|
||||
|
||||
///|
|
||||
pub fn file_rotation(max_bytes : Int, max_backups? : Int = 1) -> FileRotation {
|
||||
@utils.file_rotation(max_bytes, max_backups~)
|
||||
@file_model.file_rotation(max_bytes, max_backups~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -34,12 +20,40 @@ pub fn file_rotation_i64(
|
||||
max_bytes : Int64,
|
||||
max_backups? : Int = 1,
|
||||
) -> FileRotation {
|
||||
@utils.file_rotation_i64(max_bytes, max_backups~)
|
||||
@file_model.file_rotation_i64(max_bytes, max_backups~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn native_files_supported() -> Bool {
|
||||
native_files_supported_internal()
|
||||
@file_runtime.native_files_supported()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_policy_to_json(
|
||||
policy : FileSinkPolicy,
|
||||
) -> @json_parser.JsonValue {
|
||||
@file_model.file_sink_policy_to_json(policy)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn stringify_file_sink_policy(
|
||||
policy : FileSinkPolicy,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@file_model.stringify_file_sink_policy(policy, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_sink_state_to_json(state : FileSinkState) -> @json_parser.JsonValue {
|
||||
@file_model.file_sink_state_to_json(state)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn stringify_file_sink_state(
|
||||
state : FileSinkState,
|
||||
pretty? : Bool = false,
|
||||
) -> String {
|
||||
@file_model.stringify_file_sink_state(state, pretty~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -50,336 +64,5 @@ pub fn file_sink(
|
||||
rotation? : FileRotation? = None,
|
||||
formatter? : RecordFormatter = fn(rec) { format_text(rec) },
|
||||
) -> FileSink {
|
||||
let handle = open_file_handle_internal(path, append)
|
||||
{
|
||||
path,
|
||||
append: Ref(append),
|
||||
default_append: append,
|
||||
handle: Ref(handle),
|
||||
formatter,
|
||||
auto_flush: Ref(auto_flush),
|
||||
default_auto_flush: auto_flush,
|
||||
rotation: Ref(rotation),
|
||||
default_rotation: rotation,
|
||||
open_failures: Ref(if handle is Some(_) { 0 } else { 1 }),
|
||||
write_failures: Ref(0),
|
||||
flush_failures: Ref(0),
|
||||
rotation_failures: Ref(0),
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::is_available(self : FileSink) -> Bool {
|
||||
self.handle.val is Some(_)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::flush(self : FileSink) -> Bool {
|
||||
match self.handle.val {
|
||||
None => false
|
||||
Some(handle) => {
|
||||
let ok = flush_file_handle_internal(handle)
|
||||
if !ok {
|
||||
self.flush_failures.val += 1
|
||||
}
|
||||
ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::append_mode(self : FileSink) -> Bool {
|
||||
self.append.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_append_mode(self : FileSink, append : Bool) -> Unit {
|
||||
self.append.val = append
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::path(self : FileSink) -> String {
|
||||
self.path
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::auto_flush_enabled(self : FileSink) -> Bool {
|
||||
self.auto_flush.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::rotation_enabled(self : FileSink) -> Bool {
|
||||
self.rotation.val is Some(_)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::rotation_config(self : FileSink) -> FileRotation? {
|
||||
self.rotation.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_auto_flush(self : FileSink, enabled : Bool) -> Unit {
|
||||
self.auto_flush.val = enabled
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_policy(self : FileSink, policy : FileSinkPolicy) -> Unit {
|
||||
self.append.val = policy.append
|
||||
self.auto_flush.val = policy.auto_flush
|
||||
self.rotation.val = policy.rotation
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::set_rotation(
|
||||
self : FileSink,
|
||||
rotation : FileRotation?,
|
||||
) -> Unit {
|
||||
self.rotation.val = rotation
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::clear_rotation(self : FileSink) -> Unit {
|
||||
self.rotation.val = None
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::close(self : FileSink) -> Bool {
|
||||
match self.handle.val {
|
||||
None => false
|
||||
Some(handle) => {
|
||||
let ok = close_file_handle_internal(handle)
|
||||
self.handle.val = None
|
||||
ok
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::rotation_failures(self : FileSink) -> Int {
|
||||
self.rotation_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::open_failures(self : FileSink) -> Int {
|
||||
self.open_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::write_failures(self : FileSink) -> Int {
|
||||
self.write_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::flush_failures(self : FileSink) -> Int {
|
||||
self.flush_failures.val
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reset_failure_counters(self : FileSink) -> Unit {
|
||||
self.open_failures.val = 0
|
||||
self.write_failures.val = 0
|
||||
self.flush_failures.val = 0
|
||||
self.rotation_failures.val = 0
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reset_policy(self : FileSink) -> Unit {
|
||||
self.append.val = self.default_append
|
||||
self.auto_flush.val = self.default_auto_flush
|
||||
self.rotation.val = self.default_rotation
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::policy(self : FileSink) -> FileSinkPolicy {
|
||||
FileSinkPolicy::new(
|
||||
append=self.append.val,
|
||||
auto_flush=self.auto_flush.val,
|
||||
rotation=self.rotation.val,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::default_policy(self : FileSink) -> FileSinkPolicy {
|
||||
FileSinkPolicy::new(
|
||||
append=self.default_append,
|
||||
auto_flush=self.default_auto_flush,
|
||||
rotation=self.default_rotation,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::policy_matches_default(self : FileSink) -> Bool {
|
||||
let current = self.policy()
|
||||
let default = self.default_policy()
|
||||
current.append == default.append &&
|
||||
current.auto_flush == default.auto_flush &&
|
||||
policy_rotation_equals_internal(current.rotation, default.rotation)
|
||||
}
|
||||
|
||||
///|
|
||||
fn policy_rotation_equals_internal(
|
||||
left : FileRotation?,
|
||||
right : FileRotation?,
|
||||
) -> Bool {
|
||||
match (left, right) {
|
||||
(None, None) => true
|
||||
(Some(a), Some(b)) =>
|
||||
a.max_bytes == b.max_bytes &&
|
||||
a.max_backups == b.max_backups &&
|
||||
a.native_wide_max_bytes == b.native_wide_max_bytes
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotation_max_bytes_internal(rotation : FileRotation) -> Int64 {
|
||||
match rotation.native_wide_max_bytes {
|
||||
Some(value) => value
|
||||
None => rotation.max_bytes.to_int64()
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::state(self : FileSink) -> FileSinkState {
|
||||
FileSinkState::new(
|
||||
self.path,
|
||||
available=self.is_available(),
|
||||
append=self.append.val,
|
||||
auto_flush=self.auto_flush.val,
|
||||
rotation=self.rotation.val,
|
||||
open_failures=self.open_failures.val,
|
||||
write_failures=self.write_failures.val,
|
||||
flush_failures=self.flush_failures.val,
|
||||
rotation_failures=self.rotation_failures.val,
|
||||
)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen(self : FileSink, append? : Bool? = None) -> Bool {
|
||||
let append_mode = append.unwrap_or(self.append.val)
|
||||
self.append.val = append_mode
|
||||
match self.handle.val {
|
||||
None => ()
|
||||
Some(handle) => {
|
||||
ignore(close_file_handle_internal(handle))
|
||||
self.handle.val = None
|
||||
}
|
||||
}
|
||||
let reopened = open_file_handle_internal(self.path, append_mode)
|
||||
self.handle.val = reopened
|
||||
if reopened is Some(_) {
|
||||
true
|
||||
} else {
|
||||
self.open_failures.val += 1
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen_with_current_policy(self : FileSink) -> Bool {
|
||||
self.reopen()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen_append(self : FileSink) -> Bool {
|
||||
self.reopen(append=Some(true))
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSink::reopen_truncate(self : FileSink) -> Bool {
|
||||
self.reopen(append=Some(false))
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotated_file_path(path : String, index : Int) -> String {
|
||||
"\{path}.\{index}"
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotate_file_sink_internal(sink : FileSink, rotation : FileRotation) -> Bool {
|
||||
let closed = match sink.handle.val {
|
||||
None => true
|
||||
Some(handle) => {
|
||||
let ok = close_file_handle_internal(handle)
|
||||
sink.handle.val = None
|
||||
ok
|
||||
}
|
||||
}
|
||||
if !closed {
|
||||
return false
|
||||
}
|
||||
if rotation.max_backups > 0 {
|
||||
ignore(
|
||||
remove_file_internal(rotated_file_path(sink.path, rotation.max_backups)),
|
||||
)
|
||||
for index = rotation.max_backups - 1; index >= 1; {
|
||||
let from_path = rotated_file_path(sink.path, index)
|
||||
let to_path = rotated_file_path(sink.path, index + 1)
|
||||
ignore(rename_file_internal(from_path, to_path))
|
||||
continue index - 1
|
||||
}
|
||||
ignore(rename_file_internal(sink.path, rotated_file_path(sink.path, 1)))
|
||||
} else {
|
||||
ignore(remove_file_internal(sink.path))
|
||||
}
|
||||
sink.handle.val = open_file_handle_internal(sink.path, false)
|
||||
sink.handle.val is Some(_)
|
||||
}
|
||||
|
||||
///|
|
||||
fn rotate_if_needed_internal(sink : FileSink, next_line_bytes : Int) -> Bool {
|
||||
match sink.rotation.val {
|
||||
None => true
|
||||
Some(rotation) =>
|
||||
match sink.handle.val {
|
||||
None => false
|
||||
Some(handle) => {
|
||||
let size = file_size_i64_internal(handle)
|
||||
let next_line = next_line_bytes.to_int64()
|
||||
if size + next_line <= rotation_max_bytes_internal(rotation) {
|
||||
true
|
||||
} else {
|
||||
let rotated = rotate_file_sink_internal(sink, rotation)
|
||||
if !rotated {
|
||||
sink.rotation_failures.val += 1
|
||||
}
|
||||
rotated
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub impl Sink for FileSink with fn write(self, rec) {
|
||||
match self.handle.val {
|
||||
None => self.write_failures.val += 1
|
||||
Some(_) => {
|
||||
let line = "\{(self.formatter)(rec)}\n"
|
||||
let can_write = rotate_if_needed_internal(
|
||||
self,
|
||||
string_byte_length_internal(line),
|
||||
)
|
||||
if can_write {
|
||||
match self.handle.val {
|
||||
None => self.write_failures.val += 1
|
||||
Some(active) => {
|
||||
let wrote = write_file_handle_internal(active, line)
|
||||
if wrote {
|
||||
if self.auto_flush.val {
|
||||
let flushed = flush_file_handle_internal(active)
|
||||
if !flushed {
|
||||
self.flush_failures.val += 1
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.write_failures.val += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.write_failures.val += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@file_runtime.file_sink(path, append~, auto_flush~, rotation~, formatter~)
|
||||
}
|
||||
|
||||
@@ -93,6 +93,17 @@ pub fn open_file_handle_internal(path : String, append : Bool) -> FileHandle? {
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_exists_internal(path : String) -> Bool {
|
||||
let raw = file_open_ffi(string_to_c_bytes(path), string_to_c_bytes("rb"))
|
||||
if file_is_null_ffi(raw) {
|
||||
false
|
||||
} else {
|
||||
ignore(file_close_ffi(raw))
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn write_file_handle_internal(
|
||||
handle : FileHandle,
|
||||
|
||||
+10
-38
@@ -1,75 +1,47 @@
|
||||
///|
|
||||
pub type RecordPredicate = (@core.Record) -> Bool
|
||||
pub type RecordPredicate = @record_ops.RecordPredicate
|
||||
|
||||
///|
|
||||
pub fn level_at_least(min_level : @core.Level) -> RecordPredicate {
|
||||
fn(rec) { rec.level.priority() >= min_level.priority() }
|
||||
@record_ops.level_at_least(min_level)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_is(target : String) -> RecordPredicate {
|
||||
fn(rec) { rec.target == target }
|
||||
@record_ops.target_is(target)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn target_has_prefix(prefix : String) -> RecordPredicate {
|
||||
fn(rec) { rec.target.has_prefix(prefix) }
|
||||
@record_ops.target_has_prefix(prefix)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn message_contains(fragment : String) -> RecordPredicate {
|
||||
fn(rec) { rec.message.contains(fragment) }
|
||||
@record_ops.message_contains(fragment)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn has_field(key : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for field in rec.fields {
|
||||
if field.key == key {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
@record_ops.has_field(key)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn field_equals(key : String, value : String) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for field in rec.fields {
|
||||
if field.key == key && field.value == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
@record_ops.field_equals(key, value)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn not_(predicate : RecordPredicate) -> RecordPredicate {
|
||||
fn(rec) { !predicate(rec) }
|
||||
@record_ops.not_(predicate)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn all_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for predicate in predicates {
|
||||
if !predicate(rec) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
@record_ops.all_of(predicates)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn any_of(predicates : Array[RecordPredicate]) -> RecordPredicate {
|
||||
fn(rec) {
|
||||
for predicate in predicates {
|
||||
if predicate(rec) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
@record_ops.any_of(predicates)
|
||||
}
|
||||
|
||||
+33
-1062
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
"Nanaloveyuki/BitLogger/src/core",
|
||||
"maria/json_parser",
|
||||
"Nanaloveyuki/BitLogger/src/formatting",
|
||||
"Nanaloveyuki/BitLogger/src/record_ops",
|
||||
"moonbitlang/core/env",
|
||||
"moonbitlang/core/json",
|
||||
"moonbitlang/core/ref",
|
||||
|
||||
+8
-42
@@ -1,47 +1,29 @@
|
||||
///|
|
||||
pub type RecordPatch = (@core.Record) -> @core.Record
|
||||
pub type RecordPatch = @record_ops.RecordPatch
|
||||
|
||||
///|
|
||||
pub fn identity_patch() -> RecordPatch {
|
||||
fn(rec) { rec }
|
||||
@record_ops.identity_patch()
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn set_target(target : String) -> RecordPatch {
|
||||
fn(rec) { rec.with_target(target) }
|
||||
@record_ops.set_target(target)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn prefix_message(prefix : String) -> RecordPatch {
|
||||
fn(rec) { rec.with_message("\{prefix}\{rec.message}") }
|
||||
@record_ops.prefix_message(prefix)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn append_fields(extra_fields : Array[@core.Field]) -> RecordPatch {
|
||||
fn(rec) {
|
||||
if extra_fields.length() == 0 {
|
||||
rec
|
||||
} else if rec.fields.length() == 0 {
|
||||
rec.with_fields(extra_fields)
|
||||
} else {
|
||||
rec.with_fields(rec.fields + extra_fields)
|
||||
}
|
||||
}
|
||||
@record_ops.append_fields(extra_fields)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn redact_field(key : String, placeholder? : String = "***") -> RecordPatch {
|
||||
fn(rec) {
|
||||
rec.with_fields(
|
||||
rec.fields.map(fn(field) {
|
||||
if field.key == key {
|
||||
field.with_value(placeholder)
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
@record_ops.redact_field(key, placeholder~)
|
||||
}
|
||||
|
||||
///|
|
||||
@@ -49,26 +31,10 @@ pub fn redact_fields(
|
||||
keys : Array[String],
|
||||
placeholder? : String = "***",
|
||||
) -> RecordPatch {
|
||||
fn(rec) {
|
||||
rec.with_fields(
|
||||
rec.fields.map(fn(field) {
|
||||
if keys.contains(field.key) {
|
||||
field.with_value(placeholder)
|
||||
} else {
|
||||
field
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
@record_ops.redact_fields(keys, placeholder~)
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn compose_patches(patches : Array[RecordPatch]) -> RecordPatch {
|
||||
fn(rec) {
|
||||
let mut current = rec
|
||||
for patch in patches {
|
||||
current = patch(current)
|
||||
}
|
||||
current
|
||||
}
|
||||
@record_ops.compose_patches(patches)
|
||||
}
|
||||
|
||||
@@ -1,105 +1 @@
|
||||
///|
|
||||
pub struct FileRotation {
|
||||
max_bytes : Int
|
||||
max_backups : Int
|
||||
native_wide_max_bytes : Int64?
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FileSinkState {
|
||||
path : String
|
||||
available : Bool
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
open_failures : Int
|
||||
write_failures : Int
|
||||
flush_failures : Int
|
||||
rotation_failures : Int
|
||||
}
|
||||
|
||||
///|
|
||||
pub struct FileSinkPolicy {
|
||||
append : Bool
|
||||
auto_flush : Bool
|
||||
rotation : FileRotation?
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSinkPolicy::new(
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
) -> FileSinkPolicy {
|
||||
{ append, auto_flush, rotation }
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn FileSinkState::new(
|
||||
path : String,
|
||||
available? : Bool = false,
|
||||
append? : Bool = true,
|
||||
auto_flush? : Bool = true,
|
||||
rotation? : FileRotation? = None,
|
||||
open_failures? : Int = 0,
|
||||
write_failures? : Int = 0,
|
||||
flush_failures? : Int = 0,
|
||||
rotation_failures? : Int = 0,
|
||||
) -> FileSinkState {
|
||||
{
|
||||
path,
|
||||
available,
|
||||
append,
|
||||
auto_flush,
|
||||
rotation,
|
||||
open_failures,
|
||||
write_failures,
|
||||
flush_failures,
|
||||
rotation_failures,
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_rotation(max_bytes : Int, max_backups? : Int = 1) -> FileRotation {
|
||||
{
|
||||
max_bytes: if max_bytes <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_bytes
|
||||
},
|
||||
max_backups: if max_backups <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_backups
|
||||
},
|
||||
native_wide_max_bytes: None,
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub fn file_rotation_i64(
|
||||
max_bytes : Int64,
|
||||
max_backups? : Int = 1,
|
||||
) -> FileRotation {
|
||||
let normalized = if max_bytes <= 0L { 1L } else { max_bytes }
|
||||
let clamped_max_bytes = if normalized > 2147483647L {
|
||||
2147483647
|
||||
} else {
|
||||
normalized.to_int()
|
||||
}
|
||||
{
|
||||
max_bytes: clamped_max_bytes,
|
||||
max_backups: if max_backups <= 0 {
|
||||
1
|
||||
} else {
|
||||
max_backups
|
||||
},
|
||||
native_wide_max_bytes: Some(normalized),
|
||||
}
|
||||
}
|
||||
|
||||
///|
|
||||
pub(all) enum QueueOverflowPolicy {
|
||||
DropNewest
|
||||
DropOldest
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user