There is a story and a solution for log output.
In Logback, the "logging request generator" information can be included in the log output by specifying the following conversion specifier in the pattern layout [^ warning-1].
Conversion specifier(alias) | Output contents |
---|---|
C (class) | Caller class name(FQCN) |
M (method) | Caller method name |
F (file) | Source code file name |
L (line) | Line numbers in the source code file |
caller[^1] | Caller location information |
[^ warning-1] :: warning: Obtaining the "generator of logging request" is a costly process and slows down execution. Let's use it only in the development environment etc. [^ 1]: Due to the special output content, it is not covered in this article.
In this article, we will use the following settings as an example of log output.
Notice the contents of the pattern
element. With this setting, you can output the class name, file name, etc. to the log. Debugging progresses.
logback.xml
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>[[%class.%method\(%file:%line\)]] %logger{0} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Log output example
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:16)]] DemoLogApplication - hello
For details on the conversion specifier, refer to the manual.
Due to various reasons, you may define your own Logger without using the SLF4J Logger directly. At this time, if you simply delegate the processing to the SLF4J Logger (so-called Wrapper), all the "logging request generators" will be your own Logger.
MyWrongLogger.java
package com.example.demo;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
public class MyWrongLogger {
//Logger of SLF4J to be delegated
private final org.slf4j.Logger logger;
//Constructor private
private MyWrongLogger(org.slf4j.Logger logger) {
this.logger = logger;
}
//Factory method
public static final MyWrongLogger getLogger(Class<?> clazz) {
org.slf4j.Logger logger = LoggerFactory.getLogger(clazz);
return new MyWrongLogger(logger);
}
//Below, delegation to logger
public boolean isTraceEnabled() {
return logger.isTraceEnabled();
}
public void trace(String msg) {
logger.trace(msg);
}
// (The following is omitted)
}
DemoLogApplication.java
package com.example.demo;
public class DemoLogApplication {
private static final MyWrongLogger WRONG_LOGGER = MyWrongLogger.getLogger(DemoLogApplication.class);
public static void main(String[] args) {
WRONG_LOGGER.info("hello");
WRONG_LOGGER.info("hello {}", "xxx");
WRONG_LOGGER.info("exception", new Exception("test"));
WRONG_LOGGER.info("{} {} {} exception", 1, 2, 3, new Exception("test"));
}
}
Log output example("Generator of logging request" has become MyWrongLogger)
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:122)]] DemoLogApplication - hello
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:126)]] DemoLogApplication - hello xxx
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:138)]] DemoLogApplication - exception
java.lang.Exception: test
at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:11)
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:134)]] DemoLogApplication - 1 2 3 exception
java.lang.Exception: test
at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:12)
Certainly, it is MyWrongLogger
that actually calls the logger method ...
There are such unfortunate logs once in a while.
You can solve this problem by using SLF4J's LocationAwareLogger
[^ FQCN-1].
You can specify the FQCN in the log
method of LocationAwareLogger
.
java:org.slf4j.spi.LocationAwareLogger
public void log(Marker marker, String fqcn, int level, String message, Object[] argArray, Throwable t);
Logback's Logger
[^ FQCN-2] implements LocationAwareLogger
.
In other words, if you are using Logback to implement log output, you can cast Logger
[^ FQCN-3] obtained from LoggerFactory
to LocationAwareLogger
.
The following is an example of using LocationAwareLogger
.
MyLocationAwareLogger.java
package com.example.demo;
import static org.slf4j.spi.LocationAwareLogger.*;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
public class MyLocationAwareLogger {
// Marker(Not used this time)
private static final Marker MARKER = null;
//FQCN of this class
private static final String FQCN = MyLocationAwareLogger.class.getName();
//Location Aware Logger of SLF4J to be delegated
private final org.slf4j.spi.LocationAwareLogger logger;
//Constructor private
private MyLocationAwareLogger(org.slf4j.spi.LocationAwareLogger logger) {
this.logger = logger;
}
//Factory method
public static MyLocationAwareLogger getLogger(Class<?> clazz) {
org.slf4j.spi.LocationAwareLogger logger = (org.slf4j.spi.LocationAwareLogger) LoggerFactory.getLogger(clazz);
return new MyLocationAwareLogger(logger);
}
//<<< isXxxEnabled >>>
public boolean isTraceEnabled() { return logger.isTraceEnabled(); }
public boolean isDebugEnabled() { return logger.isDebugEnabled(); }
public boolean isInfoEnabled () { return logger.isInfoEnabled (); }
public boolean isWarnEnabled () { return logger.isWarnEnabled (); }
public boolean isErrorEnabled() { return logger.isErrorEnabled(); }
//---
//<<< log >>>
// (String msg)
public void trace(String msg) { logger.log(MARKER, FQCN, TRACE_INT, msg, null, null); }
public void debug(String msg) { logger.log(MARKER, FQCN, DEBUG_INT, msg, null, null); }
public void info (String msg) { logger.log(MARKER, FQCN, INFO_INT, msg, null, null); }
public void warn (String msg) { logger.log(MARKER, FQCN, WARN_INT, msg, null, null); }
public void error(String msg) { logger.log(MARKER, FQCN, ERROR_INT, msg, null, null); }
// (String msg, Throwable t)
public void trace(String msg, Throwable t) { logger.log(MARKER, FQCN, TRACE_INT, msg, null, t ); }
public void debug(String msg, Throwable t) { logger.log(MARKER, FQCN, DEBUG_INT, msg, null, t ); }
public void info (String msg, Throwable t) { logger.log(MARKER, FQCN, INFO_INT, msg, null, t ); }
public void warn (String msg, Throwable t) { logger.log(MARKER, FQCN, WARN_INT, msg, null, t ); }
public void error(String msg, Throwable t) { logger.log(MARKER, FQCN, ERROR_INT, msg, null, t ); }
// (String format, Object... arguments)
public void trace(String format, Object... arguments) { logger.log(MARKER, FQCN, TRACE_INT, format, arguments, null); }
public void debug(String format, Object... arguments) { logger.log(MARKER, FQCN, DEBUG_INT, format, arguments, null); }
public void info (String format, Object... arguments) { logger.log(MARKER, FQCN, INFO_INT, format, arguments, null); }
public void warn (String format, Object... arguments) { logger.log(MARKER, FQCN, WARN_INT, format, arguments, null); }
public void error(String format, Object... arguments) { logger.log(MARKER, FQCN, ERROR_INT, format, arguments, null); }
//---
}
DemoLogApplication.java
package com.example.demo;
public class DemoLogApplication {
private static final MyLocationAwareLogger MY_LOGGER = MyLocationAwareLogger.getLogger(DemoLogApplication.class);
public static void main(String[] args) {
MY_LOGGER.info("hello");
MY_LOGGER.info("hello {}", "xxx");
MY_LOGGER.info("exception", new Exception("test"));
MY_LOGGER.info("{} {} {} exception", 1, 2, 3, new Exception("test"));
}
}
Log output example(The correct "Generator of logging request" is output)
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:16)]] DemoLogApplication - hello
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:17)]] DemoLogApplication - hello xxx
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:18)]] DemoLogApplication - exception
java.lang.Exception: test
at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:18)
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:19)]] DemoLogApplication - 1 2 3 exception
java.lang.Exception: test
at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:19)
If you just want to imitate the SLF4J Logger
method, you don't need your own Logger.
If you create your own Logger, create a meaningful Logger, such as preparing methods for each log output purpose (audit log, performance log, etc.).
(In this article, I dared to imitate the method of Logger
for the sake of clarity as a sample. Please forgive me)
Recommended Posts