Java logging. Hello World / Хабр

apps Новости

Вступление

Думаю, ни для кого не секрет, что такое логгеры и для чего они нужны. За время существования java было создано немало фреймворков логгирования. Среди самых известных можно выделить:

В данной статье будет рассмотрен каждый из указанных выше фреймворков на уровне «hello world». Будут приведены простые примеры использования основного функционала и конфигурирования. Статья не преследует цель сравнения логгеров между собой и выявление лучшего из них, эту возможность автор оставляет за вами, уважаемые читатели.

, где описана история развития систем логгирования в Java.

Commons-logging


Довольно старый проект, который представляет собой обертку над JUL и log4j, не привносящая никакого дополнительного функционала. Уровни логгирования у JCL совпадают с log4j, а в случае взаимодействия с JUL происходит следующее сопоставление:

fatal = Level.SEVERE
error = Level.SEVERE
warn = Level.WARNING
info = Level.INFO
debug = Level.FINE
trace = Level.FINEST

Для использования JCL подключаем

. Создаем логгер вызовом метода фабрики:

Log log = LogFactory.getLog(LoggingCl.class);
// или
Log log = LogFactory.getLog("name");

Методы JCL очень простые, совпадают с названием уровней логгирования, принимают только объекты и исключения и имеют две вариации:

Object object = "Сообщение";
Throwable throwable = new Throwable();
log.info(object);
log.info(object, throwable);

Конфигурация JCL содержит отдельные блоки для log4j, JUL и собственной реализации. Если не задать конфигурацию, то используется собственная реализация, именуемая SimpleLog, которая выводит сообщения на консоль. Рассмотрим пример конфигурационного файла:

Java.util.logging

Данный фреймворк включен в стандарт и поставляется вместе с JDK, поэтому ничего дополнительно скачивать и подключать вам не надо. JUL имеет следующие уровни логгирования по возрастанию: FINEST, FINER, FINE, CONFIG, INFO, WARNING, SEVERE, а так же ALL и OFF, включающий и отключающий все уровни соответственно.

Логгер создается вызовом одного из статических методов класса java.util.logging.Logger:

Logger log = Logger.getLogger(LoggingJul.class.getName());

Методы логгера могут принимать в качестве аргументов строковые сообщения, шаблоны сообщений, исключения, ресурсы локализованных текстовок сообщений, а также, начиная с Java 8, поставщиков строковых сообщений:

// Строковое сообщение
String stringMessage = "Сообщение";
// Строковое сообщение с параметрами
String stringMessageFormat ="Сообщение {0}";
// Исключение
Throwable throwable = new Throwable();
// ResourceBundle хранящий сообщения
ResourceBundle resourceBundle = ResourceBundle.getBundle("logging.jul.bundle");
// Поставщик сообщений
Supplier<String> stringMessageSupplier = ()->"Сообщение";

Выделяется две группы методов: название которых соответствует уровню логгирования и методы log, loggp, logrb, принимающие уровень логгирования в качестве параметра с типом Level. Первая группа содержит методы двух типов: принимающих строковое сообщение или поставщика строковых сообщений:

log.info(stringMessage);
log.info(stringMessageSupplier);

Вторая группа методов имеет следующие вариации:

// Вывести сообщение с указанием уровня логгирования
log.log(new LogRecord(Level.INFO, stringMessage));
log.log(Level.INFO, stringMessage);
log.log(Level.INFO, stringMessageSupplier);
log.log(Level.INFO, stringMessageFormat, args);
log.log(Level.INFO, stringMessage, throwable );
log.log(Level.INFO, throwable, stringMessageSupplier);
// Вывести сообщение с указанием уровня логгирования, класса и метода
log.logp(Level.INFO, "ClassName", "MethodName", stringMessage);
log.logp(Level.INFO, "ClassName", "MethodName", stringMessageSupplier);
log.logp(Level.INFO, "ClassName", "MethodName", stringMessageFormat, args);
log.logp(Level.INFO, "ClassName", "MethodName", stringMessage, throwable);
log.logp(Level.INFO, "ClassName", "MethodName", throwable, stringMessageSupplier);
// Вывести сообщение с указанием уровня логгирования, класса,
// метода и resourceBundle, хранящего сообщения
log.logrb(Level.INFO, "ClassName", "MethodName", resourceBundle, "messageId");
log.logrb(Level.INFO, "ClassName", "MethodName", resourceBundle, "messageId", throwable);
// Вывести сообщение об ошибке
log.throwing("ClassName","MethodName", throwable);

