or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

audit.mdbuiltin-endpoints.mdendpoint-framework.mdhttp-exchanges.mdindex.mdinfo-contributors.mdjmx-integration.mdmanagement-operations.mdoperation-invocation.mdsanitization.mdsecurity.mdweb-integration.md
tile.json

index.mddocs/

Spring Boot Actuator

QUICK REFERENCE

Key Classes and Packages

// Core Annotations
org.springframework.boot.actuate.endpoint.annotation.Endpoint
org.springframework.boot.actuate.endpoint.annotation.ReadOperation
org.springframework.boot.actuate.endpoint.annotation.WriteOperation
org.springframework.boot.actuate.endpoint.annotation.DeleteOperation
org.springframework.boot.actuate.endpoint.annotation.Selector

// Web-Specific
org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint
org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension
org.springframework.boot.actuate.endpoint.web.WebEndpointResponse

// Security
org.springframework.boot.actuate.endpoint.SecurityContext
org.springframework.boot.actuate.endpoint.Access
org.springframework.boot.actuate.endpoint.Show

// Audit
org.springframework.boot.actuate.audit.AuditEvent
org.springframework.boot.actuate.audit.AuditEventRepository
org.springframework.boot.actuate.audit.InMemoryAuditEventRepository

// Sanitization
org.springframework.boot.actuate.endpoint.Sanitizer
org.springframework.boot.actuate.endpoint.SanitizingFunction
org.springframework.boot.actuate.endpoint.SanitizableData

Most Common Use Cases

  1. Create custom endpoint - Expose application-specific metrics or operations
  2. Secure sensitive endpoints - Control access with role-based security
  3. Sanitize sensitive data - Protect passwords and credentials in responses
  4. Audit security events - Track authentication and authorization
  5. Monitor HTTP traffic - Record request-response exchanges
  6. Add custom info - Contribute build/runtime information

Decision Tree: Which Endpoint Type?

Need to expose information/operations?
│
├─ Needs HTTP-specific features (status codes, headers)?
│  └─ Use @WebEndpoint
│
├─ Needs JMX-only exposure?
│  └─ Use @JmxEndpoint
│
├─ Needs both HTTP and JMX?
│  └─ Use @Endpoint (technology-agnostic)
│
└─ Extending existing endpoint with tech-specific features?
   ├─ For HTTP: Use @EndpointWebExtension
   └─ For JMX: Use @EndpointJmxExtension

Decision Tree: Operation Type

What does the operation do?
│
├─ Retrieves data without side effects?
│  └─ Use @ReadOperation (maps to GET)
│
├─ Modifies data or triggers action?
│  └─ Use @WriteOperation (maps to POST)
│
└─ Removes data or resources?
   └─ Use @DeleteOperation (maps to DELETE)

AGENT GUIDANCE

When to Use Each Access Level

// READ_ONLY - Endpoint has write operations that should be disabled
@Endpoint(id = "config", defaultAccess = Access.READ_ONLY)
// Use when: Endpoint has both read and write ops, but writes are sensitive

// UNRESTRICTED - All operations allowed (default)
@Endpoint(id = "custom", defaultAccess = Access.UNRESTRICTED)
// Use when: Endpoint operations are safe for all authenticated users

// NONE - Endpoint completely disabled by default
@Endpoint(id = "shutdown", defaultAccess = Access.NONE)
// Use when: Endpoint is dangerous and requires explicit enablement

Common Pattern vs Anti-Pattern

PATTERN: Technology-agnostic endpoint

@Endpoint(id = "custom")  // Works with HTTP, JMX, etc.
@Component
public class CustomEndpoint {
    @ReadOperation
    public CustomData getData() {
        return new CustomData();
    }
}

ANTI-PATTERN: HTTP-specific code in @Endpoint

@Endpoint(id = "bad")
@Component
public class BadEndpoint {
    @ReadOperation
    public ResponseEntity<Data> getData() {  // ❌ HTTP-specific
        return ResponseEntity.ok(data);
    }
}

PATTERN: Use web extension for HTTP features

@EndpointWebExtension(endpoint = CustomEndpoint.class)
@Component
public class CustomWebExtension {
    @ReadOperation
    public WebEndpointResponse<Data> getData() {  // ✓ HTTP-specific
        return new WebEndpointResponse<>(data, 200);
    }
}

ARCHITECTURE DIAGRAM

┌─────────────────────────────────────────────────────────────┐
│                    Spring Boot Actuator                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌───────────────────┐      ┌──────────────────┐            │
│  │  @Endpoint        │      │  Built-in        │            │
│  │  - Custom Metrics │      │  - Info          │            │
│  │  - App Status     │      │  - Env           │            │
│  │  - Config Ops     │      │  - Loggers       │            │
│  └─────────┬─────────┘      │  - Beans         │            │
│            │                │  - ConfigProps   │            │
│            │                │  - AuditEvents   │            │
│            │                └────────┬─────────┘            │
│            │                         │                      │
│            └──────────┬──────────────┘                      │
│                       │                                     │
│            ┌──────────▼──────────┐                          │
│            │  Endpoint           │                          │
│            │  Discovery          │                          │
│            │  - Scans beans      │                          │
│            │  - Creates ops      │                          │
│            └──────────┬──────────┘                          │
│                       │                                     │
│         ┌─────────────┴─────────────┐                       │
│         │                           │                       │
│  ┌──────▼──────┐           ┌────────▼─────┐                 │
│  │   Web       │           │   JMX        │                 │
│  │   Exposure  │           │   Exposure   │                 │
│  │             │           │              │                 │
│  │  - HTTP     │           │  - MBeans    │                 │
│  │  - REST     │           │  - JConsole  │                 │
│  │  - JSON     │           │  - VisualVM  │                 │
│  └──────┬──────┘           └────────┬─────┘                 │
│         │                           │                       │
│  ┌──────▼──────┐           ┌────────▼─────┐                 │
│  │  Security   │           │  Security    │                 │
│  │  - Roles    │           │  - Roles     │                 │
│  │  - Auth     │           │  - Auth      │                 │
│  └─────────────┘           └──────────────┘                 │
│                                                             │
│  ┌───────────────────────────────────────────────┐          │
│  │  Cross-Cutting Concerns                       │          │
│  │  - Sanitization (passwords, secrets)          │          │
│  │  - Audit (authentication, authorization)      │          │
│  │  - Caching (read operations)                  │          │
│  │  - Parameter mapping (type conversion)        │          │
│  └───────────────────────────────────────────────┘          │
└─────────────────────────────────────────────────────────────┘

Spring Boot Actuator provides production-ready monitoring and management features for Spring Boot applications. It includes built-in endpoints for application information, environment properties, auditing, and application introspection, enabling developers to monitor and interact with applications through HTTP endpoints or JMX. (Note: Health checks and metrics collection are provided by separate spring-boot-health and Micrometer modules.)

Package Information

  • Package Name: spring-boot-actuator
  • Package Coordinates: org.springframework.boot:spring-boot-actuator
  • Version: 4.0.0
  • Language: Java
  • Installation: Add dependency to Maven or Gradle project

Important: Spring Boot Actuator functionality is distributed across multiple modules:

  • spring-boot-actuator: Core endpoint infrastructure, audit, security, and built-in endpoints (documented in this tile)
  • spring-boot-health: Health endpoint, health indicators, and health contributor framework (separate module)
  • spring-boot-actuator-autoconfigure: Auto-configuration for actuator features

Maven:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-actuator'

Core Imports

// Endpoint annotations
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import org.springframework.boot.actuate.endpoint.annotation.DeleteOperation;
import org.springframework.boot.actuate.endpoint.annotation.Selector;

// Web endpoint annotations
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpoint;
import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExtension;

// Core types
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.boot.actuate.endpoint.Show;

Basic Usage

import org.springframework.boot.actuate.endpoint.annotation.*;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.stereotype.Component;

// Create a custom actuator endpoint
@Endpoint(id = "custom", defaultAccess = Access.UNRESTRICTED)
@Component
public class CustomEndpoint {

    @ReadOperation
    public CustomData getData() {
        return new CustomData("status", "operational");
    }

    @WriteOperation
    public void updateData(String key, String value) {
        // Update logic
    }
}

// Access endpoint at: /actuator/custom

COMPLETE WORKING EXAMPLE

package com.example.actuator;

import org.springframework.boot.actuate.endpoint.annotation.*;
import org.springframework.boot.actuate.endpoint.Access;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Complete custom endpoint with multiple operations.
 * Thread-safe: Yes
 * Nullability: All methods return non-null
 * Since: Spring Boot 2.0+
 */
@Endpoint(id = "appstatus", defaultAccess = Access.READ_ONLY)
@Component
public class ApplicationStatusEndpoint {

    private final AtomicInteger requestCount = new AtomicInteger(0);
    private final Instant startTime = Instant.now();

    /**
     * Get application status.
     *
     * @return Map containing status information (never null)
     */
    @ReadOperation
    public Map<String, Object> getStatus() {
        Map<String, Object> status = new HashMap<>();
        status.put("status", "UP");
        status.put("requests", requestCount.get());
        status.put("uptime", java.time.Duration.between(startTime, Instant.now()).toString());
        return status;
    }

    /**
     * Get status for specific component.
     *
     * @param component Component name (path variable)
     * @return Map containing component status (never null)
     */
    @ReadOperation
    public Map<String, Object> getComponentStatus(@Selector String component) {
        Map<String, Object> status = new HashMap<>();
        status.put("component", component);
        status.put("status", checkComponent(component));
        return status;
    }

    /**
     * Reset request counter (write operation).
     * Requires UNRESTRICTED access or explicit enablement.
     *
     * @param securityContext Security context for authorization check
     * @throws SecurityException if user lacks required role
     */
    @WriteOperation
    public void resetCounter(SecurityContext securityContext) {
        if (!securityContext.isUserInRole("ADMIN")) {
            throw new SecurityException("ADMIN role required");
        }
        requestCount.set(0);
    }

    private String checkComponent(String component) {
        // Component check logic
        return "HEALTHY";
    }
}

TESTING EXAMPLE

package com.example.actuator;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.boot.actuate.endpoint.SecurityContext;
import java.security.Principal;
import java.util.Map;
import static org.assertj.core.api.Assertions.*;

class ApplicationStatusEndpointTest {

    private ApplicationStatusEndpoint endpoint;
    private SecurityContext securityContext;

    @BeforeEach
    void setUp() {
        endpoint = new ApplicationStatusEndpoint();

        // Mock security context
        securityContext = new SecurityContext() {
            @Override
            public Principal getPrincipal() {
                return () -> "testuser";
            }

            @Override
            public boolean isUserInRole(String role) {
                return "ADMIN".equals(role);
            }
        };
    }

    @Test
    void getStatus_ReturnsValidStatus() {
        Map<String, Object> status = endpoint.getStatus();

        assertThat(status).isNotNull();
        assertThat(status).containsKey("status");
        assertThat(status.get("status")).isEqualTo("UP");
        assertThat(status).containsKey("requests");
        assertThat(status).containsKey("uptime");
    }

