☕ @metrics - Metrics Function in Java

Java Documentation

@metrics - Metrics Function in Java

The @metrics operator provides comprehensive metrics collection and monitoring capabilities for Java applications, integrating with Spring Boot's Micrometer, Prometheus, and enterprise monitoring systems.

Basic Syntax

// TuskLang configuration
response_time: @metrics("response_time_ms", 150)
error_rate: @metrics("error_rate_percent", 2.5)
throughput: @metrics("requests_per_second", 1000)
// Java Spring Boot integration
@Configuration
public class MetricsConfig {
    
    @Bean
    public MetricsService metricsService(MeterRegistry meterRegistry) {
        return MetricsService.builder()
            .meterRegistry(meterRegistry)
            .enablePrometheus(true)
            .enableJmx(true)
            .build();
    }
}

Basic Metrics

// Java metrics service
@Component
public class MetricsService {
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    private final Map<String, Timer> timers = new ConcurrentHashMap<>();
    private final Map<String, Counter> counters = new ConcurrentHashMap<>();
    private final Map<String, Gauge> gauges = new ConcurrentHashMap<>();
    
    public void recordMetric(String name, double value) {
        Gauge.builder(name)
            .register(meterRegistry, () -> value);
    }
    
    public void recordMetric(String name, double value, Map<String, String> tags) {
        Gauge.builder(name)
            .tags(tags.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry, () -> value);
    }
    
    public void incrementCounter(String name) {
        Counter.builder(name)
            .register(meterRegistry)
            .increment();
    }
    
    public void incrementCounter(String name, Map<String, String> tags) {
        Counter.builder(name)
            .tags(tags.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry)
            .increment();
    }
    
    public Timer.Sample startTimer(String name) {
        return Timer.start(meterRegistry);
    }
    
    public void stopTimer(Timer.Sample sample, String name) {
        sample.stop(Timer.builder(name).register(meterRegistry));
    }
    
    public void stopTimer(Timer.Sample sample, String name, Map<String, String> tags) {
        sample.stop(Timer.builder(name)
            .tags(tags.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry));
    }
}
// TuskLang metrics
metrics_config: {
    # Basic metrics
    response_time: @metrics("response_time_ms", 150)
    error_rate: @metrics("error_rate_percent", 2.5)
    throughput: @metrics("requests_per_second", 1000)
    
    # Metrics with tags
    api_response_time: @metrics("api_response_time_ms", 200, {
        endpoint: "/api/users"
        method: "GET"
        status: "200"
    })
    
    # Counter metrics
    request_count: @metrics.counter("requests_total")
    error_count: @metrics.counter("errors_total")
    
    # Timer metrics
    database_query_time: @metrics.timer("database_query_time_ms")
    external_api_time: @metrics.timer("external_api_time_ms")
}

Performance Metrics

// Java performance metrics
@Component
public class PerformanceMetricsService {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public void recordResponseTime(String endpoint, String method, int statusCode, long duration) {
        Map<String, String> tags = Map.of(
            "endpoint", endpoint,
            "method", method,
            "status", String.valueOf(statusCode)
        );
        
        Timer.builder("http.server.requests")
            .tags(tags.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry)
            .record(duration, TimeUnit.MILLISECONDS);
    }
    
    public void recordThroughput(String operation, long count) {
        Counter.builder("throughput")
            .tag("operation", operation)
            .register(meterRegistry)
            .increment(count);
    }
    
    public void recordErrorRate(String operation, double errorRate) {
        Gauge.builder("error_rate")
            .tag("operation", operation)
            .register(meterRegistry, () -> errorRate);
    }
    
    public void recordMemoryUsage() {
        Runtime runtime = Runtime.getRuntime();
        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
        long maxMemory = runtime.maxMemory();
        
        Gauge.builder("jvm.memory.used")
            .register(meterRegistry, () -> usedMemory);
        
        Gauge.builder("jvm.memory.max")
            .register(meterRegistry, () -> maxMemory);
        
        Gauge.builder("jvm.memory.usage")
            .register(meterRegistry, () -> (double) usedMemory / maxMemory * 100);
    }
    