Теперь обратимся к конфигурации фреймворка. По умолчанию JUL будет выводить сообщения на консоль, однако можно задать конфигурацию в файле свойств. Для задания способа вывода сообщений необходимо для вашего логгера указать какие хендлеры он будет использовать.

Существует следующие классы хендлеров: FileHandler, ConsoleHandler, StreamHandler, SocketHandler, MemoryHandler. Особенностью JUL является то, что настройки хендлеров задаются в целом для всего класса, а не для конкретного экземпляра, что может порождать не мало проблем, например если вам потребуется сообщения различных логгеров выводить в различные файлы или с различным форматированием. Рассмотрим простой пример конфигурационного файла:

# Настройки глобального логгера
handlers =java.util.logging. FileHandler
.level=ALL
# Конфигурация файлового хендлера
java.util.logging.FileHandler.level =ALL
java.util.logging.FileHandler.formatter =java.util.logging.SimpleFormatter
java.util.logging.FileHandler.limit = 1000000
java.util.logging.FileHandler.pattern = log.txt
# Конфигурация консольного хендлера
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.pattern = log.log
java.util.logging.ConsoleHandler.formatter =java.util.logging.SimpleFormatter


Для того что бы JUL применил данную конфигурацию нужно передать параметр -Djava.util.logging.config.file = , либо при старте приложения выполнить код:

LogManager.getLogManager().readConfiguration(<ваш класс>.class.getResourceAsStream("logging.properties"));

Log4j

Данный фреймворк на текущий момент имеет уже вторую версию, которая увы не совместима с первой. Поскольку первая версия log4j существует достаточно давно и, в виду ее большой популярности, существует не мало статей на просторах интернета, сегодня мы рассмотрим вторую. Для использования log4j2 вам необходимо подключить библиотеки

. Log4j имеет несколько отличное от JUL именование уровней логгирования: TRACE, DEBUG, INFO, WARN, ERROR, FATAL, а так же ALL и OFF включающий и отключающий все уровни соответственно.


Логгер создается вызовом статического метода класса org.apache.logging.log4j.Logger:

Logger log = LogManager.getLogger(LoggingLog4j.class);
// или
Logger log = LogManager.getLogger(“name”);

Логгер умеет принимать помимо привычных нам String, Object и Throwable еще два новых типа — MapMessage и Marker:

// Карта сообщений (напечатается как msg1="Сообщение 1” msg2="Сообщение 2”)
MapMessage mapMessage = new MapMessage();
mapMessage.put("msg1", "Сообщение 1");
mapMessage.put("msg2", "Сообщение 2");
// Маркер, объект по которому можно фильтровать сообщения
Marker marker = MarkerManager.getMarker("fileonly");
// Строковое сообщение
String stringMessage = "Сообщение";
// Строковое сообщение с параметрами
String stringMessageFormat = "Сообщение {}, от {}";
// Исключение
Throwable throwable = new Throwable();
// Объект
Object object = new Object();

В классическом для логгеров стиле методы делятся на два типа: совпадающие с названием уровня логгирования и методы log, принимающие уровень логгирования в качестве параметра. Первые имеют вид:

log.info(mapMessage);
log.info(object);
log.info(stringMessage);
log.info(marker, mapMessage);
log.info(marker, object);
log.info(marker, stringMessage);
log.info(object, throwable);
log.info(stringMessage, throwable);
log.info(stringMessageFormat, args);
log.info(marker, mapMessage, throwable);
log.info(marker, object, throwable);
log.info(marker, stringMessageFormat, args);
log.info(marker, stringMessage, throwable);
log.throwing(throwable);

Методы log в log4j2 выглядят так:

log.log(Level.INFO, mapMessage);
log.log(Level.INFO, object);
log.log(Level.INFO, stringMessage);
log.log(Level.INFO, marker, mapMessage);
log.log(Level.INFO, marker, object);
log.log(Level.INFO, marker, stringMessage);
log.log(Level.INFO, object, throwable);
log.log(Level.INFO, stringMessageFormat, args);
log.log(Level.INFO, stringMessage, throwable);
log.log(Level.INFO, marker, mapMessage, throwable);
log.log(Level.INFO, marker, object, throwable);
log.log(Level.INFO, marker, stringMessageFormat, args);
log.log(Level.INFO, marker, stringMessage, throwable);
log.throwing(Level.INFO, throwable);

