How to configure PeriodicSizeRotatingFileHandler in JBoss 7?
Asked Answered
B

5

7

I search logger configuration in the web for Jboss 7. How to configure logger using date and size together.

File Logger 1 size-rotating-file-handler

<size-rotating-file-handler name="FILE">
    <formatter>
        <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
    </formatter>
    <file relative-to="jboss.server.log.dir" path="server.log"/>
    <rotate-size value="1000k"/>
    <max-backup-index value="20"/>
    <append value="true"/>
</size-rotating-file-handler>

Out Put Files are : 
    server.log.1
    server.log.2
    server.log.3
    ..

File Logger 2 periodic-rotating-file-handler

<periodic-rotating-file-handler name="FILE">
    <formatter>
        <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
    </formatter>
    <file relative-to="jboss.server.log.dir" path="server.log"/>
    <suffix value=".yyyy-MM-dd"/>
    <append value="true"/>
</periodic-rotating-file-handler>

Out Put Files are : 
    server.log.2013-12-12
    server.log.2013-12-13
    server.log.2013-12-14
    ..

My expected files are

server.log.2013-12-12.1
server.log.2013-12-12.2
server.log.2013-12-12.3
server.log.2013-12-13.1
server.log.2013-12-13.2
server.log.2013-12-13.3         
Bathysphere answered 13/1, 2014 at 4:35 Comment(0)
D
6

Depending on your version of JBoss AS 7 there is a org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler you can use as a custom-handler. I believe it was introduced in jboss-logmanager 1.3.0.Final. I can't recall which version of JBoss AS/WildFly it is in though.

Here's an example CLI command.

/subsystem=logging/custom-handler=example:add(class=org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler, module=org.jboss.logmanager, formatter="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n", properties={rotateSize=1024000,maxBackupIndex=20,suffix=".yyyy-MM-dd",fileName="${jboss.server.log.dir}/example.log"})
Decontrol answered 15/1, 2014 at 9:37 Comment(2)
thanks for your supporting. I will research for that.Bathysphere
I got your point. I also updated my answer. Please, check and review it.Bathysphere
A
6

Here's what worked for me (make sure to change the rotationSize and maxBackupIndex to whatever makes sense for you. The numbers I have in there are just for testing):

        <custom-handler name="FILESIZEDATE" class="org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler" module="org.jboss.logmanager">
            <formatter>
                <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
            </formatter>
            <properties>
                <property name="autoFlush" value="true"/>
                <property name="append" value="true"/>
                <property name="rotateSize" value="1000"/>
                <property name="maxBackupIndex" value="20"/>
                <property name="suffix" value=".yyyy-MM-dd"/>
                <property name="fileName" value="${jboss.server.log.dir}/server.log"/>
            </properties>
        </custom-handler>

        <root-logger>
            <level name="INFO"/>
            <handlers>
                <handler name="FILESIZEDATE"/>
                <handler name="CONSOLE"/>
            </handlers>
        </root-logger>
Astraea answered 21/11, 2014 at 15:52 Comment(1)
How can i achieve same in Jboss AS 6??Stonebroke
B
3

Jboss 7 (AS) has support to either periodic-rotating-file-handler or size-rotating-file-handler but not both.

I get some reference(JBoss 7 Custom File Handler) to support periodic and size rotating. It is writing the Custom File Handler. JBoss 7 Custom File Handler is used to create daily rotating size limited log.

But, I update the source some part of original PeriodicSizeHandler.java for my requirement.

My updated source :

PeriodicSizeHandler.java

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

public class PeriodicSizeHandler extends Handler {
    private int count = 1;
    protected static Long calculatedBytes;
    private String maxBytes = "2g";
    private String logFileName = "server.log";
    private static String logDirPath;
    private File logFile;
    private FileOutputStream outputStream;

    static {
        logDirPath = System.getenv("JBOSS_HOME") + "\\standalone\\log";
    }

    public enum Bytes {
        Byte("b", 1l), KiloBytes("k", (Byte.bytes * 1024)), MegaBytes("m",
                (KiloBytes.bytes * 1024)), GigaBytes("g",
                (MegaBytes.bytes * 1024)), ;

