Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make Logback write to the console locally, but to log file on server

In a web application built with Maven 3, is there a way to have Logback use either a ConsoleAppender or a RollingFileAppender depending where/how the application is running?

In production the .war file is deployed on Tomcat 7. Locally I'm running the Jetty Maven plugin for testing purposes during development.

I would like to have the logging work like this:

  • When I run mvn jetty:run locally: Use ConsoleAppender
  • When *.war file is deployed on production (Tomcat 7): Use RollingFileAppender

During local development it just seems very comfortable to have all log output on the console. In production I would instead prefer to log to a file: CATALINA_BASE/logs/myApp.log.

Obviously you could just use both a ConsoleAppender and a RollingFileAppender in logback.xml. But to me it seems unnecessarily redundant to have all log output on production written to STDOUT AND into a log file. Also, from the Tomcat documentation it sounds like logging to STDOUT on production is a bad practice in general.

I couldn't find any nice solutions on the web. Is there a good solution for this?

Here's my current logback.xml which always logs to STDOUT and to the desired log file:

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

    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${catalina.base}/logs/myApp.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${catalina.base}/logs/myApp.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
        </rollingPolicy>

        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <logger name="com.myDomain.myApp" level="DEBUG" />

    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FILE" />
    </root>
</configuration>
like image 511
Stefan Pries Avatar asked Mar 10 '14 16:03

Stefan Pries


People also ask

How to use Logback in an application?

Basic Example and Configuration Let's start with a quick example of using Logback in an application. First, we need a configuration file. We'll create a text file named logback.xml and put it somewhere in our classpath: Next, we need a simple class with a main method: This class creates a Logger and calls info () to generate a log message.

How does Logback configure the console Appender?

By default, if we do not provide any configuration and add the dependencies in the project, Logback automatically configures the console appender and outputs the logs in the console.

What is the default log level set in Logback?

By default, if we do not provide any configuration and add the dependencies in the project, Logback automatically configures the console appender and outputs the logs in the console. The default log level set is DEBUG.

What configuration file does Logback use to print log messages?

In the previous examples, we were using the 11-line configuration file we created in section 4 to print log messages to the console. This is Logback's default behavior; if it can't find a configuration file, it creates a ConsoleAppender and associates it with the root logger. 6.1.


Video Answer


3 Answers

You may configure your logback and add profile information in it. No changes in POM required

 <springProfile name="local">
    <root level="DEBUG">
<!-- no appenders -->
        <appender-ref ref="stdout"/>
    </root>
</springProfile>
<springProfile name="prod">
    <root level="INFO">
        <appender-ref ref="FILE_APPENDER"/>
    </root>
</springProfile>

You Might need to include below spring files as well

<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />

For more info checkout logback

like image 152
Ravik Avatar answered Oct 16 '22 10:10

Ravik


I had this same need and it turned out to be quite easy with the help of spring boot"ifulness" and conditional support available for logback. The following is a template that I came up with that could be for any app as it creates the logfile using spring.applcation.name if available, which you can define in bootstrap.properties:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE project>
<configuration>
    <if condition='isDefined("logging.path")'>
        <then>
            <!--  get application name from external properties file -->
            <property resource="bootstrap.properties" />

            <!--  set local properties here for better visibility -->
            <!--  TODO: make these profile conditional based on profiles -->
            <property name="logging.maxfilesize" value="1GB" />
            <property name="logging.maxdays" value="180" />

            <!-- Assume file strategy for appender if logging path given -->
            <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
                <!-- Use application.log if s.a.n not defined in bootstrap.properties -->
                <file>${logging.path}/${spring.application.name:-application}.log</file>
                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                    <!-- daily rollover -->
                    <fileNamePattern>${logging.path}/${spring.application.name:-application}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
                    <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                        <!-- or whenever the file size reaches maxFileSize -->
                        <maxFileSize>${logging.maxfilesize}</maxFileSize>
                    </timeBasedFileNamingAndTriggeringPolicy>
                    <!-- keep max days' worth of history -->
                    <maxHistory>${logging.maxdays}</maxHistory>
                </rollingPolicy>
                <encoder>
                    <pattern>%date [%thread] %-5level %logger{36} - %msg%n</pattern>
                </encoder>
            </appender>
            <root>
                <appender-ref ref="FILE" />
            </root>
        </then>
        <else>
            <!-- The logging path not specified so assume console output -->
            <!-- Note: In this case we don't care about the full date just the hour minutes seconds -->
            <appender name="CON" class="ch.qos.logback.core.ConsoleAppender">
                <encoder>
                    <pattern>%d{HH:mm:ss.SSS} %-5level %logger{35} - %msg %n</pattern>
                </encoder>
            </appender>
            <root>
                <appender-ref ref="CON" />
            </root>
        </else>
    </if>

    <!-- in-house loggers -->


    <!-- 3rdparty Loggers -->

    <logger name="org.springframework">
        <level value="WARN" />
    </logger>

    <!-- default root level for everything else -->

    <root>
        <level value="INFO" />
    </root>

</configuration>

If spring boot app with starter parent, you only need add the following to your pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<!-- Needed for conditional logback.xml statement support - very cool stuff -->
<dependency>
    <groupId>org.codehaus.janino</groupId>
    <artifactId>janino</artifactId>
</dependency>
like image 44
Starlton Avatar answered Oct 16 '22 10:10

Starlton


You can use profiles to switch between environment. Say you have two different logback.xml files for local and prod. Create a logback directory inside your resources directory. Inside the resources directory, create an environment specific directory. the directory name and envName inside property should match. Here is an example.

<profiles>
        <profile>
            <id>local</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <properties>
                <envName>local</envName>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <envName>prod</envName>
            </properties>
        </profile>
</profiles>

<build>
    <finalName>kp-prj</finalName>
    <outputDirectory>${project.build.directory}/classes</outputDirectory>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
    <resources>
        <resource>
            <directory>${basedir}/src/main/java</directory>
            <includes>
                <include>**/*.class</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/resources/logback/${envName}</directory>
        </resource>
    </resources>
</build>

And while using running maven command you specify the profile.

mvn run -Plocal
like image 33
Karthik Prasad Avatar answered Oct 16 '22 09:10

Karthik Prasad