Configuration
When Peekaboot is on, every peekaboot.* property with its default, and what Peekaboot sets in your application.
When Peekaboot is on
Six properties default according to how the application was launched.
| Property | Local run | Anywhere else | Turns on |
|---|---|---|---|
peekaboot.enabled |
true |
false |
The dashboard, its API, and Peekaboot’s defaults. |
peekaboot.dev-toolbar |
true |
false |
The toolbar, log capture and request-detail capture. |
peekaboot.storage.enabled |
true |
false |
Writing the charts and the run history to disk. |
peekaboot.error-page.enabled |
true |
false |
The error page in place of Boot’s whitelabel page. |
peekaboot.stack-trace.fold |
true |
false |
Folding framework frames on the error page and in the Logs tab. |
peekaboot.security.enabled |
false |
true |
Peekaboot’s HTTP Basic guard on /peekaboot/**. |
Any value you set wins, in either direction: application.yml, an environment variable or a
system property. Each property is resolved on its own. Setting peekaboot.enabled=true on a
shared server gives you the dashboard, but no toolbar and no files in that host’s home directory.
Tests resolve peekaboot.security.enabled to false, like a local run. See
peekaboot.security.
Where it turns itself on
A local run is an IDE run, mvn spring-boot:run or gradle bootRun on your own machine.
Spring Boot DevTools restarts keep counting as local.
Everything else counts as not local, so the table above resolves to its “Anywhere else” column:
java -jar, a war, a native image, an AOT run, a test, a Jib image, Spring Boot’s extract
layout, a java -cp of jars, and anything in a container.
A java -cp target/classes:… launch on a host outside a container counts as local. If you
deploy that way, set peekaboot.enabled=false.
Containers, devcontainers and Codespaces
Peekaboot detects Kubernetes, Docker and Podman, and any container whose /proc/1/cgroup
names docker, kubepods or containerd. Inside one, everything is off by default.
That includes VS Code Dev Containers and GitHub Codespaces. Turn the local features on in the devcontainer’s own configuration:
peekaboot:
enabled: true
dev-toolbar: true
storage:
enabled: true
error-page:
enabled: true
stack-trace:
fold: true
Turning it on in tests
Tests start with Peekaboot off, so CI never picks up the dashboard or its defaults. A test that needs Peekaboot turns it on:
@SpringBootTest(properties = "peekaboot.enabled=true")
On a local run, the default, the dashboard and API have no authentication. Outside local
development Peekaboot’s guard challenges every /peekaboot/** request that your own security
has not already authenticated. The guard is a stop-gap for when nothing else protects the
dashboard. Before setting peekaboot.enabled=true anywhere other people can reach, read Do I
want this in production? and
Security.
What each feature needs
Every feature also needs peekaboot.enabled=true.
| Feature | Switch | Also needs |
|---|---|---|
| Dashboard and API | peekaboot.enabled |
A servlet web application and Actuator. The starter brings Actuator. |
| Dev toolbar | peekaboot.dev-toolbar (detected) |
A servlet web application. Request-detail and log capture also need tracing on. |
| Tracing | peekaboot.tracing.enabled (true) |
A servlet web application. The starter brings the OpenTelemetry SDK that fills the trace store. |
| Insights | peekaboot.insights.enabled (true) |
A servlet web application and a Micrometer MeterRegistry bean. |
| Error page | peekaboot.error-page.enabled (detected) |
A servlet web application with Spring MVC. |
| Dashboard login | peekaboot.security.enabled (detected) |
A servlet web application. |
| Startup and shutdown summaries, run history | peekaboot.lifecycle.enabled (true) |
Nothing else. The Lifecycle tab and /peekaboot/api/lifecycle/** need a servlet web application. |
| Persisted history | peekaboot.storage.enabled (detected) |
A writable directory. A failed write logs a warning and Peekaboot carries on in memory. |
| Spring Boot defaults below | peekaboot.enabled |
A servlet web application. |
On WebFlux or a non-web application there is nothing at /peekaboot/**, no trace store, no
insights and none of the Spring Boot defaults. The startup summary and run history still work.
spring.main.web-application-type decides this, whether you set it as a property or through
SpringApplicationBuilder.web(...). See Quick start.
Properties
General
| Property | Default | Effect |
|---|---|---|
peekaboot.enabled |
detected | Master switch for the dashboard, its API and Peekaboot’s Spring Boot defaults. |
peekaboot.dev-toolbar |
detected | The dev toolbar, correlated-log capture and request-detail capture. |
peekaboot.enable-unmasking |
false |
Allows unmask=true to reveal real values from the Environment and Config data. |
The toolbar captures headers, query and form parameters and the resolved controller. It does not capture request or response bodies. See Dev toolbar.
enable-unmasking changes nothing on its own. It allows the unmask=true parameter on
GET /peekaboot/api/actuator/all/insights and shows the “Show secrets” toggle. See
Masking.
Storage
Storage decides whether the insights history and the start/stop log survive a restart.
| Property | Default | Effect |
|---|---|---|
peekaboot.storage.enabled |
detected | Whether anything is written. Off, both stores live in memory and never open a file. |
peekaboot.storage.dir |
${user.home}/.peekaboot/<groupId>.<artifactId> |
Where the files live. An explicit value is used as is, with no per-application subdirectory. |
The default directory sits outside your project, so it survives mvn clean and a re-clone.
<groupId>.<artifactId> comes from build-info.properties. Generate it with the Spring Boot
Maven plugin’s build-info goal or springBoot { buildInfo() } in Gradle. Without it Peekaboot
uses spring.application.name, then a folder named application.
Two applications with the same name, or with none, share a directory. Two instances on the same
directory overwrite each other’s history. Set dir in both cases. Every character outside
A-Za-z0-9._- in the name becomes a dash.
| File | Contents | Size |
|---|---|---|
insights.snapshot |
The insights history, written every peekaboot.insights.persistence.interval and at shutdown. |
About 5 MB at the default levels. |
lifecycle.jsonl |
The start and stop history, capped at 1000 events (about 500 runs), oldest dropped first. | Typically well under 400 KB. |
On a POSIX file system Peekaboot creates the directory rwx------ and both files rw-------.
An existing directory keeps its permissions. On Windows the platform defaults apply.
Neither file can fail your application. A snapshot that is unreadable, older than
peekaboot.insights.persistence.max-age or written for different levels is dropped, and the
history starts empty. A failed write logs one warning per file and run, and
Peekaboot carries on in memory.
Dashboard login
| Property | Default | Effect |
|---|---|---|
peekaboot.security.enabled |
detected | Whether Peekaboot’s HTTP Basic guard protects /peekaboot/**. |
peekaboot.security.username |
<artifact>-admin |
The username the guard accepts. |
peekaboot.security.password |
unset | A fixed password. Nothing is generated or written to disk. |
peekaboot.security.credentials-file |
security.properties in the storage directory |
Where the generated password’s hash is stored. A path you set is written even while storage is off. |
enabled is on for a deployment launch and off for local runs and tests. Only true and
false count. Any other value, yes for example, leaves the guard off.
username uses the build’s artifact id, then spring.application.name, then peekaboot. The
suffix -admin is always appended.
With password unset, Peekaboot generates a 26-character password on first start, prints it in
the Peekaboot Security block of the startup log and stores only its hash. The hash goes to
security.properties in the storage directory. With storage off, the
default outside local development, nothing is written and the password changes on every restart.
The startup log says so. Set credentials-file or password to keep it stable.
Failed logins are not throttled. See Security, securing the dashboard.
Error page
| Property | Default | Effect |
|---|---|---|
peekaboot.error-page.enabled |
detected | Renders Peekaboot’s error page in place of Spring Boot’s whitelabel page. |
peekaboot.error-page.override |
false |
Renders Peekaboot’s page even where the application has its own error page. |
The page shows the status and reason, the request line, the exception class and message, and the stack trace with your own frames marked.
By default Peekaboot backs off when the application has its own error page: an error view
bean, an error template or a static error/*.html. It also stays off while
spring.web.error.whitelabel.enabled is false.
To keep a branded error page in production and see Peekaboot’s page while developing, set
peekaboot.error-page.override: true in your local profile. Peekaboot’s page then wins wherever
enabled is true. It also wins over an @ControllerAdvice or @ExceptionHandler that
renders your error page, and the whitelabel setting no longer applies. Requests that ask for
JSON are left alone.
The error page carries the dev toolbar, which reports the failed request. See Dev toolbar, pages that get the bar and Security, the error page.
Stack-trace folding
| Property | Default | Effect |
|---|---|---|
peekaboot.stack-trace.fold |
detected | Collapses framework frames behind a disclosure on the error page and in the Logs tab. Off, every frame is shown. |
peekaboot.stack-trace.exclude |
unset | Patterns for the frames that fold. A non-empty list replaces the default list. |
A frame folds when its line contains a pattern as a substring. Your application’s own frames never fold.
exclude comes from the first of these sources that is set:
peekaboot.stack-trace.exclude, if it is a non-empty list. You cannot add to the built-in list, only replace it.- The patterns in the
%wEx{...}block of yourlogging.exception-conversion-word. A block with no patterns, such as%wEx{full}, folds nothing. -
The built-in list:
java.lang.reflect.Method jdk.internal.reflect sun.reflect org.apache.catalina org.apache.coyote org.apache.tomcat org.springframework org.thymeleaf org.attoparser # Thymeleaf's own parser jakarta.servlet net.sf.cglib ByCGLIB # a CGLIB-generated proxy class name, not a package org.zalando.logbook net.ttddyy.dsproxy com.mysql
exclude: [] does not stop folding. It counts as unset and falls through to the next source.
Use fold: false instead.
A captured stack trace is cut at 1000 lines, whatever fold says, and ends with a
... N lines omitted marker. A StackOverflowError is the usual case. The worst case for the
whole trace store is 1000 lines × max-logs-per-trace × (max-traces +
max-error-traces + max-slow-traces).
Lifecycle
| Property | Default | Effect |
|---|---|---|
peekaboot.lifecycle.enabled |
true |
The startup and shutdown summaries and the run history behind the Lifecycle tab and /peekaboot/api/lifecycle/**. |
The startup summary shows the application name, build info, server, dashboard and datasource. The shutdown summary shows the uptime and the start and stop times.
The URLs in the summary
Service URL: http://localhost:8080
Swagger UI: http://localhost:8080/swagger-ui.html
Peekaboot Dashboard: http://localhost:8080/peekaboot/
Service URL appears whenever there is an embedded web server. It uses the bound port and
appends server.servlet.context-path. A server.address that is unset, blank, 0.0.0.0 or
:: prints as localhost.
The scheme is https when Spring Boot considers TLS on. A key store or an SSL bundle under
server.ssl is enough. server.ssl.enabled: false keeps it http.
Swagger UI appears when springdoc is on the classpath and honours springdoc.swagger-ui.path.
Peekaboot Dashboard appears only where the dashboard is served: a servlet application with
Actuator and peekaboot.enabled=true.
Tracing
| Property | Default | Effect |
|---|---|---|
peekaboot.tracing.enabled |
true |
Whether the in-memory trace store exists. |
peekaboot.tracing.async |
true |
Records a span for each task run on one of Spring’s task executors. Needs spring.task.execution.propagate-context, below. |
peekaboot.tracing.max-traces |
1000 |
Traces kept in the All bucket, oldest evicted first. |
peekaboot.tracing.max-spans-per-trace |
500 |
Spans kept per trace, counted after duplicates are merged. Past it the oldest are dropped and the trace is marked TRUNCATED. |
peekaboot.tracing.max-error-traces |
100 |
Traces kept in the Errors bucket. |
peekaboot.tracing.max-slow-traces |
100 |
Traces kept in the Slow bucket. |
peekaboot.tracing.slow-trace-threshold-ms |
1000 |
Total duration at or above which a trace enters the Slow bucket. |
peekaboot.tracing.max-logs-per-trace |
500 |
Log entries kept per trace. Only filled while the dev toolbar is on. |
See Traces for the buckets and
background work for what async shows.
Background tasks: required Spring settings
Peekaboot records no span for a background task until your application sets this:
spring:
task:
execution:
propagate-context: true
Peekaboot does not set spring.task.execution.propagate-context for you. It changes what every
task on the executor sees, so the decision stays with your application.
If your application declares its own Executor bean, Spring Boot stops creating its own task
executor, and neither context propagation nor Peekaboot reaches your tasks. Set
spring.task.execution.mode=force to keep Boot’s executor.
Issue thresholds
These decide the dashboard’s issues and badges. They do not change what is captured. See Issues.
| Property | Default | Effect |
|---|---|---|
peekaboot.ui.tracing.slow-span-threshold-ms |
100 |
A span whose own duration is at or above this gets SLOW, and its trace row a SLOW badge. |
peekaboot.ui.tracing.very-slow-span-threshold-ms |
500 |
At or above this a span gets VERY_SLOW instead of SLOW. |
peekaboot.ui.tracing.slow-query-threshold-ms |
50 |
A database query at or above this gets SLOW_QUERY and a SLOW label in the Queries tab. |
Insights
These configure the collector behind the Insights tab. Which metrics it samples comes from a
YAML file, see Insights. Whether
the history survives a restart is peekaboot.storage.enabled.
| Property | Default | Effect |
|---|---|---|
peekaboot.insights.enabled |
true |
The collector, the /api/insights/** endpoints and the Insights tab. |
peekaboot.insights.levels[n].interval |
10s, 1m, 1h |
The sampling tick (level 0) and each coarser aggregation window. |
peekaboot.insights.levels[n].size |
90, 1440, 720 |
Entries kept per series at that level. interval × size is how far back the charts reach. |
peekaboot.insights.config-location |
peekaboot-insights.yml on the classpath root |
A Spring resource location for the panel file. Peekaboot’s bundled panels are still merged underneath. |
peekaboot.insights.persistence.interval |
the coarsest level’s interval (1h) |
How often the history is written to insights.snapshot. Does nothing while storage is off. |
peekaboot.insights.persistence.max-age |
the coarsest level’s span (30 days) | The oldest snapshot that is still loaded at startup. |
Setting levels replaces the whole list, so list every level you want. Startup fails unless
all of these hold:
- At most 16 levels.
- Every
intervalandsizeis greater than zero, and everysizeis at most 1,000,000. - Each
intervalis a whole multiple of the one before it. - Each
intervalfits in the level below it. A1mlevel over a10slevel spans six entries, so the10slevel needs asizeof at least 6. persistence.intervalandpersistence.max-age, when set, are greater than zero.
Memory follows size, not interval. Level 0 stores one number per series per entry. Every
higher level stores eight. Peekaboot logs the total at startup. See what it
costs.
Spring Boot defaults Peekaboot changes
Peekaboot changes a few Spring Boot and library defaults so the dashboard has data without
further setup. Anything you set yourself wins, and every bean Peekaboot registers backs off when
you define your own. Peekaboot sets no spring.task.execution.* property.
| Property | Spring Boot default | Peekaboot default | Applies when | Why |
|---|---|---|---|---|
management.otlp.metrics.export.enabled |
true |
false |
always | The starter brings Micrometer’s OTLP registry, which would otherwise push metrics to localhost:4318. Nothing leaves the process unless you opt in. |
management.tracing.sampling.probability |
0.1 |
1.0 |
peekaboot.enabled, servlet web application |
Every request reaches the Traces tab. |
spring.jpa.properties.[hibernate.generate_statistics] |
false (Hibernate’s own) |
true |
peekaboot.enabled, servlet web application |
The hibernate.* panels on Insights need Hibernate’s statistics. |
management.info.env.enabled |
false |
true |
peekaboot.enabled, servlet web application |
Your info.* properties show on the Overview tab. OS environment variables are on the Environment tab. |
management.info.java.enabled |
false |
true |
peekaboot.enabled, servlet web application |
The Java card on Overview. |
management.info.os.enabled |
false |
true |
peekaboot.enabled, servlet web application |
The System card on Overview. |
management.info.process.enabled |
false |
true |
peekaboot.enabled, servlet web application |
PID, uptime, CPU count and memory on Overview. |
management.observations.annotations.enabled |
false |
true |
peekaboot.enabled, servlet web application |
@Observed, @Timed and @Counted work without extra wiring. |
management.opentelemetry.tracing.export.schedule-delay |
5s |
200ms |
peekaboot.enabled, servlet web application, dev toolbar on |
The toolbar shows a request’s trace while you are still on the page. |
Traces and logs need no export switch. Spring Boot creates OTLP exporters for them only once
you configure an endpoint. Peekaboot sets nothing under management.endpoint.*, changes nothing
on /actuator/**, and your endpoint settings do not affect what the dashboard shows. See
Security.
Some of these widen what is exposed, or cost something at runtime:
management.info.env.enabled: truepublishesinfo.*through/actuator/infoif you expose that endpoint.- Sampling at
1.0traces every request, for every exporter you have configured. - Hibernate statistics carry a runtime cost.
- With the toolbar on, spans reach every exporter roughly 25 times more often than at Spring’s default.
On your own machine this is harmless. Check it before peekaboot.enabled is true anywhere
other people can reach. See Do I want this in
production?.
Examples
A longer, coarser insights history
Replace the minute and hourly levels with one two-minute level to follow a long local session:
peekaboot:
insights:
levels:
- interval: 10s
size: 360 # 1 hour of tick resolution
- interval: 2m
size: 2160 # 3 days
That is (360 + 2160×8) × 8 bytes per series, about the same as the defaults. The startup log reports the actual figure. See what it costs.
Halving level 0’s interval costs no memory. It halves the window that level covers and
doubles how often every meter is read. Keeping the window means doubling size, which doubles
the memory.
Memory-constrained
Spans and logs are capped separately per trace. The All bucket holds at most max-traces
× (max-spans-per-trace + max-logs-per-trace) entries: 1,000,000 at the defaults. The
Errors and Slow buckets can keep a trace after All has evicted it, so scale them down too:
peekaboot:
tracing:
max-traces: 200
max-spans-per-trace: 50
max-logs-per-trace: 100
max-error-traces: 25
max-slow-traces: 25
Requests with more than 50 spans get truncated. Watch for the TRUNCATED badge, especially
with query-heavy endpoints.
Query-heavy application
A report or bulk export can issue hundreds of queries. Past the span cap, spans are dropped and
the row’s query count under-reports. The default of 500, counted after duplicates are merged,
covers most endpoints. If the trace list shows TRUNCATED for one, raise the cap:
peekaboot:
tracing:
max-spans-per-trace: 1500
Every span kept costs memory, so raise it only once TRUNCATED shows up.