> Для чего нужно логирование (Go)

Уровень: senior · Роль: backend · Язык: Go · Категория: Технические вопросы

Компании: Employcity

Стек: Go

> Пример ответа

Короткий ответ

Логирование - это систематическая запись событий, происходящих в приложении, с целью наблюдения за его работой, диагностики ошибок и анализа поведения системы. В backend-разработке логи - основной источник информации о том, что происходило в production-окружении: какие запросы приходили, как долго обрабатывались, где возникали сбои. Без логирования невозможно эффективно отлаживать распределённые системы, расследовать инциденты и строить наблюдаемость (observability) сервиса.

Подробное объяснение

Логирование решает несколько ключевых задач в backend-разработке:

Диагностика и отладка - когда в production возникает ошибка, логи позволяют воспроизвести последовательность событий, приведших к сбою. Это особенно важно, потому что в production-окружении недоступен debugger, а воспроизведение проблемы локально часто невозможно из-за различий в окружении.

Мониторинг и алертинг - на основе логов строятся метрики и алерты. Например, рост количества ошибок 5xx, увеличение latency или появление специфических panic-сообщений могут автоматически сигнализировать о проблеме до того, как она станет критической.

Аудит и безопасность - логи фиксируют действия пользователей и системных компонентов. Это необходимо для расследования инцидентов безопасности, проверки соответствия требованиям (compliance) и выявления подозрительной активности.

Анализ производительности - логирование времени выполнения операций, длительности SQL-запросов, времени ответа внешних сервисов позволяет выявлять узкие места и деградацию производительности.

Трассировка запросов - в микросервисной архитектуре логи с correlation ID позволяют проследить путь запроса через несколько сервисов, понять, где именно возникла задержка или ошибка.

Бизнес-аналитика - логи содержат информацию о поведении пользователей, частоте использования функций, паттернах нагрузки. Это ценный материал для продуктовых решений.

Ключевые принципы хорошего логирования:

  • Структурированность - логи в формате JSON или key-value, а не свободный текст. Это позволяет парсить и фильтровать их автоматически.
  • Уровни логирования - debug, info, warn, error. Правильное использование уровней позволяет настраивать фильтрацию в зависимости от окружения.
  • Контекст - каждый лог должен содержать достаточно информации для понимания ситуации: request ID, user ID, service name, timestamp.
  • Не логировать чувствительные данные - пароли, токены, персональные данные. Это требование безопасности и законодательства.
  • Асинхронность - запись в лог не должна блокировать основной поток обработки запроса.

На практике

В Go-проектах логирование обычно строится на библиотеках вроде logrus, zap или zerolog. Выбор зависит от требований к производительности и удобству. zap - самый быстрый, logrus - самый популярный и простой, zerolog - хороший баланс.

На практике важно:

  1. Настроить уровни логирования через конфигурацию - в development использовать debug, в production - info и выше.
  2. Использовать middleware для HTTP-серверов - чтобы автоматически логировать каждый входящий запрос с method, path, status code, duration.
  3. Добавлять correlation ID - генерировать при входе запроса в систему и пробрасывать через контекст во все вызовы.
  4. Логировать ошибки с stack trace - но только на уровне error, не на каждый вызов.
  5. Настроить ротацию логов - чтобы файлы не разрастались бесконечно, и интеграцию с системой сбора логов (ELK, Loki, CloudWatch).
  6. Не логировать тела запросов целиком - только если это необходимо для отладки, и то в debug-режиме.

Пример кода

GO
package main
import (
"context"
"net/http"
"time"
"go.uber.org/zap"
)
// middleware для логирования HTTP-запросов
func loggingMiddleware(logger *zap.Logger) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// оборачиваем ResponseWriter, чтобы перехватить status code
wrapped := &responseWriter{ResponseWriter: w, status: http.StatusOK}
next.ServeHTTP(wrapped, r)
logger.Info("http_request",
zap.String("method", r.Method),
zap.String("path", r.URL.Path),
zap.Int("status", wrapped.status),
zap.Duration("duration", time.Since(start)),
zap.String("request_id", getRequestID(r.Context())),
)
})
}
}
type responseWriter struct {
http.ResponseWriter
status int
}
func (rw *responseWriter) WriteHeader(code int) {
rw.status = code
rw.ResponseWriter.WriteHeader(code)
}
// проброс request ID через контекст
type ctxKey string
const requestIDKey ctxKey = "request_id"
func withRequestID(ctx context.Context, id string) context.Context {
return context.WithValue(ctx, requestIDKey, id)
}
func getRequestID(ctx context.Context) string {
if id, ok := ctx.Value(requestIDKey).(string); ok {
return id
}
return "unknown"
}
// пример использования
func main() {
logger, _ := zap.NewProduction()
defer logger.Sync()
mux := http.NewServeMux()
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
handler := loggingMiddleware(logger)(mux)
http.ListenAndServe(":8080", handler)
}

Как отвечать на собеседовании

Начните с краткого определения, затем перечислите основные задачи, которые решает логирование. Обязательно упомяните связь логирования с observability: логи - это один из трёх столпов (logs, metrics, traces). Покажите понимание практических аспектов: структурированные логи, уровни, контекст, производительность.

Если спросят про конкретный стек - расскажите про выбранную библиотеку, её преимущества и недостатки. Например: "zap быстрее logrus, потому что использует zero-allocation при форматировании, но logrus проще в использовании и имеет больше плагинов".

Хорошо, если вы упомянете распределённую трассировку и correlation ID - это показывает понимание реальных проблем микросервисной архитектуры. Также стоит сказать о том, что логирование - это не только про ошибки, но и про бизнес-аналитику и аудит.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание назначения - знает ли кандидат, зачем вообще нужно логирование, а не просто умеет вызывать log.Println.
  • Практический опыт - насколько глубоко кандидат работал с логированием в реальных проектах: настраивал ли middleware, работал ли с системами сбора логов.
  • Архитектурное мышление - понимает ли связь логирования с мониторингом, алертингом, трассировкой.
  • Внимание к деталям - упоминает ли про уровни логирования, структурированность, чувствительные данные, производительность.
  • Знание Go-экосистемы - знаком ли с популярными библиотеками, умеет ли выбрать подходящую под задачу.

Типичные ошибки

  • Ответ "чтобы видеть ошибки" - слишком поверхностно, не показывает понимания полного спектра задач.
  • Путаница между логированием и мониторингом - логи это источник данных, а мониторинг - система сбора и алертинга на основе этих данных.
  • Неупоминание структурированных логов - если кандидат говорит только про текстовые логи, это признак малого опыта.
  • Игнорирование производительности - непонимание того, что синхронное логирование в hot path может сильно замедлить приложение.
  • Отсутствие упоминания безопасности - если кандидат не говорит про чувствительные данные, это красный флаг для senior-позиции.
  • Слишком общий ответ без примеров из практики - senior должен уметь рассказать конкретные кейсы из своего опыта.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью