I have variables with defaults in my logback.xml
configuration file, and I would like to be able to optionally set these variables from my typesafe config application.conf
file.
I am deploying the application using one-jar, and the application.conf
file packaged up in the deployable jar contains defaults. I pass -Dconfig.file=foo.conf
on execution to provide the path to a server-specific config file.
Right now I can also pass -Dlog.level
and other variables to override my defaults in logback.xml
, and I also have to pass -Dfile.encoding=UTF-8
on the command line. I'm looking for a way to be able to specify these properties in the typesafe config instead of on the command line. It feels like there should be a way to do it, but I can't find the magic words.
logback.xml:
<configuration>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${log.path:-logs/}/${log.file:-myLog.log}</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover -->
<fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- keep 15 days' worth of history -->
<maxHistory>${log.history.days:-15}</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="${log.level:-INFO}">
<appender-ref ref="FILE" />
</root>
</configuration>
application.conf (bundled):
akka {
log-config-on-start = false
event-handlers = ["akka.event.slf4j.Slf4jEventHandler"]
}
sample server-specific app.conf:
include "/application.conf"
akka.log-config-on-start = true
log.level = WARN // this is what I'd LIKE to be able to do
How I'm currently running the app:
java -Dfile.encoding=UTF-8 -Dconfig.file=myApp.conf -Dlog.level=WARN -jar myApp_2.10-0.1-one-jar.jar
I chose to programmatically configure logback having typesafe config. It turned out to be easy.
def enableRemoteLogging(config: Config) = {
val ctx = LoggerFactory.getILoggerFactory.asInstanceOf[LoggerContext]
val gelf = new GelfAppender
gelf.setGraylog2ServerHost(config.getString("logging.remote.server"))
gelf.setUseLoggerName(true)
gelf.setUseThreadName(true)
gelf.setUseMarker(true)
gelf.setIncludeFullMDC(true)
gelf.setContext(ctx)
gelf.start()
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)
.asInstanceOf[ch.qos.logback.classic.Logger]
.addAppender(gelf)
}
You can use the PropertyDefiner
interface that logback provides. Non trivial scaffolding but allows you to configure using XML instead of within your application. E.g.:
package com.myapp;
import ch.qos.logback.core.PropertyDefinerBase;
import com.typesafe.config.ConfigFactory;
public class TypesafeConfigPropertyDefiner extends PropertyDefinerBase {
private String propertyName;
@Override
public String getPropertyValue() {
return ConfigFactory.load().getString( propertyName );
}
public void setPropertyName( String propertyName ) {
this.propertyName = propertyName;
}
}
Then, in your logback.xml file:
<configuration>
<define name="loglevel" class="com.myapp.TypesafeConfigPropertyDefiner">
<propertyName>myapp.logging.loglevel</propertyName>
</define>
<root level="${loglevel}">
...
</root>
</configuration>
Now, the above logback.xml file will read myapp.logging.loglevel
from your typesafe config file (e.g. application.conf
).
I'm not familiar with Logback, but a normal Akka application ships with default settings in its reference.conf
, and you override these settings in an application.conf
. It sounds like you want to add a third layer of configuration, which is certainly your right!
The easiest way I can see is to change your application.conf
to include your foo.conf
rather than the other way around. That way Akka will load the application.conf
, which will then load foo.conf
.
But that may not work if you need a differently-named conf file for each JAR distribution. In which case I recommend you look into Merging Config Trees to programmatically load and combine configuration. Actually, Reading configuration from a custom location in the Akka Configuration docs is almost exactly what you want, except you will want to load myConfig
from a classpath resource rather than by parsing a string (see the Typesafe Config docs to find out how to do that).
Regarding the Logback configuration, like I said, I don't know Logback. But you can read values out an Typesafe configuration like so, and you can set the Logback root logger level like so.