Progress-servis55.ru

Новости из мира ПК
16 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Logger getlogger java

Логирование в Java / quick start

В ходе моей работы в компании DataArt я, в числе прочего, занимаюсь менторской деятельностью. В частности это включает в себя проверку учебных заданий сделанных практикантами. В последнее время в заданиях наметилась тенденция «странного» использования логеров. Мы с коллегами решили включить в текст задания ссылку на статью с описанием java logging best practices, но оказалось, что такой статьи в которой бы просто и без лишних деталей на практике объяснялось бы как надо писать в лог на Java, вот так вот с ходу не находится.

Данная статья не содержит каких-то откровений, в ней не рассматриваются тонкости какого либо из многочисленных java logging frameworks. Здесь рассказываю как записать в лог так, чтобы это не вызвало удивления у Ваших коллег, основная цель написания включить ее в список обязательного чтения для практикантов. Если все еще интересно, читайте дальше

Несколько разъяснений.

  • Весь код примеров использует java.util.logging framework. Вопрос «Какой из фреймворков логирования ниболее кошерен» я оставлю за кадром. Скажу только что до java.util.logging проще всего дотянуться ибо он уже идет вместе с JRE и на самом деле рассказанное в данной статье с минимальными косметическими правками верно для подавляющего большинства систем логирования.
  • В целом рецепты приведенные в данной статье не являются единственно верными, есть моменты о которых можно поспорить, но в целом эти рецепты используются многие годы, многими разработчиками, во многих проектах и они достаточно хороши чтобы им следовать если у Вас нет каких-то совсем уже серьезных возражений.
  • В статье не рассматриваются такие «продвинутые» топики как:
    • Конфигурирование уровней для отдельных логеров
    • Форматирования логов
    • Асинхронное логирование
    • Создание собственных уровней логирования в Log4J
    • Контекстное логирование
    • И многое другое
  • Слово logging я пишу по русски как логирование с одной буквой «г» в основном потом, что такой вариант перевода чаще встречается
  • Советы, что, с каким уровнем логировать я пожалуй тоже оставлю за кадром т.к. тут все сильно зависит от приложения, условий эксплуатации, отношений с заказчиком и т.п. тонких вещей.
Пример №1
Хорошо
  1. Логер это статическое поле класса инициализируемое при загрузке класса, имеет простое, короткое имя, важно чтобы во всех Ваших классах переменная логера называлась одинаково (это диктуется общим правилом, одинаковые вещи в программе должны делаться одинаковым образом).
  2. В качестве имени логера я использую имя класса, на самом деле это не единственный способ, можно пытаться организовать какую-то свою иерархию логирования (например transport layer/app layer для подсистем имеющих дело с обменом данными), но как показывает практика выдумывать и главное потом неукоснительно следовать такой иерархии крайне сложно, а вариант с именами логеров совпадающими с именами классов весьма хорош и используется в 99% проектов
  3. Здесь для записи в лог я использую короткий метод .info, а не более общий метод .log, так много лаконичнее
  4. Имя логера берется как SomeClass.class.getName(), а не как «com.dataart.demo.java.logging.SomeClass», оба способа по идее одинаковы, но первый защищает Вас от сюрпризов при рефакторинге имени/пакета класса
Плохо

По сути тоже самое но букв больше и читается не так легко.

Замечание между примерами

Вы наверное обратили внимание, что все сообщения в примерах на английском языке. Это не случайно. Дело в том, что даже если все-все кто работает и будет работать с Вашим кодом говорят по русски, есть вероятность, что Вам придется просматривать лог сообщения на удаленном компьютере например через ssh при этом в большом количестве случаев Вы увидите примерно такое сообщение «. . . » (я безусловно знаю что через ssh можно протащить русские буквы, но вот почему-то далеко не всегда все оказывается настроенным должным образом).
Или даже на локальной машине в cmd вы можете увидеть что вот такое:
INFO: ╨Ъ╨░╨║╨╛╨╡-╤В╨╛ ╤Б╨╛╨╛╨▒╤Й╨╡╨╜╨╕╨╡ ╨▓ ╨╗╨╛╨│

С этим безусловно тоже можно бороться. Но не всегда легко объяснить заказчику на том конце телефонной трубки, как сделать так чтобы вместо крякозябр были видны русские буквы.
Совет: Пишите лог сообщения на английском языке, ну или в крайнем случае латинскими буквами.

Пример №2
Хорошо
  1. Если Вам необходимо залогировать исключение, для этого служит метод .log(level,message,exception)
  2. Если вы специально не настроили конфигурацию лог системы, сообщения с уровнем ниже info, например fine выводиться не будут. Но писать их по крайней мере для важных частей системы стоит. Когда что-то пойдет не так, Вы настроите более подробный уровень логирования и увидите много интересного.
  3. Слишком много лог сообщений, даже если они физически не пишутся в лог файл из-за своего слишком маленького уровня, могут существенно замедлить выполнение программы. Особенно если для подготовки самого сообщения надо потратить много ресурсов. Для этого есть метод .isLoggable(level) — он позволяет узнать пропустит ли текущая конфигурация логера данное сообщение
Плохо

Если логировать только ex.toString(), то потом Вы не сможете понять в какой строке изначально сработало исключение.

Пример №3

Логер надо конфигурировать. Есть конфигурация по умолчанию она выводит в консоль все сообщения с уровнем INFO и выше. Она достаточно хороша, для разработки из IDE, но для реального приложения ее обычно неплохо бы подправить.

Какие тут есть варианты

По умолчанию: Файл logging.properties для уровня INFO, вывод в консоль

#Console handler
handlers= java.util.logging.ConsoleHandler
.level=INFO

Делаем логирование более подробным выводим еще и сообщения уровня FINE

#Console handler
handlers= java.util.logging.ConsoleHandler
.level=FINE
java.util.logging.ConsoleHandler.level = FINE

Что мы тут сделали

  • Установили уровень FINE для корневого логера, просто чтобы сообщения пролезали внутрь лог системы.
  • И сказали что все что пролезет через лог систему надо выводить на консоль от уровня FINE и выше.
Выводим лог сообщения куда-то еще

Чем плох вывод на консоль? Консоль это по сути дела старый добрый stderr. Что это значит:

  • Если приложение запускается с помощью javaw Вы вообще ничего не увидите.
  • Если вывод идет в консоль и нужное вам сообщение промелькнуло 4 часа назад буфер консоли его уже съел, информация пропала.
  • Если вывод консоли направлен в файл java com.yourcompanyname.EntryClass 2>>application_log.txt и приложение работает не останавливаясь несколько недель — файл будет весьма и весьма большим, рискуя занять весь диск.
Читать еще:  Интерполяция строк javascript

Чтобы решить эти проблемы был придуман java.util.logging.FileHandler — хэндлер который выводит лог сообщения в файл. При этом он умеет ротировать файлы, т.е. после достижения максимально допустимого размера, он дописывает в файл текщуее лог сообщение и открывает новый файл с инкрементальным префиксом. И так по кругу. Например

создаст вот такие файлы (последняя колонка — размер в байтах)

Мы указали максимальный размер 50 байтов, в реальной жизни надо скорее указывать не меньше мегабайта, например вот так (я знаю, что 1000000 это чуть меньше мегабайта, но кому охота по памяти писать 1048576, если суть дела это фактически не меняет)

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

copy & paste конфиг для реальной жизни, его вполне хватает для большинства service, console и desktop приложений.

Последняя часть магии

Ну и последнее о чем осталось рассказать — как собственно сконфигурировать логер из файла свойств. Есть два способа:

  1. Из командной строки запуска приложения
  2. В первых строчках кода Вашего приложения

Первый чуть более правильный ибо он декларативный и работает сразу, до того как начал работать код Вашего приложения.

Вот так

java Djava.util.logging.config.file=logging.properties com.dataart.application.ClassName

Но к сожалению менять строку запуска не всегда можно или не всегда удобно. Второй способ тоже неплохо работает.

  • Здесь MainApplicationEntryClass — это класс — точка входа в Ваше приложение, видимо имя класса у Вас будет другое
  • Сам файл logging.properties как правило в таких случаях кладется в корень иерархии классов и выглядит это например вот так

Что осталось за кадром

В реальной жизни как минимум половина всех Java приложений это web приложения. Сама техничка логирования в них совершенно не отличается от изложенного выше. Ну может быть за тем исключением что разные сервера приложений могут использовать разные библиотеки логирования такие например как:

  • Log4J
  • JULI logger (строго говоря это не вполне самостоятельный фреймворк, а своего рода надстройка над java.util.logging)
  • SLF4J
  • Commons Logging

Соответственно несколько отличается настройка и имена методов. Но сам принцип меняется мало. Конкретные особенности как правило хорошо описаны в документации на сам сервер приложений, например

  • Tomcat
  • JBoss
  • Resin

Logger log () метод в Java с примерами

