Can you explain this Spring environment variable resolution? - spring

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?)

Related

Is there a way to provide Slueth the spring application name other than specifying that in bootstrap.properties of Spring boot application?

As per this guidelines, one has to specify application name in bootstrap.properties if using custom logback.xml. I was wondering if there's any way where I can hardcode the application name in logback.xml instead of creating the bootstrap.properties file with that property ?
I have bootstrap.properties with property spring.application.name and slueth recognizes that and things are fine. But I was wondering if there's any way where I can specify any logback property and sleuth will pick the application name up!?
Please note I am using my own custom logging format. Following is how my logback.xml file looks like.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<property name="CONSOLE_LOG_PATTERN" value="%date{ISO8601}
${LOG_LEVEL_PATTERN:-%5p} ${PID:- } [%15.15t] %-40.40logger{39} :
%m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
The <springProperty> tag lets you expose properties from the Spring Environment for use within Logback.
i.e.
<springProperty scope="context" name="fluentHost" source="myapp.fluentd.host" defaultValue="localhost"/>

How to set max number of archived logs in spring boot

I tried following settings in application.properties:
logging.file=foo/bar.log
logging.file.max-history=2
logging.file.max-size=1KB
Still, its not limiting the number of archive logs to 2.
As per application properties documentation reference, only supported when you setup logback.
logging.file.max-history=0 # Maximum of archive log files to keep. Only supported with the default logback setup.
So to add support of logback please see section 79.1 Configure Logback for Logging & 79.1.1 Configure Logback for File-only Output of Spring Boot Logging Guide
If you want to disable console logging and write output only to a
file, you need a custom logback-spring.xml that imports
file-appender.xml but not console-appender.xml, as shown in the
following example:
<?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>

Setting logback property via spring config + environment variable in spring config

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"/>

Specify default value for a logback property, in spring-boot

In spring-boot application, I am trying to config a default dir for logback.
Usually, in logback.xml I would config it this way:
<property name="logFile.dir" value="${catalina.home:-/tmp}/logs" />
The separator is :-.
But, in application.properties:
I have to config it this way:
logging.file=${catalina.home:/tmp}/logs/sportslight.log
Need to change the separator from :- to :.
The questions are:
In logback.xml, which is the correct separator, :- or :?
In application.properties, why only : works, is it because spring-boot would handle it first before pass the value to logback?
In logback.xml the correct separator is :-. More details in the logback docs.
In Spring the correct separator is : since Spring supports the ${my.property:defaultValue} syntax. More details in the PlaceholderConfigurerSupport doc.
So, when faced with a choice of default value separator for variable substitution the logback author(s) chose :- and the Spring author(s) chose :.
In logback.xml or logback-spring.xml, you can set default value for both system property and project property (or you can say spring property).
1) For system property, you can simply go with the :- syntax. In the following example, the default level of ThresholdFilter is ERROR.
<configuration>
<appender name="sentry" class="io.sentry.logback.SentryAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${sentryLevel:-ERROR}</level>
</filter>
</appender>
</configuration>
You can override it by starting the java process with, such as -DsentryLevel=INFO.
2) For project property/spring property, you can set defaultValue in the springProperty element.
<configuration>
<springProperty scope="context" name="sentryLevel" source="your.prop.path" defaultValue="ERROR"/>
<appender name="sentry" class="io.sentry.logback.SentryAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>${sentryLevel}</level>
</filter>
</appender>
</configuration>
You can override it by changing the application.properties or application.yml.
your.prop.path=INFO

Empty Default String for Property in logback.xml

Our project structure regarding the logback.xmls looks like this:
src\main\resources\logback.xml
src\main\resources\config\dev\logback.xml
src\main\resources\config\sjngm\dev\logback.xml
src\main\resources\config\int\logback.xml
src\main\resources\config\local\logback.xml
src\main\resources\config\prod\logback.xml
where the first one references to the environment specific one:
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<contextName>sjngm</contextName>
<jmxConfigurator />
<include resource="config/${extra}${env:-local}/logback.xml" />
</configuration>
Note that extra is not defined most of the times, which is why used this for a while:
<include resource="config/${extra:-}${env:-local}/logback.xml" />
This stopped working at one point, can't remember which version of logback. So we changed it to
<include resource="config/${extra:-./}${env:-local}/logback.xml" />
which also worked for quite a while.
Now we switched to Spring Boot 1.5.4 (contains logback-classic 1.1.11 and logback-core 1.1.11) and it stopped working again. The latest error message is:
11:08:15,020 |-WARN in ch.qos.logback.core.joran.action.IncludeAction - Could not find resource corresponding to [config/./local/logback.xml]
If I go back to
<include resource="config/${extra:-}${env:-local}/logback.xml" />
the message is
11:19:28,778 |-WARN in ch.qos.logback.core.joran.action.IncludeAction - Could not find resource corresponding to [config/extra_IS_UNDEFINEDlocal/logback.xml]
Note that logback still uses "local" as a default string for env, so not all is broken.
What do I do now? Basically I want to tell logback that I want an empty string where extra would be.
This also doesn't work:
<property name="defaultExtra" value="" />
<include resource="config/${extra:-${defaultExtra}}${env:-local}/logback.xml" />
as an empty string seems to always result in an undefined property.
The only working thing I can come up with is this:
<if condition='isDefined("extra")'>
<then>
<include resource="config/${extra}${env:-local}/logback.xml" />
</then>
<else>
<include resource="config/${env:-local}/logback.xml" />
</else>
</if>
plus this into the pom.xml:
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
</dependency>
Isn't this nice?! So why did they have to break what was working nicely???
This worked for me:
<property name="extra" value="${logback.myApp.extra:- }" />
Logback seems to trim Whitespace out of the value. So the default value of Space did the trick.
Embedded Whitespace is preserved, which may lead to a FileNotFoundException if Tabs were embedded, but embedded Spaces were ok.
Setting a Property in a Java Initialiser had the desired effect:
System.setProperty("logback.myApp.extra", "\t \tEXTRA_EXTRA_EXTRA\t \t");
The Tabs & Spaces were removed from the Property, which was assigned the value EXTRA_EXTRA_EXTRA
(the Java Initialiser must be invoked before any Logging has taken place & may contain no Logging itself)
You could of course set the Property on the Java Command line.
P.S. if the Property is undefined & you omit the Space (${logback.myApp.extra:-}), it is assigned the value:
logback.myApp.extra_IS_UNDEFINED
...so it may be wise to add a suitable comment:
<property name="extra" value="${logback.myApp.extra:- }" /><!-- N.B. Empty Default value must contain # least 1 Space!! -->

Resources