Как правильно логировать java

от admin

What is a logger in Java and why do you use it?

Logging is an important feature that needs to be considered by the developers to trace back the errors. Java, being one of the most popular programming languages, comes with a customizable approach to logging by providing a basic logging API. So, in this article on Logger in Java, I am going to discuss how professionals can use this feature to enable extensible logging in Java.

The following topics will be covered in this article:

  1. Need for logging
  2. Logging Components
  3. What is Logger?
  • Create new Logger
  • Log Levels
  • Properties File
  • Logging Events

4. Appender or Handlers

5. Layout or Formatters

Before, we deep dive into logging in java, let us understand the need for logging.

Need for logging

While building applications, we often face errors that have to be debugged. So, with the help of logs, we can easily get information about what is happening in the application with a record of errors and unusual circumstances. Now, it might strike your mind that, why not use the System.out.print() statement in Java. Well, the problem with these statements is that log messages will be printed only on the console. So, once you close the console, automatically, all the logs will be lost. Therefore, logs will be not be stored permanently, and are displayed one by one, as it is a single-threaded environment.

To avoid such issues, logging in Java is simplified with the help of the API provided through the package, and the java.util.logging org.apache.log4j.* package.

Logging Components

The Java logging components help the developer to create logs, pass the logs to the respective destination and maintain a proper format. The following are the three components:

  • Loggers — Responsible for capturing log records and passing them to the corresponding Appender.
  • Appenders or Handlers — They are responsible for recording log events to a destination. Appenders format events with the help of Layouts, before sending outputs.
  • Layouts or Formatters — Responsible to determine how data looks when it appears in the log entry.

You can refer to the below image for the working of all the three components:

When an application makes a logging call, the Logger component records the event in a LogRecord and forwards it to the appropriate Appender. Then it formated the record using the Layout according to the required format. Apart from this, you can also use more than one Filters to specify which Appenders should be used for events.

Now, let us understand what is a logger in Java in depth.

What is Logger in Java?

Loggers in Java are objects which trigger log events, They are created and are called in the code of the application, where they generate Log Events before passing them to the next component which is an Appender. You can use multiple loggers in a single class to respond to various events or use Loggers in a hierarchy. They are normally named using the hierarchical dot-separated namespace. Also, all the Logger names must be based on the class or the package name of the logged component.

Apart from this, each Logger keeps a track of the nearest existing ancestor in the Logger namespace and also has a “Level” associated with it. Well, I will discuss the Loggers in the latter part of this article, but before that, let me show you how to create a Logger in Java.

Create new Logger

The process of creating a new Logger in Java is quite simple. You have to use Logger.getLogger() method. The getLogger() method identifies the name of the Logger and takes string as a parameter. So, if a Logger pre-exists then, that Logger is returned, else a new Logger is created.

Syntax:

Here, SampleClass is the class name for which we are getting the Logger object.

Example:

Now that I have told you how to create a Logger in Java, let us see the different levels available in logging.

Log Levels

Log Levels are used to categorize the logs by their severity or the impact on the stability of the application. The org.apache.log4j.* package and the java.util.logging both provide different levels of logging. Let us take a look at each of them one by one.

org.apache.log4j.* the package provides the following levels in descending order:

  • FATAL
  • ERROR
  • WARN
  • INFO
  • DEBUG

java.util.logging the package provides the following levels in descending order:

  • SEVERE(HIGHEST LEVEL)
  • WARNING
  • INFO
  • CONFIG
  • FINE
  • FINER
  • FINEST(LOWEST LEVEL)

Apart from this, the above package also provides two additional levels ALL and OFF used for logging all messages and disabling logging respectively.

Example of Logging in Java using the org.apache.log4j.* package:

So if your output is root logger as WARN-level in our log4j.properties file, then all the error messages with a higher priority than WARN will be printed as below:

You can also set the level by using the setLevel() method from the java.util.logging package as below:

Example of Logging in Java using the java.util.logging package:

To enable logging in your application using the org.apache.log4j.* package or the java.util.logging package, you have to configure the properties file. Next in this article on Logger in Java, let us discuss the properties file of both of them.

Properties File of Log4j and Java Util Package

Sample Log4j Properties file:

The Log4j properties file is created inside the src folder of the project.

  • log4j.appender.file=org.apache.log4j.RollingFileAppender -> Prints all logs in a file
  • log4j.appender.stdout=org.apache.log4j.ConsoleAppender -> Prints all logs in the console
  • log4j.appender.file.File=D:loglogging.log -> Specifies the log file location
  • log4j.appender.file.MaxFileSize=10MB -> Maximum size of the log file to 10MB
  • log4j.appender.file.MaxBackupIndex=5 -> Limits the number of backup files to 5
  • log4j.appender.file.layout=org.apache.log4j.PatternLayout -> Specifies the pattern in which logs will print to the log file.
  • log4j.appender.file.layout.ConversionPattern=%d %-5p %c<1>:%L — %m%n -> Sets the default conversion pattern.

Sample Java Util Package Properties File

  • java.util.logging.FileHandler.pattern = %h/java%u.log -> Log files would be written to C:TEMPjava1.log
  • java.util.logging.FileHandler.limit = 50000 -> The maximum amount that the logger writes to any one file in bytes.
  • java.util.logging.FileHandler.count = 1 -> Specifies the number of output files
  • java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter -> Mentions the formatter used for formatting. Here XML Formatter is used.
  • java.util.logging.ConsoleHandler.level = WARNING -> Sets the default log level to WARNING
  • java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter -> Specifies the Formatter to be used by all ConsoleHandler’s. Here, SimpleFormatter is used.

Logging Events

To log events in Java, you have to make sure that you assign a level to easily filer out the events. To assign a level and mention a message you can use the below methods:

Method 1:

Method 2:

To make sure that Logger in Java, logs only events that are at or above the INFO level, you can use the setLevel() method discussed above.

Now, that I have discussed how to use Logger in Java, let us discuss the next component of Log4j architecture, i.e. Appenders.

Appender or Handlers

Appender or Handlers are responsible for recording log events to a destination. Each logger has access to multiple handlers and receives the log message from the logger. Then, Appenders use Formatters or Layouts to format the events and send them to the corresponding destination.

An Appender can be turned off using the setLevel(Level.OFF) method. The two most standard handlers in the java.util.logging package are as follows:

  • FileHandler: Writess the log message to file
  • ConsoleHandler: Writes the log message to the console

For, your better understanding, I have explained few Appenders in the properties section.

Layout or Formatters

The layout of Formatters is used to format and convert data in a log event. Logging frameworks provide Layouts for HTML, XML, Syslog, JSON, plain text, and other logs.

  1. SimpleFormatter: Generates text messages with basic information.
  2. XMLFormatter: Generates XML message for the log

For, your better understanding, I have explained a few Layouts in the properties section. With this, we come to the end of this blog on “Logger in Java”. I hope you guys are clear with what has been taught to you in this article.

This brings us to the end of this ‘Java Map Interface’ article. I have covered one of the interesting topics of Java, which is Map interface in Java. If you wish to check out more articles on the market’s most trending technologies like Artificial Intelligence, DevOps, Ethical Hacking, then you can refer to Edureka’s official site.

Do look out for other articles in this series that will explain the various other aspects of Java.

Java Logging Overview

The logging APIs are described in detail in the Java SE API Specification. The goal of this document is to provide an overview of key elements.

1.1 Overview of Control Flow

Applications make logging calls on Logger objects. Loggers are organized in a hierarchical namespace and child Loggers may inherit some logging properties from their parents in the namespace.

Applications make logging calls on Logger objects. These Logger objects allocate LogRecord objects which are passed to Handler objects for publication. Both Loggers and Handlers may use logging Levels and (optionally) Filters to decide if they are interested in a particular LogRecord. When it is necessary to publish a LogRecord externally, a Handler can (optionally) use a Formatter to localize and format the message before publishing it to an I/O stream.

Each Logger keeps track of a set of output Handlers. By default all Loggers also send their output to their parent Logger. But Loggers may also be configured to ignore Handlers higher up the tree.

Some Handlers may direct output to other Handlers. For example, the MemoryHandler maintains an internal ring buffer of LogRecords and on trigger events it publishes its LogRecords through a target Handler. In such cases, any formatting is done by the last Handler in the chain.

