6

I have several executable classes and I would like to automatically set the log filename to the name of the Java class being executed.

I know I could do this programmatically, probably using Reflection and MDC, but isn't there an easier way to achieve this by configuring logback.xml?

This seems a rather basic need to me, so I am surprised I could not find documentation about it.

Alphaaa
  • 3,936
  • 8
  • 31
  • 43

3 Answers3

3

If you're on a JVM that supports it you can use this property

<file>${sun.java.command}.log</file>

Otherwise you need to set a similar system property in all your main methods that logback can use.

OrangeDog
  • 33,501
  • 12
  • 115
  • 195
  • Thank you. This property seems to be not supported when launching through Eclipse on Windows, but it works when launching on Ubuntu through Maven. I get a string such as `org.codehaus.plexus.classworlds.launcher.Launcher exec:java -Dexec.mainClass=mypackage.MyMainClass` and with some cleaning I should be able to isolate the class name. – Alphaaa Jun 15 '17 at 09:01
0

If you don't mind specifying the application name twice in your command line, you can specify a java system variable to be the application name of your choice, and reference that system variable in your logback configuration file.

Eg. Your command...

java -DAPPNAME="Class1" Class1

... passes the value "Class1" as a java system variable which logback picks up, and you can reuse like this...

<appender name="FILE" class="ch.qos.logback.core.FileAppender">
    <file>${APPNAME}.log</file>
    <encoder>
        <pattern>%msg%n</pattern>
    </encoder>
</appender>
b4n4n4p4nd4
  • 70
  • 1
  • 10
-1

As you mentioned, you can easily achieve this by doing:
Logger loggerA = LoggerFactory.getLogger(this.getClass().getSimpleName());

I think it's pretty comfortable setup, so Logback didn't bother with allowing explicit xml configuration for that.

So, you can collect all your logs from this.getClass() that appear in Class1 and Class2 to one logger with package name com.company (Class1 and Class2 share this namespace):

    <appender name="MY_STUFF" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - %msg%n</pattern>
        </encoder>

        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_DIR}/my_log.server_%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
    </appender>

    <logger name="com.company" level="INFO" additivity="false">
        <appender-ref ref="MY_STUFF" />
    </logger>
Johnny
  • 12,661
  • 14
  • 70
  • 112
  • `LoggerFactory.getLogger` simply returns a logger named as the string passed, but it does not impact the log filename for `FileAppender`s. And even if I manage to set the log filename equivalent to the logger name, that's not what I want: every class would log to a separate file, while I want that all classes log to a file named as the main class being executed. – Alphaaa Jul 18 '16 at 08:53
  • You correct, it does not impact the log filename for FileAppender. Just use namespace that will include in all the loggers you create in `LoggerFactory.getLogger` (for example com.company.yourclass) in your `logback.xml`: ` ` Did I understood correctly? – Johnny Jul 18 '16 at 09:42
  • Let me try to explain what I need with an example. If I execute `Class1.java`, _all_ classed called during the execution should log to *class1.log*. If tomorrow I create and run a new executable class named `Class2.java`, everything within that execution should go into *class2.log*, without me having to change any setting. Makes sense now? – Alphaaa Jul 18 '16 at 16:32
  • Yes, I understand. But I don't really see the meaning for it- just catch all the Classes with the shared namespace they have in the `` itself, you will need the configure the *real* logger in any case, in the `logback.xml` file: ` ` //`com.company` is the shared namespace. – Johnny Jul 19 '16 at 08:59
  • @StasS `this.getClass()` is often a common class used by both `Class1` and `Class2`. How does your example create `class1.log` and `class2.log`? – antak Aug 22 '16 at 02:58
  • @antak it's not, in my example i'm showing how both `this.getClass()` of `Class1` and `Class2` collected to one logger that defined with the shared namespace. – Johnny Aug 22 '16 at 15:34
  • @StasS `Class1` and `Class2` may be run at the same time. Using a shared log file means you're introducing a concurrency risk. This risk may be averted by setting `prudent=true`, however this has its own problems. Aside from the [performance overhead](http://logback.qos.ch/manual/appenders.html#prudent) of using `prudent=true`, what you can do with the `RollingFileAppender` also becomes [severely limited](http://logback.qos.ch/manual/appenders.html#prudentWithRolling). – antak Aug 23 '16 at 03:58