← Назад к вопросам

Как подключить сбор метрик

2.0 Middle🔥 121 комментариев
#Другое

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как подключить сбор метрик в Java приложении

Сбор метрик - критический компонент production-ready приложений. Вот полный гайд по подключению.

1. Использование Micrometer (рекомендуется)

Micrometer - это фасад для различных систем мониторинга. Spring Boot по умолчанию использует Micrometer.

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
</dependency>

<!-- Для Prometheus -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- Для DataDog -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-datadog</artifactId>
</dependency>

2. Конфигурация в application.yml

management:
  endpoints:
    web:
      exposure:
        include: prometheus, metrics, health
  metrics:
    enabled: true
    distribution:
      percentiles-histogram:
        http.server.requests: true
      slo:
        http.server.requests: 50ms,100ms,200ms,500ms
  endpoint:
    prometheus:
      enabled: true

3. Базовый пример - счетчики и таймеры

@Service
public class OrderService {
    
    private final MeterRegistry meterRegistry;
    private final Counter orderCount;
    private final Timer orderProcessingTime;
    
    @Autowired
    public OrderService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // Создаем счетчик
        this.orderCount = Counter.builder("orders.created")
            .description("Total number of orders created")
            .register(meterRegistry);
        
        // Создаем таймер
        this.orderProcessingTime = Timer.builder("orders.processing.time")
            .description("Time taken to process orders")
            .publishPercentiles(0.5, 0.95, 0.99)
            .register(meterRegistry);
    }
    
    public void createOrder(Order order) {
        // Использование таймера
        orderProcessingTime.recordCallable(() -> {
            // Логика создания заказа
            // ...
            orderCount.increment();
            return null;
        });
    }
}

4. Gauge - для отслеживания текущих значений

@Configuration
public class MetricsConfig {
    
    @Bean
    public MeterBinder queueSizeMetrics(OrderQueue orderQueue) {
        return (meterRegistry) -> Gauge.builder("order.queue.size", 
                orderQueue::getSize)
            .description("Current size of order queue")
            .register(meterRegistry);
    }
}

public class OrderQueue {
    private Queue<Order> queue = new ConcurrentLinkedQueue<>();
    
    public int getSize() {
        return queue.size();
    }
}

5. Распределение (Distribution) для гистограмм

@Service
public class PaymentService {
    
    private final MeterRegistry meterRegistry;
    
    @Autowired
    public PaymentService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    public void processPayment(BigDecimal amount) {
        Timer.Sample sample = Timer.start(meterRegistry);
        
        try {
            // Логика обработки платежа
            Thread.sleep(100);  // Имитация работы
            
            // Запись метрики с тегами
            meterRegistry.timer("payment.processing.time",
                "currency", "USD",
                "status", "success")
                .record(() -> {});
            
            sample.stop(Timer.builder("payment.duration")
                .description("Payment processing duration")
                .register(meterRegistry));
            
        } catch (Exception e) {
            meterRegistry.timer("payment.processing.time",
                "currency", "USD",
                "status", "failed")
                .record(() -> {});
        }
    }
}

6. Annotation-based метрики

@Service
public class UserService {
    
    private final MeterRegistry meterRegistry;
    
    @Autowired
    public UserService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Timed(value = "user.lookup.time", 
            description = "Time taken to lookup user")
    public User findUserById(String userId) {
        // Логика поиска
        return new User(userId, "John Doe");
    }
}

// Для работы аннотации нужен aspect
@Configuration
@EnableAspectJAutoProxy
public class TimedAspectConfig {
}

7. Prometheus Scrape конфигурация

В Docker Compose:

services:
  app:
    image: my-app:latest
    ports:
      - "8080:8080"
    environment:
      MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE: prometheus
  
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'

prometheon.yml:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'java-app'
    static_configs:
      - targets: ['localhost:8080']
    metrics_path: '/actuator/prometheus'

8. Логирование метрик

@Aspect
@Component
class MetricsAspect {
    
    private static final Logger logger = LoggerFactory.getLogger(MetricsAspect.class);
    private final MeterRegistry meterRegistry;
    
    @Autowired
    public MetricsAspect(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }
    
    @Around("@annotation(Metered)")
    public Object recordMetrics(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        
        Timer.Sample sample = Timer.start(meterRegistry);
        try {
            return joinPoint.proceed();
        } finally {
            sample.stop(Timer.builder("method.execution.time")
                .tag("method", methodName)
                .register(meterRegistry));
        }
    }
}

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

9. Health Check Endpoints

@Component
public class DatabaseHealthIndicator implements HealthIndicator {
    
    private final DataSource dataSource;
    
    @Autowired
    public DatabaseHealthIndicator(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    @Override
    public Health health() {
        try (Connection conn = dataSource.getConnection()) {
            conn.createStatement().execute("SELECT 1");
            return Health.up()
                .withDetail("database", "PostgreSQL")
                .withDetail("url", "jdbc:postgresql://localhost:5432/db")
                .build();
        } catch (Exception e) {
            return Health.down()
                .withException(e)
                .build();
        }
    }
}

10. Интеграция с DataDog

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-datadog</artifactId>
</dependency>
management:
  metrics:
    export:
      datadog:
        enabled: true
        api-key: ${DATADOG_API_KEY}
        application-name: java-app
        host-tag: true
        descriptions: true

11. Трассировка (Tracing) с Jaeger

<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.reporter2</groupId>
    <artifactId>zipkin-reporter</artifactId>
</dependency>
management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans

12. Структурированное логирование

@Service
public class OrderService {
    
    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);
    
    public void processOrder(Order order) {
        logger.info("Processing order", 
            "orderId", order.getId(),
            "amount", order.getAmount(),
            "customerId", order.getCustomerId());
        
        try {
            // Логика
        } catch (Exception e) {
            logger.error("Failed to process order",
                "orderId", order.getId(),
                "error", e.getMessage());
        }
    }
}

Best Practices

  1. Используйте Micrometer - это стандарт Spring Boot
  2. Добавляйте tags - для фильтрации метрик
  3. Экспортируйте в Prometheus - он стал стандартом для мониторинга
  4. Не перегружайте метриками - следите за cardinality
  5. Используйте Health Checks - для диагностики проблем
  6. Настройте алерты - на основе метрик
  7. Мониторьте latency - p50, p95, p99 percentiles
  8. Логируйте структурировано - для анализа логов
  9. Используйте трассировку - для отслеживания запросов
  10. Регулярно анализируйте метрики - для оптимизации
Как подключить сбор метрик | PrepBro