Calling log4j's log methods indirectly (from a

2020-03-31 03:37发布

问题:

I'd like to put the logger.debug(...) call into a helper method, and call that helper method from anywhere that needs to write the log. While this mostly works fine, the log entry itself shows the helper method as the source of the call, which is understandable since log4j isn't aware of me using a helper method for logging.

Is there any way to tell it to skip the helper method when figuring out the source of the logger.debug(...) call and instead use its caller?

By source, I mean %F:%L of org.apache.log4j.PatternLayout: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

To illustrate what I mean, here's an example stack trace:

1. logger.debug(msg, throwable)
2. logHelper(logger, msg, throwable) <-- currently shows as the source of the call, since it calls logger.debug directly
3. someFunction <-- where the real logable event occurs, so I'd want this to be logged as the source

The reason I'm doing this is because I'd like an exception logged only by name (e.toString) if the log level is INFO, or with a full stack trace if the level is DEBUG. I'm open to suggestions for alternatives.

Thanks! :)

回答1:

You can't instruct Log4J to "skip" a level in its source detection.

What you can do, though, is subclass PatternLayout and override the format(LoggingEvent) method to your liking (i.e. only produce the exception's toString() when in INFO mode, etc).



回答2:

One way to do this is to have the helper class call:

logger.log(LogHelper.class.getName(), Level.DEBUG, message, t);

... instead of:

logger.debug(message, t);

So when log4j tries to determine the source of the event, it will stop when it reaches the parent of LogHelper instead of the parent of Logger.

Verified working as expected.



回答3:

For Log4j2 the answer is provided completely by the use of logger wrappers as described in the Log4j2 manual under Example Usage of a Generated Logger Wrapper. One can simply generate (using the org.apache.logging.log4j.core.tools.Generate$ExtendedLogger tools illustrated there) a logger wrapper with a single STUB level, and then adapt that to create custom logging methods mimicking the use of the logIfEnabled(FQCN, LEVEL, Marker, message, Throwable) - possibly ignoring the STUB level and using the regular ones - then if desired, deleting or commenting out the STUB level and its methods). For this purpose the FormattedMessage can be helpful.

The method and source line, while expensive, can then be easily shown as part of the full location information by using the %l location conversion pattern element in the PatternLayout given in the configuration, or more specifically using the %L line number and/or the %M method conversion.

Now with complete example at: Java Logging: Log4j Version2.x: show the method of an end-client caller (not an intermediate logging helper method)



回答4:

For log4j2, you can write a simple wrapper class or generate one as Webel suggests. See my answer for log4j2: https://stackoverflow.com/a/39045963/116810



标签: java log4j