Logback - одна из наиболее используемых библиотек ведения журнала, замена предшественника Log4j
Состоит из трех классов:
Logger:
Контекст для сообщений журнала. Класс с которым взаимодействуют приложения для создания сообщений
Appenders:
Помещает сообщения в места назначения. У логгера может быть несколько, можно сказать что аппендер привязан к файлу, но он более функционален
Layout:
Форматирование сообщений
Maven зависимости:(?)
<dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.3.5</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.0.4</version> <scope>test</scope> </dependency> # И еще возможно это <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.3.5</version> </dependency>
Минимальный пример:
# Файл logback.xml <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration>
Файл программы:
public class Example { private static final Logger logger = LoggerFactory.getLogger(Example.class); public static void main(String[] args) { logger.info("Example log from {}", Example.class.getSimpleName()); } } # Еще такой пример есть, пока неясно зачем приведение и что ето за класс ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger("com.baeldung.logback"); logger.debug("Hi there!");
Библиотека «logback-core» содержит следующие классы:
«Logback-classic» расширяет перечень:
Журнал отладки конфигурации:
<configuration debug="true"> ... </configuration> # Либо такой метод <configuration> <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" /> ... </configuration>
Автоматическая перезагрузка конфигурации
<configuration scan="true"> ... </configuration> # По умолчанию 60 секунд, можно изменить <configuration scan="true" scanPeriod="15 seconds"> ... </configuration>
Конфигурация логгеров
# Уровень логирования можно задать каждому персонально <configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <logger name="com.baeldung.logback" level="INFO" /> <logger name="com.baeldung.logback.tests" level="WARN" /> <root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration> # Далее использование: Logger foobar = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.foobar"); Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback"); Logger testslogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("com.baeldung.logback.tests"); foobar.debug("This is logged from foobar"); logger.debug("This is not logged from logger"); logger.info("This is logged from logger"); testslogger.info("This is not logged from tests"); testslogger.warn("This is logged from tests");
Переменные
<property name="LOG_DIR" value="/var/log/application" /> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${LOG_DIR}/tests.log</file> <append>true</append> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> # Значение объявлено в первой строке, либо можно указать в аргументах запуска джарки (возможно и через переменные окружения, но это не точно) $ java -DLOG_DIR=/var/log/application com.baeldung.logback.LogbackTests
Файловые аппендеры
<configuration debug="true"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- encoders are assigned the type ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>tests.log</file> <append>true</append> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <logger name="com.baeldung.logback" level="INFO" /> <logger name="com.baeldung.logback.tests" level="WARN"> <appender-ref ref="FILE" /> </logger> <root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration>
Ротируемый аппендер
<property name="LOG_FILE" value="LogFile" /> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOG_FILE}.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern> <!-- keep 30 days' worth of history capped at 3GB total size --> <maxHistory>30</maxHistory> <totalSizeCap>3GB</totalSizeCap> </rollingPolicy> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender>
Отдельный класс
Для того чтобы перенаправить определенные сообщение в какой либо файл, создаем ему отдельный логгер, указав любое имя, создаем ему аппендер, с нужной конфигурацией, и в логере указываем additivity=«false» чтобы сообщение не передавалось дальше
# Параметризованные сообщения # фигурные скобки используют "toString()" при возможности/необходимости log.debug("Current count is " + count); log.debug("Current count is {}", count); logger.debug("Going to divide {} by {}", 42, zero);
Например
<encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder>
root-логер является корневым, перехватывает все, с заданным уровнем
В апендерах можно настроить фильтрацию, в основном по уровню, но как то особо не развернешься с одними только ими
Есть вариант создавать свои логеры, но там нужно указывать класс, с которого идет обращения сообщения, из приложения, тобишь в приложении нужно создавать объект логера с таким же (или базовым) классом.
Вроде вариант, но базовый логер эти сообщения тоже перехватывает
Пример с разделением на три файла, общий, ошибки и спец файл, в него пишется из отдельного класса, правда в общие файлы эти сообщения тоже попадают т.к. там корневой логер
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property name="LOGS" value="./logs" /> <appender name="Console" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern> %d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n </pattern> </encoder> </appender> <appender name="SystemLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOGS}/system.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n</Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily and when the file reaches 10 MegaBytes --> <fileNamePattern>${LOGS}/archived/system_%d{yyyy-MM-dd}_%i.log.zip </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>50MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> </appender> <appender name="ErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOGS}/error.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n</Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily and when the file reaches 10 MegaBytes --> <fileNamePattern>${LOGS}/archived/error_%d{yyyy-MM-dd}_%i.log.zip </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>50MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> </appender> <appender name="WebappLog" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${LOGS}/webapp.log</file> <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> <Pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n</Pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- rollover daily and when the file reaches 10 MegaBytes --> <fileNamePattern>${LOGS}/archived/webapp_%d{yyyy-MM-dd}_%i.log.zip </fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>50MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>ERROR</level> </filter> </appender> <logger name="com.baeldung.logback" level="INFO"> <appender-ref ref="webapp" /> </logger> <root level="info"> <appender-ref ref="SystemLog" /> <appender-ref ref="Console" /> <appender-ref ref="ErrorLog"/> </root> </configuration>
private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Logger waLogger = LoggerFactory.getLogger("com.baeldung.logback"); logger.info("Запись в лог"); waLogger.info("(WA) Запись в лог");
<appender name="Commands" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>./logs/commands/commands.log</file> <append>true</append> <encoder> <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} %-5level - %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>./logs/commands/commands-%d{yyyy-MM-dd}.log.zip</fileNamePattern> <maxHistory>50</maxHistory> </rollingPolicy> </appender> (...) <logger name="com.gmware.lib.commands" level="INFO" additivity="false"> <appender-ref ref="Commands"/> </logger>
<?xml version="1.0" encoding="UTF-8" ?> <configuration scan="false" scanPeriod="1 seconds" debug="false"> <appender name="ConsoleAppender" class="ch.qos.logback.core.ConsoleAppender"> <target>System.out</target> <encoder> <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <appender name="FileMultiplicatorDefaultAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>./log/FileMultiplicator.log</file> <append>true</append> <encoder> <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>log/FileMultiplicator-%d{yyyy-MM-dd}.%i.zip</fileNamePattern> <!-- each file should be at most 100MB, keep 7 days worth of history, but at most 20GB --> <maxFileSize>100MB</maxFileSize> <maxHistory>7</maxHistory> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> </appender> <appender name="FileMultiplicatorJsonAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>log/json/FileMultiplicator.log</file> <append>true</append> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <pattern> <!-- the pattern that defines what to include --> <pattern> { "timestamp": "%date{yyyy-MM-dd'T'HH:mm:ss}", "logger": "%logger{36}", "message": "%message", "level": "%level" } </pattern> </pattern> <arguments/> <logstashMarkers/> <stackTrace> <throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter"> <maxDepthPerThrowable>30</maxDepthPerThrowable> <maxLength>2048</maxLength> <shortenedClassNameLength>20</shortenedClassNameLength> <exclude>^sun\.reflect\..*\.invoke</exclude> <exclude>^net\.sf\.cglib\.proxy\.MethodProxy\.invoke</exclude> <rootCauseFirst>true</rootCauseFirst> </throwableConverter> </stackTrace> </providers> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>log/json/FileMultiplicator-%d{yyyy-MM-dd}.%i.zip</fileNamePattern> <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB --> <maxFileSize>100MB</maxFileSize> <maxHistory>7</maxHistory> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> </appender> <appender name="Commands" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>./log/commands/commands.log</file> <append>true</append> <encoder> <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} %-5level - %msg%n</pattern> </encoder> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!-- daily rollover --> <fileNamePattern>./log/commands/commands-%d{yyyy-MM-dd}.log.zip</fileNamePattern> <maxHistory>50</maxHistory> </rollingPolicy> </appender> <root level="INFO"> <!-- <appender-ref ref="ConsoleAppender"/>--> <appender-ref ref="FileMultiplicatorDefaultAppender"/> <appender-ref ref="FileMultiplicatorJsonAppender"/> </root> <logger name="com.gmware.lib.commands" level="INFO" additivity="false"> <appender-ref ref="Commands"/> </logger> </configuration>
Аппендер класса «RollingFileAppender» расширяет класс «FileAppender», добавляя возможность ротирования файлов
Два важных подкомпонента: RollingPolicy («что делать») и TriggeringPolicy («когда это делать»)
Первый может реализовать интерфейс для второго, тогда достаточно указать только его
Внутри аппендера создается xml компонент политики, имеются разные классы, определяющие поведение
TimeBasedRollingPolicy - На основе времени, один обязательный аргумент «fileNamePattern», так же есть «MaxHistory»
Шаблон имени должен сдержать спецификатор «%d», тот может содержать шаблон даты/времени, по умолчанию «гггг-ММ-дд». Период ротирования выводится из значения в fileNamePattern
т.е. в данном случае в полночь, если время не указано
Сжатие - для этого нужно добавить расширение «gz/zip» к имени файла
SizeAndTimeBaseRollingPolicy - собсна по дате и размеру. Здесь добавляется еще один обязательный токен именования - «%i», обозначающий порядковый номер
Пример конфигурации
<configuration> <appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>mylog.txt</file> <append>true</append> <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"> <!-- rollover daily --> <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern> <maxFileSize>100MB</maxFileSize> <maxHistory>60</maxHistory> <totalSizeCap>20GB</totalSizeCap> </rollingPolicy> <encoder> <pattern>%d{yyyy-MM-dd} %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n </pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="ROLLING" /> </root> </configuration>