Метод log () Logger используется для регистрации сообщения. Если регистратор в настоящее время включен для данного уровня сообщения, который передается в качестве параметра, то создается соответствующий LogRecord и пересылается всем зарегистрированным объектам обработчика вывода. Но в классе logger существует семь различных методов log () в зависимости от параметров, передаваемых в метод.

  1. log (Level level, String msg) : этот метод используется для регистрации сообщения без аргументов. только сообщение будет записано в выходной файл журнала.
    Синтаксис:

Параметры: Этот метод принимает два параметра уровня, который является одним из идентификаторов уровня сообщения, например, SEVERE и msg, который является строковым сообщением (или ключом в каталоге сообщений).

Возвращаемое значение: этот метод ничего не возвращает

Программа 1: Журнал методов (уровень уровня, строка сообщений)

// Java-программа для демонстрации
// Logger.log (Level level, String msg) метод

public class GFG <

public static void main(String[] args)

GFG. class .getName());

// регистрируем сообщения, используя log (Level level, String msg)

logger.log(Level.INFO, «This is message 1» );

logger.log(Level.WARNING, «This is message 2» );

Выход

log (Level level, String msg, Object param1) : Этот метод используется для регистрации сообщения с одним параметром объекта.

Синтаксис:

Параметры: Этот метод принимает три параметра уровня, который является одним из идентификаторов уровня сообщения, например, SEVERE, msg, который является строковым сообщением (или ключом в каталоге сообщений), и param1, который является параметром для сообщения.

Возвращаемое значение: этот метод ничего не возвращает

Программа 2: Журнал методов (Уровень уровня, Строка msg, Объект param1)

// Java-программа для демонстрации
// Logger.log (Уровень уровня, Строка msg, Объект param1)

public class GFG <

public static void main(String[] args)

GFG. class .getName());

// регистрируем сообщения используя

// log (Уровень уровня, Строка msg, Объект param1)

logger.log(Level.INFO, «logging: <0>» , «message1» );

logger.log(Level.SEVERE, «logging: <0>» , «message2» );

Выход:

log (Level level, String msg, Object [] params) : этот метод используется для регистрации сообщения с массивом аргументов объекта.

Синтаксис:

Параметры: Этот метод принимает три параметра уровня, который является одним из идентификаторов уровня сообщения, например, SEVERE, msg, который является строковым сообщением (или ключом в каталоге сообщений), и param1, который является массивом параметров сообщения.

Возвращаемое значение: этот метод ничего не возвращает

Программа 3: Журнал методов (уровень уровня, строковое сообщение, объект [] param1)

// Java-программа для демонстрации
// Logger.log (Level level, String msg, Object [] param1)

public class GFG <

public static void main(String[] args)

GFG. class .getName());

// регистрируем сообщения используя

// log (Уровень уровня, Строка msg, Object [] param1)

Выход:

log (уровень уровня, строковое сообщение, Throwable Thrown ) : этот метод используется для регистрации сообщения со связанной информацией Throwable.

Синтаксис:

Параметры: Этот метод принимает три параметра уровня, который является одним из идентификаторов уровня сообщения, например, SEVERE, msg, который является строковым сообщением (или ключом в каталоге сообщений), и брошенный, который является Throwable, связанным с сообщением журнала.

Возвращаемое значение: этот метод ничего не возвращает

Программа 4: Журнал методов (уровень уровня, строковое сообщение, выброшенный бросок)

// Java-программа для демонстрации
// Logger.log (уровень уровня, строковое сообщение, бросаемый бросок)

public class GFG <

public static void main(String[] args)

GFG. class .getName());

// регистрируем сообщения используя

// log (уровень уровня, строковое сообщение, бросаемый бросок)

Читать еще:  Передаточная функция ошибки

new RuntimeException( «Error» ));

new Exception( «Exception» ));

Выход:

log (уровень уровня, Throwable брошенный, поставщик msgSupplier) : этот метод используется для регистрации ленивого сообщения с соответствующей информацией Throwable. Сообщение и данный Throwable затем сохраняются в LogRecord, который пересылается всем зарегистрированным обработчикам вывода.

Синтаксис:

Параметры: Этот метод принимает три уровня параметров , который является одним из идентификаторов уровня сообщения, например, Серьёзный, брошенный который является Throwable , связанный с сообщениями журнала и msgSupplier , который является функцией, которая при вызове, производит желаемое сообщение журнала.

Возвращаемое значение: этот метод ничего не возвращает

Программа 5: Журнал методов (Уровень уровня, Брошенный бросок, Поставщик msgSupplier)

