应用的日志输出频率太高,log4j同步日志输出的时候锁竞争太过激烈,导致业务线程阻塞。系统load 200+,线程数2000+ 。所以想通过切换到logback 来提升日志输出的内容。
想要切换到logback要做两件事情:
* 切换pom中依赖的jar包
* 将log4j.xml 转换成 logback.xml
第一件事情比较简单,但是第二件事情稍微有些麻烦,特别是碰到原本日志Appender就非常多的情况下(我们配置了超过50个Appender)一个一个手动改就很繁琐了。在网上找了很多都是从 log4j.properties 转换为 logback.xml 的,我们这边还是很少有用到log4j.properties的。 在Google 上找了好久找到了一个文章 http://rpuchkovskiy.blogspot.com/2014/11/xslt-to-convert-log4jxml-config-to.html。通过他可以把 log4j.xml 转换为 logback.xml ,不过他的实现比较老,我结合我们的使用场景稍微修改了下。
<!--
This XLST script converts log4j.xml.bak file to logback.xml file
trying to mimic its behavior as close as possible
@author Roman Puchkovskiy
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="log4j xalan"
xmlns:log4j="http://jakarta.apache.org/log4j/"
xmlns:xalan="http://xml.apache.org/xslt"
xmlns:xslt="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" xalan:indent-amount="4"/>
<xsl:variable name="vLower" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="vUpper" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:template match="/log4j:configuration">
<configuration>
<xsl:apply-templates select="appender"/>
<xsl:apply-templates select="logger"/>
<xsl:apply-templates select="root"/>
<xsl:apply-templates select="comment()"/>
</configuration>
</xsl:template>
<xsl:template match="appender">
<appender>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="class">
<xsl:choose>
<!-- 定义了Appender 之间的映射关系 -->
<xsl:when test="@class = 'org.apache.log4j.DailyRollingFileAppender'">ch.qos.logback.core.rolling.RollingFileAppender</xsl:when>
<xsl:when test="@class = 'com.alibaba.common.logging.spi.log4j.DailyRollingFileAppender'">ch.qos.logback.core.rolling.RollingFileAppender</xsl:when>
<xsl:when test="@class = 'org.apache.log4j.AsyncAppender'">ch.qos.logback.classic.AsyncAppender</xsl:when>
<xsl:when test="@class = 'org.apache.log4j.ConsoleAppender'">ch.qos.logback.core.ConsoleAppender</xsl:when>
<xsl:when test="@class = 'org.apache.log4j.net.SMTPAppender'">ch.qos.logback.classic.net.SMTPAppender</xsl:when>
<xsl:when test="@class = 'org.apache.log4j.net.SocketAppender'">ch.qos.logback.classic.net.SocketAppender</xsl:when>
<xsl:when test="@class = 'org.apache.log4j.net.SyslogAppender'">ch.qos.logback.classic.net.SyslogAppender</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Unknown appender class:
<xsl:value-of select="@class"/>
</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates select="param"/>
<xsl:apply-templates select="layout"/>
<xsl:apply-templates select="filter"/>
</appender>
<xsl:call-template name="newline"/>
</xsl:template>
<xsl:template match="param">
<xsl:choose>
<!-- 将log4j file 转换为 logback 的file -->
<xsl:when test="@name = 'file'">
<xsl:element name="{concat(translate(substring(@name,1,1), $vUpper, $vLower),substring(@name, 2))}">
<xsl:value-of select="@value"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="layout">
<xsl:choose>
<!-- 将PatternLayout 做转换 -->
<xsl:when test="@class = 'org.apache.log4j.PatternLayout'">
<xsl:choose>
<xsl:when
test="../@class = 'org.apache.log4j.ConsoleAppender' or ../@class = 'org.apache.log4j.DailyRollingFileAppender' or ../@class = 'com.alibaba.common.logging.spi.log4j.DailyRollingFileAppender'">
<encoder>
<pattern>
<xsl:value-of select="param[@name = 'ConversionPattern']/@value"/>
</pattern>
<charset>UTF-8</charset>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<xsl:element name="fileNamePattern">
<xsl:value-of select="../param[@name = 'file']/@value" />.%d{yyyy-MM-dd}</xsl:element>
<maxHistory>7</maxHistory>
</rollingPolicy>
</xsl:when>
<xsl:when
test="../@class = 'org.apache.log4j.net.SocketAppender' or ../@class = 'org.apache.log4j.net.SyslogAppender'">
<xsl:comment>this is NOT needed tor this logger, so it is commented out</xsl:comment>
<xsl:comment><![CDATA[
<layout>
<pattern>]]><xsl:value-of select="param[@name = 'ConversionPattern']/@value"/><![CDATA[</pattern>
</layout>]]>
</xsl:comment>
</xsl:when>
<xsl:otherwise>
<layout>
<pattern>
<xsl:value-of select="param[@name = 'ConversionPattern']/@value"/>
</pattern>
</layout>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Unknown layout class:
<xsl:value-of select="@class"/>
</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="filter">
<xsl:choose>
<xsl:when
test="@class = 'org.apache.log4j.varia.LevelRangeFilter' and param[@name = 'LevelMin']/@value != '' and param[@name = 'LevelMax']/@value = 'FATAL'">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>
<xsl:value-of select="param[@name = 'LevelMin']/@value"/>
</level>
</filter>
</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">Don't know what to do with filter</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="logger">
<logger>
<xsl:attribute name="name">
<xsl:value-of select="@name"/>
</xsl:attribute>
<xsl:attribute name="level">
<xsl:choose>
<xsl:when test="level/@value = 'FATAL'">OFF</xsl:when>
<xsl:otherwise>
<xsl:value-of select="level/@value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:if test="@additivity != ''">
<xsl:attribute name="additivity">
<xsl:value-of select="@additivity"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="appender-ref"/>
</logger>
</xsl:template>
<xsl:template match="appender-ref">
<appender-ref>
<xsl:attribute name="ref">
<xsl:value-of select="@ref"/>
</xsl:attribute>
</appender-ref>
</xsl:template>
<xsl:template match="root">
<xsl:call-template name="newline"/>
<root>
<xsl:attribute name="level">
<xsl:value-of select="level/@value"/>
</xsl:attribute>
<xsl:apply-templates select="appender-ref"/>
<xsl:apply-templates select="comment()"/>
</root>
</xsl:template>
<xsl:template match="comment()">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template name="newline">
<!-- don't reformat this! -->
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
使用方式很简单:
String[] parmas = {"-IN", "log4j.xml",
"-XSL", "log4j-to-logback.xsl",
"-OUT", "logback.xml"};
org.apache.xalan.xslt.Process.Process.main(parmas);