Search code examples
javacsvlogback

How to write logfile in csv format using logback?


I have a requirement where I need to write a log in a csv format using logback. I have found a sample where I can do just that

    <appender name="csv" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>mylog.csv</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
    <!-- rollover daily -->
    <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.csv</fileNamePattern>
        <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
        <maxFileSize>100MB</maxFileSize>    
        <maxHistory>60</maxHistory>
        <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>
       <encoder>
         <pattern>%msg%n</pattern>
        </encoder>
     </appender>

However I also need to have a standard header like this in every file:-

    Time,User,Param1,Param2

How do I add the header in every rolling file


Solution

  • You can implement your own Layout, extending Logback's PatternLayout:

    public class LogFileHeaderPatternLayout extends PatternLayout {
    
        private String header;
    
        public void setHeader(String header) {
            this.header = header;
        }
    
        @Override
        public String getFileHeader() {
            return header;
        }
    }
    

    And then reference it like so:

    <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
        <layout class="x.y.z.LogFileHeaderPatternLayout">
            <header>a,b,c,d</header>
            <pattern>%msg%n</pattern>
        </layout>
    </encoder>
    

    If Logback insists on adding this header evey time it opens the log file (i.e. every time the application starts) then you could conditionalise getFileHeader() like so:

    public String getFileHeader() {
        if (alreadyContainsHeader()) {
            return "";
        } else {
            return header;
        }
    }
    
    private boolean alreadyContainsHeader() {
        try(BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line = null;
            while ((line = br.readLine()) != null) {
                if (line.contains(header)) {
                    return true;
                } else {
                    break;
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace(System.err);
        }
        return false;
    }