In a Spring Boot / Logback project, I want to check if a system property is set to use a given appender or not. My code is:
<property name="MY_PROPERTY" value="${MY_PROPERTY:-}" />
....
<logger name="com.my.project" level="INFO">
<if condition='property("MY_PROPERTY").equalsIgnoreCase("MY_PROPERTY_IS_UNDEFINED")'>
<then>
<appender-ref ref="STDOUT" />
</then>
<else>
<appender-ref ref="APPENDER_WITH_ MY_PROPERTY" />
</else>
</if>
</logger>
The code above (seems to) works, but this is not nice. The property() method append _IS_UNDEFINED to the variable name and I use it...
I can't find any reliable documentation about it, is there a better way?
Late to the party, but hey.
The logback manual (http://logback.qos.ch/manual/configuration.html) mentions the isDefined method:
The isDefined() method can be used to check whether a property is defined. For example, to check whether the property "k" is defined you would write isDefined("k") Similarly, if you need to check whether a property is null, the isNull() method is provided. Example: isNull("k").
Related
I Configured the Cloud Logging implementation in my Java11 Google App Engine application following the guide
From the Cloud Logging UI I can see the log lines of the same request being grouped under a common parent, which is exactly what I wanted. And it's working:
I found that when a request actually triggers a new instance, this kind of behaviour is not working:
You can see that there aren't any children, only the log about the instance being created:
This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.
If I filter by the specific traceId I can actually see the logs of that specific request, the only missing part here is that are not displayed under the common parent:
Am I missing a configuration? Is this a known behaviour?
This is my current logback-spring.xml
<!-- https://spring-gcp.saturnism.me/app-dev/observability/logging#logback -->
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />
<springProfile name="development | stage | production">
<include resource="org/springframework/cloud/gcp/logging/logback-json-appender.xml" />
<root level="INFO">
<appender-ref ref="CONSOLE_JSON" />
</root>
</springProfile>
<springProfile name="default | localhost">
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>
</configuration>
I want to configure logback in such way that some specific appender will work only if system variable LOGGER_ENABLED is set to true. If the variable is not set at all it should not give any error.
So I tried several approaches
1. Set only env variable and use it in logback as
<if condition='${LOGGER_ENABLED}'>
<then>
<appender-ref ref="MyAppender"/>
</then>
</if>
it works fine if variable is set to true of false. If it is absent - it throws error like ...is undefined
2. Another catch is to use spring yml file and set it like
sendErrors=${LOGGER_ENABLED:false} //that means to use false if not set
and in logback to use like
<if condition='${sendErrors}'>
<then>
<appender-ref ref="MyAppender"/>
</then>
</if>
in such way it will work only for static "false" or "true" values and do not prefetch ${LOGGER_ENABLED:false} condition.
Is it possible to perform such configuraiton with spring boot and logback?
Ok, I found the answer on my question.
In logback file default separator is ":-" instead of ":" in general spring boot file.
After replacing separator to ":-" I'm able to specify default value exactly in logback file
Example
<if condition='${sendErrors:-true}'>
<then>
<appender-ref ref="MyAppender"/>
</then>
</if>
You should be able to configure this in your logback.xml. Something like:
<logger name="com.myorg.foo" level="${logging.level.com.myorg.foo}" additivity="false">
<!-- <appender-ref ref="console" /> -->
<appender-ref ref="MyAppender" />
</logger>
where logging.level.com.myorg.foo is a property you defined in logback.xml like your variable LOGGER_ENABLED
<property name="logging.level.com.myorg.foo" value="ERROR"/>
I've set up logback.xml to select which appender to use based on the active Spring profile. The technique works perfectly when I run the app using
java -jar -Dspring.profiles.active=local path/to/target/application.war
but not when I run it using the Spring Boot Maven Plugin, e.g.
mvn spring-boot:run -Drun.profiles=local
Here's the relevant section of the logback.xml
<root level="INFO">
<if condition='"${spring.profiles.active}".contains("local")'>
<then>
<appender-ref ref="CONSOLE"/>
</then>
<else>
<appender-ref ref="FILE"/>
</else>
</if>
</root>
I will note that the profile does show up correctly in the application itself, just isn't available when processing logback.xml.
The problem also manifests when running from the IntelliJ IDE.
Is there another way to use the Maven Spring Boot Plugin to cause the profile to be visible to the logback.xml parser, and would it work for IntelliJ, as well?
Have you tried to configure logback through logback-spring extension?
In your case logback-spring.xml could look like this:
<?xml version="1.0" encoding="UTF-8"?>
<include resource="org/springframework/boot/logging/logback/base.xml"/><!-- include this config if you want to use spring-boot's built-in appenders -->
<configuration>
<root level="INFO">
<springProfile name="local">
<appender-ref ref="CONSOLE"/>
</springProfile>
<springProfile name="otherprofile">
<appender-ref ref="FILE"/>
</springProfile>
</root>
</configuration>
More information about available options in logback-spring extensions:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html#boot-features-logback-extensions
The Spring Boot docs have the following sample logging file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
</root>
</configuration>
Can you help me understand the line ${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}spring.log}? What are the - for?
Like Bash, Logback uses :- as its default value operator. The line in question is setting the LOG_FILE property:
If LOG_FILE is already set, use that
Otherwise, if LOG_PATH is set, use that suffixed with spring.log
Otherwise, if LOG_TEMP is set, use that suffixed with /spring.log
Otherwise, if java.io.tmpdir is set, use that suffixed with /spring.log
Otherwise use /tmp/spring.log
It has nothing to do with Spring.
Logback XML configuration itself has such kind of placeholder handling to replace the placeholders with variable. The syntax for placeholder in logback is ${VARNAME}, and if you want default value if VARNAME is not present, you can do it by ${VARNAME:-DEFAULT} (ref: Logback Configuration). Yes, a :-, follow by the default value.
Then what you quote is easy to understand:
${LOG_FILE:- }
${LOG_PATH:- }spring.log
${LOG_TEMP:- }/
${java.io.tmpdir:- }
/tmp
(Do you actually need explanation on what the above means?)
I currently have the following logger defined in my logback.xml:
<logger name="Event" level="INFO" additivity="false">
<appender-ref ref="STDOUT"/>
</logger>
Is it possible to override the level here using an environment variable? I am using SpringBoot.
I have tried having these defined as ENV variables:
LOGGING_LEVEL_ROOT=ERROR
LOGGING_LEVEL_EVENT=ERROR
LOGGER_LEVEL_EVENT=ERROR
However none of these worked.
Spring Boot supports springProfile extension for the logback configuration file:
<springProfile name="test"> </springProfile>
Documentation
Also there is another way to do it using LoggingApplicationContextInitializer.