The APIs are structured so that calls on the Logger APIs can be cheap when logging is disabled. If logging is disabled for a given log level, then the Logger can make a cheap comparison test and return. If logging is enabled for a given log level, the Logger is still careful to minimize costs before passing the LogRecord into the Handlers. In particular, localization and formatting (which are relatively expensive) are deferred until the Handler requests them. For example, a MemoryHandler can maintain a circular buffer of LogRecords without having to pay formatting costs.

1.2 Log Levels

Each log message has an associated log Level. The Level gives a rough guide to the importance and urgency of a log message. Log level objects encapsulate an integer value, with higher values indicating higher priorities.

The Level class defines seven standard log levels, ranging from FINEST (the lowest priority, with the lowest value) to SEVERE (the highest priority, with the highest value).

1.3 Loggers

As stated earlier, client code sends log requests to Logger objects. Each logger keeps track of a log level that it is interested in, and discards log requests that are below this level.

Loggers are normally named entities, using dot-separated names such as "java.awt". The namespace is hierarchical and is managed by the LogManager. The namespace should typically be aligned with the Java packaging namespace, but is not required to follow it slavishly. For example, a Logger called "java.awt" might handle logging requests for classes in the java.awt package, but it might also handle logging for classes in sun.awt that support the client-visible abstractions defined in the java.awt package.

In addition to named Loggers, it is also possible to create anonymous Loggers that don’t appear in the shared namespace. See section 1.14.

Loggers keep track of their parent loggers in the logging namespace. A logger’s parent is its nearest extant ancestor in the logging namespace. The root Logger (named «») has no parent. Anonymous loggers are all given the root logger as their parent. Loggers may inherit various attributes from their parents in the logger namespace. In particular, a logger may inherit:

  • Logging level. If a Logger’s level is set to be null then the Logger will use an effective Level that will be obtained by walking up the parent tree and using the first non-null Level.
  • Handlers. By default a Logger will log any output messages to its parent’s handlers, and so on recursively up the tree.
  • Resource bundle names. If a logger has a null resource bundle name, then it will inherit any resource bundle name defined for its parent, and so on recursively up the tree.

1.4 Logging Methods

The Logger class provides a large set of convenience methods for generating log messages. For convenience, there are methods for each logging level, named after the logging level name. Thus rather than calling "logger.log(Level.WARNING. " a developer can simply call the convenience method "logger.warning(. "

There are two different styles of logging methods, to meet the needs of different communities of users.

First, there are methods that take an explicit source class name and source method name. These methods are intended for developers who want to be able to quickly locate the source of any given logging message. An example of this style is:

Second, there are a set of methods that do not take explicit source class or source method names. These are intended for developers who want easy-to-use logging and do not require detailed source information.

For this second set of methods, the Logging framework will make a "best effort" to determine which class and method called into the logging framework and will add this information into the LogRecord. However, it is important to realize that this automatically inferred information may only be approximate. The latest generation of virtual machines perform extensive optimizations when JITing and may entirely remove stack frames, making it impossible to reliably locate the calling class and method.

1.5 Handlers

Java SE provides the following Handlers:

  • StreamHandler: A simple handler for writing formatted records to an OutputStream.
  • ConsoleHandler: A simple handler for writing formatted records to System.err
  • FileHandler: A handler that writes formatted log records either to a single file, or to a set of rotating log files.
  • SocketHandler: A handler that writes formatted log records to remote TCP ports.
  • MemoryHandler: A handler that buffers log records in memory.

It is fairly straightforward to develop new Handlers. Developers requiring specific functionality can either develop a Handler from scratch or subclass one of the provided Handlers.

1.6 Formatters

  • SimpleFormatter: Writes brief "human-readable" summaries of log records.
  • XMLFormatter: Writes detailed XML-structured information.

As with Handlers, it is fairly straightforward to develop new Formatters.

1.7 The LogManager

  • A hierarchical namespace of named Loggers.
  • A set of logging control properties read from the configuration file. See section 1.8.

There is a single LogManager object that can be retrieved using the static LogManager.getLogManager method. This is created during LogManager initialization, based on a system property. This property allows container applications (such as EJB containers) to substitute their own subclass of LogManager in place of the default class.

1.8 Configuration File

The logging configuration can be initialized using a logging configuration file that will be read at startup. This logging configuration file is in standard java.util.Properties format.

Alternatively, the logging configuration can be initialized by specifying a class that can be used for reading initialization properties. This mechanism allows configuration data to be read from arbitrary sources, such as LDAP, JDBC, etc. See the LogManager API Specification for details.

There is a small set of global configuration information. This is specified in the description of the LogManager class and includes a list of root-level Handlers to install during startup.

The initial configuration may specify levels for particular loggers. These levels are applied to the named logger and any loggers below it in the naming hierarchy. The levels are applied in the order they are defined in the configuration file.

The initial configuration may contain arbitrary properties for use by Handlers or by subsystems doing logging. By convention these properties should use names starting with the name of the handler class or the name of the main Logger for the subsystem.

For example, the MemoryHandler uses a property "java.util.logging.MemoryHandler.size" to determine the default size for its ring buffer.

1.9 Default Configuration

The default logging configuration that ships with the JRE is only a default, and can be overridden by ISVs, system admins, and end users.

The default configuration makes only limited use of disk space. It doesn’t flood the user with information, but does make sure to always capture key failure information.

The default configuration establishes a single handler on the root logger for sending output to the console.

1.10 Dynamic Configuration Updates

  • FileHandlers, MemoryHandlers, and ConsoleHandlers can all be created with various attributes.
  • New Handlers can be added and old ones removed.
  • New Loggers can be created and can be supplied with specific Handlers.
  • Levels can be set on target Handlers.

1.11 Native Methods

Native code that wishes to use the Java Logging mechanisms should make normal JNI calls into the Java Logging APIs.

1.12 XML DTD

The XML DTD used by the XMLFormatter is specified in Appendix A.

The DTD is designed with a "<log>" element as the top-level document. Individual log records are then written as "<record>" elements.

Note that in the event of JVM crashes it may not be possible to cleanly terminate an XMLFormatter stream with the appropriate closing </log>. Therefore tools that are analyzing log records should be prepared to cope with un-terminated streams.

1.13 Unique Message IDs

The Java Logging APIs do not provide any direct support for unique message IDs. Those applications or subsystems requiring unique message IDs should define their own conventions and include the unique IDs in the message strings as appropriate.

1.14 Security

The principal security requirement is that untrusted code should not be able to change the logging configuration. Specifically, if the logging configuration has been set up to log a particular category of information to a particular Handler, then untrusted code should not be able to prevent or disrupt that logging.

A new security permission LoggingPermission is defined to control updates to the logging configuration.

Trusted applications are given the appropriate LoggingPermission so they can call any of the logging configuration APIs. Untrusted applets are a different story. Untrusted applets can create and use named Loggers in the normal way, but they are not allowed to change logging control settings, such as adding or removing handlers, or changing log levels. However, untrusted applets are able to create and use their own "anonymous" loggers, using Logger.getAnonymousLogger. These anonymous Loggers are not registered in the global namespace and their methods are not access-checked, allowing even untrusted code to change their logging control settings.

The logging framework does not attempt to prevent spoofing. The sources of logging calls cannot be determined reliably, so when a LogRecord is published that claims to be from a particular source class and source method, it may be a fabrication. Similarly, formatters such as the XMLFormatter do not attempt to protect themselves against nested log messages inside message strings. Thus, a spoof LogRecord might contain a spoof set of XML inside its message string to make it look as if there was an additional XML record in the output.

In addition, the logging framework does not attempt to protect itself against denial of service attacks. Any given logging client can flood the logging framework with meaningless messages in an attempt to conceal some important log message.

1.15 Configuration Management

The APIs are structured so that an initial set of configuration information is read as properties from a configuration file. The configuration information may then be changed programatically by calls on the various logging classes and objects.

In addition, there are methods on LogManager that allow the configuration file to be re-read. When this happens, the configuration file values will override any changes that have been made programatically.

1.16 Packaging

All of the logging class are in the java.* part of the namespace, in the java.util.logging package.

1.17 Localization

Log messages may need to be localized.

Each Logger may have a Resource Bundle name associated with it. The corresponding Resource Bundle can be used to map between raw message strings and localized message strings.

Normally localization will be performed by Formatters. As a convenience, the formatter class provides a formatMessage method that provides some basic localization and formatting support.

1.18 Remote Access and Serialization

As with most Java platform APIs, the logging APIs are designed for use inside a single address space. All calls are intended to be local. However, it is expected that some Handlers will want to forward their output to other systems. There are a variety of ways of doing this:

Some Handlers (such as the SocketHandler) may write data to other systems using the XMLFormatter. This provides a simple, standard, inter-change format that can be parsed and processed on a variety of systems.

Some Handlers may wish to pass LogRecord objects over RMI. The LogRecord class is therefore serializable. However there is a problem in how to deal with the LogRecord parameters. Some parameters may not be serializable and other parameters may have been designed to serialize much more state than is required for logging. To avoid these problems the LogRecord class has a custom writeObject method that converts the parameters to strings (using Object.toString()) before writing them out. See the LogRecord API Specification for details.

Most of the logging classes are not intended to be serializable. Both Loggers and Handlers are stateful classes that are tied into a specific virtual machine. In this respect they are analogous to the java.io classes, which are also not serializable.

2.0 Examples

2.1 Simple Use

The following is a small program that performs logging using the default configuration.

This program relies on the root handlers that were established by the LogManager based on the configuration file. It creates its own Logger object and then makes calls to that Logger object to report various events.

2.2 Changing the Configuration

Here’s a small program that dynamically adjusts the logging configuration to send output to a specific file and to get lots of information on wombats. The pattern "%t" means the system temporary directory.

2.3 Simple Use, Ignoring Global Configuration

Here’s a small program that sets up its own logging Handler and ignores the global configuration.

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

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

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

  • Весь код примеров использует java.util.logging framework. Вопрос «Какой из фреймворков логирования ниболее кошерен» я оставлю за кадром. Скажу только что до java.util.logging проще всего дотянуться ибо он уже идет вместе с JRE и на самом деле рассказанное в данной статье с минимальными косметическими правками верно для подавляющего большинства систем логирования.
  • В целом рецепты приведенные в данной статье не являются единственно верными, есть моменты о которых можно поспорить, но в целом эти рецепты используются многие годы, многими разработчиками, во многих проектах и они достаточно хороши чтобы им следовать если у Вас нет каких-то совсем уже серьезных возражений.
  • В статье не рассматриваются такие «продвинутые» топики как:
    • Конфигурирование уровней для отдельных логеров
    • Форматирования логов
    • Асинхронное логирование
    • Создание собственных уровней логирования в Log4J
    • Контекстное логирование
    • И многое другое
    Пример №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 и выше.
    Выводим лог сообщения куда-то еще
    • Если приложение запускается с помощью javaw Вы вообще ничего не увидите.
    • Если вывод идет в консоль и нужное вам сообщение промелькнуло 4 часа назад буфер консоли его уже съел, информация пропала.
    • Если вывод консоли направлен в файл java com.yourcompanyname.EntryClass 2>>application_log.txt и приложение работает не останавливаясь несколько недель — файл будет весьма и весьма большим, рискуя занять весь диск.

    Чтобы решить эти проблемы был придуман 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

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

    Логирование: что, как, где и чем?

    Для демонстрации будем использовать интерфейс slf4j, а реализацию — от log4j. Создать логгер очень просто: нужно написать в классе с именем MainDemo , в котором будет логирование, следующее: Это и создаст нам логгер. Чтобы сделать запись в лог, можно использовать множество методов, которые показывают, с каким уровнем будут записи. Например: Хоть мы и передаем класс, по итогу записывается именно полное имя класса с пакетами. Это делается, чтобы потом можно было разделить логирование на узлы, и для каждого узла настроить уровень логирования и аппендер. Например, имя класса: com.github.romankh3.logginglecture.MainDemo — в нем создался логгер. И вот таким образом его можно разделить на узлы логирования. Главный узел — нулевой RootLogger. Это узел, который принимает все логи всего приложения. Остальные можно изобразить, как показано ниже: Аппендеры настраивают свою работу именно на узлы логирования. Сейчас на примере log4j.properties будем смотреть, как их настроить.

    Читать:
    Usb disk security что это за программа

Похожие статьи