Gymterview
middle

Как организовать централизованное логирование?

Централизованное логирование — это сбор логов со всех микросервисов в одном месте для удобного поиска и анализа. Основные стеки: ELK (Elasticsearch + Logstash + Kibana) и Grafana Loki.

Пример
Микросервисы → Logstash (или Filebeat) → Elasticsearch → Kibana
Настройка структурированного логирования (Logback + JSON)
<!-- logback-spring.xml -->
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder class="net.logstash.logback.encoder.LogstashEncoder">
            <includeMdcKeyName>traceId</includeMdcKeyName>
            <includeMdcKeyName>spanId</includeMdcKeyName>
            <customFields>
                {"service":"payment-service","environment":"${ENV}"}
            </customFields>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

Результат — структурированный JSON-лог:

{
  "@timestamp": "2026-04-18T10:30:00.123Z",
  "level": "INFO",
  "service": "payment-service",
  "traceId": "abc123def456",
  "spanId": "span789012",
  "message": "Платёж обработан успешно",
  "paymentId": "PAY-001",
  "amount": 50000,
  "environment": "production"
}

Grafana Loki – альтернатива ELK

Loki не индексирует содержимое логов, а только метки (labels), что делает его значительно дешевле и проще в эксплуатации.

Рекомендации по логированию в микросервисах

  • Всегда включайте traceId — для связывания логов одного запроса.
  • Используйте структурированные логи (JSON) — для удобного поиска и фильтрации.
  • Логируйте бизнес-события — не только ошибки, но и важные бизнес-действия.
  • Не логируйте чувствительные данные — номера карт, пароли, персональные данные (PCI DSS!).
  • Используйте уровни логирования правильно: ERROR — сбои, WARN — нештатные ситуации, INFO — бизнес-события, DEBUG — для отладки (отключено в prod).
Пример правильного логирования
@Slf4j
@Service
public class PaymentService {

    public void processPayment(PaymentRequest request) {
        log.info("Начало обработки платежа: paymentId={}, amount={}, currency={}",
            request.getPaymentId(), request.getAmount(), request.getCurrency());
        try {
            // ... бизнес-логика
            log.info("Платёж успешно обработан: paymentId={}", request.getPaymentId());
        } catch (InsufficientFundsException e) {
            log.warn("Недостаточно средств: paymentId={}, accountId={}",
                request.getPaymentId(), request.getAccountId());
            throw e;
        } catch (Exception e) {
            log.error("Ошибка обработки платежа: paymentId={}",
                request.getPaymentId(), e);
            throw e;
        }
    }
}

На собеседовании: покажите, что знаете стек (ELK или Loki), и что логи должны быть структурированными (JSON) с traceId. Частая ошибка — забыть про маскирование чувствительных данных в логах.