    public void recordCpuUsage() {
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        
        Gauge.builder("system.cpu.usage")
            .register(meterRegistry, () -> osBean.getSystemLoadAverage());
        
        Gauge.builder("system.cpu.count")
            .register(meterRegistry, () -> osBean.getAvailableProcessors());
    }
}
// TuskLang performance metrics
performance_metrics: {
    # Response time metrics
    api_response_time: @metrics.performance("api_response_time_ms", 200, {
        endpoint: "/api/users"
        method: "GET"
    })
    
    # Throughput metrics
    requests_per_second: @metrics.performance("requests_per_second", 1000)
    transactions_per_second: @metrics.performance("transactions_per_second", 500)
    
    # Error rate metrics
    error_rate: @metrics.performance("error_rate_percent", 2.5)
    failure_rate: @metrics.performance("failure_rate_percent", 1.0)
    
    # Memory metrics
    memory_usage: @metrics.performance("memory_usage_percent", 75.0)
    heap_usage: @metrics.performance("heap_usage_percent", 60.0)
    
    # CPU metrics
    cpu_usage: @metrics.performance("cpu_usage_percent", 45.0)
    cpu_load: @metrics.performance("cpu_load_average", 2.5)
}

Business Metrics

// Java business metrics
@Component
public class BusinessMetricsService {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public void recordUserRegistration(String source) {
        Counter.builder("user.registrations")
            .tag("source", source)
            .register(meterRegistry)
            .increment();
    }
    
    public void recordOrderValue(String productCategory, double value) {
        Timer.builder("order.value")
            .tag("category", productCategory)
            .register(meterRegistry)
            .record(value, TimeUnit.MILLISECONDS);
    }
    
    public void recordConversionRate(String funnel, double rate) {
        Gauge.builder("conversion.rate")
            .tag("funnel", funnel)
            .register(meterRegistry, () -> rate);
    }
    
    public void recordCustomerSatisfaction(String product, double score) {
        Gauge.builder("customer.satisfaction")
            .tag("product", product)
            .register(meterRegistry, () -> score);
    }
    
    public void recordRevenue(String region, double amount) {
        Counter.builder("revenue.total")
            .tag("region", region)
            .register(meterRegistry)
            .increment((long) amount);
    }
}
// TuskLang business metrics
business_metrics: {
    # User metrics
    user_registrations: @metrics.business("user_registrations_total", 150)
    active_users: @metrics.business("active_users", 1000)
    user_retention: @metrics.business("user_retention_rate", 85.5)
    
    # Revenue metrics
    total_revenue: @metrics.business("total_revenue", 50000.0)
    average_order_value: @metrics.business("average_order_value", 125.0)
    revenue_growth: @metrics.business("revenue_growth_percent", 15.5)
    
    # Conversion metrics
    conversion_rate: @metrics.business("conversion_rate", 3.2)
    cart_abandonment: @metrics.business("cart_abandonment_rate", 68.0)
    
    # Customer metrics
    customer_satisfaction: @metrics.business("customer_satisfaction_score", 4.5)
    customer_lifetime_value: @metrics.business("customer_lifetime_value", 2500.0)
}

Custom Metrics

// Java custom metrics
@Component
public class CustomMetricsService {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public void recordCustomMetric(String name, double value, String... tags) {
        if (tags.length % 2 != 0) {
            throw new IllegalArgumentException("Tags must be key-value pairs");
        }
        
        Map<String, String> tagMap = new HashMap<>();
        for (int i = 0; i < tags.length; i += 2) {
            tagMap.put(tags[i], tags[i + 1]);
        }
        
        Gauge.builder(name)
            .tags(tagMap.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry, () -> value);
    }
    
    public void recordHistogram(String name, double value, String... tags) {
        if (tags.length % 2 != 0) {
            throw new IllegalArgumentException("Tags must be key-value pairs");
        }
        
        Map<String, String> tagMap = new HashMap<>();
        for (int i = 0; i < tags.length; i += 2) {
            tagMap.put(tags[i], tags[i + 1]);
        }
        
        Histogram.builder(name)
            .tags(tagMap.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry)
            .record(value);
    }
    
    public void recordDistributionSummary(String name, double value, String... tags) {
        if (tags.length % 2 != 0) {
            throw new IllegalArgumentException("Tags must be key-value pairs");
        }
        
        Map<String, String> tagMap = new HashMap<>();
        for (int i = 0; i < tags.length; i += 2) {
            tagMap.put(tags[i], tags[i + 1]);
        }
        
        DistributionSummary.builder(name)
            .tags(tagMap.entrySet().stream()
                .map(entry -> Tag.of(entry.getKey(), entry.getValue()))
                .collect(Collectors.toList()))
            .register(meterRegistry)
            .record(value);
    }
}
// TuskLang custom metrics
custom_metrics: {
    # Custom gauge metrics
    custom_gauge: @metrics.custom("custom_gauge", 42.0, {
        label1: "value1"
        label2: "value2"
    })
    
    # Custom histogram metrics
    custom_histogram: @metrics.custom.histogram("custom_histogram", 150.0, {
        bucket: "response_time"
        threshold: "200ms"
    })
    
    # Custom distribution summary
    custom_distribution: @metrics.custom.distribution("custom_distribution", 1000.0, {
        operation: "database_query"
        table: "users"
    })
    
    # Custom counter with tags
    custom_counter: @metrics.custom.counter("custom_counter", {
        operation: "file_upload"
        status: "success"
    })
}

Metrics Aggregation

// Java metrics aggregation
@Component
public class MetricsAggregationService {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public AggregatedMetrics aggregateMetrics(String metricName, Duration window) {
        List<Meter> meters = meterRegistry.find(metricName).meters();
        
        double sum = 0.0;
        double min = Double.MAX_VALUE;
        double max = Double.MIN_VALUE;
        int count = 0;
        
        for (Meter meter : meters) {
            if (meter instanceof Gauge) {
                double value = ((Gauge) meter).value();
                sum += value;
                min = Math.min(min, value);
                max = Math.max(max, value);
                count++;
            }
        }
        
        return AggregatedMetrics.builder()
            .metricName(metricName)
            .sum(sum)
            .min(min)
            .max(max)
            .average(count > 0 ? sum / count : 0.0)
            .count(count)
            .window(window)
            .build();
    }
    
    public Map<String, Double> getPercentiles(String metricName, double... percentiles) {
        Timer timer = Timer.builder(metricName).register(meterRegistry);
        
        Map<String, Double> results = new HashMap<>();
        for (double percentile : percentiles) {
            double value = timer.percentile(percentile, TimeUnit.MILLISECONDS);
            results.put("p" + (int) (percentile * 100), value);
        }
        
        return results;
    }
}
// TuskLang metrics aggregation
metrics_aggregation: {
    # Aggregated metrics
    aggregated_response_time: @metrics.aggregate("response_time_ms", {
        window: "5m"
        functions: ["sum", "avg", "min", "max", "count"]
    })
    
    # Percentile metrics
    response_time_percentiles: @metrics.percentiles("response_time_ms", [0.5, 0.9, 0.95, 0.99])
    
    # Rolling averages
    rolling_avg_response_time: @metrics.rolling_average("response_time_ms", "1m")
    rolling_avg_error_rate: @metrics.rolling_average("error_rate", "5m")
    
    # Rate calculations
    request_rate: @metrics.rate("requests_total", "1m")
    error_rate: @metrics.rate("errors_total", "1m")
}

Metrics Export

// Java metrics export
@Component
public class MetricsExportService {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public String exportPrometheusFormat() {
        StringBuilder sb = new StringBuilder();
        
        for (Meter meter : meterRegistry.getMeters()) {
            if (meter instanceof Gauge) {
                Gauge gauge = (Gauge) meter;
                sb.append(formatPrometheusMetric(gauge.getId(), gauge.value()));
            } else if (meter instanceof Counter) {
                Counter counter = (Counter) meter;
                sb.append(formatPrometheusMetric(counter.getId(), counter.count()));
            } else if (meter instanceof Timer) {
                Timer timer = (Timer) meter;
                sb.append(formatPrometheusMetric(timer.getId(), timer.totalTime(TimeUnit.SECONDS)));
            }
        }
        