Если не определить конфигурацию, то при запуске log4j2 выдаст гневное сообщение, о том, что конфигурация не задана и будет печатать ваши сообщения на консоль уровнем не ниже ERROR. Конфигурация log4j2 задается несколькими вариантами: xml, json, yaml.

Конфигурация log4j2 состоит из описания логгеров, аппендеров и фильтров. Для более детального изучения обратитесь к документации, сейчас же лишь отметим пару ключевых моментов. Во-первых, есть различные вкусности в виде фильтров, в том числе и по маркерам:

Во-вторых, имеется широкий круг классов аппендеров, в том числе асинхронные аппендеры и аппендеры оборачивающие группу других аппендеров:

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


Рассмотрим пример конфигурации, в которой объявлены два логгера (корневой и для нашего класса), первый из которых пишет в файл log.log, а второй пишет в log2.log с использованием фильтрации по маркеру:

Logback

Данный фреймворк используется только в связке с оберткой SLF4J, которую мы будем рассматривать позднее. Для начала работы вам необходимы

, а также


Взаимодействие с логгером мы будем осуществлять через API предоставляемый оберткой SLF4J. Уровни логгирования совпадают с log4j. Создание логгера в таком случае выглядит следующим образом:

org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggingLogback.class);
// или
org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("name");

API позволяет выводить строковые сообщения, шаблоны строковых сообщений, исключения, а также использовать маркеры:

// Строковое сообщение
String stringMessage = "Сообщение";
// Шаблон сообщения
String stringMessageFormat = "Сообщение {} {}";
// Ошибка
Throwable throwable = new Throwable();
// Маркер
Marker marker = MarkerFactory.getMarker("marker");

Названия методов совпадают с уровнями логгирования и имеют вид:

log.info(stringMessage);
log.info(stringMessageFormat, args);
log.info(stringMessage, throwable);
log.info(marker, stringMessage);
log.info(marker, stringMessage, throwable);
log.info(marker,stringMessageFormat, args);


Теперь рассмотрим непосредственны функционал logback. Конфигурация ищется в classpath в следующем порядке:

  1. Пытается найти logback.groovy
  2. Иначе пытается найти logback-test.xml
  3. Иначе пытается найти logback.xml
  4. Иначе использует базовую конфигурацию — выводим сообщения на консоль

Основными элементами конфигурации являются логгеры, аппендеры, лайауты, и фильтры.

Имеются следующие фильтры:


Имеются следующие аппендеры:

О том что такое Layouts и Encoders в logback предлагаю прочитать подробно в документации, а сейчас лишь приведу простой пример файла logback.xml:

Serilog

Одной из удобных библиотек .NET, которые поддерживают структурное логирование является


Библиотека поддерживает все основные функции логирования, которые есть у log4net, Nlog, и других известных библиотек:

Slf4j

Как уже говорилось ранее SLF4J является оберткой над logback, а также над JUL, log4j, или JCL, а также над любым логгером, который реализует ее интерфейс. Для работы с SLF4J нужны библиотека slf4j-api-1.x.x.jar и реализация одного из логгеров либо заглушка.

Как правило реализации всех логгеров ( кроме logback) поставляются вместе с SLF4J и имеют названия на подобии slf4j-jcl-1.x.jar, slf4j-log4j12-1.x.jar, slf4j-nop-1.x.jar и т.п. Если в classpath не будет найдена реализация логгера ( или заглушка nop)

API SLF4J мы рассмотрели в предыдущем пункте, поэтому давайте рассмотрим еще одну возможность обертки. В идеальном мире мы должны выводить сообщения через интерфейс обертки, и тогда у нас все будет хорошо, но реальный жестокий мир говорит о том, что всем нам приходится взаимодействовать со сторонними библиотеками или кодом, в которых используются другие логгеры и которые знать не знают о SLF4J.

Что бы не подстраиваться под каждый логгер, а пустить все сообщения через одну реализацию интерфейса SLF4J, можно использовать bridging. В поставке обертки содержаться библиотеки jcl-over-slf4j.jar, log4j-over-slf4j.jar и jul-to-slf4j.jar, которые переопределяют поведение соответствующих логгеров и перенаправляют сообщения в обертку.

Что бы стало понятнее выше сказанное, рассмотрим пример. Допустим у нас имеются следующие логгеры:

java.util.logging.Logger julLog = java.util.logging.Logger.getLogger("julLog");
java.util.logging.Logger log4jLog = java.util.logging.Logger.getLogger("log4jLog");
org.slf4j.Logger slf4jLog = org.slf4j.LoggerFactory.getLogger(LoggingSlf4j.class);
julLog.info("Сообщение от jul");
log4jLog.info("Сообщение от log4j");
slf4jLog.info("Сообщение от slf4j");

