log4j xml что это
Log4j xml что это
Configuration
Inserting log requests into the application code requires a fair amount of planning and effort. Observation shows that approximately 4 percent of code is dedicated to logging. Consequently, even moderately sized applications will have thousands of logging statements embedded within their code. Given their number, it becomes imperative to manage these log statements without the need to modify them manually.
Configuration of Log4j 2 can be accomplished in 1 of 4 ways:
This page focuses primarily on configuring Log4j through a configuration file. Information on programmatically configuring Log4j can be found at Extending Log4j 2 and Programmatic Log4j Configuration.
All available formats are functionally equivalent. For example, a configuration file in XML can be rewritten using the properties format (and the opposite) without any loss of functionality. However, the hierarchical nature of a Log4j configuration can be captured better in formats which naturally support nesting so XML, JSON, and YAML files, are usually easier to use.
Note that unlike Log4j 1.x, the public Log4j 2 API does not expose methods to add, modify or remove appenders and filters or manipulate the configuration in any way.
Configuration Archhitecture
In part because support for XML was added first, Log4j’s configuration is reflected as a tree structure. In fact every configuration dialect, including the ConfigurationBuilder, generates a Node for every configuration element. A node is a fairly simple structure that contains a set of attributes, a set of child nodes and a PluginType. It is important to note that every Node must have a corresponding plugn, as the plugin is the component that actually performs the work represented by the node.
Every document type supported by Log4j has a ConfigurationFactory. The factory itself is a Log4j plugin that declares what file extensions it supports and what its priority is. Properties have the highest precedence with a value of 8, followed by yaml, json and xml. When autoconfiguration is performed Log4j will call each of these factories in order to determine which, if any, support the specified configuration file format. If one is found that factory will create the corresponding Configuratoin object and pass the reference to the configuration data to it.
Every configuration implementation, such as XMLConfiguration, YamlConfiguration, JsonConfiguration, etc. has the primary task of converting the configuration text into the Node tree, typically by parsing the text with whatever tool is available for that document type. It should be noted that while most of the supported document types are inherintly tree structured, the Java properties syntax is not. Because of the need to convert the syntax into a Node tree the Java properties syntax used by Log4j required all properties follow a naming pattern that made the tree structure clear. As a consequence, the Java Properties format tends to be more verbose than using a different document type.
Once the Node tree is created control is delegated to AbstractConfiguration, which convertes the Nodes into their respective Java objects using Log4j’s Plugin system and provides all the common functionality.
Arbiters
In some situations it is desirable to have a single logging configuration that can be used in any deployment environment. For example, it may be necessary to have a different default logging level in production then in development. Another case might be where one type of appender is used when running natively but another is used when deployed to a docker container. One way to handle that is to use a tool such as Spring Cloud Config Server that can be environment aware and serve a different file for each environment. Another option is to include Arbiters in the configuration.
An Arbiter is a Log4j plugin that has the job of determining whether other configured elements should be included in the generated configuration. While all other «Core» plugins are designed to execute as part of Log4j’s runtime logic Arbiters execute after the Node tree has been constructed but before the tree is converted to a configuration. An Arbiter is a Node itself which is always removed from the Node tree before it the tree is processed. All an arbiter really does is provide a method that returns a boolean result that determines whether the child nodes of the arbiter should remain in the configuration or be pruned.
Arbiters may occur anywhere an element is allowed in the configuration. So an Aribiter could encapsulate something as simple as a single property declaration or a whole set of Appenders or Loggers. Arbiters may also be nested although Arbiters that are the descendant of another arbiter will only be evalued if the ancestor returned true. The child elements of an Arbiter must be valid elements for whatever element is the parent of the Arbiter.
This example shows two Arbiters configured that will include either a Console Appender or a List Appender depending on whether the value of the env System Property is «dev» or «prod».
Normally Arbiters act in isolation from other Arbiters. That is, the outcome of one Arbiter will not impact any other Arbiters. This can be cumbersome when you simply want to use one of a set of choices. A special plugin named «Select» can be used in this case. Each element under the Select is required to be an Arbiter. The first Arbiter that returns a true value will be the one used while others are ignored. If no Arbiter returns true a DefaultAtrbiter may be configured with the default configuration elements. The DefaultArbiter is an Arbiter that always returns true, so using it outside of a Select would result in its configured elements always being included just as if it hadn’t been present.
This example shows an Arbiter that uses Javascript residing in a separate file to determine whether to include the Console Appender. If the result is false then a List Appender will be included.
If the status attribute on the Configuration element is set to DEBUG the list of script engines currently installed and their attributes will be listed. Although some engines may say they are not thread safe, Log4j takes steps to insure that the scripts will run in a thread-safe manner if the engine advertises that it is not thread safe.
When the scripts are executed they will be provided with a set of variables that should allow them to accomplish whatever task they are expected to perform. See the documentation for the individual components for the list of variables that are available to the script.
The components that support scripting expect a return value to be passed back to the calling Java code. This is not a problem for several of the scripting languages, but Javascript does not allow a return statement unless it is within a function. However, Javascript will return the value of the last statement executed in the script. As a consequence, code such as that shown below will result in the desired behavior.
A special note on Beanshell
JSR 223 scripting engines are supposed to identify that they support the Compilable interface if they support compiling their scripts. Beanshell does this. However, whenever the compile method is called it throws an Error (not an Exception). Log4j catches this but will log the warning shown below for each Beanshell script when it tries to compile them. All Beanshell scripts will then be interpreted on each execution.
XInclude
XML configuration files can include other files with XInclude. Here is an example log4j2.xml file that includes two other files:
Composite Configuration
Log4j allows multiple configuration files to be used by specifying them as a list of comma separated file paths on log4j.configurationFile or, when using urls, by adding secondary configuration locations as query parameters named «override». The merge logic can be controlled by specifying a class that implements the MergeStrategy interface on the log4j.mergeStrategy property. The default merge strategy will merge the files using the following rules:
Status Messages
From log4j-2.9 onward, log4j2 will print all internal logging to the console if system property log4j2.debug is either defined empty or its value equals to true (ignoring case).
Prior to log4j-2.9, there are two places where internal logging can be controlled:
Just as it is desirable to be able to diagnose problems in applications, it is frequently necessary to be able to diagnose problems in the logging configuration or in the configured components. Since logging has not been configured, «normal» logging cannot be used during initialization. In addition, normal logging within appenders could create infinite recursion which Log4j will detect and cause the recursive events to be ignored. To accomodate this need, the Log4j 2 API includes a StatusLogger. Components declare an instance of the StatusLogger similar to:
Since StatusLogger implements the Log4j 2 API’s Logger interface, all the normal Logger methods may be used.
When configuring Log4j it is sometimes necessary to view the generated status events. This can be accomplished by adding the status attribute to the configuration element or a default value can be provided by setting the «Log4jDefaultStatusLevel» system property. Valid values of the status attribute are «trace», «debug», «info», «warn», «error» and «fatal». The following configuration has the status attribute set to debug.
During startup this configuration produces:
If the status attribute is set to error than only error messages will be written to the console. This makes troubleshooting configuration errors possible. As an example, if the configuration above is changed to have the status set to error and the logger declaration is:
the following error message will be produced.
Applications may wish to direct the status output to some other destination. This can be accomplished by setting the dest attribute to either «err» to send the output to stderr or to a file location or URL. This can also be done by insuring the configured status is set to OFF and then configuring the application programmatically such as:
Testing in Maven
Maven can run unit and functional tests during the build cycle. By default, any files placed in src/test/resources are automatically copied to target/test-classes and are included in the classpath during execution of any tests. As such, placing a log4j2-test.xml into this directory will cause it to be used instead of a log4j2.xml or log4j2.json that might be present. Thus a different log configuration can be used during testing than what is used in production.
A second approach, which is extensively used by Log4j 2, is to set the log4j.configurationFile property in the method annotated with @BeforeClass in the junit test class. This will allow an arbitrarily named file to be used during the test.
A third approach, also used extensively by Log4j 2, is to use the LoggerContextRule JUnit test rule which provides additional convenience methods for testing. This requires adding the log4j-core test-jar dependency to your test scope dependencies. For example:
System Properties
The Log4j documentation references a number of System Properties that can be used to control various aspects of Log4j 2 behavior. The table below lists these properties along with their default value and a description of what they control. Any spaces present in the property name are for visual flow and should be removed.
Note that beginning in Log4j 2.10, all system property names have been normalized to follow a consistent naming scheme. While the old property names are still supported for backwards compatibility, it is recommended to update configurations to use the new style. This system is extensible and is enabled through the PropertySource interface. Additional property source classes can be added through the standard ServiceLoader mechanism in Java SE.
Source | Priority | Description |
---|---|---|
Environment Variables | -100 | Environment variables are all prefixed with LOG4J_, are in all caps, and words are all separated by underscores. Only this naming scheme is support for environment variables as there were no old naming schemes to maintain compatibility with. |
log4j2.component.properties file | 0 | Including this file on the classpath can be used as an alternative to providing properties as system properties. This has priority over system properties, but they can be overridden by environment variables as described above. |
System Properties | 100 | All properties can be set using normal system property patterns. These have the lowest priority and can be overridden by included properties files or environment variables. |
The following is a list of available global configuration properties. Note that these can only be set once per JVM process unlike configuration settings available in configuration files. The Property Name column contains the name used in properties files and system properties; Environemt Variable for the equivalent environment variable; and Legacy Property Name for the pre-2.10 name.
The StatusLogger logs events that occur in the logging system to the console. During configuration, AbstractConfiguration registers a StatusConsoleListener with the StatusLogger that may redirect status log events from the default console output to a file. The listener also supports fine-grained filtering. This system property specifies the default status log level for the listener to use if the configuration does not specify a status level.
Note: this property is used by the log4j-core implementation only after a configuration file has been found.
( log4j2.StatusLogger.level)
The initial «listenersLevel» of the StatusLogger. If StatusLogger listeners are added, the «listenerLevel» is changed to that of the most verbose listener. If any listeners are registered, the listenerLevel is used to quickly determine if an interested listener exists.
Used by Async Loggers and the AsyncAppender to maintain application throughput even when the underlying appender cannot keep up with the logging rate and the queue is filling up.
If no value is specified (the default) events are never discarded. If the queue is full, the logger call blocks until the event can be added to the queue.
Specify Discard to drop events whose level is equal or less than the threshold level (INFO by default) when the queue is full.
( log4j2.DiscardThreshold)
( log4j2.messageFactory)
( log4j2.flowMessageFactory)
( log4j2.is.webapp)
( log4j2.enable.threadlocals)
( log4j2.enable.direct.encoders)
( log4j.initialReusableMsgSize)
( log4j.maxReusableMsgSize)
( log4j.layoutStringBuilder.maxSize)
( log4j.unbox.ringbuffer.size)
If more slots are required, set system property log4j.unbox.ringbuffer.size to the desired ring buffer size. Note that the specified number will be rounded up to the nearest power of 2.
( log4j.LoggerContext.stacktrace.on.start)
t
Copyright © 1999-2021 The Apache Software Foundation. All Rights Reserved.
Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the Apache Logging project logo are trademarks of The Apache Software Foundation.
Заметки разработчика
узнал сам – поделись с другими
26 октября 2012 г.
Простое логирование при помощи Log4j
В большинстве информационных систем среди уровней логирования выделяют следующие (от более низкого к более высокому):
В качестве примера рассмотрим простое приложение, состоящее всего из одного класса и одного конфигурационного файла. Если вы разрабатываете в Idea, то вот вам пошаговая инструкция:
Создайте в папке src вашего проекта какой-нибудь пакет (например, ru.nordmine), а в нём создайте класс SimpleMain с таким содержимым:
public class SimpleMain <
private static final Logger logger = Logger.getLogger(SimpleMain.class);
public static void main(String[] args) <
for(int i = 0; i try <
logger.info(«result: » + divide(i));
> catch (Exception e) <
logger.error(e.getMessage(), e);
>
>
>
public static int divide(int x) <
logger.debug(«divide method invoked; 2 / » + x);
if(x == 0) <
logger.warn(«x = 0; exception may occur»);
>
return 2 / x;
>
>
В классе SimpleMain логгер определён в виде приватного статического и неизменяемого поля. В качестве параметра метода, который его создаёт, передаём текущий класс. В самом методе main в цикле вызывается метод divide, который выполняет какую-то работу. Неважно какую, в качестве примера он делит 2 на то число, которое ему передали. Обратите внимание на уровни логирования.
В методе divide при старте выводится сообщение уровня debug о том, что метод запущен и с каким параметром. Предположим, что мы используем уровень логирования INFO, поэтому данное сообщение будет выводится не будет. И зачем, ведь нам не интересно знать о каждом выводе метода и с каким параметром.
Далее, поскольку метод делит 2 на то, что к нему пришло, есть некая вероятность деления на нуль (что и прозойдёт в нашем примере). Поэтому лучше проверять входные аргументы и выводить предупреждение, если что-то будет не так. Уровень WARN выше, чем INFO, поэтому при текущем уровне логирования предупреждение будет выведено.
В методе main в цикле мы вызываем метод divide, передавая ему последовательно аргументы от 0 до 2. Зная, что в вызываемом методе потенциально может возникнуть ошибка, обернём его вызов в конструкцию try-catch. Обратите внимание, что она внутри цикла, а не снаружи. То есть ошибочный аргумент метода не остановит весь цикл, а только одну итерацию, что логично. Если вызов пройдёт успешно, будет показан результат с уровнем INFO, если произойдёт исключение, то будет выведен текст ошибки с уровнем ERROR и полный stack trace, ведь мы передаём логгеру не только текст ошибки, но и объект исключения. И это правильно, т.к. среди однотипных записей лога гораздо быстрее обнаружить stack trace, чем неприметную запись ERROR.
Теперь осталось сконфигурировать логгер. Его конфигурация может быть в двух форматах: обычном текстовом property-файле (log4j.properties) и в формате xml (log4j.xml). Начнём с более простого текстового. Положите файл log4j.properties со следующим содержимым в корень вашего проекта:
# Root logger option
log4j.rootLogger=INFO, stdout
Это пожалуй самый простой вариант настройки логгирования, при котором сообщения в указанном формате будут выводить только на консоль, причём только если уровень не ниже INFO.
А теперь давайте сконфигурируем логгер таким образом, чтобы сообщения выводились в консоль и в файл. Поместим эту конфигурацию в файл log4j.xml, который положим в корень папки src.
В этой конфигурации мы отключаем вывод отладочной информации самого логгера (иногда это тоже может пригодиться). Для добавления записи в лог используется так называемый аппендер. В библиотеке определено множество различных типов аппендеров, мы же здесь рассмотрим два из них: ConsoleAppender (вывод в консоль) и DailyRollingFileAppender (запись в файл).
Если с консолью всё понятно, то почему был выбран именно DailyRollingFileAppender? Дело в том, что этот тип аппендера позволяет не просто записывать в файл, а ещё и автоматически архивировать эти файлы. Например, создавать каждые сутки новый файл для лога. Имя файла, а заодно и правила ротации, задаёт параметр DatePattern. В нашем примере файлы будут создаваться каждые сутки. Имя файла будет иметь формат «messages-ГГГГ-ММ-ДД». Файл, в который в настоящий момент ведётся запись, имеет имя «messages» (параметр File) без метки времени. Можно настроить ротацию также каждый час и даже каждую минуту. В зависимости от того, как много записей добавляется в лог.
В конце указываем минимальный корневой уровень логирования (INFO) для обоих аппендеров. Записи ниже этого уровня добавляться не будут.
Теперь, если запустить наше приложение, мы увидим только одну строку с уровнем INFO (в файл была добавлена точно такая же строка):
Здесь мы видим, что сначала было предупреждение, а затем произошла ошибка, поэтому понижаем уровень логирования до DEBUG, чтобы получить больше отладочной информации, и тогда мы увидим, какие методы вызывались и с какими параметрами: