blob: 0b21f7d8adc9c0ff7302d35460c2608476774423 [file] [log] [blame]
////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
= Flow Tracing
Flow tracing in Log4j is an advanced logging technique designed to enhance
the visibility of application processes. With this technique, developers can track
the flow of data through their application by using special methods that log entry
and exit points within the code.
These methods are:
* `entry()` or `traceEntry()`
* `exit()` or `traceExit()`
* `throwing()`
* `catching()`
With these methods, we can investigate environments where traditional debugging is not possible,
such as in production or during live application monitoring.
Furthermore, new developers can be educated on the application's behavior by examining the logs.
Flow tracing offers a structured approach to all this.
== Flow Tracing Methods
The methods used most often are `entry()` or `traceEntry()` and `exit()` or `traceExit()`.
As the name suggests, the "entry" methods are used at the beginning of a method,
while the "exit" methods are used at the end of a method.
[source, java]
----
public void someMethod() {
logger.entry(); <1>
// method body
logger.exit(); <2>
}
----
<1> The `entry()` method is called at the beginning of the method.
<2> The `exit()` method is called at the end of the method.
Both `entry()` and `exit()` methods can be called with or without parameters.
In the case of `entry()` it makes sense to pass the method parameters as arguments.
[source, java]
----
public void someMethod(String param) {
logger.entry(param); <1>
// method body
logger.exit(); <2>
}
----
<1> The `entry()` method is called at the beginning of the method.
The `traceEntry()` also supports messages.
[source, java]
----
public void someMethod(String[] text) {
logger.traceEntry(new JsonMessage(text)); <1>
// method body
}
----
<1> Using the `JsonMessage` class to log the `text` parameter.
Very similar, it is possible to use `exit()` with methods that return a value.
[source, java]
----
public String someMethod() {
String result = "Hello";
// method body
return logger.exit(result); <1>
}
----
<1> The `exit()` method can also return a value.
To work with exceptions, the `catching()` and `throwing()` methods are used.
The following code shows, how to use the `catching()` method. It will be called
inside the `catch` block of a try-catch statement.
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`.
[source, java]
----
public void someMethod() {
try {
// Lets assume an exception is thrown here
String msg = messages[messages.length];
} catch (Exception ex) {
logger.catching(ex); <1>
}
}
----
<1> The `catching()` method is used to log exceptions that are caught and not rethrown.
The `throwing()` method is used to log exceptions that are thrown and not caught.
The code shows how to use the `throwing()` method- like `catching()` it will be called
inside the `catch` block of a try-catch statement.
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 ensure that proper diagnostics are available if needed. The
logging event generated will have a level of `ERROR`.
[source, java]
----
public void someMethod() {
try {
// Lets assume an exception is thrown here
String msg = messages[messages.length];
} catch (Exception ex) {
logger.throwing(ex); <1>
}
}
----
<1> The `throwing()` method is used to log exceptions that are thrown and not caught.
== Differences in flow tracing methods
Flow tracing methods have specific markers assigned and logs with a level of `TRACE`.
It's also noteworthy that all messages will begin with the word "event".
The table below shows the methods and their special features.
[cols="3,3,3", options="header"]
|===
| Method Name | Marker Name | Special Features
| `entry()`
| `ENTER`, `FLOW`
| Accepts 0 to 4 parameters
| `traceEntry()`
| `ENTER`, `FLOW`
| Can take a format string and a variable list of parameters.
| `exit()`
| `EXIT`, `FLOW`
| Can be called with or without parameters.
| `traceExit()`
| `EXIT`, `FLOW`
| Handles return values differently based on the method signature.
| `throwing()`
| `THROWING`, `EXCEPTION`
| Typically used when an application throws an exception that is unlikely to be handled, such as a RuntimeException.
| `catching()`
| `CATCHING`, `EXCEPTION`
| Used when catching exceptions that are not rethrown; logs with ERROR level.
|===
== Flow Tracing Example Configuration
The following example demonstrates how to configure Log4j to use flow tracing.
While it is recommended to use the `JsonTemplateLayout` in production, we are using the
`PatternLayout` in this example for simplicity.
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 is
critical for the log to be of value.
The following example demonstrates how you could use flow tracing.
The Configuration element is set with a status of "error," which means Log4j
will only report issues that are of error severity or higher.
Within the Appenders section, two appenders are defined: Console and File.
The Console appender is configured to output logs to `SYSTEM_OUT`, typically the console.
It includes a `ThresholdFilter` set to only accept messages at the `ERROR` level or above.
This filters out less severe messages.
The output format is specified by a `PatternLayout`, designed to include detailed
trace information such as time, log level, class name, line number, and method name.
Please note, that we are recommending `JsonTemplateLayout` over `PatternLayout` in production.
Similarly, the File appender directs logs to a file named `target/test.log`.
The appenders configuration will create a new file for every application run.
Finally, in the Loggers section, the Root logger is set to a `TRACE` level which is necessary
to see flow tracing in action. The Root logger references the File appender, directing
its output to the configured file.
[source,xml]
----
<?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>
----
By changing the level of the Root logger to `DEBUG`, you can reduce the amount of output.