Logování a diagnostika
Dokumentace/Provoz serveru
Logování a diagnostika8 min čtení

Logging

Zdrojová dokumentace je zatím dostupná v angličtině. Ovládání čtečky odpovídá zvolenému jazyku.

Na této stránce

Selection

scribe, scribe-server, scribe-auth, and scribe-runner accept --log-level off|error|warn|info|debug|trace, --log-filter 'warn,scribe_server=info,scribe_objects=debug', --log-format text|json, -v (debug), -vv (trace), -q (errors only, no progress). SCRIBE_LOG holds the same target/level filter syntax.

scribe-gateway and scribe-ctl accept --log-level, --log-format, and --timings, and honor SCRIBE_LOG. They do not expose --log-filter, -v, or -q. All but scribe-runner accept global --json for command results; see JSON output for automation. JSON result selection is independent of logging format.

Precedence: explicit CLI selection > SCRIBE_LOG > configuration ([logging].filter, server only) > default (info for scribe-server, scribe-auth, scribe-gateway, and scribe-runner; warn for scribe and scribe-ctl). --log-level with --log-filter, or -v with -q, is an error. A malformed filter from any source is an error even when overridden. All levels remain selectable in release builds; nothing is compiled out.

Sinks

  • Client: stderr. Command results go to stdout only; --json output remains parseable with -vv enabled.
  • Server: stderr by default; --log-dir or [server].log_dir selects daily files scribe-server.<date>.log with [logging].keep_files retained (default 14). Auth: the same with --log-dir and --log-keep-files, files scribe-auth.<date>.log.
  • Terminal stderr uses colored levels; NO_COLOR=1 or TERM=dumb disables them, and files and redirected streams are plain.
  • Both sinks sit behind a bounded, lossy, off-thread queue (32,768 lines). When the sink stalls, events are dropped and counted; the count is reported at shutdown. Individual events are bounded by keeping peer strings short at the emission site. Sink write failures are counted, never propagated into request paths. An unwritable log directory fails startup. Diagnostic events are never fsynced; logs are not part of commit authority.
  • Shutdown flushes the queue with a bounded wait (about 1.1 s in tracing-appender 0.2). Forced kill may lose the last buffered lines.

Levels

ERROR failed operations, integrity or persistence failures. WARN recoverable failures, retry exhaustion, degraded resources, plaintext exposure. INFO lifecycle, submit.committed, submit.rejected (a client outcome, not a server error), maintenance outcomes. DEBUG batching, publication, cache, scheduling, retries. TRACE per-request timings; never raw asset bytes.

Events and context

Stable event names: server.starting, server.ready, server.draining, server.stopped, repo.created, repo.opened, objects.published, submit.committed (emitted only after the durable commit; a lost response does not turn it into a failure), submit.rejected, lock.acquired, lock.released, request.rejected, request.failed, conn.opened, conn.closed, sync.done, sync.displaced, submit.accepted, init.done, backup.done, restore.done, server.plaintext_exposed, auth.listening, auth.stopped, auth.failed, fault.armed (test builds only).

Admission and identity events: conn.refused (warn, with reason source pending limit or connection limit), conn.evicted (debug, the oldest pending connection closed to admit a newcomer), and conn.principal_limit (warn, one user at max_connections_per_principal) on storage; the auth service logs connection.refused and connection.evicted (debug), login.succeeded and login.failed (info), their administrator sign-in counterparts admin_login.succeeded (with expires), admin_login.failed and admin_login.forbidden (info, a correct password of an account that is no auth administrator), and login.throttled (warn, the per-username ceiling, shared by both sign-ins). None carries a password or key. A storage server that receives an auth answer from behind the newest auth revision it has seen logs auth.rollback_detected (error) and refuses it; a new auth incarnation after scribe-auth restore is logged as auth.incarnation_changed (warn), and the restore itself as auth.restored (warn) by scribe-auth. A client that cannot revoke its previous session during a new login logs session.revoke_failed (warn).

Lock releases are audited under the scribe_server::locks target. A holder releasing its own lock emits lock.released at debug level; a forced release of another workspace's lock emits lock.force_released at info level. Both carry repo, path, generation, workspace (the releasing workspace), principal and principal_id (the authenticated caller; absent for an in-process local service), and forced. lock.force_released adds holder_workspace and holder, the workspace and author that held the lock. Online verification adds integrity.pass_completed, integrity.scan_failed, and integrity.generation_changed. Both the online checker and offline doctor emit integrity.object_failed with the repository, object identity, check name, and error. See Online integrity checking for coverage and saved progress reports.

Fields include repository, workspace, session, operation id, request id, change number, counts, bytes, gate wait, transaction hold time, flush counts and time. Timestamps are UTC YYYY-MM-DDTHH:MM:SS.mmmZ.

JSON logs use one object per line, with control characters, quotes, and newlines escaped inside string values. Passwords, private keys, credential file contents, asset file contents, and raw frames are never logged.

Measuring logging overhead

Developers can measure logging overhead with:

sh
cargo bench --locked -p scribe-log --bench logging

Results depend on the machine, output format, sink, and event volume. Use the performance harness with phase timings disabled for regression comparisons; enable timings when investigating where an operation spends time.

Opt-in phase timings

All six executables accept the global --timings flag, before or after a subcommand. For scribe, scribe-server, and scribe-auth its help text is:

text
      --timings
          Report nested phase timings to the diagnostic sink (text or --log-format json)

scribe-runner describes it as reporting nested phase timings to the diagnostic sink; scribe-gateway and scribe-ctl report their phase timings to stderr.

Examples:

sh
scribe --timings submit --message "Update assets"
scribe sync --timings --log-format json
scribe-server serve --config server.toml --timings
scribe-auth serve --data-dir auth-data --pepper-file auth.pepper --revision-file auth.revision --tls-cert server.pem --tls-key server-key.pem --timings

Timing records use the scribe_timings target and the existing diagnostic sink: stderr by default, or the service's configured log directory. They never go to stdout; --json command output remains independently parseable. --log-format json produces JSON lines with span and the parent spans. No separate tracing flag is needed: existing -v, -vv, and --log-filter control ordinary diagnostic detail. --timings independently enables timing even with --log-level off or -q; verbosity alone does not enable timings. The scribe_timings target is reserved and controlled by the flag.

A record is emitted when each phase closes, including early error returns. Text output shows the nested phase path followed by time.busy and time.idle, with automatically selected units. Busy means wall time while the span is entered, not CPU time; it includes blocking I/O. Idle includes async suspension and other time outside the entered span. Their sum is the phase lifetime. Parent phases include their children: do not add all rows to estimate total time. A closed phase is not proof of success; the command result and normal error diagnostics still determine the outcome.

Instrumented boundaries include:

  • connection.resolve_and_connect, connection.tcp, connection.tls, and server connection/handshake phases.
  • rpc.round_trip (including the server wait), uploads, downloads, and manifest fetching. RPC context includes operation name, request and session.
  • hashing.analyze_file, hashing.chunk_stream, hashing.verify_file, and object verification. Streaming hashing includes input reads and chunk sinks.
  • compression.encode and compression.decode, per bounded block, with the original byte count. These measure codec work separately from stream I/O.
  • Sync planning, workspace status, materialization and journal application.
  • Storage staging/verification, durable object publication, individual file and directory flushes, publication-gate waits/holds, and durable metadata acceptance. Branch preparation/finalization also has timing spans.
  • Server transfer/storage admission waits; auth connection, admission, execution and response phases. Connection/request context is propagated into blocking jobs without holding an entered span across an async wait.
  • Submit selection, analysis/cache publication, upload-intent and candidate persistence, the remote submit, and workspace finalization. Server submit spans distinguish submit_turn.wait/submit_turn.hold from publication.wait/hold, acceptance preparation, envelope publication, and upload-intent cleanup.
  • Buffered parallel preparation, group rebasing, submit.group, and submit.group.wait. A leader's durable spans can cover multiple submissions; waiting members retain their own request spans and operation outcomes.
  • Metadata writer acquisition, staged commit, and recovery archive publication. Writer-acquisition spans include prerequisite archive work; they are not pure mutex-wait measurements.

Timing RPC request/session identities are decimal strings in JSON to preserve all 64 bits in analysis tools. Server request and admission spans carry the same identities as the client's rpc.round_trip. These are diagnostic fields only; the wire and persisted formats are unchanged.

The development-only scribe-perf helper uses this same subscriber and flags. node tools/concurrency.js --timings correlates client/server phases, summarizes them in the requested reports, and cleans raw logs. See the concurrency profiling guide.

command.total reports numeric elapsed_ms from successful logging setup until the log guard is dropped, on success or failure. For serve, this is service lifetime; use the per-request phases for latency. Argument parsing, configuration work before logging setup, process startup and final log drain are outside this total. Use an external harness for complete process timing.

Without --timings, timing callsites are filtered out: no timing-span clock reads, allocations, field evaluation, or formatting. There remains a small runtime enabled check; existing operational metrics are unchanged. Enabled timings add measurement and logging overhead, especially for many compression blocks. They use the existing bounded lossy queue, so diagnostic loss cannot stall durable operations; inspect the shutdown drop count before treating a trace as complete. No function arguments, credentials, asset contents, or raw frames are recorded by the timing instrumentation.

The logging benchmark also compares an uninstrumented function with a disabled timing span. Use node tools/scenario.js --profile ci with timings disabled for regression comparisons, and opt-in timings to investigate where time is spent.

Compiling timing instrumentation out

The native Cargo feature timings is enabled by default. To remove all --timings instrumentation from all six executables and their dependencies:

sh
cargo build --release --locked --no-default-features \
  -p scribe-cli -p scribe-server-cli -p scribe-auth-cli -p scribe-gateway -p scribe-ctl -p scribe-runner

A single executable can be built the same way, for example:

sh
cargo build --release --locked -p scribe-cli --no-default-features

These builds reject --timings with:

text
--timings is unavailable: this binary was built without the timings Cargo feature

Scope attributes, guards, async instrumentation wrappers, context propagation, and the command-total timer are removed by conditional compilation. There is no runtime timing-scope enabled check in this mode. Ordinary logging and existing operational metrics remain available.

Normal builds retain timings. To enable it explicitly while disabling other default features, use --no-default-features --features timings. Cargo features are additive across a shared dependency graph: keep timings disabled for every selected package when building without instrumentation; --all-features enables it. Internal dependencies disable their own defaults and forward timings explicitly so individual client and service builds work consistently.

Developer reference: command styling

Executables can use scribe_log::terminal::{Color, stdout, stderr} for a consistent palette: Heading (cyan), Success (green), Warning (yellow), Error (red), and Muted (dim). For example:

rust
use std::io::Write;
use scribe_log::terminal::{self, Color};
writeln!(terminal::stdout(), "{}", Color::Success.paint("Ready"))?;

Write painted labels through these adaptive streams, which detect stdout and stderr independently and remove styling for redirected output, nonempty NO_COLOR, or TERM=dumb. Keep JSON and other machine-readable formats unstyled. Pad table cells before applying color so escape sequences do not affect column alignment. Always include a meaningful text label; color should never be the only signal.

Zdroj docs/logging.mdVerze 2b8dcccb