Logback log framework learning (3) configuration configuration file

Configuration at initialization

Inserting log requests into the application code requires a fair amount of planning and effort. Observation shows that approximately four percent of code is dedicated to logging. Consequently, even a moderately sized application will contain thousands of logging statements embedded within its code. Given their number, we need tools to manage these log statements.

Logback can be configured either programmatically or with a configuration script expressed in XML, Groovy or serialized model format. By the way, existing log4j users can convert their log4j.properties files to logback.xml using our PropertiesTranslator web-application.

Inserting log requests into application code requires considerable planning and effort. Observation shows that about 4% of the code is dedicated to logging. Therefore, even a moderately sized application can have thousands of logging statements in its code. Given their volume, we need tools to manage these log statements.
Logback can be configured programmatically or using configuration scripts expressed in XML, Groovy, or serialized model formats. By the way, existing log4j users can use our PropertiesTranslator web application to convert their log4j.properties files to logback.xml.

Let us begin by discussing the initialization steps that logback follows to try to configure itself:

  1. Logback will search for any custom Configurator providers using
    service-provider loading facility. If any such custom provider is
    found, it takes precedence over logback’s own configurators, e.g.
    DefaultJoranConfigurator (see below). A custom Configurator is an
    implementation of ch.qos.logback.classic.spi.Configurator interface.
    Custom configurators are searched by looking up file resources
    located under
    META-INF/services/ch.qos.logback.classic.spi.Configurator. The
    contents of this file should specify the fully qualified class name
    of the desired Configurator implementation.
  2. SINCE 1.3.9/1.4.9 If no user-supplied custom Configurator was found
    in the previous step, logback will instantiate a
    SerializedModelConfigurator.
    • If the system property “logback.serializedModelFile” is set, then
    SerializedModelConfigurator will try to locate the file specified
    the aforementioned system property. If the designated file could be
    located, it will be read and interpreted for configuration.
    • If the aforementioned system property was not set or if the
    designated file could not be found, SerializedModelConfigurator will
    search for the serialized configuration model file logback-test.scmo
    in the classpath. If this file can be located, it will be read and
    interpreted for configuration.
    • If the aforementioned file cannot be found,
    SerializedModelConfigurator will search for the serialized
    configuration model file logback.scmo in the classpath.
    • If no serialized configuration model file could be located,
    SerializedModelConfigurator will return with an execution status
    asking for the next available configurator, i.e.
    DefaultJoranConfigurator, to be invoked.
    Configuration from a serialized model file executes faster and does
    not require any XML libraries. In conjunction with GraalVM, this may
    yield smaller executables that start faster.
  3. NOMINAL STEP If the previous configurators could not locate their
    required resources, then an instance of DefaultJoranConfigurator
    will be created and invoked.
    • If the system property “logback.configurationFile” is set, then
    DefaultJoranConfigurator will try to locate the file specified the
    aforementioned system property. If this file can be located, it will
    be read and interpreted for configuration.
    • If the previous step fails, DefaultJoranConfigurator will try to
    locate the configuration file “logback-test.xml” on the classpath.
    If this file can be located, it will be read and interpreted for
    configuration.
    • If no such file is found, it will try to locate the configuration
    file “logback.xml” in the classpath. If this file can be located, it
    will be read and interpreted for configuration. Note that this is
    the nominal configuration step.
    • If no configuration file could be located,
    DefaultJoranConfigurator will return with an execution status asking
    for the next available configurator, i.e. BasicConfigurator, to be
    invoked.

If none of the above succeeds, logback-classic will configure itself using the BasicConfigurator which will cause logging output to be directed to the console.

2. There is an additional SerializedModelConfigurator from 1.3.9 and 1.4.9.
Insert image description here
Note that the higher version logback 1.4.9 has it, but the previous version 1.2.4 did not have the serialized and defaultjoran classes.

Automatically configuring logback

The simplest way to configure logback is by letting logback fall back to its default configuration. Let us give a taste of how this is done in an imaginary application called MyApp1.
前面有点复杂直接看demo
(logback-examples/src/main/java/chapters/configuration/MyApp1.java)

package chapters.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyApp1 {
 final static Logger logger = LoggerFactory.getLogger(MyApp1.class);

 public static void main(String[] args) {
   logger.info("Entering application.");

   Foo foo = new Foo();
   foo.doIt();
   logger.info("Exiting application.");
 }
}

(logback-examples/src/main/java/chapters/configuration/Foo.java)

package chapters.configuration;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Foo {
  static final Logger logger = LoggerFactory.getLogger(Foo.class);

  public void doIt() {
    logger.debug("Did it again!");
  }
}

pom import jar

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.7</version>
        </dependency>

Print results

17:18:04.095 [main] INFO com.chenchi.log.chapter3.MyApp1 -- Entering application.
17:18:04.108 [main] DEBUG com.chenchi.log.chapter3.Foo -- Did it again!
17:18:04.108 [main] INFO com.chenchi.log.chapter3.MyApp1 -- Exiting application.

Assuming the configuration files logback-test.xml or logback.xml are not present, logback will default to invoking BasicConfigurator which will set up a minimal configuration. This minimal configuration consists of a ConsoleAppender attached to the root logger. The output is formatted using a PatternLayoutEncoder set to the pattern %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n. Moreover, by default the root logger is assigned the DEBUG level.

Assuming that the configuration file logback-test.xml or logback.xml does not exist, logback will default to calling BasicConfigurator, which will set the minimum configuration. This minimum configuration includes a console attachment that connects to the root logger. The output is formatted using a PatternLayoutEncoder set to pattern %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n. Additionally, by default, the root logger is assigned DEBUG level.
Insert image description here
The three sections set appender layout and level respectively.

Configuration with logback-test.xml or logback.xml

(logback-examples/src/main/resources/chapters/configuration/sample0.xml)

<configuration>
<!-- STDOUT 这个是appendername 可以随便取 sout print啥都行-->
<!-- ch.qos.logback.core.ConsoleAppender 是具体的类 一般用自带的 也可以自定义-->
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <!-- encoders are assigned the type
         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

After you have renamed sample0.xml as logback.xml (or logback-test.xml) place it into a directory accessible from the class path. Running the MyApp1 application should give identical results to its previous run. You renamed logback.xml
or Put logback-test.xml on the classpath and run it again.

Automatic printing of status messages in case of warning or errors

If a warning or error occurs while parsing the configuration file, logback will automatically print its internal status messages on the console.

public static void main(String[] args) {
  // assume SLF4J is bound to logback in the current environment
  LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
  // print logback's internal status
  StatusPrinter.print(lc);
  ...
}

Print log

17:29:25.146 [main] INFO  [com.chenchi.log.chapter3.MyApp2] [-]- Entering application.
17:29:25.160 [main] DEBUG [com.chenchi.log.chapter3.Foo] [-]- Did it again!
17:29:25.160 [main] INFO  [com.chenchi.log.chapter3.MyApp2] [-]- Exiting application.
17:29:24,747 |-INFO in ch.qos.logback.classic.LoggerContext[default] - This is logback-classic version 1.3.9
17:29:24,751 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - No custom configurators were discovered as a service.
17:29:24,751 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - Trying to configure with ch.qos.logback.classic.joran.SerializedModelConfigurator
17:29:24,752 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - Constructed configurator of type class ch.qos.logback.classic.joran.SerializedModelConfigurator
17:29:24,761 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback-test.scmo]
17:29:24,761 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Could NOT find resource [logback.scmo]
17:29:24,762 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - ch.qos.logback.classic.joran.SerializedModelConfigurator.configure() call lasted 10 milliseconds. ExecutionStatus=INVOKE_NEXT_IF_ANY
17:29:24,762 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - Trying to configure with ch.qos.logback.classic.util.DefaultJoranConfigurator
17:29:24,763 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - Constructed configurator of type class ch.qos.logback.classic.util.DefaultJoranConfigurator
17:29:24,763 |-INFO in ch.qos.logback.classic.LoggerContext[default] - Found resource [logback-test.xml] at [file:/D:/install/code/learning/bigdata_learining/log/logback/target/classes/logback-test.xml]
17:29:25,054 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - Processing appender named [STDOUT]
17:29:25,054 |-INFO in ch.qos.logback.core.model.processor.AppenderModelHandler - About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender]
17:29:25,063 |-INFO in ch.qos.logback.core.model.processor.ImplicitModelHandler - Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property
17:29:25,119 |-INFO in ch.qos.logback.classic.model.processor.RootLoggerModelHandler - Setting level of ROOT logger to DEBUG
17:29:25,119 |-INFO in ch.qos.logback.core.model.processor.AppenderRefModelHandler - Attaching appender named [STDOUT] to Logger[ROOT]
17:29:25,119 |-INFO in ch.qos.logback.core.model.processor.DefaultProcessor@1e127982 - End of configuration.
17:29:25,120 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@60c6f5b - Registering current configuration as safe fallback point
17:29:25,120 |-INFO in ch.qos.logback.classic.util.ContextInitializer@617faa95 - ch.qos.logback.classic.util.DefaultJoranConfigurator.configure() call lasted 357 milliseconds. ExecutionStatus=DO_NOT_INVOKE_NEXT_IF_ANY

This is suitable for sometimes introducing various log jar conflicts, and you don’t know where the conflict is, or there are a bunch of various log configuration file xml properties and you don’t know which one works. Printing the kernel information can quickly locate it.

Status data

Enabling the output of status data is often very helpful in diagnosing logback problems
(logback-examples/src/main/resources/chapters/configuration/onConsoleStatusListener.xml)
status data This is to force the printing context
to be equivalent to
LoggerContext lc = (LoggerContext) LoggerFactory. getILoggerFactory();
// print logback's internal status
StatusPrinter.print(lc);

Automatically reloading configuration file upon modification

This is more useful to automatically load updated configuration files.

<configuration scan="true" scanPeriod="30 seconds" >
  ...
</configuration> 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MyAppScan {
    final static Logger logger = LoggerFactory.getLogger(MyAppScan.class);

    public static void main(String[] args) throws InterruptedException {
        MyAppScan myAppScan = new MyAppScan();
        while (true){
            myAppScan.printAll();
            Thread.sleep(10000);
        }
    }
    private void printAll(){
        logger.trace("trace");
        logger.debug("debug");
        logger.info("info");
        logger.warn("warn");
        logger.error("error");
        System.out.println("==============================");
    }
}

logback.xml

<configuration scan="true" scanPeriod="15 seconds" >
        <!-- STDOUT 这个是appendername 可以随便取 sout print啥都行-->
    <!-- ch.qos.logback.core.ConsoleAppender 是具体的类 一般用自带的 也可以自定义-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <!-- encoders are assigned the type
             ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] [-%kvp]- %msg%n</pattern>
        </encoder>
    </appender>
    <!-- status data 这个就是强行打印 context-->
    <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />

    <root level="error">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

Note that when testing, you need to modify the xml file under target/class because the resource may not be compiled in time.
Insert image description here

Enabling packaging data in stack traces

Insert image description here
If instructed to do so, logback can include packed data for each line of the stack trace line it outputs. The packaging data consists of the name and version of the jar file that is the source of the class for the stack trace line. Packaging data is useful for identifying software version control issues. However, the computational cost is quite high, especially in applications that frequently throw exceptions.
How to set up

<configuration packagingData="true">
  ...
</configuration>

or

 LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
  lc.setPackagingDataEnabled(true);

Suddenly I don't know what anomaly to find, but it feels like the log output is more complete?

Invoking JoranConfigurator directly

(logback-examples/src/main/java/chapters/configuration/MyApp3.java)
I don’t see any use

Stopping logback-classic

Release resources


import org.sflf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
...

// assume SLF4J is bound to logback-classic in the current environment
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
loggerContext.stop();
Stopping logback-classic via a shutdown hook

Installing a JVM shutdown hook is a convenient way for shutting down logback and releasing associated resources.

<configuration debug="true">
   <!-- in the absence of the class attribute, assume
   ch.qos.logback.core.hook.DefaultShutdownHook -->
   <shutdownHook/>

   <!-- rest of the config file.. -->

</configuration>

Configuration file syntax

Insert image description here

Case sensitivity of tag names

If you are unsure which case to use for a given tag name, just follow the camelCase convention which is almost always the correct convention.
遵循驼峰命名即可
and are equivalent but not

Configuring loggers, or the element
<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
     </pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO" />
  <logger name="chapters.configuration.Foo" level="DEBUG" />

  <root level="DEBUG">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

Insert image description here
This is the level inheritance appender mentioned before. In fact, it can also be inherited.

<configuration>

  <appender name="STDOUT"
   class="ch.qos.logback.core.ConsoleAppender">
   <encoder>
     <pattern>
        %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
      </pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration" level="INFO" />
 
  <!-- turn OFF all logging (children can override) -->
  <root level="OFF">
    <appender-ref ref="STDOUT" />
  </root>

</configuration>

Insert image description here

Configuring Appenders

An appender is configured with the element, which takes two mandatory attributes name and class. The name attribute specifies the name of the appender whereas the class attribute specifies the fully qualified name of the appender class to instantiate. The element may contain zero or one elements, zero or more elements and zero or more elements. Apart from these three common elements, elements may contain any number of elements corresponding to JavaBean properties of the appender class. Seamlessly supporting any property of a given logback component is one of the major strengths of Joran as discussed in a later chapter. The following diagram illustrates the common structure. Note that support for properties is not shown in the diagram below.

The appender is configured with an <appender> element, which has two mandatory attributes, name and class. The name attribute specifies the name of the appender, and
the class attribute specifies the full path name of the appender class to be instantiated.
An <appender> element can contain zero or one <layout> elements, zero or more <encoder> elements, and zero or more <filter> elements. In addition to these three common elements, the <appender> element can contain any number of elements that correspond to the JavaBean properties of the appender class. Seamlessly supporting any property of a given logback component is one of Joran's main strengths and will be discussed in a later chapter. The diagram below illustrates common structures. Note that support for properties is not shown in the image below.
Insert image description here

<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>myApp.log</file>

    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n</pattern>
    </encoder>
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%kvp %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

These configuration scripts define two appenders named FILE and STDOUT.
The FILE appender logs to a file named myApp.log. The encoder is PatternLayoutEncoder, which outputs the date, level, thread name, logger name, file name and line number of the log request, message and line separator.
The second appender named STDOUT outputs to the console. This add-on's encoder only outputs a message string followed by a line separator.

Appenders accumulate
<configuration>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration">
    <appender-ref ref="STDOUT" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Insert image description here
The log will be repeated because chapters.configuration inherits root, has a stdout, and adds another one.
In fact, you can choose not to inherit it here.

The demo below has

Overriding the default cumulative behaviour
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>foo.log</file>
    <encoder>
      <pattern>%date %level [%thread] %logger{10} [%file : %line] -%kvp- %msg%n</pattern>
    </encoder> 
  </appender>

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>%msg%n</pattern>
    </encoder>
  </appender>

  <logger name="chapters.configuration.Foo" additivity="false">
    <appender-ref ref="FILE" />
  </logger>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

This example, the appender named FILE is attached to the chapters.configuration.Foo logger. Moreover, the chapters.configuration.Foo logger has its additivity flag set to false such that its logging output will be sent to the appender named FILE but not to any appender attached higher in the hierarchy. Other loggers remain oblivious to the additivity setting of the chapters.configuration.Foo logger. Running the MyApp3 application with the additivityFlag.xml configuration file will output results on the console from the chapters.configuration.MyApp3 logger. However, output from the chapters.configuration.Foo logger will appear in the foo.log file and only in that file.
chapters.configuration.Foo 只有file appender 没有stdout

Variable substitution

Earlier versions of this document used the term "property substitution" instead of the term "variable". Consider that these two terms are interchangeable, although the latter term expresses a more specific meaning.
Like many scripting languages, logback configuration files support the definition and substitution of variables. Variables have a scope (see below). Additionally, variables can be defined in the configuration file itself, in external files, external resources, and can even be calculated and defined dynamically.
Variable substitution can occur anywhere in the configuration file where a value can be specified. The syntax for variable substitution is similar to that of the Unix shell. The string between the beginning { and the end } is interpreted as a reference to the attribute value. For the attribute a Name , the string " between { and the end } is interpreted as a reference to the attribute value. For the attribute aName , the string "The string between { and the end } is interpreted as a reference to the attribute value. For the attribute a N am e , the string " {aName}" is replaced by the value held by the aName attribute.
The HOSTNAME and CONTEXT_NAME variables are often convenient, they are automatically defined and have context scope. Taking into account that calculating the hostname may take some time in some environments, its value is calculated lazily (only when needed). Additionally, HOSTNAME can be set directly from the configuration.

Defining variables

<variable><properties> can define variables

demo1
<configuration>

  <variable name="USER_HOME" value="/home/sebastien" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%kvp %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>
demo2
<configuration>

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${USER_HOME}/myApp.log</file>
    <encoder>
      <pattern>%kvp %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>

java -DUSER_HOME=“/home/sebastien” MyApp2

demo3
<configuration>

  <variable file="src/main/java/chapters/configuration/variables1.properties" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${USER_HOME}/myApp.log</file>
     <encoder>
       <pattern>%kvp %msg%n</pattern>
     </encoder>
   </appender>

   <root level="debug">
     <appender-ref ref="FILE" />
   </root>
</configuration>

logback-examples/src/main/resources/chapters/configuration/variables1.properties

USER_HOME=/home/sebastien

demo4

You may also reference a resource on the class path instead of a file.

<configuration>

  <variable resource="resource1.properties" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
     <file>${USER_HOME}/myApp.log</file>
     <encoder>
       <pattern>%kvp %msg%n</pattern>
     </encoder>
   </appender>

   <root level="debug">
     <appender-ref ref="FILE" />
   </root>
</configuration>

Scopes

A property can be defined for insertion in local scope, in context scope, or in system scope. Local scope is the default. Although it is possible to read variables from the OS environment, it is not possible to write into the OS environment.

LOCAL SCOPE A property with local scope exists from the point of its definition in a configuration file until the end of interpretation/execution of said configuration file. As a corollary, each time a configuration file is parsed and executed, variables in local scope are defined anew.

CONTEXT SCOPE A property with context scope is inserted into the context and lasts as long as the context or until it is cleared. Once defined, a property in context scope is part of the context. As such, it is available in all logging events, including those sent to remote hosts via serialization.

SYSTEM SCOPE A property with system scope is inserted into the JVM’s system properties and lasts as long as the JVM or until it is cleared.

demo1

<configuration>

  <variable scope="context" name="nodeId" value="firstNode" />

  <appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>/opt/${nodeId}/myApp.log</file>
    <encoder>
      <pattern>%kvp %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="FILE" />
  </root>
</configuration>

In the example above, assuming the nodeId attribute is defined in the context scope, it will be available on every logging event, even those sent to the remote host via serialization.

Default values for variables

Under certain circumstances, it may be desirable for a variable to have a default value if it is not declared or its value is null. As in the Bash shell, default values can be specified using the “:-” operator. For example, assuming the variable named aName is not defined, “${aName:-golden}” will be interpreted as “golden”.

In some cases, you may want a variable to have a default value if it is not declared or if its value is null. As with Bashshell, default values ​​can be specified using the ":-" operator. For example, assuming a variable named aName is not defined, "${aName:-golden}" will be interpreted as "golden".

Nested variables

Variable nesting is fully supported. Both the name, default-value and value definition of a variable can reference other variables.

Variable nesting is fully supported. Variable names, default values, and value definitions can all reference other variables.

Guess you like

Origin blog.csdn.net/cclovezbf/article/details/133315371