CtrlK
BlogDocsLog inGet started
Tessl Logo

giuseppe-trisciuoglio/developer-kit

Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.

82

Quality

82%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

Validation failed for skills in this tile
One or more skills have errors that need to be fixed before they can move to Implementation and Discovery review.
Overview
Quality
Evals
Security
Files

examples.mdplugins/developer-kit-java/skills/spring-boot-actuator/references/

Spring Boot Actuator Examples

Complete Application Example

Application Configuration

@SpringBootApplication
public class MonitoringApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(MonitoringApplication.class);
        // Enable startup tracking
        app.setApplicationStartup(new BufferingApplicationStartup(2048));
        app.run(args);
    }

    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> registry.config()
            .commonTags("application", "order-service", "environment", "production");
    }
}

Application Properties

spring:
  application:
    name: order-service

info:
  app:
    name: ${spring.application.name}
    description: Order Processing Service
    version: "@project.version@"
    encoding: "@project.build.sourceEncoding@"
    java:
      version: "@java.version@"

management:
  endpoints:
    web:
      exposure:
        include: "health,info,metrics,prometheus,startup"
      base-path: "/actuator"
  
  endpoint:
    health:
      show-details: when-authorized
      show-components: always
      probes:
        enabled: true
      group:
        liveness:
          include: "ping,diskSpace"
        readiness:
          include: "readinessState,db,redis,externalApi"
          show-details: always
      status:
        order: "fatal,down,out-of-service,warning,unknown,up"
        http-mapping:
          down: 503
          fatal: 503
          warning: 500
    
    info:
      enabled: true
    
    metrics:
      enabled: true
  
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: ${spring.application.name}
      region: eu-west-1

  info:
    git:
      mode: full
    build:
      enabled: true

Health Indicators Examples

Database Health Indicator

@Component
public class DatabaseHealthIndicator implements HealthIndicator {

    private static final Logger log = LoggerFactory.getLogger(DatabaseHealthIndicator.class);
    private final DataSource dataSource;

    public DatabaseHealthIndicator(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Override
    public Health health() {
        try (Connection connection = dataSource.getConnection()) {
            long startTime = System.currentTimeMillis();
            boolean valid = connection.isValid(1000);
            long responseTime = System.currentTimeMillis() - startTime;

            if (!valid) {
                return Health.down()
                    .withDetail("database", "Connection not valid")
                    .build();
            }

            DatabaseMetaData metaData = connection.getMetaData();
            
            Health.Builder builder = Health.up()
                .withDetail("database", metaData.getDatabaseProductName())
                .withDetail("version", metaData.getDatabaseProductVersion())
                .withDetail("responseTime", responseTime + "ms");

            if (responseTime > 500) {
                builder.status("WARNING")
                    .withDetail("warning", "Slow database connection");
            }

            return builder.build();

        } catch (SQLException ex) {
            log.error("Database health check failed", ex);
            return Health.down()
                .withDetail("error", ex.getMessage())
                .withException(ex)
                .build();
        }
    }
}

External API Health Indicator with Circuit Breaker

@Component
public class PaymentGatewayHealthIndicator implements HealthIndicator {

    private final RestTemplate restTemplate;
    private final CircuitBreaker circuitBreaker;

    public PaymentGatewayHealthIndicator(
            RestTemplate restTemplate,
            @Qualifier("paymentCircuitBreaker") CircuitBreaker circuitBreaker) {
        this.restTemplate = restTemplate;
        this.circuitBreaker = circuitBreaker;
    }