// Java-программа для демонстрации
// Logger.log (Уровень уровня, Брошенный выброс, Поставщик msgSupplier)

public class GFG <

public static void main(String[] args)

GFG. class .getName());

// Создать метод поставщика

= () -> new String( «Logger logs» );

// регистрируем сообщения используя

// log (Уровень уровня, Throwable бросил, поставщик msgSupplier)

new RuntimeException( «Error» ),

Выход:

log (уровень уровня, поставщик msgSupplier) : этот метод используется для регистрации сообщения, которое должно быть построено только в том случае, если уровень ведения журнала таков, что сообщение будет фактически зарегистрировано.

Синтаксис:

Параметры: Этот метод принимает два параметра уровня, который является одним из идентификаторов уровня сообщения, например, SEVERE и msgSupplier, который является функцией, которая при вызове создает желаемое сообщение журнала.

Возвращаемое значение: этот метод ничего не возвращает

Программа 6: Журнал методов (уровень уровня, поставщик msgSupplier)

// Java-программа для демонстрации
// Logger.log (Level level, msgSupplier)

public class GFG <

public static void main(String[] args)

GFG. class .getName());

// Создать метод поставщика

= () -> new String( «Logger messages» );

// регистрируем сообщения используя

// log (уровень уровня, поставщик msgSupplier)

Выход:

log (LogRecord record) : этот метод используется для регистрации LogRecord. Используя logRecord, мы записываем информацию на выходы регистратора.

Синтаксис:

Параметры: Этот метод принимает одну запись параметра, которая является LogRecord для публикации.

Возвращаемое значение: этот метод ничего не возвращает

Программа 7: Журнал методов (запись LogRecord)

Logger getLogger() Method in Java with Examples

The getLogger() method of a Logger class used find or create a logger. If there is a logger exists with the passed name then the method will return that logger else method will create a new logger with that name and return it.

There are two types of getLogger() method depending upon no of the parameter passed.

    getLogger(java.lang.String): This method is used to find or create a logger with the name passed as parameter. It will create a new logger if logger does not exist with the passed name. If a new logger is created by this method then its log level will be configured based on the LogManager configuration and it will be configured to also send logging output to its parent’s Handlers. It will be registered in the LogManager global namespace.

Syntax:

Parameters: This method accepts a single parameter name which is the String representing name for the logger. This should be a dot-separated name and should normally be based on the package name or class name of the subsystem, such as java.net or javax.swing

Return value: This method returns a suitable Logger.

Exception: This method will throw NullPointerException if the passed name is null.

Below programs illustrate getLogger(java.lang.String) method:
Program 1:

The output printed on console is shown below.
Output:

Program 2:

The output printed on console is shown below.
Output:

getLogger(String name, String resourceBundleName): This method is used to find or creates a logger with the passed name. If a logger has already been created with the given name it is returned. Otherwise, a new logger is created. If the Logger with the passed name already exists and does not have a localization resource bundle then the given resource bundle name is used as a localization resource bundle for this logger. If the named Logger has a different resource bundle name then an IllegalArgumentException is thrown by this method.

Syntax:

Parameters: This method accepts two different parameters:

Return value: This method returns a suitable Logger.

Exception: This method will throws following Exceptions:

  1. NullPointerException: if the passed name is null.
  2. MissingResourceException: if the resourceBundleName is non-null and no corresponding resource can be found.
  3. IllegalArgumentException: if the Logger already exists and uses a different resource bundle name; or if resourceBundleName is null but the named logger has a resource bundle set.

Below programs illustrate getLogger(String name, String resourceBundleName) method:

Logger getlogger java

Logger objects may be obtained by calls on one of the getLogger factory methods. These will either create a new Logger or return a suitable existing Logger. It is important to note that the Logger returned by one of the getLogger factory methods may be garbage collected at any time if a strong reference to the Logger is not kept.

Logging messages will be forwarded to registered Handler objects, which can forward the messages to a variety of destinations, including consoles, files, OS logs, etc.

Each Logger keeps track of a «parent» Logger, which is its nearest existing ancestor in the Logger namespace.

Each Logger has a «Level» associated with it. This reflects a minimum Level that this logger cares about. If a Logger’s level is set to null, then its effective level is inherited from its parent, which may in turn obtain it recursively from its parent, and so on up the tree.

The log level can be configured based on the properties from the logging configuration file, as described in the description of the LogManager class. However it may also be dynamically changed by calls on the Logger.setLevel method. If a logger’s level is changed the change may also affect child loggers, since any child logger that has null as its level will inherit its effective level from its parent.

