Observability
Wolpi exposes a small built-in observability surface for health checks, metrics, and structured application logging.
Health endpoints
By default, Wolpi exposes the following health endpoints under the /monitoring base path:
/monitoring/health: overall health status/monitoring/health/liveness: liveness probe endpoint/monitoring/health/readiness: readiness probe endpoint
These endpoints are compatible with common orchestration environments such as Kubernetes.
Metrics endpoint
Wolpi exposes Prometheus-format metrics at:
/monitoring/prometheus
This endpoint includes:
- built-in Wolpi metrics
- custom metrics registered by extensions
- selected JVM / Spring Boot metrics
Requests to /monitoring/* are excluded from the standard http_server_requests metric so that
health checks and metrics scraping do not distort application request latency metrics.
But I don't use Prometheus?
Wolpi exposes Prometheus-format metrics directly. If you want to export metrics to other
backends such as OTLP or Datadog, configure the corresponding Spring Boot exporter under the
spring section of your wolpi.yml and refer to the
Spring Boot metrics exporter documentation.
If you have defined custom metrics in your extensions, those are exposed at the same endpoint automatically.
Built-in Wolpi metrics
wolpi_images_processed_total
- Type: Counter
- Measures: Number of images successfully processed and encoded
- Tags:
format: Output format such asjpg,png, orwebpquality: IIIF quality such ascolor,gray, orbitonaliiif_version: Requested IIIF Image API version,v2orv3
This counter increments after a successful image response.
For performance analysis, this metric is most useful as a throughput breakdown. Compare it with
wolpi_image_processing_seconds to see which output formats or quality modes dominate request
volume and whether slow requests are simply the most common requests.
wolpi_image_processing_seconds
- Type: Timer
- Measures: End-to-end time spent in Wolpi's built-in image processing and encoding pipeline for a successful image request
- Tags:
format: Output format such asjpg,png, orwebpoutput_size: Bucketed output size based on the largest output dimension:tiny(up to 256),small(up to 512),medium(up to 1024),large(up to 2048),xlarge(up to 4096),huge(above 4096),unknowncropped_area: Bucketed crop area:tiny(up to 256x256),small(up to 512x512),medium(up to 1024x1024),large(up to 2048x2048),xlarge(up to 4096x4096),huge,unknownrequest_type: Heuristic request class:tile,thumbnail,full,otherscale_crop_mode: Processing strategy:scale_no_crop,scale_then_crop,crop_then_scale
This timer records how long Wolpi spends processing and encoding successful image responses.
The tags are intended to support performance investigation:
output_sizeseparates small thumbnail-style work from large full-resolution work.cropped_areashows whether cost is driven by large crop windows even when the final output is small.request_typehelps distinguish common access patterns such as tiled viewers versus thumbnail grids.scale_crop_modereveals which internal processing path dominates.scale_no_cropis usually the cheapest path,crop_then_scaleis the most general path, andscale_then_cropis an optimization that is mainly helpful for untiled formats.
If this metric is slow overall, break it down by request_type, then by output_size and
scale_crop_mode before tuning image encoding or extension pool settings.
wolpi_source_loads_total
- Type: Counter
- Measures: Number of source image loads by source type and load strategy
- Tags:
source_type: Source category such as a filesystem-backed or HTTP-backed sourceload_type: Load strategy, one ofopen,thumbnail, orshrink_on_load
This counter tracks where Wolpi loads source images from and which load path was used.
For performance analysis, load_type is the important dimension:
open: Full open with no load-time scalingthumbnail: Load-time scaling through libvips thumbnail supportshrink_on_load: Loader-level downscaling for suitable pyramidal formats when the requested size matches an available reduced resolution
High open rates for workloads dominated by small outputs can indicate missed opportunities for
more efficient source loading.
wolpi_vips_errors_total
- Type: Counter
- Measures: Number of libvips-related processing errors
- Tags:
context: Processing context in which the error occurred
This is the primary built-in error metric for failures in native image processing operations.
Use context to distinguish where failures occur, for example during image processing rather than
source loading or metadata extraction. A rising error rate here should usually be correlated with
application logs.
wolpi_validation_requests_total
- Type: Counter
- Measures: Number of IIIF validation test image requests
- Tags: none
This metric is mainly relevant while validating Wolpi or extensions against the IIIF validation suite. It is usually not operationally important in normal production traffic.
wolpi_extension_invocations_total
- Type: Counter
- Measures: Number of extension hook invocations
- Tags:
extension_name: Extension name as returned by the extension'sinfohookhook_type: Invoked hook name
This counter increments every time Wolpi calls an extension hook.
Use it as the volume companion to wolpi_extension_execution_seconds. A slow hook with a very low
invocation rate is a different problem from a moderately slow hook that runs on every request.
wolpi_extension_execution_seconds
- Type: Timer
- Measures: Time spent executing extension hooks
- Tags:
extension_name: Extension name as returned by the extension'sinfohookhook_type: Executed hook name
This timer helps identify slow hooks and slow extensions.
For performance analysis:
extension_nameshows which extension contributes latency.hook_typeshows where in the extension API the time is spent, such as resolving, metadata loading, or image processing hooks.
If request latency is high and this timer is a major contributor, optimize the extension itself or increase extension pool capacity if the bottleneck is concurrency rather than per-call cost.
wolpi_extension_errors_total
- Type: Counter
- Measures: Number of extension hook errors
- Tags:
extension_name: Extension name as returned by the extension'sinfohookhook_type: Hook that raised or propagated an error
This is the primary built-in error metric for extension execution.
Track it together with wolpi_extension_invocations_total to distinguish a high absolute error
count on a busy hook from a genuinely high failure rate.
wolpi_extensions_loaded
- Type: Gauge
- Measures: Number of configured extensions currently loaded
- Tags: none
This gauge is registered once the application is fully started. It is mainly useful as a sanity check that the expected set of configured extensions was loaded.
wolpi_extensions_pool
- Type: Gauge
- Measures: Current extension runtime pool state per extension
- Tags:
extension_name: Extension name as returned by the extension'sinfohookstate: Pool state, one ofactive,idle, orclient_waiting
This gauge reports the live state of the extension runtime pool for each extension.
The state tag is the key performance dimension:
active: Contexts currently borrowed and processing workidle: Contexts currently available for reuseclient_waiting: Request-handling threads currently blocked waiting for a context
For performance analysis, sustained non-zero client_waiting is the clearest sign of pool
exhaustion. High active with near-zero idle during peak traffic usually means the pool is
running at its concurrency limit.
wolpi_extensions_pool_events
- Type: Counter
- Measures: Cumulative extension runtime pool lifecycle events per extension
- Tags:
extension_name: Extension name as returned by the extension'sinfohookevent: Pool lifecycle event, one ofcreated,destroyed,borrowed, orreturned
This counter tracks how the extension runtime pool changes over time.
The event tag supports different questions:
created: How often Wolpi has to create new contextsdestroyed: How often contexts are evicted or torn downborrowed: How often work is handed to the poolreturned: How often contexts finish work and go back to idle
For performance analysis:
createdshould usually stabilize after warm-up.- A rising
createdrate during steady-state traffic suggestsmin-idleis too low or eviction is too aggressive. - High
destroyedrates suggest churn and avoidable startup overhead. borrowedandreturnedare useful as throughput counters for extension-backed work.
See the extension pool configuration documentation for details on the relevant pool settings.
Example Prometheus queries
# Pool utilization (percentage of contexts in use)
wolpi_extensions_pool{state="active"} /
(wolpi_extensions_pool{state="active"} + wolpi_extensions_pool{state="idle"}) * 100
# Rate of context creation (contexts/sec) - should be near zero after warm-up
rate(wolpi_extensions_pool_events{event="created"}[5m])
# Contexts created but not yet destroyed (should match active + idle)
wolpi_extensions_pool_events{event="created"} - wolpi_extensions_pool_events{event="destroyed"}
Structured logging
Wolpi always logs to standard output.
To enable structured JSON logging, set:
This switches console output to one JSON object per line.
The structured output includes core fields such as:
@timestamplevellogger_namemessage
When applicable, it also includes structured stack-trace and request-correlation fields such as:
stack_tracestack_hashrequest_id
Additional structured key/value pairs passed to the logger are emitted as separate JSON fields.
Access logs
Wolpi does not provide built-in access logs in its normal application log output.
If you need access logs, the preferred approach is to run Wolpi behind a reverse proxy or API gateway that provides access logging.
For the Wolpi-specific reverse-proxy considerations, see Expose Wolpi Behind a Reverse Proxy.
For cache headers, redirects, CORS, and other IIIF-facing HTTP behavior, see the HTTP integration reference.
If you need local access logs from Wolpi itself, you can configure Tomcat access logging through the Spring Boot configuration. These logs are separate from Wolpi's normal structured/text application logs and can only be written to a file, not standard output.