Комментарии (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
- Используйте Micrometer - это стандарт Spring Boot
- Добавляйте tags - для фильтрации метрик
- Экспортируйте в Prometheus - он стал стандартом для мониторинга
- Не перегружайте метриками - следите за cardinality
- Используйте Health Checks - для диагностики проблем
- Настройте алерты - на основе метрик
- Мониторьте latency - p50, p95, p99 percentiles
- Логируйте структурировано - для анализа логов
- Используйте трассировку - для отслеживания запросов
- Регулярно анализируйте метрики - для оптимизации