        return sb.toString();
    }
    
    public Map<String, Object> exportJsonFormat() {
        Map<String, Object> metrics = new HashMap<>();
        
        for (Meter meter : meterRegistry.getMeters()) {
            Map<String, Object> metricData = new HashMap<>();
            metricData.put("type", meter.getId().getType().name());
            metricData.put("tags", meter.getId().getTags());
            
            if (meter instanceof Gauge) {
                metricData.put("value", ((Gauge) meter).value());
            } else if (meter instanceof Counter) {
                metricData.put("value", ((Counter) meter).count());
            } else if (meter instanceof Timer) {
                Timer timer = (Timer) meter;
                metricData.put("total_time", timer.totalTime(TimeUnit.MILLISECONDS));
                metricData.put("count", timer.count());
                metricData.put("mean", timer.mean(TimeUnit.MILLISECONDS));
            }
            
            metrics.put(meter.getId().getName(), metricData);
        }
        
        return metrics;
    }
    
    private String formatPrometheusMetric(Meter.Id id, double value) {
        StringBuilder sb = new StringBuilder();
        sb.append(id.getName());
        
        if (!id.getTags().isEmpty()) {
            sb.append("{");
            sb.append(id.getTags().stream()
                .map(tag -> tag.getKey() + "=\"" + tag.getValue() + "\"")
                .collect(Collectors.joining(",")));
            sb.append("}");
        }
        
        sb.append(" ").append(value).append("\n");
        return sb.toString();
    }
}
// TuskLang metrics export
metrics_export: {
    # Export to Prometheus format
    prometheus_metrics: @metrics.export.prometheus()
    
    # Export to JSON format
    json_metrics: @metrics.export.json()
    
    # Export specific metrics
    custom_export: @metrics.export.custom({
        format: "json"
        metrics: ["response_time", "error_rate", "throughput"]
        include_tags: true
    })
    
    # Export with filtering
    filtered_export: @metrics.export.filter({
        format: "prometheus"
        include: ["api.", "database."]
        exclude: ["debug.", "test."]
    })
}

Metrics Alerting

// Java metrics alerting
@Component
public class MetricsAlertingService {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    public void checkAlerts() {
        checkResponseTimeAlert();
        checkErrorRateAlert();
        checkMemoryUsageAlert();
        checkCpuUsageAlert();
    }
    
    private void checkResponseTimeAlert() {
        Timer responseTimeTimer = Timer.builder("http.server.requests").register(meterRegistry);
        double p95ResponseTime = responseTimeTimer.percentile(0.95, TimeUnit.MILLISECONDS);
        
        if (p95ResponseTime > 500) {
            sendAlert("High response time detected", Map.of(
                "metric", "response_time_p95",
                "value", p95ResponseTime,
                "threshold", 500
            ));
        }
    }
    
    private void checkErrorRateAlert() {
        Counter errorCounter = Counter.builder("http.server.requests")
            .tag("status", "5xx")
            .register(meterRegistry);
        
        Counter totalCounter = Counter.builder("http.server.requests").register(meterRegistry);
        
        double errorRate = totalCounter.count() > 0 ? 
            (errorCounter.count() / totalCounter.count()) * 100 : 0;
        
        if (errorRate > 5.0) {
            sendAlert("High error rate detected", Map.of(
                "metric", "error_rate",
                "value", errorRate,
                "threshold", 5.0
            ));
        }
    }
    
    private void checkMemoryUsageAlert() {
        Runtime runtime = Runtime.getRuntime();
        double memoryUsage = (double) (runtime.totalMemory() - runtime.freeMemory()) / runtime.maxMemory() * 100;
        
        if (memoryUsage > 90) {
            sendAlert("High memory usage detected", Map.of(
                "metric", "memory_usage",
                "value", memoryUsage,
                "threshold", 90
            ));
        }
    }
    
