Log4j2 custom layout
Asked Answered
N

2

9

I am using Log4j2 with a PatternLayout. Is it possible to write my own Layout that extends AbstractStringLayout, so that I can customize my output message?

I have read the docs but I only see variations of layouts - no custom one.

https://logging.apache.org/log4j/2.x/manual/layouts.html

Nappie answered 16/5, 2017 at 15:7 Comment(1)
Check andrew-flower.com/blog/Create_Custom_Log4j_PluginsHanna
M
17

Yes it is possible

You can use custom AbstractStringLayout or LogEventPatternConverter

EX : AbstractStringLayout

@Plugin(name = "NewCustLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)
public class NewCustLayout  extends AbstractStringLayout
{
    protected NewCustLayout( Charset charset )
    {
        super( charset );
    }

    @Override public String toSerializable( LogEvent event )
    {
        return null;
    }
}

EX : LogEventPatternConverter

@Plugin(name = "NewLayoutConverter", category = "Converter")
@ConverterKeys({"custLayConv"})
public class NewLayoutConverter extends LogEventPatternConverter
{

    /**
     * Constructs an instance of LoggingEventPatternConverter.
     *
     * @param name  name of converter.
     * @param style CSS style for output.
     */
    protected NewLayoutConverter( String name, String style )
    {
        super( name, style );
    }

    @Override public void format( LogEvent event, StringBuilder toAppendTo )
    {

    }
}

Make sure that your configuration file contain the package that all the custom plugins are located ,

packages="logging.log4j.custom.plugins"

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Configuration packages="logging.log4j.custom.plugins" name="SOME NAME">
    <Appenders>
        <Console name="CONSOLE" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{MM-dd-yyyy HH:mm:ss,SSS} [%t] %custLayConv %msg%n"/>
        </Console>

        <RollingRandomAccessFile name="example" fileName="${sys:tbx.log.path}example.log" filePattern="${sys:tbx.log.path}example.log.%i" append="true" immediateFlush="true" bufferSize="262144">
            <NewCustLayout pattern="%d{MM-dd-yyyy HH:mm:ss,SSS} - %msg%n"/>
            <Policies>
                <SizeBasedTriggeringPolicy size="100MB"/>
            </Policies>
            <DefaultRolloverStrategy fileIndex="max" min="1" max="100" compressionLevel="3"/>
        </RollingRandomAccessFile>
    </Appenders>
    <Loggers>
        <logger name="logger" level="INFO" additivity="false">
            <AppenderRef ref="example" level="INFO"/>
        </logger>
        <Root level="INFO">
            <AppenderRef ref="CONSOLE" level="INFO"/>
        </Root>
    </Loggers>
</Configuration>    
Maintopmast answered 17/5, 2017 at 12:36 Comment(3)
+1 to "Make sure that your configuration file contain the package that all the custom plugins are located " packages="logging.log4j.custom.plugins"Mcclintock
@Tharinda_tpw Excellent answer!Pincushion
+1 to "Make sure that your configuration file contain the package that all the custom plugins are located" --> Resolved it after couple of try, The custom layout was not getting load after log4j2 upgrade to 2.13 from 2.5. For log4j2 version 2.5 I did not need to write "packages" attribute explicitly in the configuration.Jimmie
A
3
package com.mytest;
@Plugin(name = "MyHtmlLayout", category = Node.CATEGORY, elementType = Layout.ELEMENT_TYPE, printObject = true)

public class MyHtmlLayout  extends AbstractStringLayout{
    protected MyHtmlLayout( Charset charset ){
        super( charset );
    }

    @Override
    public String toSerializable( LogEvent event ) {
        StringBuilder throwable = new StringBuilder();
        if (event.getThrown() != null) {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            pw.println();
            event.getThrown().printStackTrace(pw);
            pw.close();
            throwable.append(sw.toString());
        }
        StringBuilder retValue=new StringBuilder();
        retValue.append("<tr><td>").append(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss:S").format(event.getTimeMillis())).append(" ")
        .append(event.getLevel().toString()).append(" ").append(event.getLoggerName()).append(" ").append(event.getMessage().getFormattedMessage()).append(" ").append(throwable).append("</tr></td>\n");

        return retValue.toString();
    }

    @PluginFactory
    public static MyHtmlLayout createLayout(@PluginAttribute(value = "charset", defaultString = "UTF-8") Charset charset) {
        return new MyHtmlLayout(charset);
    }
    @Override
    public byte[] getHeader() {
        return ("<html>\n  <body>\n" + "<Table>\n").getBytes();
    }
    @Override
    public byte[] getFooter() {
        return ("</table>\n</body>\n</html>").getBytes();
    }
}

Configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG" packages="com.mytest" name="NewCustLayout">
    <Appenders>
        <Console name="LogToConsole" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>

        
        <RollingFile name="LogToRollingFile" fileName="logs/app.html"
                     filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <!-- <PatternLayout>
                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
            </PatternLayout>-->
            <MyHtmlLayout/>
            <Policies>
                <TimeBasedTriggeringPolicy/>
                <SizeBasedTriggeringPolicy size="100 MB"/>
            </Policies>
            <DefaultRolloverStrategy max="100"/>
        </RollingFile>
    </Appenders>
    <Loggers>
        <!-- avoid duplicated logs with additivity=false -->
        <Logger name="com.psx.logtest" level="debug" additivity="false">
            <AppenderRef ref="LogToRollingFile"/>
        </Logger>
        <Root level="error">
            <AppenderRef ref="LogToConsole"/>
        </Root>
    </Loggers>
</Configuration>
Anarchic answered 11/1, 2020 at 7:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.