jtsampson
jtsampson

Reputation: 218

Multiple Grails Application + tomcat-slf4j-logback, how to get application name into logfile

We are currently deploying several Grails (2.4.4) applications to a Tomcat 7 server and have configured logging exactly as described here tomcat-slf4j-logback.

The desire is to configure all grails applications via one logback.xml file as well as log all applications to a single file, but discriminate log messages by their application name as defined in grails' application.properties:

#Grails Metadata file
app.name=my-application

Our logback.xml appender currently looks like this:

<appender name="FILE" 
         class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${catalina.base}/logs/all.log</file>
    <append>true</append>
    <encoder>
        <charset>utf-8</charset>
        <pattern>%d [%X{appname:-null}] %-5level %logger : %msg%n</pattern>
    </encoder>
    ...
</appender>

As you can see we are currently pulling the 'appname' from the MDC (Mapped Diagnostic Context). It is placed there by a Grails Filter in a Grails Plugin shared by all the applications which looks it up from the application.properties file. This produces output in the log file similar to:

13:34:18.796 [application-1] DEBUG a.b.c.MyClass : hello
13:34:18.797 [application-2] DEBUG a.b.c.MyClass : hello
13:34:18.798 [null] DEBUG b.c.d.OtherClass : No App Name
13:34:18.798 [application-3] DEBUG a.b.c.MyClass : hello
13:34:18.799 [null] DEBUG b.c.d.OtherClass : No App Name

This solution is lacking due to the threadLocal nature of the MDC. Those classes executing outside of the request/response threads don't have access to the same MDC to get the 'appname' and instead print '[null]'.

I have tried the following in logback.xml

<property resource="application.properties" />

Which is supposed to load the application.properties from the classpath but gives:

  13:34:18.796 [app.name_IS_UNDEFINED] DEBUG a.b.c.MyClass : hello

Which I think means logback can't find the application.properties files (they are packaged in WEB-INF\classes\ in each of the wars)...

I've also tried locally using logback.groovy ala:

// logback.groovy
// Read in the Grails application.properties
def props = new Properties()
new File("application.properties").withInputStream { 
    stream -> props.load(stream) 
}

def slurper = new ConfigSlurper().parse(props)

// Get the application name.
String grailsAppName = slurper.app.name

appender("CONSOLE", ConsoleAppender) {
encoder(PatternLayoutEncoder) {
  pattern = "%d [${grailsAppName ?: 'Application Name Not Set'}]  %-5level %logger - %msg%n"]
}

}

And this works, as long as I set 'logback.configurationFile' to point to it but I don't think replacing the single logback.xml the Tomcat 7 server with logback.groovy will work (but it is next on my list to try)

Other things I've tried

Any help would be appreciated

Upvotes: 2

Views: 1388

Answers (1)

Gom
Gom

Reputation: 26

Steps to configure:

  1. Add the below line in the grails-app/conf/application.yml or external application configuration file:

     logging:
     config: "C:/Application/config/logback.groovy"  
     file: "app.log"  
     path: "C:/Application/logs"  
    
  2. Put the configuration file in the above provided config path(in above e.g C:/Application/config/logback.groovy):

Ex.:

import grails.util.BuildSettings  
import grails.util.Environment  

import ch.qos.logback.classic.encoder.PatternLayoutEncoder  
import ch.qos.logback.core.ConsoleAppender  
import ch.qos.logback.core.FileAppender  

import static ch.qos.logback.classic.Level.DEBUG  

def targetDir = System.getProperty("LOG_PATH")  
def targetFile = System.getProperty("LOG_FILE")  

appender("FILE", FileAppender) {  
file = "${targetDir}/${targetFile}"  
encoder(PatternLayoutEncoder) {  
pattern = "%date %level %logger - %msg%n"  
}  
}
appender("STDOUT", ConsoleAppender) {  
encoder(PatternLayoutEncoder) {  
pattern = "%msg%n"  
}  
}  
root(INFO, ["FILE", "STDOUT"])  

All the applications can point to same configuration file by following the first step. So, all the logs will be generated according to the path and file specified in step 1.

System properties which the Logging System takes care of creating for you:

•   ${PID} the current process ID.  
•   ${LOG_FILE} if logging.file was set in Boot’s external configuration.  
•   ${LOG_PATH} if logging.path was set (representing a directory for log files   to live in).  
•   ${LOG_EXCEPTION_CONVERSION_WORD} if logging.exception-conversion-word was   set in Boot’s external configuration.  

So you can use them in logback.groovy file as shown above System.getProperty("LOG_PATH").
References:
https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html

Upvotes: 1

Related Questions