    private void checkCpuUsageAlert() {
        OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
        double cpuLoad = osBean.getSystemLoadAverage();
        
        if (cpuLoad > 0.8) {
            sendAlert("High CPU usage detected", Map.of(
                "metric", "cpu_load",
                "value", cpuLoad,
                "threshold", 0.8
            ));
        }
    }
    
    private void sendAlert(String message, Map<String, Object> details) {
        // Implementation for sending alerts (email, Slack, etc.)
        log.warn("Alert: {} - Details: {}", message, details);
    }
}
// TuskLang metrics alerting
metrics_alerting: {
    # Response time alerts
    response_time_alert: @metrics.alert("response_time_ms", {
        threshold: 500
        condition: ">"
        severity: "warning"
        message: "High response time detected"
    })
    
    # Error rate alerts
    error_rate_alert: @metrics.alert("error_rate_percent", {
        threshold: 5.0
        condition: ">"
        severity: "critical"
        message: "High error rate detected"
    })
    
    # Memory usage alerts
    memory_alert: @metrics.alert("memory_usage_percent", {
        threshold: 90
        condition: ">"
        severity: "warning"
        message: "High memory usage detected"
    })
    
    # Custom alert conditions
    custom_alert: @metrics.alert.custom({
        metric: "custom_metric"
        condition: "value > threshold * 2"
        threshold: 100
        severity: "critical"
        message: "Custom alert triggered"
    })
}

Metrics Testing

// JUnit test for metrics
@SpringBootTest
class MetricsServiceTest {
    
    @Autowired
    private MetricsService metricsService;
    
    @Autowired
    private MeterRegistry meterRegistry;
    
    @Test
    void testRecordMetric() {
        metricsService.recordMetric("test_metric", 42.0);
        
        Gauge gauge = meterRegistry.find("test_metric").gauge();
        assertThat(gauge).isNotNull();
        assertThat(gauge.value()).isEqualTo(42.0);
    }
    
    @Test
    void testIncrementCounter() {
        metricsService.incrementCounter("test_counter");
        
        Counter counter = meterRegistry.find("test_counter").counter();
        assertThat(counter).isNotNull();
        assertThat(counter.count()).isEqualTo(1.0);
    }
    
    @Test
    void testTimer() {
        Timer.Sample sample = metricsService.startTimer("test_timer");
        Thread.sleep(100); // Simulate work
        metricsService.stopTimer(sample, "test_timer");
        
        Timer timer = meterRegistry.find("test_timer").timer();
        assertThat(timer).isNotNull();
        assertThat(timer.count()).isEqualTo(1);
        assertThat(timer.totalTime(TimeUnit.MILLISECONDS)).isGreaterThan(0);
    }
    
    @Test
    void testMetricsWithTags() {
        Map<String, String> tags = Map.of("tag1", "value1", "tag2", "value2");
        metricsService.recordMetric("test_metric_with_tags", 100.0, tags);
        
        Gauge gauge = meterRegistry.find("test_metric_with_tags").gauge();
        assertThat(gauge).isNotNull();
        assertThat(gauge.getId().getTags()).contains(
            Tag.of("tag1", "value1"),
            Tag.of("tag2", "value2")
        );
    }
}
// TuskLang metrics testing
test_metrics: {
    # Test basic metrics
    test_metric: @metrics("test_metric", 42.0)
    assert(@test_metric == 42.0, "Metric should be recorded correctly")
    
    # Test counter metrics
    @metrics.counter("test_counter")
    assert(@metrics.get("test_counter") > 0, "Counter should be incremented")
    
    # Test timer metrics
    timer_result: @metrics.timer("test_timer", {
        operation: "test_operation"
    })
    assert(@timer_result.duration > 0, "Timer should record duration")
    
    # Test metrics with tags
    tagged_metric: @metrics("test_tagged_metric", 100.0, {
        tag1: "value1"
        tag2: "value2"
    })
    assert(@tagged_metric == 100.0, "Tagged metric should be recorded correctly")
}

