7

I tried the following loggers

  • Java Logging API
  • Log4j
  • slf4j

All of these requires a LOGGER declaration at the class level, like the ones below

private final static java.util.logging.Logger.Logger LOGGER = java.util.logging.Logger.Logger.getLogger(MyClass.class.getName());
private final Logger slf4jLogger = LoggerFactory.getLogger(SLF4JHello.class);
private final static Logger log4jLogger = Logger.getLogger(Log4jHello.class);

This looks hideous to me, is there an logger framework in java that does not require this declaration?

What I'm looking for is, I can have a global declaration like

private final static Logger Logger = Logger.getLogger(MyApp.class);

But when I call Logger.log(..) from class XXX.class then the Logger should make use of the XXX.class name.

Edi
  • 327
  • 4
  • 16
  • 2
    It is completely up to you (in any of these frameworks) how you define and name your loggers. You could just have one for your whole application, or call `getLogger` on any call. – Thilo Feb 24 '16 at 04:00
  • Related: http://stackoverflow.com/questions/26600757/standard-way-to-implement-a-logger-across-classes-in-java?rq=1 http://stackoverflow.com/questions/27038694/is-there-an-easy-way-to-create-a-logger-instance-for-every-class?rq=1 – Thilo Feb 24 '16 at 04:02
  • @Thilo having one for the whole application will make all the logs with the same name. Which is not I'm looking for. Instead the framework has to display the class name of the caller. – Edi Feb 24 '16 at 04:04
  • 2
    The name of the logger is not necessarily tied to what it displays, either. All this can be configured. – Thilo Feb 24 '16 at 04:12
  • you can configure the caller class and method name and source code file name and line number to be displayed in most logging frameworks. But there is some runtime cost to it. – Thilo Feb 24 '16 at 04:14
  • The main impact of the logger name is that it allows the hierarchical application of rules (such as raise log level to DEBUG for `org.apache.commons.*`). I'd just stick to the established pattern. Most flexible, easy, fast (and a little ugliness that could only be resolved by macros or preprocessors or other nastiness). – Thilo Feb 24 '16 at 04:18
  • 1
    All I am saying is "a) that all logging frameworks present this pattern is a clue that it works very well b) they don't require you to follow this pattern" – Thilo Feb 24 '16 at 04:19
  • 1
    The modern way is to use Dependency Injection to set dependencies, such as the logging interface to use, which this pattern supports. So no modern logging framework is likely to do things differently. – Raedwald Feb 25 '16 at 09:33
  • @Raedwald I don't know. Logging seems to be one of those things where "dependency lookup" is still widely accepted. And you can only inject a logging implementation, the interface is still fixed at compile-time (even with DI). And that implementation can be configured independent of the code that uses it, all that would be fixed without DI is the name of the logger. – Thilo Feb 25 '16 at 23:41

2 Answers2

2

Your problem is more than likely not with the logging framework but with the layout.

Concrete example

so35592962/App.java

package so35592962;
import org.apache.logging.log4j.*;
import so35592962.sub.OtherClass;
public class App {
  public static final Logger logger = LogManager.getLogger();
  public static void main(String[] args) {
    logger.error("in App.main");
    OtherClass.act();
  }
}

so35592962/sub/OtherClass.java

package so35592962.sub;
import static so35592962.App.logger;

public class OtherClass {
  public static void act() {
    logger.error("OtherClass.act");
  }
}

So you can see this is totally what you want: classes that use a single logger. So good point, Log4J2 can be used for that.

Now I add the magic file log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %C{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="error">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

Running this will print:

12:05:28.834 [main] ERROR so35592962.App - in App.main
12:05:28.836 [main] ERROR so35592962.sub.OtherClass - OtherClass.act

Look, there are different class names here! Yet I used Log4J2.

What happened here?

Note the pattern used in the PatternLayout tag:

%d{HH:mm:ss.SSS} [%t] %-5level %C{36} - %msg%n

The standard examples and what you usually see on the Internet all use the %L pattern. This pattern is to show the logger name. But you said you don't want it. Fortunately, other patterns exist. %C will show the class name instead of the logger name. This is the pattern that is used here.

According to the PatternLayout documentation, the %C pattern does the following:

Outputs the fully qualified class name of the caller issuing the logging request.

Important note, also mentioned in the documentation:

Generating the class name of the caller (location information) is an expensive operation and may impact performance. Use with caution.

Olivier Grégoire
  • 33,839
  • 23
  • 96
  • 137
  • But if you only have a single Logger, you cannot assign different log levels (or different formatters, or different appenders) to different Loggers anymore. – Thilo Feb 24 '16 at 23:43
  • Correct, but this answers the initial question, I believe. One unique logger, using the class name. – Olivier Grégoire Feb 25 '16 at 08:30
  • 3
    Also, this answer is not a "yes, by all means, do this", but a "your request can be done, here's how". I personally don't endorse this, but if ti works for the OP, I'm glad I helped! – Olivier Grégoire Feb 25 '16 at 09:08
1

You could change both of these to class annotations with Lombok.

Tyler
  • 827
  • 2
  • 11
  • 25