github ferronweb/ferron 3.0.0-beta.7

pre-release4 hours ago

Added

Observability & tracing

  • Prometheus native histogram support — the Prometheus observability backend now supports OpenMetrics native histograms alongside classic bucket histograms. Enable with endpoint_native_histograms true in the observability.prometheus block. Native histograms are only available in protobuf format; the text format continues to expose classic bucket histograms. Note that native histograms and exemplars are mutually exclusive for histograms — when native histograms are enabled, histogram exemplars are disabled.
  • Prometheus metric exemplars — the Prometheus observability backend now emits OpenMetrics exemplars on counter and histogram metrics when request trace context is available. Each exemplar carries the trace_id and span_id of the request that triggered the observation, enabling direct correlation between metric spikes and distributed trace flame graphs in compatible observability backends (Grafana, Prometheus 2.23+). Exemplars are enabled by default for counters. For histograms, exemplars are active only when endpoint_native_histograms is false (the default), since native histograms and exemplars are mutually exclusive.
  • Configuration content hash — new ferron.admin.config_mtime Gauge metric and config_file_hash / config_file_mtime fields on the /status Admin API endpoint expose the xxh3 content hash and last-modified time of the loaded configuration files. This enables rapid cluster-wide drift detection via a single PromQL query checking for hash mismatch across instances.
  • DNS cache TTL remaining gauge — new ferron.proxy.dns.cache_ttl_remaining_seconds Gauge metric exposes aggregated remaining TTL for DNS cache entries (min, max, avg aggregation via aggregation attribute). A companion ferron.proxy.dns.cache_entries Gauge tracks the number of active cache entries. This allows operators to alert on impending DNS record expiration before backend connections break.
  • Pool connection limit metrics — the ferron.proxy.pool.local_limit and ferron.proxy.pool.global_limit pool metrics are now available for monitoring connection pool usage.
  • Method and idempotency labels on retry metrics — the ferron.proxy.retry.count Counter and ferron.proxy.retry.final Gauge now include http.request.method (categorized: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS, CONNECT, TRACE, _other) and ferron.proxy.method_idempotent (bool per RFC 9110 §9.2.2) labels, enabling zero-delay alerting on non-idempotent retry anomalies that indicate potential state corruption.
  • Selected backends per request metric — the ferron.proxy.backends.selected_per_request Counter metric is now emitted for every proxied request, with backend_url and backend_unix_path attributes. This allows operators to see traffic amplification effects when multiple backends are selected for a single request.

Security

  • Rate limit throttling — the rate_limit directive now supports a throttle subdirective that allows rate-limited requests to be delayed instead of rejected. When enabled, requests exceeding the configured rate limit are queued before being processed. This reduces the likelihood of client-side errors and improves user experience during temporary traffic spikes.

Reverse proxying

  • Token-bucket retry budget — the new retry_budget directive implements a token-bucket-based retry budget that limits retries to a configurable fraction of steady-state traffic. When enabled alongside retry_connection true, retries consume tokens from a shared pool that is replenished by successful requests. If the retry budget is exhausted, further retries are refused and the request immediately returns 503 Service Unavailable, preventing cascading retry storms from amplifying backend failures into a self-inflicted DDoS. Supports max_retry_rate (default: 10%), max_tokens (default: 10), and refill_rate (default: 2.0 tokens/sec) subdirectives. New metrics: ferron.proxy.retry.budget_exhausted (Counter) and ferron.proxy.retry.budget_tokens_available (Gauge).

HTTP server core

  • JSON error responses — the new json_errors directive in the http-jsonerror module enables structured JSON error responses for HTTP 4xx/5xx errors. Supports both RFC 9457 application/problem+json (with type, title, status, detail, and optional trace_id fields) and simple application/json output formats. The type URI is configurable (default: about:blank), with support for {status} placeholder substitution (e.g., https://http.dev/{status}). Use location /api { json_errors true } to scope JSON errors to REST API endpoints. (http-jsonerror)
  • Client certificate common name variable — the mtls.cn variable is now available for interpolations in the server configuration, allowing to use the client certificate's common name in routing rules and conditionals.
  • HTTP error page placeholders — custom error page files now support optional placeholder substitution. Enable with error_page_placeholders true; the {{trace.id}} and {{trace.spanid}} placeholders are then replaced with the current request's trace ID and span ID before the page is served. Substitution reads the file into memory, bypassing the zerocopy/sendfile optimization for those responses.
  • Static file resolution tracing — the file resolution process now emits a dedicated ferron.pipeline.file_resolve trace span with ferron.file_resolve.request_path, ferron.file_resolve.root_path, ferron.file_resolve.outcome, and ferron.file_resolve.resolved_path (success) or ferron.file_resolve.last_candidate_path (error) attributes. Resolution error paths (403 Forbidden, 400 Bad Request) now include ferron.file_resolve.* fields in access logs, replacing the previous "black box" behavior where the file resolution process produced no observability signals. Directory listings now emit ferron.static.dir_path trace span and access log attributes, and contribute to the ferron.static.responses counter metric with ferron.static.outcome values "listing", "listing_disabled", "method_not_allowed", or "options".

Changed

Default pages

  • Redesigned default error and directory listing pages — the built-in error pages and static directory listings have been redesigned with a modern, minimal, neutral style (system fonts, subtle accent gradient, responsive layout, and automatic light/dark mode). All styling remains inlined with no external assets. Default error pages now display the request's trace ID when trace context is available, improving debuggability. The installation landing page (wwwroot) has also been refreshed to match.

HTTP caching

  • Unified cache eviction log summaries — the cache eviction log summaries are now unified to not include eviction reasons (they're already in log attributes).

Observability & tracing

  • Prometheus text format content-type — the Prometheus text endpoint now serves application/openmetrics-text; version=1.0.0 instead of text/plain; version=0.0.4, matching the OpenMetrics specification used by prometheus-client. Prometheus scrapers that do not support OpenMetrics content negotiation may need to be updated.
  • Native exponential histograms for OTLP latency metrics — all OTLP histogram metrics now use Base2 Exponential Histograms instead of fixed linear buckets. This provides high-resolution percentile data across deep orders of magnitude (1ms to 100s), eliminating the need for manual bucket allocation and preserving tail-latency outliers that were previously masked by coarse bucketing. Affected metrics include ferron.proxy.upstream.duration, ferron.proxy.pool.wait_time, ferron.proxy.tls.handshake_time, ferron.proxy.connect.latency, ferron.proxy.ttfb, http.server.request.duration, and all other histogram instruments exported via OTLP.
  • QUIC client/server address logging — QUIC connection error logs now include the client and server IP addresses, making it easier to trace connections and identify potential bottlenecks.
  • stage.name in traces renamed to ferron.stage.name — renamed stage.name to ferron.stage.name traces to ensure consistency with other Ferron-specific attributes.

Reverse proxying

  • DNS thundering herd prevention — the DNS resolver now uses a singleflight mechanism to prevent multiple concurrent DNS queries for the same hostname, reducing load on DNS servers and improving performance.
  • DNS resolution status metric attribute — the metrics_resolved_ip directive now also emits a ferron.proxy.dns_status attribute on all proxy metrics and access logs when enabled. Values: "resolved" (DNS succeeded), "nxdomain" (domain not found), "dns_error" (other DNS failure), "logical_dns" (resolution deferred to connect time), "static" (DNS not applicable). This provides visibility into DNS resolution outcomes without requiring per-IP label explosion.

Fixed

HTTP caching

  • Duplicate eviction metrics — eviction metrics (and logs) were being emitted twice for cache hits, leading to incorrect metric values. This has been fixed.

Observability & tracing

  • Prometheus endpoint is no longer on-demand — the Prometheus endpoint is now always available on the configured port, regardless of the number of active connections.
  • Reverse proxy metric naming consistency — the ferron.proxy.backend.excluded metric name has been renamed to ferron.proxy.backends.excluded for consistency with other reverse proxy metrics.

Don't miss a new ferron release

NewReleases is sending notifications on new releases.