    @Override
    public Health health() {
        CircuitBreaker.State state = circuitBreaker.getState();
        
        Health.Builder builder = Health.up()
            .withDetail("circuitBreaker", state.toString())
            .withDetail("service", "Payment Gateway");

        if (state == CircuitBreaker.State.OPEN) {
            return builder
                .down()
                .withDetail("reason", "Circuit breaker is open")
                .build();
        }

        if (state == CircuitBreaker.State.HALF_OPEN) {
            builder.status("WARNING")
                .withDetail("reason", "Circuit breaker is testing");
        }

        try {
            long startTime = System.currentTimeMillis();
            ResponseEntity<Map> response = restTemplate.getForEntity(
                "https://api.payment.com/health", 
                Map.class
            );
            long responseTime = System.currentTimeMillis() - startTime;

            return builder
                .withDetail("responseTime", responseTime + "ms")
                .withDetail("statusCode", response.getStatusCode().value())
                .build();

        } catch (Exception ex) {
            return builder
                .down()
                .withDetail("error", ex.getMessage())
                .build();
        }
    }
}

Cache Health Indicator

@Component
public class CacheHealthIndicator implements HealthIndicator {

    private final CacheManager cacheManager;

    public CacheHealthIndicator(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @Override
    public Health health() {
        Collection<String> cacheNames = cacheManager.getCacheNames();
        
        Map<String, Object> cacheDetails = new HashMap<>();
        boolean allHealthy = true;

        for (String cacheName : cacheNames) {
            Cache cache = cacheManager.getCache(cacheName);
            if (cache != null) {
                try {
                    // Test cache operations
                    cache.put("health-check", "test");
                    String value = cache.get("health-check", String.class);
                    cache.evict("health-check");
                    
                    cacheDetails.put(cacheName, "UP");
                } catch (Exception ex) {
                    cacheDetails.put(cacheName, "DOWN: " + ex.getMessage());
                    allHealthy = false;
                }
            }
        }

        Health.Builder builder = allHealthy ? Health.up() : Health.down();
        return builder
            .withDetail("caches", cacheDetails)
            .withDetail("totalCaches", cacheNames.size())
            .build();
    }
}

Reactive Health Indicator

@Component
public class ReactiveExternalServiceHealthIndicator implements ReactiveHealthIndicator {

    private final WebClient webClient;

    public ReactiveExternalServiceHealthIndicator(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder
            .baseUrl("https://api.example.com")
            .build();
    }

    @Override
    public Mono<Health> health() {
        return webClient
            .get()
            .uri("/health")
            .retrieve()
            .toBodilessEntity()
            .map(response -> Health.up()
                .withDetail("statusCode", response.getStatusCode().value())
                .withDetail("service", "External API")
                .build())
            .timeout(Duration.ofSeconds(2))
            .onErrorResume(TimeoutException.class, ex -> 
                Mono.just(Health.down()
                    .withDetail("error", "Timeout after 2 seconds")
                    .build()))
            .onErrorResume(ex -> 
                Mono.just(Health.down()
                    .withDetail("error", ex.getMessage())
                    .build()));
    }
}

Custom Endpoints Examples

Application Statistics Endpoint

@Component
@Endpoint(id = "appstats")
public class AppStatisticsEndpoint {

    private final UserRepository userRepository;
    private final OrderRepository orderRepository;
    private final MeterRegistry meterRegistry;

    public AppStatisticsEndpoint(
            UserRepository userRepository,
            OrderRepository orderRepository,
            MeterRegistry meterRegistry) {
        this.userRepository = userRepository;
        this.orderRepository = orderRepository;
        this.meterRegistry = meterRegistry;
    }

    @ReadOperation
    public Map<String, Object> getStatistics() {
        Map<String, Object> stats = new HashMap<>();
        
        // User statistics
        stats.put("users", Map.of(
            "total", userRepository.count(),
            "active", userRepository.countByStatus("ACTIVE"),
            "inactive", userRepository.countByStatus("INACTIVE")
        ));
        
        // Order statistics
        stats.put("orders", Map.of(
            "total", orderRepository.count(),
            "pending", orderRepository.countByStatus("PENDING"),
            "completed", orderRepository.countByStatus("COMPLETED"),
            "cancelled", orderRepository.countByStatus("CANCELLED")
        ));
        
        // JVM statistics
        stats.put("jvm", Map.of(
            "memoryUsed", getMetricValue("jvm.memory.used"),
            "memoryMax", getMetricValue("jvm.memory.max"),
            "threadCount", getMetricValue("jvm.threads.live")
        ));
        
        stats.put("timestamp", Instant.now());
        
        return stats;
    }

