This the multi-page printable view of this section. Click here to print.
Observability
1 - Trickster Metrics
Trickster exposes a Prometheus /metrics endpoint with a customizable listener port number (default is 8481). For more information on customizing the metrics configuration, see configuring.md.
The following metrics are available for polling with any Trickster configuration:
trickster_build_info(Gauge) - This gauge is always 1 when Trickster is running- labels:
goversion- the version of go under which the running Trickster binary was builtrevision- the commit ID on which the running Trickster binary was builtversion- semantic version of the running Trickster binary
- labels:
trickster_config_last_reload_successful(Gauge) - The value is 1 when true (the last config reload was successful) or 0 when falsetrickster_config_last_reload_success_time_seconds(Gauge) - Epoch timestamp of the last successful configuration reloadtrickster_frontend_requests_total(Counter) - Count of front end requests handled by Trickster- labels:
backend_name- the name of the configured backend handling the proxy requestprovider- the type of the configured backend handling the proxy requestmethod- the HTTP Method of the proxied requesthttp_status- The HTTP response code provided by the backendpath- the Path portion of the requested URL
- labels:
trickster_frontend_requests_duration_seconds(Histogram) - Histogram of front end request durations handled by Trickster- labels:
backend_name- the name of the configured backend handling the proxy requestprovider- the type of the configured backend handling the proxy requestmethod- the HTTP Method of the proxied requesthttp_status- The HTTP response code provided by the backendpath- the Path portion of the requested URL
- labels:
trickster_frontend_written_byte_total(Counter) - Count of bytes written in front end requests handled by Trickster- labels:
backend_name- the name of the configured backend handling the proxy requestprovider- the type of the configured backend handling the proxy requestmethod- the HTTP Method of the proxied requesthttp_status- The HTTP response code provided by the backendpath- the Path portion of the requested URL
- labels:
trickster_proxy_requests_total(Counter) - The total number of requests Trickster has handled.- labels:
backend_name- the name of the configured backend handling the proxy requestprovider- the type of the configured backend handling the proxy requestmethod- the HTTP Method of the proxied requestcache_status- status codes are described herehttp_status- The HTTP response code provided by the backendpath- the Path portion of the requested URL
- labels:
trickster_proxy_points_total(Counter) - The total number of data points Trickster has handled.- labels:
backend_name- the name of the configured backend handling the proxy requestprovider- the type of the configured backend handling the proxy requestcache_status- status codes are described herepath- the Path portion of the requested URL
- labels:
trickster_proxy_request_duration_seconds(Histogram) - Time required to proxy a given Prometheus query.- labels:
backend_name- the name of the configured backend handling the proxy requestprovider- the type of the configured backend handling the proxy requestmethod- the HTTP Method of the proxied requestcache_status- status codes are described herehttp_status- The HTTP response code provided by the backendpath- the Path portion of the requested URL
- labels:
trickster_proxy_max_connections(Gauge) - Trickster max number of allowed concurrent connectionstrickster_proxy_active_connections(Gauge) - Trickster number of concurrent connectionstrickster_proxy_requested_connections_total(Counter) - Trickster total number of connections requested by clients.trickster_proxy_accepted_connections_total(Counter) - Trickster total number of accepted client connections.trickster_proxy_closed_connections_total(Counter) - Trickster total number of administratively closed client connections.trickster_proxy_failed_connections_total(Counter) - Trickster total number of failed client connections.trickster_proxy_query_range_rejected_total(Counter) - Trickster total number of queries rejected due to exceeding themax_query_rangelimit.- labels:
backend- the name of the configured backend rejecting the query
- labels:
trickster_graphite_resolution_lookups_total(Counter) - Count of Graphite step-resolution lookups. Labels never include a metric path or target expression.- labels:
backend_name- the name of the configured Graphite backendconfidence- how the step was established:exact(read from an origin response for this leaf set and age),derived(computed from known leaf ladders),configured(fromstatic_retentions, not yet probe-confirmed), orunknown(no usable step; the request is served unaccelerated)source- where it came from:registry,response,probe,static,function, ornone
- labels:
trickster_graphite_probes_total(Counter) - Count of synthetic requests issued to learn a metric’s archive ladder. Expect a spike at startup that collapses toward zero as ladders are learned.- labels:
backend_name- the name of the configured Graphite backendkind-narrow(a one-second window that also discovers the retention edge),wide(what a real query at that age receives), orfind(a/metrics/expandlookup)result-step(a stepped series came back),empty(no series: beyond retention, or no such metric), orerror
- labels:
trickster_graphite_ladders(Gauge) - Number of distinct archive ladders known to the resolution registry. Ladders come fromstorage-schemas.confpatterns, so this should flatten at a small number.- labels:
backend_name- the name of the configured Graphite backend
- labels:
trickster_graphite_registry_entries(Gauge) - Number of entries in each layer of the resolution registry.- labels:
backend_name- the name of the configured Graphite backendlayer-leaf(metric path to ladder),ladder(the ladders themselves),target(cached wildcard expansions), ornegative(paths in resolution backoff)
- labels:
trickster_graphite_step_mispredictions_total(Counter) - Count of origin responses whose step differed from the predicted step. This should always be zero. A non-zero value means a cached ladder was wrong; Trickster discards the prediction, relearns and re-serves the request unaccelerated, so clients still receive correct data.- labels:
backend_name- the name of the configured Graphite backend
- labels:
trickster_graphite_fallbacks_total(Counter) - Count of render requests served without delta caching. Labels never include a target expression.- labels:
backend_name- the name of the configured Graphite backendreason-parse_error,non_series_format,function_not_allowlisted,unknown_step,missing_target,multi_target_step_mismatch,passthrough_max_data_points,misprediction,client_identity,tz_unavailable, orresolution_identity
- labels:
trickster_sql_query_analysis_total(Counter) - Count of SQL query cache-eligibility classifications. Labels never include query text.- labels:
backend_name- the name of the configured backend analyzing the querydialect- the SQL dialect of the analyzing backend (e.g.,clickhouse)cache_mode- the strongest cache mode supported by the query (delta,object, ornone)reason- the stable classification reason code (e.g.,delta_cacheable,unsafe_predicate,unsupported_bucket)
- labels:
trickster_sql_query_rewrite_failures_total(Counter) - Count of SQL cache-miss extent rewrite failures. Labels never include query text.- labels:
backend_name- the name of the configured backend rendering the querydialect- the SQL dialect of the rendering backendreason- the fixed internal failure category
- labels:
trickster_cache_operation_objects_total(Counter) - The total number of objects upon which the Trickster cache has operated.- labels:
cache_name- the name of the configured cache performing the operation$provider- the type of the configured cache performing the operationoperation- the name of the operation being performed (read, write, etc.)status- the result of the operation being performed
- labels:
trickster_cache_operation_bytes_total(Counter) - The total number of bytes upon which the Trickster cache has operated.- labels:
cache_name- the name of the configured cache performing the operation$provider- the type of the configured cache performing the operationoperation- the name of the operation being performed (read, write, etc.)status- the result of the operation being performed
- labels:
trickster_alb_pool_admits_failing(Gauge) - 1 when an ALB pool’shealthy_flooradmits members in theunavailablestate, 0 otherwise. See alb.md for the recommended floor.- labels:
backend_name- the name of the configured ALB backend
- labels:
trickster_alb_pool_floor_reset(Gauge) - 1 when an ALB pool’shealthy_floorwas reset to 0 at startup because pool members have no health check and could never reach the configured floor, 0 otherwise. See alb.md.- labels:
backend_name- the name of the configured ALB backend
- labels:
The following metrics are available when ALB Autodiscovery is configured:
trickster_alb_discovery_members(Gauge) - Current number of discovered ALB pool members- labels:
alb_name- the name of the discovery-backed ALB backenddiscoverer- the name of the discoverer serving the ALB
- labels:
trickster_alb_discovery_member_changes_total(Counter) - Count of discovered pool member additions and removals- labels:
alb_name- the name of the discovery-backed ALB backenddiscoverer- the name of the discoverer serving the ALBevent-addorremove
- labels:
trickster_alb_discovery_snapshots_total(Counter) - Count of membership snapshots processed, by result- labels:
alb_name- the name of the discovery-backed ALB backenddiscoverer- the name of the discoverer serving the ALBresult-applied(membership updated),unchanged(no-op),rejected(guardrail-refused, e.g.min_members), orpartial(applied with member instantiation failures)
- labels:
trickster_alb_discovery_last_refresh_success_time_seconds(Gauge) - Epoch timestamp of the last successfully processed snapshot, for staleness alerting- labels:
alb_name- the name of the discovery-backed ALB backenddiscoverer- the name of the discoverer serving the ALB
- labels:
trickster_discovery_refresh_errors_total(Counter) - Count of provider-side refresh/watch errors (DNS resolution failures, Kubernetes list/sync failures, member-file read/parse failures)- labels:
discoverer- the name of the discoverer experiencing the errorprovider- the discoverer’s provider type
- labels:
trickster_tls_certificate_expiration_time_seconds(Gauge) - NotAfter time of a serving TLS certificate, as unix seconds. See tls.md.- labels:
listener- the name of the listener serving the certificateentry- the certificate’s source identity
- labels:
trickster_tls_certificate_last_load_time_seconds(Gauge) - Epoch timestamp a serving TLS certificate was last loaded from its source- labels:
listener- the name of the listener serving the certificateentry- the certificate’s source identity
- labels:
trickster_tls_certificate_swaps_total(Counter) - Count of TLS certificates hot-swapped into a live listener by rotation detection- labels:
listener- the name of the listener serving the certificateentry- the certificate’s source identity
- labels:
trickster_tls_certificate_validation_failures_total(Counter) - Count of detected TLS certificate source changes that failed pair validation (e.g. a mid-rotation partial write) and were not swapped in- labels:
entry- the certificate’s source identity
- labels:
trickster_tls_watcher_errors_total(Counter) - Count of errors reading watched TLS certificate source files- labels:
entry- the certificate’s source identity
- labels:
trickster_tls_certificate_store_size(Gauge) - Number of certificates in a listener’s TLS certificate store- labels:
listener- the name of the listener
- labels:
The following metrics are available only for Caches Types whose object lifecycle Trickster manages internally (Memory, Filesystem and bbolt):
trickster_cache_events_total(Counter) - The total number of events that change the Trickster cache, such as retention policy evictions.- labels:
cache_name- the name of the configured cache experiencing the event$provider- the type of the configured cache experiencing the eventevent- the name of the event being performedreason- the reason the event occurred
- labels:
trickster_cache_usage_objects(Gauge) - The current count of objects in the Trickster cache.- labels:
cache_name- the name of the configured cache$provider- the type of the configured cache$
- labels:
trickster_cache_usage_bytes(Gauge) - The current count of bytes in the Trickster cache.- labels:
cache_name- the name of the configured cache$provider- the type of the configured cache$
- labels:
trickster_cache_max_usage_objects(Gauge) - The maximum allowed size of the Trickster cache in objects.- labels:
cache_name- the name of the configured cache$provider- the type of the configured cache
- labels:
trickster_cache_max_usage_bytes(Gauge) - The maximum allowed size of the Trickster cache in bytes.- labels:
cache_name- the name of the configured cache$provider- the type of the configured cache
- labels:
In addition to these custom metrics, Trickster also exposes the standard Prometheus metrics that are part of the client_golang metrics instrumentation package, including memory and cpu utilization, etc.
2 - Distributed Tracing via OpenTelemetry
Trickster instruments Distributed Tracing with OpenTelemetry. We import the OpenTelemetry golang packages to instrument support for tracing.
As OpenTelemetry evolves to support additional exporter formats, we will work to extend Trickster to support those as quickly as possible. We also make a best effort to update our otel package imports to the latest releases, whenever we publish a new Trickster release. You can check the go.mod file to see which release of opentelemetry-go we are is using. In this view, to see which version of otel a specific Trickster release imports, use the branch selector dropdown to switch to the tag corresponding to that version of Trickster.
Supported Tracing Backends
- Jaeger (via OTLP)
- Console/Stdout (printed locally by the Trickster process)
Trickster’s OTLP exporter supports OTLP over HTTP and gRPC. HTTP is the default
for existing OTLP configs. For Jaeger over OTLP/HTTP, configure Trickster with
the collector’s HTTP endpoint, for example http://jaeger:4318/v1/traces. For
Jaeger over OTLP/gRPC, set protocol: grpc and use the collector’s gRPC
endpoint, for example http://jaeger:4317 from another Compose service or
http://127.0.0.1:4317 from the host when using the developer Compose
environment.
Configuration
Trickster allows the operator to configure multiple tracing configurations, which can be associated into each Backend configuration by name.
The example config has exhaustive examples of configuring Trickster for distributed tracing.
For OTLP tracing, protocol selects the exporter transport. Supported values
are http and grpc; when omitted, Trickster uses http for backward
compatibility with existing configs.
Context Propagation
When tracing is enabled for a Backend, Trickster uses the W3C Trace Context and Baggage propagators. It extracts incoming traceparent, tracestate, and baggage headers from client requests and injects the active outbound origin request span into the proxied request. This lets downstream Origins continue the same distributed trace instead of starting an unrelated trace.
Sampling
Trickster uses parent-based sampling for traced requests. The configured sample_rate controls root traces that Trickster starts when there is no sampled upstream trace context. When an incoming request already has a remote parent trace, Trickster follows the parent’s sampling decision so sampled upstream traces continue across the proxy boundary and unsampled upstream traces remain unsampled.
Span List
Trickster can insert several spans to the traces that it captures, depending upon the type and cacheability of the inbound client request, as described in the table below.
| Span Name | Observes when Trickster is: |
|---|---|
| request | initially handling the client request by a Backend |
| QueryCache | querying the cache for an object |
| WriteCache | writing an object to the cache |
| DeltaProxyCacheRequest | handling a Time Series-based client request |
| FetchFastForward | making a Fast Forward request for time series data |
| FetchTimeSeries | retrieving time series data from an Origin |
| FetchRange | retrieving one sharded time range from an Origin |
| Fetch | retrieving one object or range from an Origin |
| FetchRevalidation | revalidating a stale cache object against its Origin |
| ProxyRequest | communicating with an Origin server to fulfill a client request |
| PrepareFetchReader | preparing a client response from a cached or Origin response |
| CacheRevalidation | revalidating a stale cache object against its Origin |
| FetchObject | retrieving a non-time-series object from an Origin |
Tags / Attributes
Trickster supports adding custom tags to every span via the configuration. Depending upon your preferred tracing backend, these may be referred to as attributes. See the example config for examples of adding custom attributes.
Trickster also supports omitting any tags that Trickster inserts by default. The list of default tags are below. For example on the “request” span, an http.url tag is attached with the current full URL. In deployments where that tag may introduce too much cardinality in your backend trace storage system, you may wish to omit that tag and rely on the more concise path tag. Each tracer config can be provided a string list of tags to omit from traces.
Attributes added to request and core proxy/cache/fetch spans
backend.namebackend.providercache.namecache.providerrouter.path- request path trimmed to the route match path for the request (e.g.,/api/v1/query), good for aggregating when there are large variations in the full URL pathrouter.handler
These resource attributes are attached when the corresponding backend, cache, or route configuration is available to the request flow.
Attributes added to top level (request) span
http.url- the full HTTP request URL
Attributes added to cache/proxy spans
cache.status- the lookup or proxy cache status where available. See the cache status reference for a description of the attribute values.
Attributes added to proxy/fetch spans
http.status_code- the HTTP status returned by the Origin or generated proxy response, when available.
Attributes added to the FetchRevalidation span
isRange- is true if the client request includes an HTTPRangeheader
Attributes added to the FetchObject span
isPCF- is true if the origin is configured for Progressive Collapsed Forwarding
3 - Access and Error Logs
Trickster can write per-backend HTTP access logs and error logs, with customizable formats, rotation and retention. Both logs are off by default; each is enabled by configuring its filename.
Basic Configuration
backends:
example1:
provider: rp
origin_url: http://example.com/
access_log:
filename: /var/log/trickster/example1.access.log
error_filename: /var/log/trickster/example1.error.log
- The access log receives one line per request handled by the backend and is
written only when
filenameis set. - The error log receives one line per request whose response status is at or
above
error_threshold(default400) and is written only whenerror_filenameis set. An error-logged request also appears in the access log when both are configured. - Two backends may share a filename; they will safely share the underlying file and its rotation.
- When
instance_idis set in the main config, it is inserted into log filenames just as with the application log (e.g.,example1.access.1.log).
Log Format
The format option accepts either a named preset or a custom format string
using Apache-style % tokens, so the well-known conventions from Apache
HTTP Server, Apache Traffic Server, Lighttpd, and similar servers apply
directly.
Presets
| Name | Description |
|---|---|
common | NCSA Common Log Format: %h %l %u %t "%r" %>s %b |
combined | Apache/Nginx Combined format: common + Referer and User-Agent. This is the default. |
extended | combined + duration (ms), cache status and backend name |
json | One JSON object per line with a fixed field set (see below) |
Custom Formats
access_log:
filename: /var/log/trickster/example1.access.log
format: '%h %u %t "%r" %>s %b %{ms}T %{cache-status}x'
Supported tokens:
| Token | Description |
|---|---|
%h, %a | client IP address |
%l | remote logname (always -) |
%u | authenticated username (from HTTP Basic Auth), else - |
%t | request start time in CLF format: [26/Aug/2026:10:30:00 +0000] |
%{sec}t, %{msec}t, %{usec}t | request start time as a Unix epoch value |
%{LAYOUT}t | request start time in a custom Go time layout |
%r | first line of the request: GET /path?query HTTP/1.1 |
%m | request method |
%U | request URL path |
%q | query string, prefixed with ?, or empty when none |
%H | request protocol (e.g., HTTP/1.1) |
%s, %>s | response status code |
%b | response body bytes, or - when zero (CLF style) |
%B | response body bytes, numeric |
%D | request duration in microseconds |
%T | request duration in whole seconds |
%{us}T, %{ms}T, %{s}T | request duration in the given unit |
%{Name}i | request header value |
%{Name}o | response header value |
%{Name}c | request cookie value |
%v | requested virtual host |
%p | listener port that served the request |
%A | listener IP address that served the request |
%% | a literal % |
Trickster-specific values use the %{key}x extension namespace:
| Token | Description |
|---|---|
%{backend}x | backend name |
%{provider}x | backend provider type |
%{cache-status}x | cache result (hit, phit, kmiss, …); see Cache Status |
%{engine}x | proxy engine that handled the request (e.g., DeltaProxyCache) |
%{path-config}x | the matched path config path |
Missing values render as -. Values derived from the request (like headers
and usernames) are backslash-escaped so they cannot corrupt the log line
structure. Unknown tokens fail validation at startup.
The json preset emits these fields per line: time, client_ip, user,
method, path, query, proto, status, bytes, duration_ms,
host, referer, user_agent, backend, provider, path_config,
cache_status, engine.
Rotation and Retention
Access and error logs are rotated and pruned automatically, using
nginx/logrotate-style numbered archives (example1.access.log.1.gz is the
most recent archive, .2.gz the next, and so on).
access_log:
filename: /var/log/trickster/example1.access.log
rotation:
size: 256MB # rotate when the live file would exceed this size (default 256MB)
interval: 1d # also rotate when the live file is older than this (default off)
retention:
count: 3 # keep at most 3 archives (default 80)
age: 7d # also prune archives older than this (default 7d)
compress: true # gzip archives (default true)
sizeandintervalmay be combined; the log rotates when either threshold is reached. Setting both to0disables rotation.- Sizes accept
KB,MB,GBandTBsuffixes (binary multiples), or a plain byte count. retention.count: 0disables count-based pruning and keeps all archives.- Writes are buffered for up to one second or 64 KiB. A process or machine crash can lose the buffered tail; an orderly shutdown flushes it.
- Interval rotation keeps its epoch in a
<filename>.rotationsidecar so a restart does not reset the interval clock.
Archives created by older Trickster releases use timestamped lumberjack names and are not included in numbered-archive retention. They form a bounded legacy set and may be removed manually after upgrading.
When upgrading from the original logging implementation, note these filename and retention changes:
retention.count: 0now keeps all archives; configure a positive count to bound archive retention.- With
main.instance_idenabled, filenames without a.logsuffix now also include the instance ID (trickster.outbecomestrickster.2.out). Update log shippers that still follow the unsuffixed filename.
The same rotation, retention and compress options are also available
in the main logging: config section to control rotation of the Trickster
application log, with the same defaults.
Error Log Settings
Each error_* option inherits its value from the corresponding access log
option when unset:
access_log:
filename: /var/log/trickster/example1.access.log
format: combined
error_filename: /var/log/trickster/example1.error.log
error_format: '' # default: inherits format
error_threshold: 400 # log responses with status >= this (default 400)
error_rotation: # default: inherits rotation
size: 64MB
error_retention: # default: inherits retention
count: 7
error_compress: true # default: inherits compress
4 - X-Trickster-Result Header
Trickster adds the X-Trickster-Result response header to describe how it handled a request. The header is intended for debugging cache behavior, proxy fallbacks, and partial origin fetches.
Example:
X-Trickster-Result: engine=DeltaProxyCache; status=phit; fetched=[1612804980000-1612808580000]; ffstatus=hit
The header value is a semicolon-separated list of fields. Optional fields are included only when Trickster has a value for them.
| Field | Description |
|---|---|
engine | The proxy engine that handled the response, such as HTTPProxy, ObjectProxyCache, or DeltaProxyCache. |
status | The cache or proxy result. See Cache Status. |
fetched | Time ranges fetched from the origin to satisfy the response. Ranges are formatted as start-end; multiple ranges are separated by semicolons inside the brackets. |
ffstatus | Fast Forward cache result for time series requests. Possible values are hit, miss, off, or err. |
failed | Time ranges that Trickster attempted to fetch but could not fetch successfully. This usually appears with proxy-error or partial fanout failures. |
Result Statuses
status uses the same values reported in metrics, logs, and tracing. Common examples are:
| Status | Meaning |
|---|---|
hit | The response was served fully from cache. |
phit | Part of the response was served from cache and part was fetched from the origin. |
kmiss | Trickster had no object for the cache key and fetched the response from the origin. |
rmiss | Trickster had an object for the cache key, but not for the requested range. |
rhit | Trickster revalidated a stale cached object against the origin and served it as a hit. |
nchit | The response was served from the Negative Cache. |
purge | The cache key was purged as directed by a request or response header. |
proxy-hit | The request joined an in-flight origin fetch for the same cache key. |
proxy-only | The request was proxied to the origin without writing or reading a cache object. |
proxy-error | An upstream request needed for the response returned an error. |
error | Trickster encountered a cache lookup or cache handling error. |
Proxy-Only Results
status=proxy-only means the response came from the origin through Trickster’s proxy path, without a cache read or cache write for that request. It does not necessarily mean the origin response was wrong.
Common reasons include:
| Cause | Example |
|---|---|
| Backend or path is configured to bypass caching | provider: reverseproxy or proxy_only: true. |
| Client request prevents caching | A request such as Cache-Control: no-cache can force Trickster to proxy and remove the existing object for that cache key. |
| Origin response is not cacheable | For example, response cache headers do not provide cacheability, or the response includes headers that Trickster treats as not cacheable. |
| Time series request cannot be parsed for delta caching | Trickster may fall back to object proxy cache for compatible requests, or proxy the request directly when it cannot safely cache the query shape. |
| Time series range is outside the retained cache window | Old data may be proxied without caching while newer ranges remain cacheable. |
When investigating proxy-only, check the backend provider, any proxy_only setting, request and response Cache-Control headers, and whether the request shape is supported by the configured backend provider.
Fetched And Failed Ranges
fetched and failed describe the ranges Trickster fetched or failed to fetch while serving the response.
Example:
X-Trickster-Result: engine=DeltaProxyCache; status=phit; fetched=[1612804980000-1612808580000;1612812180000-1612815780000]
For time series responses, range values are Unix timestamps in milliseconds. A phit result with fetched ranges usually means Trickster had some of the requested data cached and fetched the missing ranges from the origin.
failed ranges indicate the origin request for those ranges failed. Depending on the proxy engine and fanout behavior, Trickster may return an error response or a partial response with failure metadata.
Fast Forward Status
ffstatus appears on time series responses when the Delta Proxy Cache checks Fast Forward data:
| Fast Forward Status | Meaning |
|---|---|
hit | Fast Forward data was served from cache. |
miss | Fast Forward data was fetched from the origin. |
off | Fast Forward was not attempted for this request. |
err | Fast Forward was attempted but failed or returned unusable data. |
Fast Forward is only relevant for supported time series backends and only when the request is eligible for the latest datapoint optimization.