CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-micronaut

Modern, JVM-based framework for building modular, easily testable microservice and serverless applications with compile-time DI and fast startup.

Pending
Overview
Eval results
Files

management.mddocs/

Application Management

Micronaut provides built-in management endpoints for monitoring, health checks, metrics, and application information, following Spring Boot Actuator patterns.

Capabilities

Health Checks

Built-in and custom health indicators for monitoring application health.

/**
 * Custom health indicator
 */
@Singleton
public class DatabaseHealthIndicator implements HealthIndicator {
    
    private final DataSource dataSource;
    
    public DatabaseHealthIndicator(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public Publisher<HealthResult> getResult() {
        return Single.fromCallable(() -> {
            try (Connection connection = dataSource.getConnection()) {
                return HealthResult.builder("database")
                    .status(HealthStatus.UP)
                    .details("connection", "available")
                    .build();
            } catch (SQLException e) {
                return HealthResult.builder("database")
                    .status(HealthStatus.DOWN)
                    .exception(e)
                    .build();
            }
        });
    }
}

Custom Management Endpoints

Create custom endpoints for application management and monitoring.

/**
 * Custom management endpoint
 */
@Endpoint(id = "custom", defaultEnabled = true)
public class CustomEndpoint {
    
    @Read
    public Map<String, Object> status() {
        return Map.of(
            "status", "healthy",
            "timestamp", Instant.now(),
            "version", "1.0.0"
        );
    }
    
    @Write
    public String refresh(@Selector String component) {
        // Perform refresh operation
        return "Refreshed component: " + component;
    }
    
    @Delete
    public String reset(@Selector String component) {
        // Perform reset operation
        return "Reset component: " + component;
    }
}

Metrics Collection

Collect and expose application metrics using Micrometer.

/**
 * Custom metrics
 */
@Singleton
public class OrderMetrics {
    
    private final Counter orderCounter;
    private final Timer orderProcessingTimer;
    private final Gauge activeOrdersGauge;
    
    public OrderMetrics(MeterRegistry meterRegistry) {
        this.orderCounter = Counter.builder("orders.created")
            .description("Total orders created")
            .register(meterRegistry);
            
        this.orderProcessingTimer = Timer.builder("orders.processing.time")
            .description("Order processing time")
            .register(meterRegistry);
            
        this.activeOrdersGauge = Gauge.builder("orders.active")
            .description("Active orders count")
            .register(meterRegistry, this, OrderMetrics::getActiveOrdersCount);
    }
    
    public void recordOrderCreated() {
        orderCounter.increment();
    }
    
    public void recordProcessingTime(Duration duration) {
        orderProcessingTimer.record(duration);
    }
    
    private double getActiveOrdersCount() {
        // Return current active orders count
        return activeOrders.size();
    }
}

Application Info

Provide application information through the info endpoint.

/**
 * Custom application info contributor
 */
@Singleton
public class CustomInfoContributor implements InfoContributor {
    
    @Override
    public Publisher<Map<String, Object>> getInfo() {
        return Single.fromCallable(() -> Map.of(
            "app", Map.of(
                "name", "My Application",
                "description", "Sample Micronaut application",
                "version", "1.0.0"
            ),
            "build", Map.of(
                "timestamp", "2023-01-01T00:00:00Z",
                "version", "1.0.0-SNAPSHOT"
            )
        ));
    }
}

Environment Information

Access environment and configuration information.

/**
 * Environment endpoint for configuration details
 */
@Endpoint(id = "env", defaultEnabled = false)
public class EnvironmentEndpoint {
    
    private final Environment environment;
    
    public EnvironmentEndpoint(Environment environment) {
        this.environment = environment;
    }
    
    @Read
    public Map<String, Object> getEnvironment() {
        return Map.of(
            "activeNames", environment.getActiveNames(),
            "packages", environment.getPackages(),
            "properties", getProperties()
        );
    }
    
    @Read
    public Map<String, Object> getProperty(@Selector String name) {
        return environment.getProperty(name, Object.class)
            .map(value -> Map.of("property", name, "value", value))
            .orElse(Map.of("property", name, "value", null));
    }
    
    private Map<String, Object> getProperties() {
        // Return filtered properties (exclude sensitive data)
        return environment.getPropertySources().stream()
            .flatMap(ps -> ps.asMap().entrySet().stream())
            .filter(entry -> !isSensitive(entry.getKey()))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }
}

Thread Dump

Monitor application threads and their states.

/**
 * Thread dump endpoint
 */
@Endpoint(id = "threaddump", defaultEnabled = true)
public class ThreadDumpEndpoint {
    
    @Read
    public ThreadDumpInfo getThreadDump() {
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(true, true);
        
        return ThreadDumpInfo.builder()
            .threads(Arrays.stream(threadInfos)
                .map(this::mapThreadInfo)
                .collect(Collectors.toList()))
            .build();
    }
    
    private ThreadDetail mapThreadInfo(ThreadInfo threadInfo) {
        return ThreadDetail.builder()
            .threadName(threadInfo.getThreadName())
            .threadId(threadInfo.getThreadId())
            .threadState(threadInfo.getThreadState().name())
            .blockedTime(threadInfo.getBlockedTime())
            .waitedTime(threadInfo.getWaitedTime())
            .stackTrace(Arrays.stream(threadInfo.getStackTrace())
                .map(StackTraceElement::toString)
                .collect(Collectors.toList()))
            .build();
    }
}

Types

// Management annotations
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Endpoint {
    String id();
    boolean defaultEnabled() default true;
    boolean defaultSensitive() default true;
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Read {
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Write {
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Delete {
}

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Selector {
}

// Health check interfaces
public interface HealthIndicator {
    Publisher<HealthResult> getResult();
}

public final class HealthResult {
    public static Builder builder(String name);
    public String getName();
    public HealthStatus getStatus();
    public Map<String, Object> getDetails();
    
    public static class Builder {
        public Builder status(HealthStatus status);
        public Builder details(String key, Object value);
        public Builder details(Map<String, Object> details);
        public Builder exception(Throwable exception);
        public HealthResult build();
    }
}

public enum HealthStatus {
    UP, DOWN, OUT_OF_SERVICE, UNKNOWN
}

// Info contributor interface
public interface InfoContributor {
    Publisher<Map<String, Object>> getInfo();
}

// Metrics interfaces
public interface MeterRegistry {
    Counter counter(String name);
    Timer timer(String name);
    Gauge gauge(String name, Object obj, ToDoubleFunction<Object> valueFunction);
}

public interface Counter extends Meter {
    void increment();
    void increment(double amount);
    double count();
}

public interface Timer extends Meter {
    void record(long amount, TimeUnit unit);
    void record(Duration duration);
    long count();
    double totalTime(TimeUnit unit);
}

Install with Tessl CLI

npx tessl i tessl/maven-micronaut

docs

aop.md

configuration.md

dependency-injection.md

functions.md

http-client.md

http-server.md

index.md

management.md

messaging.md

reactive.md

retry.md

scheduling.md

websocket.md

tile.json