Best Practices

1. Metrics Naming Convention

// Use consistent naming conventions
@Component
public class MetricsNamingService {
    
    @Autowired
    private MetricsService metricsService;
    
    public void recordHttpMetric(String endpoint, String method, int statusCode, long duration) {
        // Use dot notation for hierarchical metrics
        String metricName = "http.server.requests";
        
        Map<String, String> tags = Map.of(
            "endpoint", endpoint,
            "method", method,
            "status", String.valueOf(statusCode)
        );
        
        metricsService.recordMetric(metricName, duration, tags);
    }
    
    public void recordDatabaseMetric(String operation, String table, long duration) {
        // Use consistent naming for database metrics
        String metricName = "database.operations";
        
        Map<String, String> tags = Map.of(
            "operation", operation,
            "table", table
        );
        
        metricsService.recordMetric(metricName, duration, tags);
    }
    
    public void recordBusinessMetric(String event, String category, double value) {
        // Use business-specific naming
        String metricName = "business." + event;
        
        Map<String, String> tags = Map.of(
            "category", category
        );
        
        metricsService.recordMetric(metricName, value, tags);
    }
}

2. Metrics Cardinality Management

// Manage metrics cardinality to prevent explosion
@Component
public class MetricsCardinalityService {
    
    @Autowired
    private MetricsService metricsService;
    
    public void recordUserMetric(String userId, String action) {
        // Use bounded sets for high-cardinality values
        String boundedUserId = boundUserId(userId);
        
        Map<String, String> tags = Map.of(
            "user_id", boundedUserId,
            "action", action
        );
        
        metricsService.incrementCounter("user.actions", tags);
    }
    
    private String boundUserId(String userId) {
        // Limit cardinality by using user segments instead of individual IDs
        if (userId.length() > 10) {
            return userId.substring(0, 10) + "...";
        }
        return userId;
    }
    
    public void recordRequestMetric(String url, String method) {
        // Normalize URLs to reduce cardinality
        String normalizedUrl = normalizeUrl(url);
        
        Map<String, String> tags = Map.of(
            "url", normalizedUrl,
            "method", method
        );
        
        metricsService.incrementCounter("http.requests", tags);
    }
    
    private String normalizeUrl(String url) {
        // Remove dynamic parts from URLs
        return url.replaceAll("/\\d+", "/{id}")
                 .replaceAll("/[a-f0-9]{8,}", "/{hash}");
    }
}

3. Metrics Performance Optimization

// Optimize metrics collection for performance
@Component
public class MetricsPerformanceService {
    
    @Autowired
    private MetricsService metricsService;
    
    private final Map<String, Timer.Sample> activeTimers = new ConcurrentHashMap<>();
    
    public void startOperationTimer(String operationId) {
        Timer.Sample sample = Timer.start();
        activeTimers.put(operationId, sample);
    }
    
    public void stopOperationTimer(String operationId, String operationName) {
        Timer.Sample sample = activeTimers.remove(operationId);
        if (sample != null) {
            metricsService.stopTimer(sample, "operation.duration", 
                Map.of("operation", operationName));
        }
    }
    
    public void recordBatchMetrics(List<MetricData> metrics) {
        // Batch metrics recording for better performance
        for (MetricData metric : metrics) {
            metricsService.recordMetric(metric.getName(), metric.getValue(), metric.getTags());
        }
    }
    
    @Scheduled(fixedRate = 60000) // Every minute
    public void recordSystemMetrics() {
        // Record system metrics periodically
        recordMemoryMetrics();
        recordCpuMetrics();
        recordGcMetrics();
    }
    
    private void recordMemoryMetrics() {
        Runtime runtime = Runtime.getRuntime();
        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
        
        metricsService.recordMetric("jvm.memory.used", usedMemory);
        metricsService.recordMetric("jvm.memory.max", runtime.maxMemory());
    }
}

The @metrics operator in Java provides comprehensive metrics collection and monitoring capabilities that enable applications to track performance, business metrics, and system health in enterprise environments.