Apache Log4j2 API官方使用指南(三) —— Flow Tracing

The Logger class provides logging methods that are quite useful for following the execution path of applications. These methods generate logging events that can be filtered separately from other debug logging. Liberal use of these methods is encouraged as the output has been found to
记录器类提供的日志记录方法对于跟踪应用程序的执行路径非常有用。这些方法生成可以与其他debug日志记录分开筛选的日志记录事件。鼓励自由使用这些方法,因为它们的输出已被发现

  • aid in problem diagnosis in development without requiring a debug session
    有助于在开发中的问题诊断,而无需一个debug会话
  • aid in problem diagnosis in production where no debugging is possible
    有助于在生产环境中(在无法进行debug的时候)进行问题诊断
  • help educate new developers in learning the application.
    帮助教育新的开发人员学习应用程序。

The most used methods are the entry() or traceEntry() and exit() or traceExit() methods. entry() or traceEntry() should be placed at the beginning of methods, except perhaps for simple getters and setters. entry() can be called passing from 0 to 4 parameters. Typically these will be parameters passed to the method. traceEntry() can be passed a format String and a variable list of parameters, or a Message. The entry() and traceEntry() methods log with a level of TRACE and uses a Marker with a name of “ENTER” which is also a “FLOW” Marker and all message strings will begin with “event”, even if a format String or Message is used.
最常用的方法是 入口 entry() 或 跟踪入口 traceEntry() 和 退出 exit() 或 跟踪退出 traceExit() 方法。 entry() 或 traceEntry() 应放置在方法的开头,除了简单的 getters 和 setters 方法。 entry() 可以调用并传递0-4个参数。通常,这些参数将传递给方法。traceEntry() 可以传递一个format String和参数的变量列表,或一个Message对象。entry() 和 traceEntry() 方法使用 TRACE 级别进行log 并 使用一个名称为"ENTER"的Marker,该Marker也是一个"FLOW" Marker,即使使用了format String或Message,所有消息字符串仍将以"event"开头。

The main difference between the entry and traceEntry methods is that the entry method accepts a variable list of objects where presumably each is a method parameter. The traceEntry method accepts a format string followed by a variable list of objects, presumably included in the format String. It is not possible to have a single method that includes both of these as it would be ambiguous whether the first String is a parameter or a format String.
entry 和 traceEntry 方法之间的主要区别是,

  • entry方法接受一个对象的变量列表,其中可能每个(对象)都是一个方法参数。
  • traceEntry 方法接受格式字符串format String,后面跟着一个对象的变量列表,可能包含在格式字符串format String里面。
  • 不可能有一个单独的方法 同时包含这两种方法,因为这样会变得模棱两可:到底第一个字符串是参数还是格式字符串format String。

An exit() or traceExit() method should be placed before any return statement or as the last statement of methods without a return. exit() and traceExit() can be called with or without a parameter. Typically, methods that return void will use exit() or traceExit() while methods that return an Object will use exit(Object obj) or traceExit(object, new SomeMessage(object)). The exit() and traceExit() methods log with a level of TRACE and uses a Marker with a name of “EXIT” which is also a “FLOW” Marker and all message strings will begin with “exit”, even if a format String or Message is used.
一个exit() 或是 traceExit() 方法应放在任何返回语句之前,或着作为没有返回语句的方法的最后一行。exit() 和 traceExit() 可以使用或不使用参数进行调用。通常,返回 void 的方法将使用 exit() 或 traceExit() ,而返回对象的方法将使用 exit(Object obj) 或者 traceExit(object, new SomeMessage(object))。The exit() and traceExit() 方法使用 TRACE 级别进行 log 并使用一个名为"EXIT"的Marker,该Marker也是一个"FLOW"Marker,即使使用了格式字符format String或Message,所有消息字符串仍将以"exit"开头,。

The throwing() method can be used by an application when it is throwing an exception that is unlikely to be handled, such as a RuntimeException. This will insure that proper diagnostics are available if needed. The logging event generated will have a level of ERROR and will have an associated Marker with a name of “THROWING” which is also an “EXCEPTION” Marker.
当应用程序抛出一个不太可能被处理的异常(如运行时异常RuntimeException)时,应用程序可以使用 throwing() 方法。这将确保在需要时提供适当的诊断。生成的日志记录事件将具有ERROR级别,并将有一个名为"THROWING"的关联Marker,该标记同时也是一个"EXCEPTION"Marker。

The catching() method can be used by an application when it catches an Exception that it is not going to rethrow, either explicitly or attached to another Exception. The logging event generated will have a level of ERROR and will have an associated Marker with a name of “CATCHING” which is also an “EXCEPTION” Marker.
当应用程序捕获一个不会rethrow(重新抛出)的异常时,可以使用 catching() 方法,显式或附加到另一个异常。生成的日志记录事件将具有 ERROR 级别,并将有一个名为"CATCHING"的关联Marker,该标记同时也是一个"EXCEPTION"Marker。

The following example shows a simple application using these methods in a fairly typical manner. The throwing() is not present since no Exceptions are explicitly thrown and not handled.
下面的示例以相当典型的方式显示了一个使用了这些方法的简单应用程序。由于没有被显式抛出和未被处理的异常,因此没有用到throwing() 。

示例代码

package com.test;
 
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
 
import java.util.Random;
 
public class TestService {
    private Logger logger = LogManager.getLogger(TestService.class.getName());
 
    private String[] messages = new String[] {
        "Hello, World",
        "Goodbye Cruel World",
        "You had me at hello"
    };
    private Random rand = new Random(1);
 
    public void setMessages(String[] messages) {
        logger.traceEntry(new JsonMessage(messages));
        this.messages = messages;
        logger.traceExit();
    }
 