Мы хотим, что бы сообщение от JUL записывались в один файл, от log4j в другой, а от slf4j выводились на консоль. В качестве реализации обертки будем использовать logback, конфигурация сего безобразия будет выглядеть следующим образом:

Бизнес требования


Как и любую новую, модную, светящуюся программу надо проверять, задавая вопросы:

«Какую выгоду несет данная программа для бизнеса?», «Какую задачу она решает и за какую цену?».

Часто в отношение логирования цели сводятся к

Если первые два пункта решаются детальными записями и удобным поиском, то информирование об ошибках часто пропускают. Я это называю «спокойствием в неведении». Откроем журналы событий Windows и окажется, что почти на каждом сервере есть программы, которые сыпятся с критическими ошибками.

С помощью расширений Seq можно информировать о происходящих событиях. К примеру, сразу посылать сообщение программисту/администратору, если случилась критическая ошибка. И отправлять список всех ошибок, произошедших за день или неделю. Настроить расширения можно в разделе Seq -> Settings -> Apps
Java logging. Hello World / Хабр

Вредоносные приложения для android

В основном это приложения, которые потенциально высоко востребованы пользователями. Среди них есть скины для клавиатуры, фоторедакторы, приложения для создания рингтонов и др.:

  • com.studio.keypaper2021
  • com.pip.editor.camera
  • org.my.famorites.up.keypaper
  • com.super.color.hairdryer
  • com.celab3.app.photo.editor
  • com.hit.camera.pip
  • com.daynight.keyboard.wallpaper
  • com.super.star.ringtones

Huawei нашла легкий способ переноса приложений из Google Play в AppGallery

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

Как найти вирус на android

Но ведь, скажете вы, на смартфоны софт устанавливается с пользовательскими названиями. Да, это так. Поэтому вам понадобится небольшая утилита, которая позволит вам эффективно выявить весь шлаковый софт, который вы себе установили, определив название их пакетов.

  • Поочерёдно вбивайте в поиск названия пакетов, приведённые выше;
  • При обнаружении приложений с такими именами, нажимайте на них и удаляйте.

А вы говорите Google Play! Как App Store превратился в опасную помойку

Package Name Viewer удобен тем, что позволяет не просто найти нужное приложение по названию его пакета, но и при необходимости перейти в настройки для его удаления. Для этого достаточно просто нажать на иконку приложения, как вы попадёте в соответствующий раздел системы, где сможете остановить, отключить, удалить накопленные данные, отозвать привилегии или просто стереть нежелательную программу.

Как отменить подписку на андроиде

Лучше всего приложение именно удалить. Это наиболее действенный способ защитить себя от его активности. Однако не исключено, что оно могло подписать вас на платные абонементы, поэтому для начала проверьте свою карту на предмет неизвестных списаний, а потом просмотрите список действующих подписок в Google Play:

  • Запустите Google Play и нажмите на иконку своего профиля;
  • В открывшемся окне выберите раздел «Платежи и подписки»;
  • Здесь выберите «Подписки» и проверьте, нет ли среди них неизвестных;
  • Если есть, просто нажмите напротив неё на кнопку «Отменить».

Google убрала боковое меню в Google Play. Где теперь отменять подписки

В принципе, если подписка была оформлена через Google Play и оплата уже прошла, вы можете потребовать у Google вернуть уплаченные деньги. О том, как это делается, мы описывали в отдельной статье. Но поскольку разработчики таких приложений обычно тщательно продумывают способы воровства денег, как правило, они не используют встроенный в Google Play инструмент проведения платежей, чтобы их в случае чего не могли отозвать.

Минусы структурного логирования

К минусу структурного логирования можно отнести необходимость в определении параметров по которым будет производится поиск. Они же потом будут использоваться для создания NoSql индексов. Если забыли определить параметр, то поиск сводится к старому сканированию строк через регулярные выражения.


Гигантский шаг в этом направлении делает приложение

. Идея заключается в сборе строковых данных, абсолютно любых и в любом формате (логи приложения, события о работе ОС, и т.д.). А далее потрясающее разбиение строки в зависимости от запросов и динамическое построение результата через Map/Reduce. Splunk является большой инфраструктурой для сбора и анализа данных, и выходит за тему логирования и данной статьи.

Заключение

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

Оцените статью
Huawei Devices