52

The configuration file for logback gets found on the classpath, and is therefore Eclipse-project-specific, which is not what I want. I'm using multiple Java utilities, all of them residing in a single project (this sharing the classpath), and I need to use a specific configuration for some of them.

I've tried variable substitution and Joram configurator, but nothing worked for me. This was most probably my fault, and I'm going to solve it one day, but for now I'd need a simple solution.

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • What is the "specific configuration" that you need for your different pieces? – Ryan Stewart Jul 14 '11 at 20:52
  • Nothing really "special"... in some utilities I need to log more, in others I need to log less. This is the most important part for me. I also want to redirect the output in different files (ideally based of the main class). – maaartinus Jul 14 '11 at 21:06
  • That sounds like you should be able to manage it all from a single config file. I'm not sure what you mean by the "Eclipse-project-specific" bit in your question. Can you clarify what exactly you're after? – Ryan Stewart Jul 14 '11 at 22:03
  • 1
    @Ryan Stewart I see no way how to manage it from a single config file. There are classes `Main1` and `Main2`. For them I use different loggers and can set different logging levels. That's fine. But both of them use the class `Common1` for which I need to set the logging level according to which of the `Main*` classes is the main class (i.e, what program was started). – maaartinus Jul 14 '11 at 22:38
  • @Ryan Stewart By **Eclipse-project-specific** I simply mean, that there's a single classpath per Eclipse project and therefore there's a single logback configuration file per Eclipse project. This is fine unless there are multiple main classes in the project for which you want differently verbose logging. – maaartinus Jul 14 '11 at 22:39
  • Out of curiosity, did you try any of the options that I suggested? Do you still have a logging configuration problem? – jtoberon Jul 22 '11 at 14:35
  • Sorry, I haven't got the time yet, but I'm sure it solves my problem. Your answer is awesome, indeed. I'll comment on it as soon as I get the time to try it out. – maaartinus Jul 22 '11 at 19:17
  • I'm sad to say that I've actually used all of these options over the years :) – jtoberon Jul 22 '11 at 19:25

3 Answers3

81

OPTION 1: specify the location of the logback configuration file with the logback.configurationFile system property. This does in fact allow you to have multiple configuration files per project. As per the logback documentation, the value of the this property can be a URL, a resource on the class path or a path to a file external to the application. For example:
-Dlogback.configurationFile=/path/to/config.xml

OPTION 2: use variable substitution to set the name of the log file with a system property. For example:

  1. Your appender can set the file as follows:
    <file>/var/tmp/${mycompany.myapplication}.log</file>
  2. And then you can specify the value of that variable when launching java:
    -Dmycompany.myapplication=SomeUtility

OPTION 3: set the logger level with a system property. This will allow you to log more/less. For example:

  1. Put this into your logback config file:
    <logger name="com.mycompany" level="${mycompany.logging.level:-DEBUG}"/>
    This causes the specified package to log at DEBUG level by default.
  2. If you want to change the logging level to INFO in a specific application, then pass the following to java when launching that application:
    -Dmycompany.logging.level=INFO

OPTION 4: add/remove an appender by passing a system property command-line parameter to java. This will allow you to log to different places. Note that conditional processing requires janino. For example:

  1. Put this into your logback config file wherever you would put an <appender-ref>, changing the ref value to one of your own <appender>s, of course:
    <if condition="property("mycompany.logging.console").equalsIgnoreCase("true")"> <then><appender-ref ref="STDOUT"/></then></if>
  2. If you want to enable this appender, then pass the following to java when launching that application:
    -Dmycompany.logging.console=true

Regarding system properties, you pass them to java as -D arguments, e.g.
java -Dmy.property=/path/to/config.xml com.mycompany.MyMain

Roy Truelove
  • 22,016
  • 18
  • 111
  • 153
jtoberon
  • 8,706
  • 1
  • 35
  • 48
  • 5
    Nice list! Another option: logback supports programmatic configuration. If the point of differentiation in the application is the main classes, those classes could configure logback themselves. – Ryan Stewart Jul 15 '11 at 03:33
  • On option 4 you have started the condition with " but it should be ' – D.Tomov Dec 12 '18 at 09:41
3

In a Spring Boot application, you can reference Spring Profiles inside logback configuration file.

See this article.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 <springProfile name="dev">
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
        <pattern>
          %d{HH:mm:ss.SSS} | %5p | %logger{25} | %m%n
        </pattern>
        <charset>utf8</charset>
      </encoder>
    </appender>
    <root level="DEBUG">
      <appender-ref ref="CONSOLE"/>
    </root>
  </springProfile>
  ...
Agustí Sánchez
  • 10,455
  • 2
  • 34
  • 25
3

I have used another option based on Leonidas blog. There are two files:

  • the optional property file (environment.properties) that contains the environment property
  • and custom configurations (e.g. logback-env-test.xml). All these files have to be on the classpath.

If the property file exists and defines logEnv property e.g.

logEnv = dev66

the logback tries to find and include the custom configuration from logback-env-dev66.xml

<included>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>
    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>
</included>

Overwise it will be falback to default (<else> section) configuration. Please, note the <included> tag are using instead of <configuration> in custom configuration files.

the logback.xml to manage all the above things:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="5 seconds" debug="true">
    <!-- To skip error if property file doesn't exist -->
    <define name="propExists" class="ch.qos.logback.core.property.ResourceExistsPropertyDefiner">
        <resource>environment.properties</resource>
    </define>
    <if condition='${propExists}'>
        <then>
            <property resource="environment.properties" />
        </then>
    </if>
    <!-- If specific configuration exists, load it otherwise fallback to default (<else> section)  -->
    <define name="confExists" class="ch.qos.logback.core.property.ResourceExistsPropertyDefiner">
        <resource>logback-env-${logEnv}.xml</resource>
    </define>
    <if condition='${confExists}'>
        <then>
            <include resource="logback-env-${logEnv}.xml"/>
        </then>
        <else>
            <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
                <encoder>
                    <pattern>%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n</pattern>
                </encoder>
            </appender>
            <root level="INFO">
                <appender-ref ref="STDOUT" />
            </root>
        </else>
    </if>
</configuration>

It will allow you to have separate configuration for all environments, define own custom configuration (e.g. local development) without influence on others.

Derek Lee
  • 3,452
  • 3
  • 30
  • 39
foal
  • 693
  • 7
  • 20