Читать еще:  Integer valueof java

On each logging call the Logger initially performs a cheap check of the request level (e.g., SEVERE or FINE) against the effective log level of the logger. If the request level is lower than the log level, the logging call returns immediately.

After passing this initial (cheap) test, the Logger will allocate a LogRecord to describe the logging message. It will then call a Filter (if present) to do a more detailed check on whether the record should be published. If that passes it will then publish the LogRecord to its output Handlers. By default, loggers also publish to their parent’s Handlers, recursively up the tree.

Each Logger may have a ResourceBundle associated with it. The ResourceBundle may be specified by name, using the getLogger(java.lang.String, java.lang.String) factory method, or by value — using the setResourceBundle method. This bundle will be used for localizing logging messages. If a Logger does not have its own ResourceBundle or resource bundle name, then it will inherit the ResourceBundle or resource bundle name from its parent, recursively up the tree.

Most of the logger output methods take a «msg» argument. This msg argument may be either a raw value or a localization key. During formatting, if the logger has (or inherits) a localization ResourceBundle and if the ResourceBundle has a mapping for the msg string, then the msg string is replaced by the localized value. Otherwise the original msg string is used. Typically, formatters use java.text.MessageFormat style formatting to format parameters, so for example a format string » <0><1>» would format two parameters as strings.

A set of methods alternatively take a «msgSupplier» instead of a «msg» argument. These methods take a Supplier function which is invoked to construct the desired log message only when the message actually is to be logged based on the effective log level thus eliminating unnecessary message construction. For example, if the developer wants to log system health status for diagnosis, with the String-accepting version, the code would look like: With the above code, the health status is collected unnecessarily even when the log level FINER is disabled. With the Supplier-accepting version as below, the status will only be collected when the log level FINER is enabled.

When looking for a ResourceBundle , the logger will first look at whether a bundle was specified using setResourceBundle , and then only whether a resource bundle name was specified through the getLogger factory method. If no ResourceBundle or no resource bundle name is found, then it will use the nearest ResourceBundle or resource bundle name inherited from its parent tree.
When a ResourceBundle was inherited or specified through the setResourceBundle method, then that ResourceBundle will be used. Otherwise if the logger only has or inherited a resource bundle name, then that resource bundle name will be mapped to a ResourceBundle object, using the default Locale at the time of logging.
When mapping resource bundle names to ResourceBundle objects, the logger will first try to use the Thread’s context class loader to map the given resource bundle name to a ResourceBundle . If the thread context class loader is null , it will try the system class loader instead. If the ResourceBundle is still not found, it will use the class loader of the first caller of the getLogger factory method.

Formatting (including localization) is the responsibility of the output Handler, which will typically call a Formatter.

Note that formatting need not occur synchronously. It may be delayed until a LogRecord is actually written to an external sink.

The logging methods are grouped in five main categories:

    There are a set of «log» methods that take a log level, a message string, and optionally some parameters to the message string.

    There are a set of «logp» methods (for «log precise») that are like the «log» methods, but also take an explicit source class name and method name.

    There are a set of «logrb» method (for «log with resource bundle») that are like the «logp» method, but also take an explicit resource bundle object for use in localizing the log message.

    There are convenience methods for tracing method entries (the «entering» methods), method returns (the «exiting» methods) and throwing exceptions (the «throwing» methods).

    Finally, there are a set of convenience methods for use in the very simplest cases, when a developer simply wants to log a simple string at a given log level. These methods are named after the standard Level names («severe», «warning», «info», etc.) and take a single argument, a message string.

    For the methods that do not take an explicit source name and method name, the Logging framework will make a «best effort» to determine which class and method called into the logging method. However, it is important to realize that this automatically inferred information may only be approximate (or may even be quite wrong!). Virtual machines are allowed to do extensive optimizations when JITing and may entirely remove stack frames, making it impossible to reliably locate the calling class and method.

    All methods on Logger are multi-thread safe.

    Subclassing Information: Note that a LogManager class may provide its own implementation of named Loggers for any point in the namespace. Therefore, any subclasses of Logger (unless they are implemented in conjunction with a new LogManager class) should take care to obtain a Logger instance from the LogManager class and should delegate operations such as «isLoggable» and «log(LogRecord)» to that instance. Note that in order to intercept all logging output, subclasses need only override the log(LogRecord) method. All the other logging methods are implemented as calls on this log(LogRecord) method.

    Ссылка на основную публикацию
    Adblock
    detector