How can I dynamically (by env variable) activate/deactivate logback or logback appender?
Asked Answered
S

3

7

is there a way to choose if I want to have a logback appender or not, via environment variable?

I have a dockerized spring boot Microservice and added now the ELK stack.
That works fine so far.
But now if I want to start my service without ELK stack, the application throws an error, that it doesn't know the host of Logstash:

app | 10:09:23,537 |-ERROR in ch.qos.logback.classic.net.SyslogAppender[SYSLOG] - Could not create SyslogWriter java.net.UnknownHostException: logstash: Name or service not known
app |   at java.net.UnknownHostException: logstash: Name or service not known

Here is my logback.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
        <syslogHost>logstash</syslogHost>
        <port>5000</port>
        <facility>LOCAL1</facility>
        <suffixPattern>[%thread] %logger %msg</suffixPattern>
    </appender>

    <root level="INFO">
        <appender-ref ref="SYSLOG"/>
    </root>

</configuration>

I know this is a very simple version, but I am new in logging with logback/ELK stack.

So is there a way to inject something with an environment variable like in yaml files e.g. active=${LOGBACK_ACTIVE:false} like I can do it with my prometheus metrics?

Steffen answered 5/11, 2018 at 10:25 Comment(2)
#33029342 might help youMonophagous
no the problem is not, that the application can't find the host of Logstash. the problem is, I only want to start the app, without ELK stack (so there is no host of logstash^^)Steffen
F
5

In your logback.xml you could use the <if> construct to enable the SYSLOG appender when a named JVM parameter is present.

In the following example if you run your application with -Dsyslog then your SYSLOG appender will be engaged otherwise it will be ignored and the default appender, CONSOLE, will be engaged:

<if condition='isDefined("syslog")'>
  <then>
    <appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender">
      ...
    </appender>

    <root level="INFO">
      <appender-ref ref="SYSLOG" />
    </root>
  </then>
  <else>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
      ...
    </appender>

    <root level="INFO">
      <appender-ref ref="CONSOLE" />
    </root>
  </else>
</if>

This requires some duplication of the root declaration but since you need to conditionally prevent the SYSLOG appender from being instantiated I think this might be your only option.

Fog answered 5/11, 2018 at 11:34 Comment(2)
good point, but also didn't work. the app instatiate the appenders on startup: app | 11:53:12,409 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - About to instantiate appender of type [ch.qos.logback.classic.net.SyslogAppender] app | 11:53:12,441 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [SYSLOG] app | 11:53:12,462 |-ERROR in ch.qos.logback.classic.net.SyslogAppender[SYSLOG] - Could not create SyslogWriter java.net.UnknownHostException: logstash: Name or service not known Steffen
In that case put the entire appender (and the root reference) inside the <if> block.Fog
D
4

You can set an environment variable such as LOGSTASH_ENABLED and only activate that appender if it is true.

In logback-spring.xml :

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <springProperty name="logHost" source="appname.logstash.host" />
  <springProperty name="logstashEnabled" source="appname.logstash.enabled" />

  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
      <Pattern>
        %green(%d{yyyy-MM-dd HH:mm:ss}) %magenta([%thread]) %blue(%-5level) %yellow(%logger{36}) - %msg%n
      </Pattern>
    </layout>

  </appender>
  <root level="INFO">
    <appender-ref ref="STDOUT"/>
  </root>

  <if condition='${logstashEnabled} == true'>
    <then>

      <appender name="STASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
        <destination>${logHost}</destination>
        <!-- encoder is required -->
        <encoder class="net.logstash.logback.encoder.LogstashEncoder" />
        <keepAliveDuration>5 minutes</keepAliveDuration>
      </appender>

      <root level="INFO">
        <appender-ref ref="STASH"/>
      </root>

    </then>
  </if>

</configuration>

in docker-compose.yml:

environment:
  LOGSTASH_HOST: logstash:5000
  LOGSTASH_ENABLED: "true"

in bootstrap.yml:

appname:
  logstash:
    host: ${LOGSTASH_HOST:localhost:5000}
    enabled: ${LOGSTASH_ENABLED:false} # default, when not using docker-compose set to false
Delaware answered 24/5, 2020 at 22:22 Comment(0)
P
0

The following worked for me. Note that it requires janino library on classpath

<dependency>
   <groupId>org.codehaus.janino</groupId>
   <artifactId>janino</artifactId>
</dependency>

logback.xml:

<springProperty name="LOGSTASH_ENABLED" source="app-properties.log.logstash.enabled"/>
<springProperty scope="local" name="logstash_host" source="app-properties.log.logstash.host"/>
<springProperty scope="local" name="logstash_port" source="app-properties.log.logstash.port"/>
<if condition='p("LOGSTASH_ENABLED").equals("true")'>
    <then>
        <appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
            <destination>${logstash_host}:${logstash_port}</destination>
            <encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
        </appender>

        <root level="DEBUG">
            <appender-ref ref="logstash"/>
        </root>
    </then>
</if>

application-${ENV}.yml file:

app-properties:
    log.logstash:
        host: localhost
        port: 5000
Pleat answered 9/6, 2024 at 15:21 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.