    @Test
    void getComponentStatus_WithValidComponent_ReturnsStatus() {
        Map<String, Object> status = endpoint.getComponentStatus("database");

        assertThat(status).containsKey("component");
        assertThat(status.get("component")).isEqualTo("database");
        assertThat(status).containsKey("status");
    }

    @Test
    void resetCounter_WithAdminRole_Succeeds() {
        // Should not throw exception
        assertThatNoException().isThrownBy(() ->
            endpoint.resetCounter(securityContext)
        );
    }

    @Test
    void resetCounter_WithoutAdminRole_ThrowsException() {
        SecurityContext nonAdminContext = new SecurityContext() {
            @Override
            public Principal getPrincipal() {
                return () -> "user";
            }

            @Override
            public boolean isUserInRole(String role) {
                return false;
            }
        };

        assertThatThrownBy(() -> endpoint.resetCounter(nonAdminContext))
            .isInstanceOf(SecurityException.class)
            .hasMessageContaining("ADMIN role required");
    }
}

Architecture

Spring Boot Actuator is built around a flexible endpoint architecture:

  • Endpoints: Technology-agnostic abstraction for exposing monitoring and management operations
  • Operations: Individual read, write, or delete operations within an endpoint
  • Extensions: Technology-specific extensions for Web (HTTP) and JMX protocols
  • Security: Integrated access control through Access levels and SecurityContext
  • Sanitization: Built-in framework for protecting sensitive data in responses
  • Discovery: Automatic discovery of endpoints via annotations

The framework supports:

  • Multiple exposure technologies (HTTP via Spring MVC/WebFlux, JMX)
  • Flexible security integration with role-based access control
  • Extensible endpoint creation through annotations
  • Automatic JSON serialization with Jackson
  • Built-in data sanitization for sensitive properties

Capabilities

Endpoint Framework

Core framework for creating and managing actuator endpoints with support for multiple exposure technologies (HTTP, JMX), operations (read, write, delete), and security integration.

// Endpoint declaration
@interface Endpoint {
    String id() default "";
    Access defaultAccess() default Access.UNRESTRICTED;
}

@interface WebEndpoint {
    String id(); // Aliases to @Endpoint.id() via @AliasFor
    Access defaultAccess() default Access.UNRESTRICTED;
}

@interface JmxEndpoint {
    String id() default "";
    Access defaultAccess() default Access.UNRESTRICTED;
}

// Extension annotations
@interface EndpointExtension {
    Class<? extends EndpointFilter<?>> filter();
    Class<?> endpoint() default Void.class;
}

@interface EndpointWebExtension {
    Class<?> endpoint();
}

@interface EndpointJmxExtension {
    Class<?> endpoint();
}

@interface FilteredEndpoint {
    Class<? extends EndpointFilter<?>> value();
}

@interface EndpointConverter {
    // Marker annotation for endpoint input parameter converters
}

// Operation declarations
@interface ReadOperation {
    String[] produces() default {};
    Class<? extends Producible> producesFrom() default Producible.class;
}

@interface WriteOperation {
    String[] produces() default {};
    Class<? extends Producible> producesFrom() default Producible.class;
}

@interface DeleteOperation {
    String[] produces() default {};
    Class<? extends Producible> producesFrom() default Producible.class;
}

// Parameter selector
@interface Selector {
    Match match() default Match.SINGLE;

    enum Match {
        SINGLE,
        ALL_REMAINING
    }
}

// Access control
enum Access {
    NONE,
    READ_ONLY,
    UNRESTRICTED;

    public Access cap(Access maxPermitted);
}

// Visibility control
enum Show {
    NEVER,
    WHEN_AUTHORIZED,
    ALWAYS;

    boolean isShown(boolean unauthorizedResult);
    boolean isShown(SecurityContext securityContext, Collection<String> roles);
}

// Operation type classification
enum OperationType {
    READ,
    WRITE,
    DELETE
}

// Security context
interface SecurityContext {
    SecurityContext NONE = /* empty context */;

    @Nullable Principal getPrincipal();
    boolean isUserInRole(String role);
}

// Producible content types
interface Producible<E extends Enum<E> & Producible<E>> {
    MimeType getProducedMimeType();
    default boolean isDefault() {
        return false;
    }
}

Endpoint Framework

Built-in Endpoints

Production-ready endpoints providing monitoring and management capabilities including application information, environment properties, logger configuration, log file access, audit events, beans, configuration properties, auto-configuration conditions, scheduled tasks, thread dumps, heap dumps, HTTP exchanges, request mappings, SBOM, and shutdown. (Note: Health endpoints are in the separate spring-boot-health module.)

// Info endpoint - Application information
@Endpoint(id = "info")
class InfoEndpoint {
    InfoEndpoint(List<InfoContributor> infoContributors);
    Map<String, Object> info();
}

// Environment endpoint - Environment properties
@Endpoint(id = "env")
class EnvironmentEndpoint {
    EnvironmentEndpoint(Environment environment, Iterable<SanitizingFunction> sanitizingFunctions, Show showValues);
    EnvironmentDescriptor environment(@Nullable String pattern);
    EnvironmentEntryDescriptor environmentEntry(String toMatch);
}

@EndpointWebExtension(endpoint = EnvironmentEndpoint.class)
class EnvironmentEndpointWebExtension {
    EnvironmentEndpointWebExtension(EnvironmentEndpoint delegate, Show showValues, Set<String> roles);
    EnvironmentDescriptor environment(SecurityContext securityContext, @Nullable String pattern);
    WebEndpointResponse<EnvironmentEntryDescriptor> environmentEntry(SecurityContext securityContext, String toMatch);
}

// Loggers endpoint - Logger configuration
@Endpoint(id = "loggers")
class LoggersEndpoint {
    LoggersEndpoint(LoggingSystem loggingSystem, LoggerGroups loggerGroups);
    LoggersDescriptor loggers();
    LoggerLevelsDescriptor loggerLevels(String name);
    void configureLogLevel(String name, LogLevel configuredLevel);
}

// Log file endpoint - Log file download
@WebEndpoint(id = "logfile")
class LogFileWebEndpoint {
    LogFileWebEndpoint(@Nullable LogFile logFile, @Nullable File externalFile);
    @ReadOperation(produces = "text/plain; charset=UTF-8")
    @Nullable Resource logFile();
}

// Beans endpoint - Application beans
@Endpoint(id = "beans")
class BeansEndpoint {
    BeansEndpoint(ConfigurableApplicationContext context);
    BeansDescriptor beans();
}

// Config properties endpoint - Configuration properties
@Endpoint(id = "configprops")
class ConfigurationPropertiesReportEndpoint {
    ConfigurationPropertiesReportEndpoint(Iterable<SanitizingFunction> sanitizingFunctions, Show showValues);
    ConfigurationPropertiesDescriptor configurationProperties();
    ConfigurationPropertiesDescriptor configurationPropertiesWithPrefix(String prefix);
}

@EndpointWebExtension(endpoint = ConfigurationPropertiesReportEndpoint.class)
class ConfigurationPropertiesReportEndpointWebExtension {
    ConfigurationPropertiesReportEndpointWebExtension(ConfigurationPropertiesReportEndpoint delegate, Show showValues, Set<String> roles);
    ConfigurationPropertiesDescriptor configurationProperties(SecurityContext securityContext);
    WebEndpointResponse<ConfigurationPropertiesDescriptor> configurationPropertiesWithPrefix(SecurityContext securityContext, String prefix);
}

Built-in Endpoints

Audit Framework

Flexible audit event tracking and storage framework for recording security events, authentication attempts, authorization decisions, and custom application events with repository abstraction and Spring event integration.

// Core audit types
class AuditEvent {
    AuditEvent(@Nullable String principal, String type, Map<String, @Nullable Object> data);
    AuditEvent(@Nullable String principal, String type, String... data);
    AuditEvent(Instant timestamp, @Nullable String principal, String type, Map<String, @Nullable Object> data);

    Instant getTimestamp();
    /**
     * Returns the principal or empty string if not available.
     * NOTE: Never returns null - returns "" when principal is unavailable.
     */
    String getPrincipal();
    String getType();
    Map<String, @Nullable Object> getData();
}

interface AuditEventRepository {
    void add(AuditEvent event);
    List<AuditEvent> find(@Nullable String principal, @Nullable Instant after, @Nullable String type);
}

class InMemoryAuditEventRepository implements AuditEventRepository {
    InMemoryAuditEventRepository();
    InMemoryAuditEventRepository(int capacity);

    void setCapacity(int capacity);
    void add(AuditEvent event);
    List<AuditEvent> find(String principal, Instant after, String type);
}

// Audit events endpoint
@Endpoint(id = "auditevents")
class AuditEventsEndpoint {
    AuditEventsEndpoint(AuditEventRepository auditEventRepository);
    AuditEventsDescriptor events(String principal, OffsetDateTime after, String type);

    static final class AuditEventsDescriptor implements OperationResponseBody {
        List<AuditEvent> getEvents();
    }
}

// Audit event as Spring application event
// Package: org.springframework.boot.actuate.audit.listener
class AuditApplicationEvent extends ApplicationEvent {
    AuditApplicationEvent(String principal, String type, Map<String, @Nullable Object> data);
    AuditApplicationEvent(String principal, String type, String... data);
    AuditApplicationEvent(Instant timestamp, String principal, String type, Map<String, @Nullable Object> data);
    AuditApplicationEvent(AuditEvent auditEvent);

    AuditEvent getAuditEvent();
}

// Abstract base listener for audit events
// Package: org.springframework.boot.actuate.audit.listener
abstract class AbstractAuditListener implements ApplicationListener<AuditApplicationEvent> {
    void onApplicationEvent(AuditApplicationEvent event);
    protected abstract void onAuditEvent(AuditEvent event);
}

// Repository-backed audit listener
// Package: org.springframework.boot.actuate.audit.listener
class AuditListener extends AbstractAuditListener {
    AuditListener(AuditEventRepository auditEventRepository);
    protected void onAuditEvent(AuditEvent event);
}

Audit Framework

HTTP Exchange Tracking

HTTP request-response exchange recording and repository framework for monitoring web traffic, analyzing API usage, and debugging HTTP interactions with configurable capture options and in-memory storage.

// HTTP exchange tracking
class HttpExchange {
    HttpExchange(Instant timestamp, Request request, Response response,
                 @Nullable Principal principal, @Nullable Session session, @Nullable Duration timeTaken);

    static Started start(RecordableHttpRequest request);
    static Started start(Clock clock, RecordableHttpRequest request);

    Instant getTimestamp();
    Request getRequest();
    Response getResponse();
    Principal getPrincipal();
    Session getSession();
    Duration getTimeTaken();

    static class Started {
        HttpExchange finish(RecordableHttpResponse response,
                          Supplier<Principal> principalSupplier,
                          Supplier<String> sessionIdSupplier,
                          Include... includes);
    }

    class Request {
        Request(URI uri, @Nullable String remoteAddress, String method, Map<String, List<String>> headers);
        String getMethod();
        URI getUri();
        Map<String, List<String>> getHeaders();
        @Nullable String getRemoteAddress();
    }

    class Response {
        Response(int status, Map<String, List<String>> headers);
        int getStatus();
        Map<String, List<String>> getHeaders();
    }
}

enum Include {
    REQUEST_HEADERS,
    RESPONSE_HEADERS,
    COOKIE_HEADERS,
    AUTHORIZATION_HEADER,
    PRINCIPAL,
    SESSION_ID,
    TIME_TAKEN,
    REMOTE_ADDRESS
}

interface HttpExchangeRepository {
    List<HttpExchange> findAll();
    void add(HttpExchange httpExchange);
}

class InMemoryHttpExchangeRepository implements HttpExchangeRepository {
    InMemoryHttpExchangeRepository();
    void setCapacity(int capacity);
    void setReverse(boolean reverse);
}

HTTP Exchange Tracking

Data Sanitization

Comprehensive framework for protecting sensitive data in endpoint responses with fluent API for pattern matching, flexible sanitization strategies, and built-in detection of credentials, URIs, and sensitive keys.

class Sanitizer {
    Sanitizer();
    Sanitizer(Iterable<SanitizingFunction> sanitizingFunctions);

    @Nullable Object sanitize(SanitizableData data, boolean showUnsanitized);
}

class SanitizableData {
    static final String SANITIZED_VALUE = "******";

    SanitizableData(PropertySource<?> propertySource, String key, Object value);

    PropertySource<?> getPropertySource();
    String getKey();
    String getLowerCaseKey();
    Object getValue();
    SanitizableData withSanitizedValue();
    SanitizableData withValue(Object value);
}

@FunctionalInterface
interface SanitizingFunction {
    SanitizableData apply(SanitizableData data);

    // Filter and application control (@since 3.5.0)
    default Predicate<SanitizableData> filter();
    default SanitizableData applyUnlessFiltered(SanitizableData data);

    // High-level detection helpers
    default SanitizingFunction ifLikelySensitive();
    default SanitizingFunction ifLikelyCredential();
    default SanitizingFunction ifLikelyUri();
    default SanitizingFunction ifLikelySensitiveProperty();  // @since 3.5.0
    default SanitizingFunction ifVcapServices();  // @since 3.5.0

    // Key matching methods
    default SanitizingFunction ifKeyEquals(String... values);
    default SanitizingFunction ifKeyEndsWith(String... suffixes);
    default SanitizingFunction ifKeyContains(String... values);
    default SanitizingFunction ifKeyMatchesIgnoringCase(BiPredicate<String, String> predicate, String... values);  // @since 3.5.0
    default SanitizingFunction ifKeyMatches(String... regexes);
    default SanitizingFunction ifKeyMatches(Pattern... patterns);
    default SanitizingFunction ifKeyMatches(List<Predicate<String>> predicates);  // @since 3.5.0
    default SanitizingFunction ifKeyMatches(Predicate<String> predicate);  // @since 3.5.0

    // Value matching methods (@since 3.5.0)
    default SanitizingFunction ifValueStringMatches(String... regexes);
    default SanitizingFunction ifValueStringMatches(Pattern... patterns);
    default SanitizingFunction ifValueStringMatches(List<Predicate<String>> predicates);
    default SanitizingFunction ifValueStringMatches(Predicate<String> predicate);
    default SanitizingFunction ifValueMatches(List<Predicate<Object>> predicates);
    default SanitizingFunction ifValueMatches(Predicate<Object> predicate);

    // General data matching (@since 3.5.0)
    default SanitizingFunction ifMatches(List<Predicate<SanitizableData>> predicates);
    default SanitizingFunction ifMatches(Predicate<SanitizableData> predicate);

    // Factory methods
    static SanitizingFunction sanitizeValue();
    static SanitizingFunction of(SanitizingFunction sanitizingFunction);  // @since 3.5.0
}

Data Sanitization

Info Contributors

Extensible framework for contributing application information to the info endpoint including build metadata, git information, Java runtime details, OS information, and SSL certificate data.

// Info building
class Info {
    Map<String, Object> getDetails();
    Object get(String id);
    <T> T get(String id, Class<T> type);

    static class Builder {
        Builder withDetail(String key, Object value);
        Builder withDetails(Map<String, Object> details);
        Info build();
    }
}

@FunctionalInterface
interface InfoContributor {
    void contribute(Info.Builder builder);
}

// Base class for property-based contributors
abstract class InfoPropertiesInfoContributor<T extends InfoProperties> implements InfoContributor {
    protected InfoPropertiesInfoContributor(T properties, Mode mode);

    protected final T getProperties();
    protected final Mode getMode();
    protected abstract PropertySource<?> toSimplePropertySource();
    protected Map<String, Object> generateContent();
    protected Map<String, Object> extractContent(PropertySource<?> propertySource);
    protected void postProcessContent(Map<String, Object> content);
    protected PropertySource<?> toPropertySource();
    protected void copyIfSet(Properties target, String key);
    protected void replaceValue(Map<String, Object> content, String key, @Nullable Object value);
    protected Map<String, Object> getNestedMap(Map<String, Object> map, String key);

    enum Mode {
        FULL,    // Expose all available data including custom properties
        SIMPLE   // Expose pre-defined core settings only
    }
}

// Built-in contributors
class BuildInfoContributor extends InfoPropertiesInfoContributor<BuildProperties> {
    BuildInfoContributor(BuildProperties buildProperties);
}

class GitInfoContributor extends InfoPropertiesInfoContributor<GitProperties> {
    GitInfoContributor(GitProperties gitProperties);
    GitInfoContributor(GitProperties gitProperties, InfoPropertiesInfoContributor.Mode mode);
}

class JavaInfoContributor implements InfoContributor {
    JavaInfoContributor();
}

class OsInfoContributor implements InfoContributor {
    OsInfoContributor();
}

class ProcessInfoContributor implements InfoContributor {
    ProcessInfoContributor();
}

class EnvironmentInfoContributor implements InfoContributor {
    EnvironmentInfoContributor(ConfigurableEnvironment environment);
}

class SslInfoContributor implements InfoContributor {
    SslInfoContributor(SslInfo sslInfo);
}

class SimpleInfoContributor implements InfoContributor {
    SimpleInfoContributor(String prefix, @Nullable Object detail);
}

class MapInfoContributor implements InfoContributor {
    MapInfoContributor(Map<String, Object> content);
}

Info Contributors

Web Integration

Web-specific endpoint support with HTTP method mapping, status code handling, content negotiation, hypermedia links, path mapping, media type configuration, and servlet endpoint registration for Spring MVC and WebFlux.

// Web response wrapper
class WebEndpointResponse<T> {
    static final int STATUS_OK = 200;
    static final int STATUS_NO_CONTENT = 204;
    static final int STATUS_BAD_REQUEST = 400;
    static final int STATUS_NOT_FOUND = 404;
    static final int STATUS_TOO_MANY_REQUESTS = 429;
    static final int STATUS_INTERNAL_SERVER_ERROR = 500;
    static final int STATUS_SERVICE_UNAVAILABLE = 503;

    WebEndpointResponse();
    WebEndpointResponse(int status);
    WebEndpointResponse(T body);
    WebEndpointResponse(T body, Producible<?> producible);
    WebEndpointResponse(T body, MimeType contentType);
    WebEndpointResponse(T body, int status);
    WebEndpointResponse(T body, int status, MimeType contentType);

    @Nullable MimeType getContentType();
    @Nullable T getBody();
    int getStatus();
}

enum WebEndpointHttpMethod {
    GET,
    POST,
    DELETE
}

// Web endpoint extension
@EndpointWebExtension
@interface EndpointWebExtension {
    Class<?> endpoint();
}

// Hypermedia links
class Link {
    Link(String href);

    String getHref();
    boolean isTemplated();
}

class EndpointLinksResolver {
    EndpointLinksResolver(Collection<? extends ExposableEndpoint<?>> endpoints);
    EndpointLinksResolver(Collection<? extends ExposableEndpoint<?>> endpoints, String basePath);

    Map<String, Link> resolveLinks(String requestUrl);
}

// Path mapping
interface PathMappedEndpoint {
    String getRootPath();
    default List<String> getAdditionalPaths(WebServerNamespace webServerNamespace);
}

interface PathMapper {
    @Nullable String getRootPath(EndpointId endpointId);
    static String getRootPath(@Nullable List<PathMapper> pathMappers, EndpointId endpointId);
}

class EndpointMapping {
    EndpointMapping(String path);
    String getPath();
    String createSubPath(String path);
}

class PathMappedEndpoints implements Iterable<PathMappedEndpoint> {
    PathMappedEndpoints(@Nullable String basePath, EndpointsSupplier<?> supplier);
    PathMappedEndpoints(@Nullable String basePath, Collection<EndpointsSupplier<?>> suppliers);
    String getBasePath();
    @Nullable String getRootPath(EndpointId endpointId);
    @Nullable String getPath(EndpointId endpointId);
    Collection<String> getAllRootPaths();
    Collection<String> getAllPaths();
}

// Media types
class EndpointMediaTypes {
    static final EndpointMediaTypes DEFAULT;
    EndpointMediaTypes(String... producedAndConsumed);
    EndpointMediaTypes(List<String> producedAndConsumed);
    EndpointMediaTypes(List<String> produced, List<String> consumed);
    List<String> getProduced();
    List<String> getConsumed();
}

Web Integration

Security Integration

Security context abstraction and audit listeners for authentication and authorization events with role-based access control and Spring Security integration.

// Security context
interface SecurityContext {
    SecurityContext NONE = /* empty context */;

    @Nullable Principal getPrincipal();
    boolean isUserInRole(String role);
}

// Authentication audit
// Package: org.springframework.boot.actuate.security
abstract class AbstractAuthenticationAuditListener
        implements ApplicationListener<AbstractAuthenticationEvent>, ApplicationEventPublisherAware {
    void setApplicationEventPublisher(ApplicationEventPublisher publisher);
    protected ApplicationEventPublisher getPublisher();
    protected void publish(AuditEvent event);
}

class AuthenticationAuditListener extends AbstractAuthenticationAuditListener {
    static final String AUTHENTICATION_SUCCESS = "AUTHENTICATION_SUCCESS";
    static final String AUTHENTICATION_FAILURE = "AUTHENTICATION_FAILURE";
    static final String AUTHENTICATION_SWITCH = "AUTHENTICATION_SWITCH";
    static final String LOGOUT_SUCCESS = "LOGOUT_SUCCESS";
}

// Authorization audit
// Package: org.springframework.boot.actuate.security
abstract class AbstractAuthorizationAuditListener
        implements ApplicationListener<AuthorizationEvent>, ApplicationEventPublisherAware {
    void setApplicationEventPublisher(ApplicationEventPublisher publisher);
    protected ApplicationEventPublisher getPublisher();
    protected void publish(AuditEvent event);
}

class AuthorizationAuditListener extends AbstractAuthorizationAuditListener {
    static final String AUTHORIZATION_FAILURE = "AUTHORIZATION_FAILURE";
}

Security Integration

Management Operations

Thread dump, heap dump, and startup information endpoints for runtime diagnostics and performance analysis.

// Thread dump endpoint
@Endpoint(id = "threaddump")
class ThreadDumpEndpoint {
    ThreadDumpDescriptor threadDump();
}

// Heap dump endpoint
@WebEndpoint(id = "heapdump", defaultAccess = Access.NONE)
class HeapDumpWebEndpoint {
    HeapDumpWebEndpoint();
    protected HeapDumpWebEndpoint(long timeout);
    @ReadOperation WebEndpointResponse<Resource> heapDump(@Nullable Boolean live);
}

// Startup endpoint
@Endpoint(id = "startup")
class StartupEndpoint {
    StartupEndpoint(BufferingApplicationStartup applicationStartup);
    @ReadOperation StartupDescriptor startupSnapshot();
    @WriteOperation StartupDescriptor startup();
}

// SBOM endpoint
@Endpoint(id = "sbom")
class SbomEndpoint {
    SbomEndpoint(SbomProperties properties, ResourceLoader resourceLoader);
    @ReadOperation Sboms sboms();
    @ReadOperation @Nullable Resource sbom(@Selector String id);

    record Sboms(Collection<String> ids) implements OperationResponseBody {}
}

// SBOM web extension - SBOM download with content type
@EndpointWebExtension(endpoint = SbomEndpoint.class)
class SbomEndpointWebExtension {
    SbomEndpointWebExtension(SbomEndpoint sbomEndpoint, SbomProperties properties);
    @ReadOperation WebEndpointResponse<Resource> sbom(@Selector String id);
}

// SBOM configuration properties
@ConfigurationProperties("management.endpoint.sbom")
class SbomProperties {
    Sbom getApplication();
    Map<String, Sbom> getAdditional();
    void setAdditional(Map<String, Sbom> additional);

    static class Sbom {
        @Nullable String getLocation();
        void setLocation(@Nullable String location);
        @Nullable MimeType getMediaType();
        void setMediaType(@Nullable MimeType mediaType);
    }
}

// Shutdown endpoint
@Endpoint(id = "shutdown", defaultAccess = Access.NONE)
class ShutdownEndpoint implements ApplicationContextAware {
    @WriteOperation ShutdownDescriptor shutdown();
}

// Scheduled tasks endpoint
@Endpoint(id = "scheduledtasks")
class ScheduledTasksEndpoint {
    ScheduledTasksEndpoint(Collection<ScheduledTaskHolder> scheduledTaskHolders);
    @ReadOperation ScheduledTasksDescriptor scheduledTasks();
}

// Request mappings endpoint
@Endpoint(id = "mappings")
class MappingsEndpoint {
    MappingsEndpoint(Collection<MappingDescriptionProvider> descriptionProviders, ApplicationContext context);
    @ReadOperation ApplicationMappingsDescriptor mappings();
}

Management Operations

JMX Integration

JMX-specific endpoint support with MBean export, object name generation, and operation response mapping for JMX management tools.

// JMX endpoint annotation
@JmxEndpoint
@interface JmxEndpoint {
    String id();
    Access defaultAccess() default Access.UNRESTRICTED;
}

@EndpointJmxExtension
@interface EndpointJmxExtension {
    Class<?> endpoint();
}

// JMX endpoint exporter
class JmxEndpointExporter {
    JmxEndpointExporter(MBeanServer mBeanServer,
                       EndpointObjectNameFactory objectNameFactory,
                       JmxOperationResponseMapper responseMapper,
                       Collection<ExposableJmxEndpoint> endpoints);
}

// Object name factory
@FunctionalInterface
interface EndpointObjectNameFactory {
    ObjectName getObjectName(ExposableJmxEndpoint endpoint) throws MalformedObjectNameException;
}

// Response mapper
interface JmxOperationResponseMapper {
    Object mapResponse(Object response);
    Class<?> mapResponseType(Class<?> responseType);
}

class JacksonJmxOperationResponseMapper implements JmxOperationResponseMapper {
    JacksonJmxOperationResponseMapper(JsonMapper jsonMapper);
}

JMX Integration

Operation Invocation

Framework for invoking endpoint operations with parameter mapping, reflection-based invocation, caching support, and argument resolution.

// Core invocation
interface OperationInvoker {
    Object invoke(InvocationContext context);
}

class InvocationContext {
    InvocationContext(SecurityContext securityContext,
                     Map<String, Object> arguments,
                     OperationArgumentResolver... argumentResolvers);

    Map<String, Object> getArguments();
    <T> T resolveArgument(Class<T> argumentType);
    boolean canResolve(Class<?> type);
}

// Parameter mapping
interface ParameterValueMapper {
    Object mapParameterValue(OperationParameter parameter, Object value);
}

class ConversionServiceParameterValueMapper implements ParameterValueMapper {
    ConversionServiceParameterValueMapper();
    ConversionServiceParameterValueMapper(ConversionService conversionService);
}

// Reflective invocation
class ReflectiveOperationInvoker implements OperationInvoker {
    ReflectiveOperationInvoker(Object target,
                              OperationMethod operationMethod,
                              ParameterValueMapper parameterValueMapper);
}

class OperationMethod {
    OperationMethod(Method method, OperationType operationType);

    Method getMethod();
    OperationType getOperationType();
    OperationParameters getParameters();
}

// Caching
class CachingOperationInvoker implements OperationInvoker {
    CachingOperationInvoker(OperationInvoker invoker, long timeToLive);
    Object invoke(InvocationContext context);
}

class CachingOperationInvokerAdvisor implements OperationInvokerAdvisor {
    CachingOperationInvokerAdvisor(Function<EndpointId, Long> endpointIdTimeToLive);
}

Operation Invocation

Common Types

EndpointId

final class EndpointId {
    static EndpointId of(String value);
    static EndpointId of(Environment environment, String value);
    static EndpointId fromPropertyValue(String value);

    String toLowerCaseString();
    String toString();
    boolean equals(Object obj);
    int hashCode();
}

OperationType

enum OperationType {
    READ,
    WRITE,
    DELETE
}

ApiVersion

/**
 * Interface implemented by types that produce a specific MIME type.
 * Used for content negotiation in operations.
 *
 * @param <E> enum type that implements this interface
 * @since 2.5.0
 */
interface Producible<E extends Enum<E> & Producible<E>> {
    /**
     * Get the MIME type produced.
     *
     * @return the MIME type (never null)
     */
    MimeType getProducedMimeType();

    /**
     * Return if this enum value should be used as the default value when an accept
     * header of &#42;&#47;&#42; is provided, or if the {@code Accept} header is missing.
     * Only one value can be marked as default. If no value is marked, then the value
     * with the highest {@link Enum#ordinal() ordinal} is used as the default.
     *
     * @return if this value should be used as the default value
     * @since 2.5.6
     */
    default boolean isDefault() {
        return false;
    }
}

enum ApiVersion implements Producible<ApiVersion> {
    V2,
    V3;

    static final ApiVersion LATEST = V3;

    MimeType getProducedMimeType();
    // isDefault() inherited from Producible interface (both V2 and V3 return false)
}

OperationResponseBody

interface OperationResponseBody {
    static <K, V> @Nullable Map<K, V> of(@Nullable Map<K, V> map);
}

Exception Types

class InvalidEndpointRequestException extends RuntimeException {
    InvalidEndpointRequestException(String message, String reason);
    InvalidEndpointRequestException(String message, String reason, Throwable cause);
    String getReason();
}

class MissingParametersException extends RuntimeException {
    MissingParametersException(Set<OperationParameter> missingParameters);
    Set<OperationParameter> getMissingParameters();
}

class ParameterMappingException extends RuntimeException {
    ParameterMappingException(OperationParameter parameter, Object value, Throwable cause);
}

TROUBLESHOOTING

Common Error: Endpoint Not Found

Problem: GET /actuator/custom returns 404

Causes:

  1. Endpoint not registered as Spring bean
  2. Endpoint not exposed in configuration
  3. Endpoint ID mismatch

Solutions:

// 1. Add @Component annotation
@Endpoint(id = "custom")
@Component  // <-- Add this
public class CustomEndpoint { }

// 2. Configure exposure in application.yml
management:
  endpoints:
    web:
      exposure:
        include: custom  # Add your endpoint ID

// 3. Check endpoint ID matches URL
@Endpoint(id = "custom")  // Access at /actuator/custom

Common Error: Access Denied

Problem: 403 Forbidden when accessing endpoint

Causes:

  1. Security blocks unauthenticated access
  2. Missing required role
  3. Endpoint has Access.NONE

Solutions:

// 1. Configure security
@Bean
public SecurityFilterChain actuatorSecurity(HttpSecurity http) {
    http.securityMatcher("/actuator/**")
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/actuator/custom").hasRole("USER")
            .anyRequest().permitAll()
        );
    return http.build();
}

// 2. Check endpoint access level
@Endpoint(id = "custom", defaultAccess = Access.UNRESTRICTED)

// 3. Enable endpoint explicitly
management:
  endpoint:
    custom:
      enabled: true

Common Error: Parameter Mapping Failed

Problem: ParameterMappingException when calling endpoint

Causes:

  1. Invalid parameter type conversion
  2. Missing required parameter
  3. Wrong parameter format

Solutions:

// 1. Add custom converter
@Configuration
public class ConverterConfiguration {
    @Bean
    public ParameterValueMapper parameterValueMapper() {
        DefaultConversionService service = new DefaultConversionService();
        service.addConverter(new MyCustomConverter());
        return new ConversionServiceParameterValueMapper(service);
    }
}

// 2. Make parameter nullable
@ReadOperation
public Data getData(@Nullable String filter) { }

// 3. Document expected format
/**
 * @param date Date in ISO format (yyyy-MM-dd'T'HH:mm:ss'Z')
 */
@ReadOperation
public Data getData(OffsetDateTime date) { }

PERFORMANCE NOTES

Caching Strategy

// Read operations with no parameters are cacheable
@ReadOperation  // Can be cached
public Map<String, Object> getStatus() { }

@ReadOperation  // Cannot be cached (has parameters)
public Map<String, Object> search(String query) { }

// Configure caching per endpoint
@Bean
public CachingOperationInvokerAdvisor cachingAdvisor() {
    return new CachingOperationInvokerAdvisor(endpointId -> {
        switch (endpointId.toLowerCaseString()) {
            case "health": return 10_000L;  // 10 seconds
            case "info": return 60_000L;    // 60 seconds
            default: return 0L;             // No caching
        }
    });
}

Memory Considerations

// In-memory repositories have capacity limits
InMemoryAuditEventRepository auditRepo =
    new InMemoryAuditEventRepository(1000); // Max 1000 events

InMemoryHttpExchangeRepository httpRepo =
    new InMemoryHttpExchangeRepository();
httpRepo.setCapacity(500); // Max 500 exchanges

// For production: implement persistent repositories
@Bean
public AuditEventRepository persistentAuditRepo(JdbcTemplate jdbc) {
    return new JdbcAuditEventRepository(jdbc);
}

Thread Safety

// Endpoint beans must be thread-safe
@Endpoint(id = "counter")
@Component
public class CounterEndpoint {
    // ✓ Thread-safe
    private final AtomicInteger counter = new AtomicInteger(0);

    // ❌ NOT thread-safe
    // private int counter = 0;

    @ReadOperation
    public int getCount() {
        return counter.get();
    }

    @WriteOperation
    public void increment() {
        counter.incrementAndGet();
    }
}