    @ReadOperation
    public Map<String, Object> getStatisticsByType(@Selector String type) {
        return switch (type.toLowerCase()) {
            case "users" -> Map.of(
                "total", userRepository.count(),
                "byStatus", userRepository.countByStatusGrouped()
            );
            case "orders" -> Map.of(
                "total", orderRepository.count(),
                "byStatus", orderRepository.countByStatusGrouped()
            );
            default -> Map.of("error", "Unknown type: " + type);
        };
    }

    private Double getMetricValue(String meterName) {
        return meterRegistry.find(meterName)
            .gauge()
            .map(Gauge::value)
            .orElse(0.0);
    }
}

Feature Flags Endpoint

@Component
@Endpoint(id = "features")
public class FeatureFlagsEndpoint {

    private final Map<String, FeatureFlag> features = new ConcurrentHashMap<>();
    private final ApplicationEventPublisher eventPublisher;

    public FeatureFlagsEndpoint(ApplicationEventPublisher eventPublisher) {
        this.eventPublisher = eventPublisher;
        initializeDefaultFeatures();
    }

    private void initializeDefaultFeatures() {
        features.put("dark-mode", new FeatureFlag(true, "Dark mode UI"));
        features.put("new-checkout", new FeatureFlag(false, "New checkout flow"));
        features.put("ai-recommendations", new FeatureFlag(false, "AI-powered recommendations"));
    }

    @ReadOperation
    public Map<String, FeatureFlag> getAllFeatures() {
        return features;
    }

    @ReadOperation
    public FeatureFlag getFeature(@Selector String name) {
        return features.get(name);
    }

    @WriteOperation
    public void updateFeature(
            @Selector String name,
            @Nullable Boolean enabled,
            @Nullable String description) {
        
        features.compute(name, (key, existing) -> {
            if (existing == null) {
                existing = new FeatureFlag(false, "");
            }
            
            if (enabled != null) {
                existing.setEnabled(enabled);
            }
            if (description != null) {
                existing.setDescription(description);
            }
            
            return existing;
        });

        eventPublisher.publishEvent(new FeatureFlagChangedEvent(name, features.get(name)));
    }

    @DeleteOperation
    public void deleteFeature(@Selector String name) {
        FeatureFlag removed = features.remove(name);
        if (removed != null) {
            eventPublisher.publishEvent(new FeatureFlagDeletedEvent(name));
        }
    }

    public static class FeatureFlag {
        private boolean enabled;
        private String description;
        private Instant lastModified = Instant.now();

        public FeatureFlag() {}

        public FeatureFlag(boolean enabled, String description) {
            this.enabled = enabled;
            this.description = description;
        }

        // Getters and setters
        public boolean isEnabled() { return enabled; }
        public void setEnabled(boolean enabled) {
            this.enabled = enabled;
            this.lastModified = Instant.now();
        }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public Instant getLastModified() { return lastModified; }
    }
}

Cache Management Endpoint

@Component
@Endpoint(id = "caches")
public class CacheManagementEndpoint {

    private final CacheManager cacheManager;

    public CacheManagementEndpoint(CacheManager cacheManager) {
        this.cacheManager = cacheManager;
    }

    @ReadOperation
    public Map<String, Object> getCaches() {
        Collection<String> cacheNames = cacheManager.getCacheNames();
        Map<String, Object> result = new HashMap<>();
        
        result.put("totalCaches", cacheNames.size());
        result.put("caches", cacheNames);
        
        return result;
    }

    @ReadOperation
    public Map<String, Object> getCache(@Selector String cacheName) {
        Cache cache = cacheManager.getCache(cacheName);
        if (cache == null) {
            return Map.of("error", "Cache not found: " + cacheName);
        }

        return Map.of(
            "name", cacheName,
            "type", cache.getClass().getSimpleName()
        );
    }

    @DeleteOperation
    public void clearCache(@Selector String cacheName) {
        Cache cache = cacheManager.getCache(cacheName);
        if (cache != null) {
            cache.clear();
        }
    }

    @WriteOperation
    public void clearAllCaches() {
        cacheManager.getCacheNames()
            .forEach(name -> {
                Cache cache = cacheManager.getCache(name);
                if (cache != null) {
                    cache.clear();
                }
            });
    }
}

Custom Info Contributors

Detailed Application Info

@Component
public class DetailedApplicationInfoContributor implements InfoContributor {

    private final Environment environment;
    private final UserRepository userRepository;
    private final OrderRepository orderRepository;

    public DetailedApplicationInfoContributor(
            Environment environment,
            UserRepository userRepository,
            OrderRepository orderRepository) {
        this.environment = environment;
        this.userRepository = userRepository;
        this.orderRepository = orderRepository;
    }

    @Override
    public void contribute(Info.Builder builder) {
        // Runtime information
        Runtime runtime = Runtime.getRuntime();
        builder.withDetail("runtime", Map.of(
            "processors", runtime.availableProcessors(),
            "freeMemory", runtime.freeMemory(),
            "totalMemory", runtime.totalMemory(),
            "maxMemory", runtime.maxMemory(),
            "uptime", ManagementFactory.getRuntimeMXBean().getUptime()
        ));

        // Active profiles
        builder.withDetail("profiles", List.of(environment.getActiveProfiles()));

        // Database statistics
        builder.withDetail("database", Map.of(
            "users", Map.of(
                "total", userRepository.count(),
                "active", userRepository.countByStatus("ACTIVE")
            ),
            "orders", Map.of(
                "total", orderRepository.count(),
                "pending", orderRepository.countByStatus("PENDING"),
                "completed", orderRepository.countByStatus("COMPLETED")
            )
        ));

        // Deployment information
        builder.withDetail("deployment", Map.of(
            "environment", environment.getProperty("app.environment", "unknown"),
            "region", environment.getProperty("app.region", "unknown"),
            "instance", getHostname()
        ));
    }

    private String getHostname() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (Exception e) {
            return "unknown";
        }
    }
}

Dependency Version Info

@Component
public class DependencyVersionInfoContributor implements InfoContributor {

    @Override
    public void contribute(Info.Builder builder) {
        Map<String, String> versions = new HashMap<>();
        
        // Spring versions
        versions.put("spring-boot", SpringBootVersion.getVersion());
        versions.put("spring-framework", SpringVersion.getVersion());
        
        // Java version
        versions.put("java", System.getProperty("java.version"));
        versions.put("java-vendor", System.getProperty("java.vendor"));
        
        // Other dependencies (if available)
        addVersionIfPresent(versions, "hibernate", "org.hibernate.Version", "getVersionString");
        addVersionIfPresent(versions, "jackson", "com.fasterxml.jackson.core.Version", "versionString");
        
        builder.withDetail("dependencies", versions);
    }

    private void addVersionIfPresent(Map<String, String> versions, String key, 
                                      String className, String methodName) {
        try {
            Class<?> clazz = Class.forName(className);
            Object versionInstance = clazz.getDeclaredConstructor().newInstance();
            String version = (String) clazz.getMethod(methodName).invoke(versionInstance);
            versions.put(key, version);
        } catch (Exception e) {
            // Dependency not present or version not accessible
        }
    }
}

Metrics Examples

Service Metrics

@Service
public class OrderService {

    private final OrderRepository orderRepository;
    private final MeterRegistry meterRegistry;
    private final Counter orderCreatedCounter;
    private final Counter orderFailedCounter;
    private final Timer orderProcessingTimer;
    private final DistributionSummary orderAmountSummary;

