3

I have configured logback xml for a spring boot project.

I want to configure another appender based on the property configured. We want to create an appender either for JSON logs or for text log, this will be decided either by property file or by environment variable.

So I am thinking about the best approach to do this.

  • Using filters to print logs to 1 of the file (either to JSON or to Txt). But this will create both of the appenders. I want to create only 1 appender.
  • Use "If else" blocks in logback XML file. To put if else around appenders, loggers seems untidy and error prone. So will try to avoid as much as possible.
  • So now exploring options where I can add appender at runtime.

So I want to know if it is possible to add appender at runtime. And will it be added before spring boots up or it could be done anytime in the project.

What could be the best approach to include this scenario.

eis
  • 51,991
  • 13
  • 150
  • 199
Onki
  • 1,879
  • 6
  • 38
  • 58
  • Would this help you? https://stackoverflow.com/questions/16910955/programmatically-configure-logback-appender – mrkurtan Aug 21 '19 at 16:53

2 Answers2

4

As you're already using Spring, I suggest using Spring Profiles, lot cleaner than trying to do the same programmatically. This approach is also outlined in Spring Boot docs.

You can set an active profile from either property file:

spring.profiles.active=jsonlogs

or from environment value:

spring_profiles_active=jsonlogs

of from startup parameter:

-Dspring.profiles.active=jsonlogs

Then have separate configurations per profile:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <appender name="stdout-classic" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
          <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n</pattern>
      </encoder>
  </appender>
  <appender name="stdout-json" class="ch.qos.logback.core.ConsoleAppender">
      <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
          <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
              <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
              <timestampFormatTimezoneId>Etc/UTC</timestampFormatTimezoneId>
              <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
                  <prettyPrint>true</prettyPrint>
              </jsonFormatter>
          </layout>
      </encoder>
  </appender>
  <!-- begin profile-specific stuff -->
    <springProfile name="jsonlogs">
        <root level="info">
            <appender-ref ref="stdout-json" />
        </root>
    </springProfile>
    <springProfile name="classiclogs">
        <root level="info">
            <appender-ref ref="stdout-classic" />
        </root>
    </springProfile>
</configuration>
jasiek.miko
  • 471
  • 6
  • 12
eis
  • 51,991
  • 13
  • 150
  • 199
  • After all my study of logback, this is again new to me that we can use profiles too for this purpose. I related profiles with user only till now. Will experiment this too and update results here. Just wondering more thing, is this a commonly seen project requirement where you have to choose a log format based on user input? Just wondering how its actually done in industry – Onki Aug 21 '19 at 17:05
  • 1
    @Onki more common would be having environment-specific configuration files that are used when deploying. So for example production would use one configuration and test environment something else, but this would not be chosen based on user input. – eis Aug 21 '19 at 17:12
  • thanks for your answer, Its very cleaner then all the available approaches. – Onki Aug 23 '19 at 16:13
  • I have implemented this approach now in my project. But I have ran into 1 more issue. I posted that as separate question but I did not get any answer so thought of putting that here even though its not a right thing to do. See if you have anything to say on it : https://stackoverflow.com/questions/57602337/logback-how-to-log-entire-msg-using-jsonlayout – Onki Aug 23 '19 at 16:16
  • Same can be done without spring: https://stackoverflow.com/questions/53152471/how-can-i-dynamically-by-env-variable-activate-deactivate-logback-or-logback-a – Kukeltje Jan 16 '20 at 17:20
  • @Kukeltje yes. I think this is one of the options mentioned in the question, right? the if-else blocks. – eis Jan 16 '20 at 17:51
  • @eis: yes, seem like that one. – Kukeltje Jan 16 '20 at 18:31
  • You can also add to use all other profiles that aren't jsonlogs when you have multiple appenders. – thonnor Feb 13 '20 at 14:03
4

As the previous answer states, you can set different appenders based on Spring Profiles.

However, if you do not want to rely on that feature, you can use environments variables as described in the Logback manual. I.e.:

<appender name="json" class="ch.qos.logback.core.ConsoleAppender">
  <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
    <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
      <jsonFormatter class="ch.qos.logback.contrib.jackson.JacksonJsonFormatter">
        <prettyPrint>true</prettyPrint>
      </jsonFormatter>
      <appendLineSeparator>true</appendLineSeparator>
    </layout>
  </encoder>
</appender>

<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
  <encoder>
    <pattern>
      %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n
    </pattern>
  </encoder>
</appender>

<root level="info">
  <!--
   ! Use the content of the LOGBACK_APPENDER environment variable falling back
   ! to 'json' if it is not defined
   -->
  <appender-ref ref="${LOGBACK_APPENDER:-json}"/>
</root>
jaguililla
  • 1,916
  • 18
  • 21