====== Логирование ====== ===== Сведения =====
:!: Logback **Logback** - одна из наиболее используемых библиотек ведения журнала, замена предшественника **Log4j**\\ Состоит из трех классов:\\ **Logger**:\\ Контекст для сообщений журнала. Класс с которым взаимодействуют приложения для создания сообщений\\ **Appenders**:\\ Помещает сообщения в места назначения. У логгера может быть несколько, можно сказать что аппендер привязан к файлу, но он более функционален\\ **Layout**:\\ Форматирование сообщений\\ Maven зависимости:(?)\\ ch.qos.logback logback-core 1.3.5 org.slf4j slf4j-api 2.0.4 test # И еще возможно это ch.qos.logback logback-classic 1.3.5 Минимальный пример: # Файл logback.xml %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n Файл программы: 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!");
:!: Уровни * TRACE — самый низкий уровень информации, в основном используемый для очень глубокой отладки кода, обычно не включаемый в производственные журналы. * DEBUG — информация низкого уровня, используемая для целей отладки, обычно не включаемая в производственные журналы. * INFO — серьезность журнала, содержащая информацию, например, о начавшейся или завершенной операции. * WARN – уровень журнала, информирующий о событии, которое может потребовать нашего внимания, но не является критическим и может быть ожидаемым. * ОШИБКА — уровень журнала, сообщающий об ошибке, ожидаемой или неожиданной, обычно означающей, что часть системы работает неправильно. Библиотека "logback-core" содержит следующие классы:\\ * ConsoleAppender — добавляет события журнала в System.out или System.err. * OutputStreamAppender — добавляет события журнала в java.io.Outputstream, предоставляя базовые услуги для других приложений. * FileAppender — добавляет события журнала в файл. * RollingFileAppender — добавляет события журнала в файл с возможностью автоматического переключения файлов. "Logback-classic" расширяет перечень:\\ * SocketAppender — добавляет события журнала в сокет * SSLSocketAppender — добавляет события журнала в сокет, используя безопасное соединение. * SMTPAppender — накапливает данные в пакетах и ​​отправляет содержимое пакета на указанный пользователем адрес электронной почты после наступления указанного пользователем события. * DBAppender — добавляет данные в таблицы базы данных * SyslogAppender — добавляет данные в место назначения, совместимое с Syslog. * SiftingAppender — приложение, которое может разделять ведение журнала в соответствии с заданным атрибутом времени выполнения. * AsyncAppender — асинхронно добавляет события журнала.
===== Конфигурация =====
:!: Конфигурация Журнал отладки конфигурации: ... # Либо такой метод ... Автоматическая перезагрузка конфигурации ... # По умолчанию 60 секунд, можно изменить ... Конфигурация логгеров # Уровень логирования можно задать каждому персонально %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n # Далее использование: 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"); Переменные ${LOG_DIR}/tests.log true %-4relative [%thread] %-5level %logger{35} - %msg%n # Значение объявлено в первой строке, либо можно указать в аргументах запуска джарки (возможно и через переменные окружения, но это не точно) $ java -DLOG_DIR=/var/log/application com.baeldung.logback.LogbackTests
:!: Appenders Файловые аппендеры %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n tests.log true %-4relative [%thread] %-5level %logger{35} - %msg%n Ротируемый аппендер ${LOG_FILE}.log ${LOG_FILE}.%d{yyyy-MM-dd}.gz 30 3GB %-4relative [%thread] %-5level %logger{35} - %msg%n
===== Использование =====
:!: Приемы/детали **Отдельный класс**\\ Для того чтобы перенаправить определенные сообщение в какой либо файл, создаем ему отдельный логгер, указав любое имя, создаем ему аппендер, с нужной конфигурацией, и в логере указываем **additivity="false"** чтобы сообщение не передавалось дальше\\ # Параметризованные сообщения # фигурные скобки используют "toString()" при возможности/необходимости log.debug("Current count is " + count); log.debug("Current count is {}", count); logger.debug("Going to divide {} by {}", 42, zero);
:!: Макеты Например %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n * %d{HH:mm:ss.SSS} – метка времени с часами, минутами, секундами и миллисекундами * [%thread] — имя потока, создающего сообщение журнала, заключенное в квадратные скобки. * %-5level — уровень события логирования, дополненный до 5 символов * %logger{36} – имя логгера , усеченное до 35 символов. * %msg%n — сообщения журнала, за которыми следует символ-разделитель строк, зависящий от платформы. [[https://logback.qos.ch/manual/layouts.html#conversionWord|Перечень]]\\
:!: Итого root-логер является корневым, перехватывает все, с заданным уровнем\\ В апендерах можно настроить фильтрацию, в основном по уровню, но как то особо не развернешься с одними только ими\\ Есть вариант создавать свои логеры, но там нужно указывать класс, с которого идет обращения сообщения, из приложения, тобишь в приложении нужно создавать объект логера с таким же (или базовым) классом.\\ Вроде вариант, но базовый логер эти сообщения тоже перехватывает\\ Пример с разделением на три файла, общий, ошибки и спец файл, в него пишется из отдельного класса, правда в общие файлы эти сообщения тоже попадают т.к. там корневой логер\\ %d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n ${LOGS}/system.log %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n ${LOGS}/archived/system_%d{yyyy-MM-dd}_%i.log.zip 50MB INFO ${LOGS}/error.log %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n ${LOGS}/archived/error_%d{yyyy-MM-dd}_%i.log.zip 50MB ERROR ${LOGS}/webapp.log %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n ${LOGS}/archived/webapp_%d{yyyy-MM-dd}_%i.log.zip 50MB ERROR private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Logger waLogger = LoggerFactory.getLogger("com.baeldung.logback"); logger.info("Запись в лог"); waLogger.info("(WA) Запись в лог");
:!: Еще пример ./logs/commands/commands.log true %d{yyyy-MM-dd} %d{HH:mm:ss.SSS} %-5level - %msg%n ./logs/commands/commands-%d{yyyy-MM-dd}.log.zip 50 (...)
:!: Рабочий пример, есть Json System.out %d{yyyy-MM-dd} %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n ./log/FileMultiplicator.log true %d{yyyy-MM-dd} %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n log/FileMultiplicator-%d{yyyy-MM-dd}.%i.zip 100MB 7 20GB log/json/FileMultiplicator.log true { "timestamp": "%date{yyyy-MM-dd'T'HH:mm:ss}", "logger": "%logger{36}", "message": "%message", "level": "%level" } 30 2048 20 ^sun\.reflect\..*\.invoke ^net\.sf\.cglib\.proxy\.MethodProxy\.invoke true log/json/FileMultiplicator-%d{yyyy-MM-dd}.%i.zip 100MB 7 20GB INFO ./log/commands/commands.log true %d{yyyy-MM-dd} %d{HH:mm:ss.SSS} %-5level - %msg%n ./log/commands/commands-%d{yyyy-MM-dd}.log.zip 50
===== Ротирование логов ===== Аппендер класса **"RollingFileAppender"** расширяет класс **"FileAppender"**, добавляя возможность ротирования файлов\\ Два важных подкомпонента: **RollingPolicy** ("что делать") и **TriggeringPolicy** ("когда это делать")\\ Первый может реализовать интерфейс для второго, тогда достаточно указать только его\\ ==== RollingPolicy ==== Внутри аппендера создается xml компонент политики, имеются разные классы, определяющие поведение\\
:!: Примеры классов для RollingPolicy **TimeBasedRollingPolicy** - На основе времени, один обязательный аргумент "fileNamePattern", так же есть "MaxHistory"\\ Шаблон имени должен сдержать спецификатор "%d", тот может содержать шаблон даты/времени, по умолчанию "гггг-ММ-дд". **Период ротирования выводится из значения в fileNamePattern**\\ т.е. в данном случае в полночь, если время не указано\\ **Сжатие** - для этого нужно добавить расширение "gz/zip" к имени файла\\ **SizeAndTimeBaseRollingPolicy** - собсна по дате и размеру. Здесь добавляется еще один обязательный токен именования - "%i", обозначающий порядковый номер\\ Пример конфигурации mylog.txt true mylog-%d{yyyy-MM-dd}.%i.txt 100MB 60 20GB %d{yyyy-MM-dd} %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n