        private Bytes(String byteAcronym, Long bytes) {
            this.byteAcronym = byteAcronym;
            this.bytes = bytes;
        }

        private String byteAcronym;
        private Long bytes;

        public static long getBytes(String maxBytesRep) throws Exception {
            if (maxBytesRep == null && "".equals(maxBytesRep)) {
                throw new Exception(
                        "The max bytes representation cannot be empty or null");
            }
            String uByteRepresentation = maxBytesRep.toLowerCase();
            for (Bytes b : values()) {
                if (uByteRepresentation.endsWith(b.byteAcronym)) {
                    String strNumVal = uByteRepresentation.substring(0,
                            uByteRepresentation.indexOf(b.byteAcronym));
                    try {
                        return getBytes(Double.valueOf(strNumVal), b);
                    } catch (Exception e) {
                        throw new Exception(
                                "The max bytes representation: "
                                        + maxBytesRep
                                        + ", is not valid. Shoubl be of the form XXX..(B or b) / M or m /G or g). Ex: '1000b', '100m', '1g'");
                    }
                }
            }
            // If no acronym is mentioned consider it as Byte representation Ex.
            // maxBytes = 1000
            try {
                return getBytes(Double.valueOf(uByteRepresentation), Bytes.Byte);
            } catch (Exception e) {
                throw new Exception(
                        "The max bytes representation: "
                                + maxBytesRep
                                + ", is not valid. Shoubl      be of the form XXX../(B or b) / M or m /G or g). Ex: '1000', '1000b', '100m', '1g'");
            }
        }

        public String getByteAcronym() {
            return this.byteAcronym;
        }

        public Long getBytes() {
            return this.bytes;
        }

        public static long getBytes(double multiple, Bytes bytes) {
            return Math.round(multiple * bytes.bytes);
        }
    }

    public PeriodicSizeHandler() {
    }

    @Override
    public void flush() {
        try {
            if (outputStream != null) {
                outputStream.flush();
            }
        } catch (IOException e) {
            reportError(e.getMessage(), e, ErrorManager.FLUSH_FAILURE);
        }
    }

    @Override
    public void close() {
        if (outputStream != null) {
            try {
                outputStream.close();
            } catch (IOException e) {
                reportError(e.getMessage(), e, ErrorManager.CLOSE_FAILURE);
            }

        }
    }

    @Override
    public void publish(LogRecord record) {
        init();
        if (rollOver(record)) {
            archiveFile();
            createLogChannel();
        }
        logToFile(record);
    }

    // Initialize
    public synchronized void init() {
        if (outputStream == null) {
            try {
                logFile = new File(getFilePath());
                if (logFile.exists()) {
                    outputStream = new FileOutputStream(logFile, true);
                } else {
                    createLogChannel();
                }
            } catch (FileNotFoundException e) {
                reportError(e.getMessage(), e, ErrorManager.OPEN_FAILURE);
            }
        }
    }

    private String getFilePath() {
        return getLogDirPath() + File.separator + logFileName;
    }

    // check the file size
    private boolean rollOver(LogRecord record) {
        try {
            StringBuilder logMessage = new StringBuilder(getFormatter().format(record));
            if ((outputStream.getChannel().size() + logMessage.length()) > getByteValue(getMaxBytes())) {
                return true;
            }
        } catch (IOException e) {
            reportError(e.getMessage(), e, ErrorManager.GENERIC_FAILURE);
        }
        return false;
    }

    /**
     * Rename with date and time stamp
     */
    private void archiveFile() {
        System.out.println("archiveFile..........");
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//      String logDir = getLogDirPath() +  File.separator + simpleDateFormat.format(new Date());
        String newFilePath = getLogDirPath()  + File.separator + logFileName + "_" + simpleDateFormat.format(new Date()) + "_" + count++;
        File newFile = new File(newFilePath);
        try {
            OutputStream oos = new FileOutputStream(newFile);
            byte[] buf = new byte[8192];
            InputStream is = new FileInputStream(logFile);
            int c = 0;
            while ((c = is.read(buf, 0, buf.length)) > 0) {
                oos.write(buf, 0, c);
                oos.flush();
            }
            oos.close();
            is.close();
            PrintWriter writer = new PrintWriter(logFile);
            writer.print("");
            writer.close();         
        } catch(Exception e) {
            reportError("Unable to rename old file: " + logFile.getName()
                    + " to new file: " + newFile, null, ErrorManager.GENERIC_FAILURE);
        }
    }

    private void createLogChannel() {
        try {
            // make directories
            File logDir = new File(getLogDirPath());
            logDir.mkdirs();

            // create log file
            System.out.println("getFilePath( : " + getFilePath());
            logFile = new File(getFilePath());
            logFile.createNewFile();

            // create the channel
            outputStream = new FileOutputStream(logFile, true);
        } catch (FileNotFoundException e) {
            reportError(e.getMessage(), e, ErrorManager.OPEN_FAILURE);
        } catch (IOException e) {
            reportError(e.getMessage(), e, ErrorManager.OPEN_FAILURE);
        }
    }

    private synchronized void logToFile(LogRecord record) {
        StringBuilder logMessage = new StringBuilder(getFormatter().format(record));
        try {
            if (outputStream != null) {
                outputStream.write(logMessage.toString().getBytes());
                outputStream.flush();
            }
        } catch (IOException e) {
            reportError(e.getMessage(), e, ErrorManager.WRITE_FAILURE);
        }
    }

    protected long getByteValue(String maxBytes) {
        if (calculatedBytes != null) {
            return calculatedBytes;
        }
        try {
            calculatedBytes = Bytes.getBytes(maxBytes);
        } catch (Exception e) {
            logToFile(new LogRecord(Level.INFO, "Failed to get byte value from maxBytes: " + maxBytes + ", exception: " + e));
            calculatedBytes = getDefaultBytes();
        }
        return calculatedBytes;
    }

    // Use Default - 2GB
    protected Long getDefaultBytes() {
        int multiple = 2;
        logToFile(new LogRecord(Level.INFO, "Using the default: '" + multiple + Bytes.GigaBytes.byteAcronym + "'"));
        return Bytes.getBytes(multiple, Bytes.GigaBytes);
    }

    public String getMaxBytes() {
        return maxBytes;
    }

    public void setMaxBytes(String maxBytes) {
        this.maxBytes = maxBytes;
    }

    public String getLogFileName() {
        return logFileName;
    }

    public void setLogFileName(String logFileName) {
        this.logFileName = logFileName;
    }

    public File getLogFile() {
        return logFile;
    }

    public void setLogFile(File logFile) {
        this.logFile = logFile;
    }

    public FileOutputStream getOutputStream() {
        return outputStream;
    }

    public void setOutputStream(FileOutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public void setLogDirPath(String logDirPath) {
        this.logDirPath = logDirPath;
    }

    public String getLogDirPath() {
        return logDirPath;
    }
}

PeriodicSizeHandlerTest.java

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import junit.framework.TestCase;

import org.junit.Before;
import org.junit.Test;

import com.cyc.jboss.logging.PeriodicSizeHandler.Bytes;

public class PeriodicSizeHandlerTest extends TestCase {
    @Before
    public void setUp() {
        PeriodicSizeHandler.calculatedBytes = null;
    }

    Long bytes = Bytes.getBytes(100, Bytes.Byte);

    @Test
    public void testPublishRollOverTrue() throws Exception {
        PeriodicSizeHandler psh = new PeriodicSizeHandler();
        psh.setMaxBytes("3k");
        setupFormatter(psh);
        // text.txt file size is `151k`
        FileReader fr = new FileReader("D:/temp/test.txt");
        BufferedReader br = new BufferedReader(fr);
        String message;
        while ((message = br.readLine()) != null) {
            LogRecord logRecord = new LogRecord(Level.INFO, message);
            psh.publish(logRecord);
        }
        fr.close();
        assertTrue(psh.getOutputStream() != null);
    }

    private void setupFormatter(PeriodicSizeHandler psh) {
        Formatter formatr = new Formatter() {
            @Override
            public String format(LogRecord record) {
                return record.getLevel() + " :: " + record.getMessage();
            }
        };
        psh.setFormatter(formatr);
    }

    public static void main(String[] args) {
        org.junit.runner.JUnitCore
                .main(PeriodicSizeHandlerTest.class.getName());
    }
}

I got my expected output file as below

server.log_2014-01-13_1
server.log_2014-01-13_2
server.log_2014-01-13_3
....
server.log_2014-01-13_55

If you would like use your customize file format, you just need to update archiveFile() method, I think so.

Next solution : after James R. Perkins suggestion.

Download jboss-logmanager-1.5.1.Final.jar here.

Replace old jboss-logmanger-xxxx.jar with jboss-logmanager-1.5.1.Final.jar at <JBOSS_HOME>\modules\org\jboss\logmanager\main directory.

Change your module.xml configuration as below

<module xmlns="urn:jboss:module:1.1" name="org.jboss.logmanager">
    <resources>
        <resource-root path="jboss-logmanager-1.5.1.Final.jar"/>
        <!-- Insert resources here -->
    </resources>

    <dependencies/>
</module>

Configuration for standalone.xml

<subsystem xmlns="urn:jboss:domain:logging:1.1">
    .....
    <custom-handler name="FILE" class="org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler" module="org.jboss.logmanager">
        <formatter>
            <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
        </formatter>
        <properties>
            <property name="file" value="D:\temp\server.log"/>  <--- your log directory          
            <property name="rotateSize" value="50000"/>         <--- 50000 byte
            <property name="maxBackupIndex" value="50"/>        
            <property name="append " value="true"/>
            <property name="suffix" value=".yyyy-MM-dd"/>
            <property name="autoflush" value="true"/>
        </properties>
    </custom-handler>
    ....
    <root-logger>
        <level name="INFO"/>
        <handlers>
            <handler name="CONSOLE"/>
            <handler name="FILE"/>
        </handlers>
    </root-logger>
</subsystem>    

Output :

server.log.2014-01-16.1 
server.log.2014-01-16.2 
server.log.2014-01-16.3 
Bathysphere answered 13/1, 2014 at 9:51 Comment(4)
I hope any suggestion or comment. Because it is just my solution.Bathysphere
Just a couple comments. The handler isn't really thread-safe and use the reportError() method rather than using another creating a new record and logging to the file.Decontrol
Might want to use relative log file location, like ${jboss.server.log.dir}/server.logIllusionism
How can i achieve the same in Jboss AS 6??Stonebroke
I
1

Another approach is to change JBOSS logging properties to both rotate log file based on time and size. Below is the way I did it and it works greatly for me.

        <periodic-size-rotating-file-handler name="FILE" autoflush="true">
            <formatter>
                <named-formatter name="PATTERN"/>
            </formatter>
            <file relative-to="jboss.server.log.dir" path="server.log"/>
            <suffix value=".yyyy-MM-dd"/>
            <append value="true"/>
            <max-backup-index value="4"/>
            <rotate-size value="10000k"/>
            <encoding value="UTF-8"/>
        </periodic-size-rotating-file-handler>
Ileac answered 12/7, 2018 at 18:58 Comment(0)
P
-1

The examples by Creature and CycDemo worked for me. However, there is one important thing to note.

            <custom-handler name="FILE"
            class="org.jboss.logmanager.handlers.PeriodicSizeRotatingFileHandler"
            module="org.jboss.logmanager">
            <properties>
                <property name="maxBackupIndex" value="10"/>
                <property name="rotateSize" value="500000"/> <!-- 500 Kb -->
                <property name="suffix" value=".yyyy-MM-dd"/>
                <property name="fileName" value="${jboss.server.log.dir}/server.log"/>
                <property name="append" value="true"/>
                <property name="autoFlush" value="true"/>
            </properties>
        </custom-handler>

A maxBackupIndex value of ten means that there could be ten index files for that particular day. However, this will NOT clean up log files that are more than ten days old, or after ten have been written. There is no parameter here like the old MaxRollFileCount in the old log4j.xml TimeAndSizeRollingAppender specification that will clean up log files after a certain number of them have been written.

If you want to clean up old JBoss log files, you will have to use cron and the find command with the +mtime parameter.

Pharyngology answered 9/12, 2015 at 15:27 Comment(1)
How can i achieve same in Jboss AS 6??Stonebroke

© 2022 - 2024 — McMap. All rights reserved.