How can I log the logback actions into a file?
Asked Answered
P

2

6

I'd like to log the "ch.qos.logback" classes into a log file using Logback, but it is logging just in the Console and not in the file.

Is it possible?

I need it for an investigation of some problems with logback.

This is my logback configuration file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<configuration scan="true" scanPeriod="60 seconds">

    <property name="base-path" value="../../xpto/sysX/logs"/>
    <property name="application-name" value="app_X"/>

    <appender class="ch.qos.logback.core.ConsoleAppender" name="CONSOLE">
        <param name="Threshold" value="INFO"/> 
        <encoder>
            <pattern>%d{dd/MM/yyyy HH:mm:ss.SSS} %-5level %logger{30} - %msg%n</pattern>
        </encoder>
    </appender>
    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" name="FILE_LOGBACK">
            <param name="Threshold" value="DEBUG"/>
            <file>${base-path}/mylog.log</file>
            <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <fileNamePattern>${base-path}/%d{yyyy-MM-dd_HH}/mylog.%i.log</fileNamePattern>
                <maxHistory>72</maxHistory>
                <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                    <maxFileSize>20MB</maxFileSize>
                </timeBasedFileNamingAndTriggeringPolicy>
            </rollingPolicy>
            <encoder>
                <pattern>%date{yyyy-MM-dd HH:mm:ss.SSS} [%.30thread] %-5level %logger{50} - %msg%n</pattern>
            </encoder>
        </appender>
        <appender class="ch.qos.logback.classic.AsyncAppender" name="FILE_LOGBACK_ASYNC">
            <param name="Threshold" value="DEBUG"/>
            <appender-ref ref="FILE_LOGBACK"/>
            <queueSize>1000</queueSize>
            <discardingThreshold>0</discardingThreshold>
        </appender> 
        <logger additivity="false" level="DEBUG" name="ch.qos.logback">
            <appender-ref ref="FILE_LOGBACK"/>
        </logger>
        <root level="INFO">
           <appender-ref ref="CONSOLE"/> 
           <appender-ref ref="FILE_LOGBACK_ASYNC"/>
        </root>
</configuration>

This is a example logged in console, I'd like to have it in the file and not just in the Console.

14:17:37,117 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE_LOGBACK]
14:17:37,117 |-WARN in ch.qos.logback.core.joran.util.PropertySetter@7f7f557 - No setter for property [Threshold] in ch.qos.logb ack.core.rolling.RollingFileAppender.
14:17:37,118 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy@671885015 - No compression will be used
14:17:37,118 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy@671885015 - Will use the pattern ../../xpto/sysX/logs/%d{ yyyy-MM-dd_HH}/mylog.%i.log for the active file
14:17:37,119 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@35ca01cb - The date pattern is 'yyyy-MM-dd_HH' from fil e name pattern '.../../xpto/sysX/logs/%d{yyyy-MM-dd_HH}/mylog.%i.log'.
14:17:37,119 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@35ca01cb - Roll-over at the top of every hour.
14:17:37,119 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@35ca01cb - Setting initial period to Mon Oct 02 14:17:3

I'm using this dependencies:

log4j-over-slf4j-1.7.2.jar
logback-classic-1.1.7.jar
logback-core-1.1.7.jar
slf4j-api-1.7.2.jar

Thanks in advance

Postdiluvian answered 2/10, 2017 at 17:31 Comment(0)
I
5

For background, this ouput ...

14:17:37,117 |-INFO in ch.qos.logback.core.joran.action.AppenderAction - Naming appender as [FILE_LOGBACK]
14:17:37,117 |-WARN in ch.qos.logback.core.joran.util.PropertySetter@7f7f557 - No setter for property [Threshold] in ch.qos.logb ack.core.rolling.RollingFileAppender.
14:17:37,118 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy@671885015 - No compression will be used
14:17:37,118 |-INFO in c.q.l.core.rolling.TimeBasedRollingPolicy@671885015 - Will use the pattern ../../xpto/sysX/logs/%d{ yyyy-MM-dd_HH}/mylog.%i.log for the active file
14:17:37,119 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@35ca01cb - The date pattern is 'yyyy-MM-dd_HH' from fil e name pattern '.../../xpto/sysX/logs/%d{yyyy-MM-dd_HH}/mylog.%i.log'.
14:17:37,119 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@35ca01cb - Roll-over at the top of every hour.
14:17:37,119 |-INFO in ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP@35ca01cb - Setting initial period to Mon Oct 02 14:17:3

... is emitted by Logback under the following conditions:

  • Your configuration has debug enabled (e.g. <configuration debug="true">...</configuration>
  • Logback has determined that there is something about your configuration which warrants the emission of an ERROR or WARN message
  • Multiple Logback configuration files are found on your classpath

These log events are emitted before Logback has been initialised with your configuration so at the time they are emitted Logback knows nothing about your configured appenders etc. The only safe target for these event is a ConsoleAppender which Logback creates for this purpose.

So, there is no way to tell Logback to direct its own on-startup-log-events to a file appender.

However, do you actually want this Logback output? If not then you can suppress it by either of ...

  • Removing its cause; change your configuration so that debug=false and there are no ERROR/WARN events and there is a single Logback configuration file on the classpath
  • Add the no-op status listener to your configuration file: <statusListener class="ch.qos.logback.core.status.NopStatusListener" />

If you do want this output then you could ...

  • Redirect STDOUT to a log file when running your Java process. For example:
    • Add this to the main method in your Java application (before initialising Logback): System.setOut(new PrintStream("/Users/al/Projects/Sarah2/std.out"));
    • Pipe the Java output to a file: java -jar ... > /some/directory/application_stdout.log
  • Provide your own implementation of ch.qos.logback.core.status.StatusListener (instead of NopStatusListener) to write these status events ot a file of your choosing
  • Use ch.qos.logback.core.status.StatusListenerAsList (instead of NopStatusListener) and then add something to your application which writes the contents of getStatusList() to a file of your choosing
Illampu answered 2/10, 2017 at 18:5 Comment(1)
Thank you very much for your explanation! I was thinking about it for an investigation about a problem with the log in the production environment of a big client. So it's complicated to simply log all stout in a single file. The logback simply stops logging just in file (if I turn on the console it continue logging just in console and stops in the file) Usually the it's configurated just for file. I'll wait for more ideas, but I'm really thankful for your help!!Postdiluvian
E
2

You can write your own StatusListener that writes to a file. I couldn't find a lot of examples out there, but if you look at the source code for OnConsoleStatusListener, it's pretty simple to take what's there and modify to write to a file.


import ch.qos.logback.core.status.Status;
import ch.qos.logback.core.status.StatusListener;
import ch.qos.logback.core.util.StatusPrinter;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class FileStatusListener implements StatusListener {

    private final static String fileName = "path/logbackStatusMessages.log";

    @Override
    public void addStatusEvent(Status status) {
        StringBuilder sb = new StringBuilder();
        StatusPrinter.buildStr(sb, "", status);

        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new FileWriter(fileName, true));
            writer.append(sb.toString());
        } catch (Throwable ex) {
            System.out.println("Error writing to file in FileStatusListener");
            ex.printStackTrace(System.err);
        } finally {
            if (writer != null) {
                try {
                    writer.close();      
                } catch (IOException ex) {
                    System.err.println("Error closing file in FileStatusListener");
                    ex.printStackTrace(System.err);
                }
            }
        }
    }
}

Then just specify your class as the Status Listener class in your config file:

<statusListener class="FileStatusListener" />

Of course you might want to make the code a little more robust, but writing to a rolling file.

Edit:

Better yet, the OnPrintStreamStatusListenerBase is an abstract class that provides a little more robust framework for writing to a file. It would probably be a better choice than the code above.

Epitomize answered 14/12, 2017 at 21:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.