← Назад к вопросам
Какие знаешь способы реализации логирования?
2.0 Middle🔥 261 комментариев
#Spring Boot и Spring Data#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Способы реализации логирования в Java
Логирование — неотъемлемая часть каждого приложения. От выбора подходящего фреймворка и уровня логирования зависит эффективность отладки и мониторинга.
1. Основные уровни логирования
Стандартные уровни от наиболее до наименее серьёзных:
logger.error("Критическая ошибка"); // Ошибка, требующая внимания
logger.warn("Предупреждение"); // Потенциальная проблема
logger.info("Информационное сообщение"); // Важные события
logger.debug("Отладочная информация"); // Для разработки
logger.trace("Трассировка"); // Самая детальная информация
2. SLF4J с Logback (рекомендуемый подход)
SLF4J — фасад, который позволяет менять реализацию без изменения кода:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
public class UserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
public User createUser(CreateUserRequest request) {
logger.info("Creating user: {}", request.getName());
try {
User user = repository.save(mapToUser(request));
logger.info("User created successfully with id: {}", user.getId());
return user;
} catch (Exception e) {
logger.error("Failed to create user", e);
throw e;
}
}
}
logback.xml конфигурация
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Роль консоли -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- Роль файла -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/application.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/application-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10GB</totalSizeCap>
</rollingPolicy>
</appender>
<!-- Уровни логирования по пакетам -->
<logger name="com.myapp" level="DEBUG" />
<logger name="org.springframework" level="INFO" />
<logger name="org.hibernate" level="WARN" />
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>
3. Параметризованные сообщения
Никогда не используй конкатенацию строк:
// ❌ Плохо: конкатенация происходит всегда
logger.debug("User " + user.getName() + " logged in");
// ✅ Хорошо: параметризация (конкатенация только если DEBUG включен)
logger.debug("User {} logged in", user.getName());
// ✅ Множественные параметры
logger.info("User {} with email {} created at {}",
user.getId(), user.getEmail(), user.getCreatedAt());
// ✅ С исключением
logger.error("Failed to process order {}", orderId, exception);
4. Structured Logging (логирование структурированных данных)
Использование MDC (Mapped Diagnostic Context)
import org.slf4j.MDC;
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws Exception {
String requestId = UUID.randomUUID().toString();
MDC.put("requestId", requestId);
MDC.put("userId", getUserId(request));
try {
filterChain.doFilter(request, response);
} finally {
MDC.clear();
}
}
}
// В конфиге logback
<pattern>%d [%X{requestId}] [%X{userId}] %-5level %logger - %msg%n</pattern>
// Результат лога
// 2024-03-22 10:15:30 [a1b2c3d4] [user123] INFO UserService - User created
5. JSON логирование (для машинной обработки)
Logstash Logback Encoder
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.2</version>
</dependency>
<appender name="JSON_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.json</file>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"service":"user-service","env":"prod"}</customFields>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/app-%d{yyyy-MM-dd}.%i.json</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
Результат
{
"@timestamp": "2024-03-22T10:15:30.123Z",
"message": "User created successfully",
"level": "INFO",
"logger_name": "com.myapp.UserService",
"thread_name": "http-nio-8080-exec-1",
"requestId": "a1b2c3d4",
"userId": "user123",
"service": "user-service",
"env": "prod"
}
6. Log Aggregation (ELK Stack)
Отправка логов в Elasticsearch
<appender name="ELASTIC" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/elasticsearch.log</file>
<encoder class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<!-- Filebeat подхватит файл и отправит в Elasticsearch -->
Kibana запрос
kibana_sample_data_logs | stats count() by level
kibana_sample_data_logs | where requestId == "a1b2c3d4" | sort timestamp desc
7. Асинхронное логирование
Для высоконагруженных систем:
<configuration>
<!-- Асинхронный appender -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<queueSize>512</queueSize>
<discardingThreshold>0</discardingThreshold>
<appender-ref ref="FILE" />
</appender>
<root level="INFO">
<appender-ref ref="ASYNC" />
</root>
</configuration>
8. Логирование с Spring Boot
application.properties
logging.level.root=INFO
logging.level.com.myapp=DEBUG
logging.level.org.springframework.web=WARN
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} - %msg%n
logging.file.name=logs/application.log
logging.file.max-size=100MB
logging.file.max-history=30
9. Логирование исключений
@Service
public class PaymentService {
private static final Logger logger = LoggerFactory.getLogger(PaymentService.class);
public Payment processPayment(PaymentRequest request) {
try {
return externalPaymentApi.charge(request);
} catch (NetworkTimeoutException e) {
logger.warn("Payment timeout for order {}, will retry", request.getOrderId(), e);
return retry(request);
} catch (PaymentDeclinedException e) {
logger.error("Payment declined for user {}, order {}, amount {}",
request.getUserId(), request.getOrderId(), request.getAmount(), e);
throw new PaymentFailedException(e);
} catch (Exception e) {
logger.error("Unexpected error processing payment", e);
throw e;
}
}
}
10. Performance Logging
@Component
public class PerformanceLoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(PerformanceLoggingAspect.class);
@Around("@annotation(com.myapp.annotations.Timed)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
logger.info("Method {} executed in {} ms",
joinPoint.getSignature().getName(), duration);
return result;
} catch (Exception e) {
long duration = System.currentTimeMillis() - start;
logger.error("Method {} failed after {} ms",
joinPoint.getSignature().getName(), duration, e);
throw e;
}
}
}
11. Логирование при Debug mode
public class DebugLogger {
private static final Logger logger = LoggerFactory.getLogger(DebugLogger.class);
public static void debugObject(Object obj) {
if (logger.isDebugEnabled()) {
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(obj);
logger.debug("Object: {}", json);
} catch (JsonProcessingException e) {
logger.debug("Failed to serialize object", e);
}
}
}
}
12. Кастомные аннотации для логирования
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogMe {
String value() default "";
boolean logArgs() default true;
boolean logResult() default true;
}
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Around("@annotation(com.myapp.annotations.LogMe)")
public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable {
LogMe annotation = getAnnotation(joinPoint, LogMe.class);
String message = annotation.value();
if (annotation.logArgs()) {
Object[] args = joinPoint.getArgs();
logger.info("{} called with args: {}", message, Arrays.toString(args));
}
Object result = joinPoint.proceed();
if (annotation.logResult()) {
logger.info("{} returned: {}", message, result);
}
return result;
}
}
// Использование
@Service
public class UserService {
@LogMe("Creating new user")
public User createUser(CreateUserRequest request) {
// ...
}
}
Лучшие практики логирования
- Используй SLF4J — универсальный фасад
- Параметризованные сообщения — избегай конкатенации
- Правильные уровни — ERROR для ошибок, DEBUG для отладки
- Структурированное логирование — используй JSON для машинной обработки
- MDC для контекста — requestId, userId, sessionId
- Асинхронное логирование — не замораживай основной поток
- Ротация файлов — не позволяй логам занимать всё место
- Агрегация логов — используй ELK или подобные системы
- Мониторинг и алерты — настрой оповещения о критичных ошибках
- Performance logging — отслеживай медленные операции