    public String[] getMessages() {
        logger.traceEntry();
        return logger.traceExit(messages, new JsonMessage(messages));
    }
 
    public String retrieveMessage() {
        logger.entry();
        String testMsg = getMessage(getKey());
        return logger.exit(testMsg);
    }
 
    public void exampleException() {
        logger.entry();
        try {
            String msg = messages[messages.length];
            logger.error("An exception should have been thrown");
        } catch (Exception ex) {
            logger.catching(ex);
        }
        logger.exit();
    }
 
    public String getMessage(int key) {
        logger.entry(key);
        String value = messages[key];
        return logger.exit(value);
    }
 
    private int getKey() {
        logger.entry();
        int key = rand.nextInt(messages.length);
        return logger.exit(key);
    }
}

This test application uses the preceding service to generate logging events.
下面这个测试程序使用了上面的服务来生成日志事件。

package com.test;
 
public class App {
 
    public static void main( String[] args ) {
        TestService service = new TestService();
        service.retrieveMessage();
        service.retrieveMessage();
        service.exampleException();
    }
}

配置文件

The configuration below will cause all output to be routed to target/test.log. The pattern for the FileAppender includes the class name, line number and method name. Including these in the pattern are critical for the log to be of value.
下面的配置将导致所有输出都被路由到targe/test.log。FileAppender的模块包括类名、行号和方法名(%class{36} %L %M)。要使日志具有价值,在模式中包含这些是至关重要的。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
      <!-- Flow tracing is most useful with a pattern that shows location.
           Below pattern outputs class, line number and method name. -->
      <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
    </Console>
    <File name="log" fileName="target/test.log" append="false">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
    </File>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="log"/>
    </Root>
  </Loggers>
</Configuration>

Here is the output that results from the Java classes and configuration above.
这是上面的java类和配置生成的输出

19:08:07.056 TRACE com.test.TestService 19 retrieveMessage -  entry
19:08:07.060 TRACE com.test.TestService 46 getKey -  entry
19:08:07.060 TRACE com.test.TestService 48 getKey -  exit with (0)
19:08:07.060 TRACE com.test.TestService 38 getMessage -  entry parms(0)
19:08:07.060 TRACE com.test.TestService 42 getMessage -  exit with (Hello, World)
19:08:07.060 TRACE com.test.TestService 23 retrieveMessage -  exit with (Hello, World)
19:08:07.061 TRACE com.test.TestService 19 retrieveMessage -  entry
19:08:07.061 TRACE com.test.TestService 46 getKey -  entry
19:08:07.061 TRACE com.test.TestService 48 getKey -  exit with (1)
19:08:07.061 TRACE com.test.TestService 38 getMessage -  entry parms(1)
19:08:07.061 TRACE com.test.TestService 42 getMessage -  exit with (Goodbye Cruel World)
19:08:07.061 TRACE com.test.TestService 23 retrieveMessage -  exit with (Goodbye Cruel World)
19:08:07.062 TRACE com.test.TestService 27 exampleException -  entry
19:08:07.077 DEBUG com.test.TestService 32 exampleException - catching java.lang.ArrayIndexOutOfBoundsException: 3
        at com.test.TestService.exampleException(TestService.java:29) [classes/:?]
        at com.test.App.main(App.java:9) [classes/:?]
        at com.test.AppTest.testApp(AppTest.java:15) [test-classes/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.6.0_29]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[?:1.6.0_29]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[?:1.6.0_29]
        at java.lang.reflect.Method.invoke(Method.java:597) ~[?:1.6.0_29]
        at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52) [junit-4.3.1.jar:?]
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35) [surefire-junit4-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115) [surefire-junit4-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97) [surefire-junit4-2.7.2.jar:2.7.2]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.6.0_29]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[?:1.6.0_29]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[?:1.6.0_29]
        at java.lang.reflect.Method.invoke(Method.java:597) ~[?:1.6.0_29]
        at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) [surefire-booter-2.7.2.jar:2.7.2]
        at $Proxy0.invoke(Unknown Source) [?:?]
        at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150) [surefire-booter-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91) [surefire-booter-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) [surefire-booter-2.7.2.jar:2.7.2]
19:08:07.087 TRACE com.test.TestService 34 exampleException -  exit

Simply changing the root logger level to DEBUG in the example above will reduce the output considerably.
上面例子中,仅将root logger的级别调整为DEBUG,就会大大减少输出。

19:13:24.963 DEBUG com.test.TestService 32 exampleException - catching java.lang.ArrayIndexOutOfBoundsException: 3
        at com.test.TestService.exampleException(TestService.java:29) [classes/:?]
        at com.test.App.main(App.java:9) [classes/:?]
        at com.test.AppTest.testApp(AppTest.java:15) [test-classes/:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.6.0_29]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[?:1.6.0_29]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[?:1.6.0_29]
        at java.lang.reflect.Method.invoke(Method.java:597) ~[?:1.6.0_29]
        at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:66) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34) [junit-4.3.1.jar:?]
        at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52) [junit-4.3.1.jar:?]
        at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:35) [surefire-junit4-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:115) [surefire-junit4-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:97) [surefire-junit4-2.7.2.jar:2.7.2]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.6.0_29]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[?:1.6.0_29]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[?:1.6.0_29]
        at java.lang.reflect.Method.invoke(Method.java:597) ~[?:1.6.0_29]
        at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) [surefire-booter-2.7.2.jar:2.7.2]
        at $Proxy0.invoke(Unknown Source) [?:?]
        at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150) [surefire-booter-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91) [surefire-booter-2.7.2.jar:2.7.2]
        at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) [surefire-booter-2.7.2.jar:2.7.2]

如果以上内容对你有所帮助,点个赞呗~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值