Skip to content

feat(logging): add logger freeze/unfreeze#189

Merged
TheJokr merged 2 commits intocloudflare:mainfrom
jgpaiva:logger-freezing
Apr 9, 2026
Merged

feat(logging): add logger freeze/unfreeze#189
TheJokr merged 2 commits intocloudflare:mainfrom
jgpaiva:logger-freezing

Conversation

@jgpaiva
Copy link
Copy Markdown
Contributor

@jgpaiva jgpaiva commented Apr 7, 2026

Foundations supports forking a logger so that when e.g. a request arrives, the application can fork the root logger into a request-scoped context and add fields there. However, if code running in a spawned thread or async task lacks a forked context, it falls back to the root logger and mutates it directly. This silently accumulates irrelevant fields on the root logger over time. This leads to two problems: 1. eventually the logger will hit the KV nesting limit and panic or reject changes, and 2. all request/connection logs will inherit fields that were added by mistake to the root logger.

This change introduces freeze_log(), unfreeze_log(), and is_log_frozen(), to enable applications to freeze any logger after it's fully initialized. Any subsequent mutation attempt is caught at the (presumably wrong) call site, by either panicking if the panic_on_frozen_logger feature flag is enabled, or by logging an error otherwise.

@jgpaiva jgpaiva force-pushed the logger-freezing branch 2 times, most recently from 1f4cd38 to 437e099 Compare April 8, 2026 17:06
Foundations supports forking a logger so that when e.g. a request
arrives, the application can fork the root logger into a request-scoped
context and add fields there. However, if code running in a spawned
thread or async task lacks a forked context, it falls back to the root
logger and mutates it directly. This silently accumulates irrelevant
fields on the root logger over time. This leads to two problems: 1.
eventually the logger will hit the KV nesting limit and panic or reject
changes, and 2. all request/connection logs will inherit fields that
were added by mistake to the root logger.

This change introduces freeze_log(), unfreeze_log(), and
is_log_frozen(), to enable applications to freeze any logger after
it's fully initialized. Any subsequent mutation attempt is caught
at the (presumably wrong) call site, by either panicking if the
panic_on_frozen_logger feature flag is enabled, or by logging an error
otherwise.
@TheJokr TheJokr merged commit 3f945ca into cloudflare:main Apr 9, 2026
18 checks passed
TheJokr added a commit that referenced this pull request Apr 9, 2026
Added:
- The `ratelimit!` utility macro simplifies the setup required for
  rate-limiting a code block into a single macro expression. There is
  also a special `ratelimit=` prefix syntax for log statements
  specifically. (#182)
- The sentry metrics hook added in v5.5 now also supports rate-limiting
  for sentry events. To make use of this feature, call the new
  `foundations::sentry::install_hook_with_settings` setup function.
  (#183)
- The telemetry server implements a `/pprof/symbol` endpoint now, which
  can be used for remote symbolization with pprof-compatible tools.
  (#186)
- `foundations::telemetry::tracing::span_is_sampled()` provides a cheap
  way to check whether the current trace has been sampled. This allows
  skipping expensive tag/log formatting code if the values would be
  discarded anyway. (#187)
- `Secret` (string) and `RawSecret` (bytes) wrappers have been added to
  aid with confidential values in config files. Both types hide their
  contents from Debug/Display calls and require an explicit accessors to
  retrieve the secret. Additionally, they zero their memory when
  dropped. (#188)
- `MaybeExternal` is a new settings type that can load plain data
  (strings, bytes, and secrets) from either inline config or external
  sources (environment variables or file system). (#188)

Improved:
- `serde_yaml` was replaced by the new `serde-saphyr` YAML
  implementation. `serde_yaml` has been unmaintained since 2024. (#181)
- Loggers can now be frozen, meaning any further mutation (such as
  `add_fields!`) will lead to an error. This is useful to catch bugs
  where mutations are applied to the wrong logger instance. (#189)
- The maximum queue size for trace span output can now be limited via
  telemetry settings. The default has been set at 1 million spans.
  Additionally, there are new metrics to observe the queue size, total
  number of spans exported, and how many spans have been dropped. (#190)
- Tracing can now be configured with multiple concurrent output tasks to
  boost span throughput. The tasks now run independently of the
  TelemetryDriver to ensure spans are output throughout the lifetime of
  the process. (#191)

Fixed:
- Log rate limiting now correctly applies across `set_verbosity` calls.
  (#180)

Deprecated:
- `foundations::sentry::install_hook` is deprecated in favor of
  `foundations::sentry::install_hook_with_settings`.
@TheJokr TheJokr mentioned this pull request Apr 9, 2026
TheJokr added a commit that referenced this pull request Apr 9, 2026
Added:
- The `ratelimit!` utility macro simplifies the setup required for
  rate-limiting a code block into a single macro expression. There is
  also a special `ratelimit=` prefix syntax for log statements
  specifically. (#182)
- The sentry metrics hook added in v5.5 now also supports rate-limiting
  for sentry events. To make use of this feature, call the new
  `foundations::sentry::install_hook_with_settings` setup function.
  (#183)
- The telemetry server implements a `/pprof/symbol` endpoint now, which
  can be used for remote symbolization with pprof-compatible tools.
  (#186)
- `foundations::telemetry::tracing::span_is_sampled()` provides a cheap
  way to check whether the current trace has been sampled. This allows
  skipping expensive tag/log formatting code if the values would be
  discarded anyway. (#187)
- `Secret` (string) and `RawSecret` (bytes) wrappers have been added to
  aid with confidential values in config files. Both types hide their
  contents from Debug/Display calls and require an explicit accessors to
  retrieve the secret. Additionally, they zero their memory when
  dropped. (#188)
- `MaybeExternal` is a new settings type that can load plain data
  (strings, bytes, and secrets) from either inline config or external
  sources (environment variables or file system). (#188)

Improved:
- `serde_yaml` was replaced by the new `serde-saphyr` YAML
  implementation. `serde_yaml` has been unmaintained since 2024. (#181)
- Loggers can now be frozen, meaning any further mutation (such as
  `add_fields!`) will lead to an error. This is useful to catch bugs
  where mutations are applied to the wrong logger instance. (#189)
- The maximum queue size for trace span output can now be limited via
  telemetry settings. The default has been set at 1 million spans.
  Additionally, there are new metrics to observe the queue size, total
  number of spans exported, and how many spans have been dropped. (#190)
- Tracing can now be configured with multiple concurrent output tasks to
  boost span throughput. The tasks now run independently of the
  TelemetryDriver to ensure spans are output throughout the lifetime of
  the process. (#191)

Fixed:
- Log rate limiting now correctly applies across `set_verbosity` calls.
  (#180)

Deprecated:
- `foundations::sentry::install_hook` is deprecated in favor of
  `foundations::sentry::install_hook_with_settings`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants