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.
将日志请求插入到应用程序代码中需要相当多的计划和精力。观察表明,大约4%的代码专门用于日志记录。因此,即使是中等大小的应用程序,其代码中也会包含数千条日志记录语句。考虑到它们的数量,我们需要工具来管理这些日志语句。
Logback可以通过编程方式进行配置,也可以使用以XML、Groovy或序列化模型格式表示的配置脚本进行配置。顺便说一句,现有的log4j用户可以使用我们的PropertiesTranslator web应用程序将他们的log4j.properties文件转换为logback.xml。
Let us begin by discussing the initialization steps that logback follows to try to configure itself:
- 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.- 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.- 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.从1.3.9和1.4.9 多了一个SerializedModelConfigurator.
注意高版本logback 1.4.9有,之前1.2.4没有serialized和defaultjoran类。
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引入jar
ch.qos.logback
logback-classic
${logback.version}
org.slf4j
slf4j-api
2.0.7
打印结果
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.
假设配置文件logback-test.xml或logback.xml不存在,logback将默认为调用BasicConfigurator,它将设置最小配置。此最低配置包含一个连接到根记录器的控制台附件。输出使用PatternLayoutEncoder进行格式化,该编码器设置为模式 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n。此外,默认情况下,根记录器被分配DEBUG级别。
三段分别设置了appender layout 和level
(logback-examples/src/main/resources/chapters/configuration/sample0.xml)
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
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.
你改名为logback.xml或者logback-test.xml 放到classpath时再跑一遍。
如果在解析配置文件的过程中出现警告或错误,logback将自动在控制台上打印其内部状态消息。
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);
...
}
打印日志
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
这种适合于 有时候引入各种日志jar冲突了,又不知道哪里冲突了或者各种日志配置文件xml properties一堆不知道哪个起作用了,打印内核信息,可以快速定位
启用状态数据的输出通常对诊断logback问题有很大帮助
(logback-examples/src/main/resources/chapters/configuration/onConsoleStatusListener.xml)
status data 这个就是强行打印 context
等同于
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
// print logback’s internal status
StatusPrinter.print(lc);
这个比较有用 自动加载更新的配置文件
...
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
%d{HH:mm:ss.SSS} [%thread] %-5level [%logger{36}] [-%kvp]- %msg%n
注意测试的时候要修改target/class下的xml文件 因为resource的不一定能及时编译
如果被指示这样做,logback可以包括它输出的堆栈跟踪行的每一行的打包数据。打包数据由jar文件的名称和版本组成,jar文件是堆栈跟踪行的类的来源。打包数据对于识别软件版本控制问题非常有用。然而,计算成本相当高,尤其是在频繁抛出异常的应用程序中。
如何设置
...
或者
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
lc.setPackagingDataEnabled(true);
一下子不知道找个啥异常,,感觉就是日志输出的更完善了?
(logback-examples/src/main/java/chapters/configuration/MyApp3.java)
看不出来有啥用
释放资源
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();
Installing a JVM shutdown hook is a convenient way for shutting down logback and releasing associated resources.
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
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
这个就是之前说过的level继承 appender其实也可以继承
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
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.
appender配置有<appender>元素,该元素具有两个强制性属性name和class。name属性指定appender的名称,
class属性指定要实例化的appender类的全路径名称。
<appender>元素可以包含零个或一个<layout>元素、零个或多个<encoder>元素以及零个或更多个<filter>元素。除了这三个常见元素之外,<appender>元素可以包含与appender类的JavaBean属性相对应的任意数量的元素。无缝地支持给定logback组件的任何属性是Joran的主要优势之一,稍后章节将对此进行讨论。下图说明了常见的结构。请注意,下图中没有显示对属性的支持。
myApp.log
%date %level [%thread] %logger{10} [%file:%line] -%kvp- %msg%n
%kvp %msg%n
这些配置脚本定义了两个名为FILE和STDOUT的appender。
FILE附加程序记录到名为myApp.log的文件。encoder时PatternLayoutEncoder,它输出日期、级别、线程名称、记录器名称、文件名和日志请求所在的行号、消息和行分隔符。
第二个名为STDOUT的附加程序输出到控制台。此附加程序的编码器仅输出后面跟有行分隔符的消息字符串。
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} -%kvp- %msg%n
日志会重复因为chapters.configuration继承了root有了一个stdout 自己又add了一个
其实这里可以选择不继承 也就是
下面的demo有
foo.log
%date %level [%thread] %logger{10} [%file : %line] -%kvp- %msg%n
%msg%n
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
本文件的早期版本使用了“属性替换”一词,而不是“变量”一词。请考虑这两个术语可以互换,尽管后一个术语表达了更明确的含义。
与许多脚本语言一样,logback配置文件支持变量的定义和替换。变量有一个作用域(见下文)。此外,变量可以在配置文件本身、外部文件、外部资源中定义,甚至可以动态计算和定义。
变量替换可以发生在配置文件中可以指定值的任何位置。变量替换的语法与Unix shell的语法相似。开头 {和结尾}之间的字符串被解释为对属性值的引用。对于属性 a N a m e ,字符串“ {和结尾}之间的字符串被解释为对属性值的引用。对于属性aName,字符串“ {和结尾}之间的字符串被解释为对属性值的引用。对于属性aName,字符串“{aName}”将替换为aName属性所持有的值。
HOSTNAME和CONTEXT_NAME变量通常很方便,它们是自动定义的,并且具有上下文范围。考虑到在某些环境中计算主机名可能需要一些时间,它的值会延迟计算(仅在需要时)。此外,HOSTNAME可以直接从配置中进行设置。
<variable><properties>都可以定义变量
${USER_HOME}/myApp.log
%kvp %msg%n
${USER_HOME}/myApp.log
%kvp %msg%n
java -DUSER_HOME=“/home/sebastien” MyApp2
${USER_HOME}/myApp.log
%kvp %msg%n
logback-examples/src/main/resources/chapters/configuration/variables1.properties
USER_HOME=/home/sebastien
You may also reference a resource on the class path instead of a file.
${USER_HOME}/myApp.log
%kvp %msg%n
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
/opt/${nodeId}/myApp.log
%kvp %msg%n
在上面的示例中,假设nodeId属性是在上下文范围中定义的,那么它将在每个日志记录事件中可用,即使是那些通过序列化发送到远程主机的事件。
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”.
在某些情况下,如果变量未声明或其值为null,则可能希望该变量具有默认值。与Bashshell一样,可以使用“:-”运算符指定默认值。例如,假设未定义名为aName的变量,“${aName:-golden}”将被解释为“golden”。
Variable nesting is fully supported. Both the name, default-value and value definition of a variable can reference other variables.
完全支持变量嵌套。变量的名称、默认值和值定义都可以引用其他变量。