    public OrderService(OrderRepository orderRepository, MeterRegistry meterRegistry) {
        this.orderRepository = orderRepository;
        this.meterRegistry = meterRegistry;

        // Counters
        this.orderCreatedCounter = Counter.builder("orders.created")
            .description("Total number of orders created")
            .tag("service", "order")
            .register(meterRegistry);

        this.orderFailedCounter = Counter.builder("orders.failed")
            .description("Total number of failed orders")
            .tag("service", "order")
            .register(meterRegistry);

        // Timer for processing duration
        this.orderProcessingTimer = Timer.builder("order.processing.time")
            .description("Order processing duration")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(meterRegistry);

        // Distribution summary for order amounts
        this.orderAmountSummary = DistributionSummary.builder("order.amount")
            .description("Order amount distribution")
            .baseUnit("EUR")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(meterRegistry);

        // Gauge for pending orders
        Gauge.builder("orders.pending", orderRepository, repo -> repo.countByStatus("PENDING"))
            .description("Number of pending orders")
            .register(meterRegistry);
    }

    public Order createOrder(OrderRequest request) {
        return orderProcessingTimer.record(() -> {
            try {
                Order order = processOrder(request);
                orderCreatedCounter.increment();
                orderAmountSummary.record(order.getTotalAmount());
                
                // Tag by payment method
                Counter.builder("orders.created.by.payment")
                    .tag("paymentMethod", order.getPaymentMethod())
                    .register(meterRegistry)
                    .increment();
                
                return order;
            } catch (Exception ex) {
                orderFailedCounter.increment();
                throw ex;
            }
        });
    }

    private Order processOrder(OrderRequest request) {
        // Implementation
        return new Order();
    }
}

Custom Metrics with Tags

@Service
public class MetricsService {

    private final MeterRegistry registry;

    public MetricsService(MeterRegistry registry) {
        this.registry = registry;
    }

    public void recordHttpRequest(String method, String endpoint, int statusCode, long duration) {
        Timer.builder("http.requests")
            .tag("method", method)
            .tag("endpoint", endpoint)
            .tag("status", String.valueOf(statusCode))
            .register(registry)
            .record(duration, TimeUnit.MILLISECONDS);
    }

    public void recordDatabaseQuery(String query, long duration, boolean success) {
        Timer.builder("db.queries")
            .tag("query", query)
            .tag("success", String.valueOf(success))
            .register(registry)
            .record(duration, TimeUnit.MILLISECONDS);
    }

    public void trackCacheHit(String cacheName, boolean hit) {
        Counter.builder("cache.operations")
            .tag("cache", cacheName)
            .tag("result", hit ? "hit" : "miss")
            .register(registry)
            .increment();
    }

    public void recordBusinessMetric(String metricName, double value, Map<String, String> tags) {
        DistributionSummary.Builder builder = DistributionSummary.builder(metricName);
        tags.forEach(builder::tag);
        builder.register(registry).record(value);
    }
}

Security Configuration Examples

Complete Security Setup

@Configuration
@EnableWebSecurity
public class ActuatorSecurityConfiguration {

    @Bean
    public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
        return http
            .securityMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(auth -> auth
                // Public health check (for load balancers)
                .requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
                
                // Info endpoint for authenticated users
                .requestMatchers(EndpointRequest.to(InfoEndpoint.class)).authenticated()
                
                // Read-only metrics for monitoring role
                .requestMatchers(HttpMethod.GET, "/actuator/metrics/**")
                    .hasAnyRole("MONITOR", "ADMIN")
                
                // Prometheus endpoint for monitoring tools
                .requestMatchers(EndpointRequest.to("prometheus"))
                    .hasRole("MONITOR")
                
                // Write operations only for admin
                .requestMatchers(HttpMethod.POST, "/actuator/**").hasRole("ADMIN")
                .requestMatchers(HttpMethod.DELETE, "/actuator/**").hasRole("ADMIN")
                
                // Everything else requires admin
                .anyRequest().hasRole("ADMIN")
            )
            .httpBasic(Customizer.withDefaults())
            .build();
    }

    @Bean
    public UserDetailsService actuatorUsers() {
        UserDetails monitor = User.builder()
            .username("monitor")
            .password("{noop}monitor-password")
            .roles("MONITOR")
            .build();

        UserDetails admin = User.builder()
            .username("admin")
            .password("{noop}admin-password")
            .roles("ADMIN", "MONITOR")
            .build();

        return new InMemoryUserDetailsManager(monitor, admin);
    }
}

IP-Based Access Control

@Configuration
public class IpBasedActuatorSecurity {

    @Bean
    public SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
        return http
            .securityMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers(request -> 
                    isFromAllowedIp(request.getRemoteAddr())
                ).permitAll()
                .anyRequest().denyAll()
            )
            .build();
    }

    private boolean isFromAllowedIp(String remoteAddr) {
        // Allow localhost and specific IPs
        return remoteAddr.equals("127.0.0.1") ||
               remoteAddr.equals("0:0:0:0:0:0:0:1") ||
               remoteAddr.startsWith("10.0.0.");
    }
}

Testing Examples

Health Indicator Tests

@SpringBootTest
class DatabaseHealthIndicatorTest {

    @Autowired
    private DatabaseHealthIndicator healthIndicator;

    @MockBean
    private DataSource dataSource;

    @Test
    void shouldReturnUpWhenDatabaseIsHealthy() throws Exception {
        Connection connection = mock(Connection.class);
        when(dataSource.getConnection()).thenReturn(connection);
        when(connection.isValid(1000)).thenReturn(true);

        DatabaseMetaData metaData = mock(DatabaseMetaData.class);
        when(connection.getMetaData()).thenReturn(metaData);
        when(metaData.getDatabaseProductName()).thenReturn("PostgreSQL");

        Health health = healthIndicator.health();

        assertThat(health.getStatus()).isEqualTo(Status.UP);
        assertThat(health.getDetails()).containsKey("database");
    }

    @Test
    void shouldReturnDownWhenDatabaseConnectionFails() throws Exception {
        when(dataSource.getConnection()).thenThrow(new SQLException("Connection failed"));

        Health health = healthIndicator.health();

        assertThat(health.getStatus()).isEqualTo(Status.DOWN);
        assertThat(health.getDetails()).containsKey("error");
    }
}

Endpoint Tests

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class ActuatorEndpointIntegrationTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void healthEndpointShouldBeAccessible() throws Exception {
        mockMvc.perform(get("/actuator/health"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.status").value("UP"));
    }

    @Test
    void metricsEndpointShouldListAvailableMetrics() throws Exception {
        mockMvc.perform(get("/actuator/metrics"))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.names").isArray())
            .andExpect(jsonPath("$.names[*]", hasItem("jvm.memory.used")));
    }

    @Test
    void customEndpointShouldWork() throws Exception {
        mockMvc.perform(get("/actuator/features"))
            .andExpect(status().isOk())
            .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }

    @Test
    @WithMockUser(roles = "ADMIN")
    void securedEndpointShouldRequireAuthentication() throws Exception {
        mockMvc.perform(post("/actuator/features/test")
                .contentType(MediaType.APPLICATION_JSON)
                .content("{\"enabled\":true}"))
            .andExpect(status().isOk());
    }
}

Kubernetes Integration Example

Deployment with Probes

apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
      - name: order-service
        image: order-service:1.0.0
        ports:
        - containerPort: 8080
          name: http
        - containerPort: 8081
          name: management
        
        env:
        - name: MANAGEMENT_SERVER_PORT
          value: "8081"
        - name: MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE
          value: "health,info,prometheus"
        
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: management
          initialDelaySeconds: 60
          periodSeconds: 10
          timeoutSeconds: 5
          failureThreshold: 3
        
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: management
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 3
          failureThreshold: 3
        
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
---
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
  - name: http
    port: 8080
    targetPort: http
  - name: management
    port: 8081
    targetPort: management

ServiceMonitor for Prometheus Operator

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: order-service-metrics
  labels:
    app: order-service
spec:
  selector:
    matchLabels:
      app: order-service
  endpoints:
  - port: management
    path: /actuator/prometheus
    interval: 30s
    scrapeTimeout: 10s

plugins

developer-kit-java

skills

README.md

tile.json