logback、log4j混用,指定log未输出问题排查

问题描述:

某个SDK(有一定历史的祖传代码)中自定义了一个logger,并且在应用初始化时调用log4j为该logger配置了Appender、Layout,filePath,logName命名为logA.log。而使用了这个SDK的应用,正好在需要查看这个log时,发现logA.log是存在的,但是文件内容却为空。

结论:翻了一下源码,结合当前使用这个SDK的应用的日志配置,得出结论:

1) SDK中自定义的那个logger的声明,使用的日志框架为common-logging+log4j,虽然通过代码指定了使用log4j为其配置Appender、filePath,但是该应用采用的日志框架为slf4j+logback,SDK中的所有log在运行时其实是使用的logback,以logback配置为输出标准。所以,自然不会输出到log4j指定的file中。

2)在SDK中指定某个日志的具体实现,并配置日志名称、输出路径,理解这种做法的初衷,但是,该log的level、appender、filepath最好是由用户自己按需配置。

场景还原:

抽象出代码如下,sdk-a中指定logName=“log4jLog”,并通过log4j进行配置,本意是想把Log4jTest中的日志单独打印到一个文件中。

package com.sdk.a;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Appender;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import java.io.File;
import java.util.Enumeration;
import java.util.Properties;

public class Log4jInit {
    private static final Log logger = LogFactory.getLog(Log4jInit.class);
    static private volatile boolean initOK = false;
    public static final String LOG_NAME = "log4jLog";
    static private Properties defaultProperties = new Properties();
    static {
        defaultProperties.put("log4j.logger.log4jLog", "info, D");
        defaultProperties.put("log4j.additivity.log4jLog", "false");
        defaultProperties.put("log4j.appender.D", "org.apache.log4j.DailyRollingFileAppender");
        defaultProperties.put("log4j.appender.D.DatePattern", "'.'yyyy-MM-dd");
        defaultProperties.put("log4j.appender.D.File", "log4j_data.log");
        defaultProperties.put("log4j.appender.D.layout", "org.apache.log4j.PatternLayout");
        defaultProperties.put("log4j.appender.D.layout.ConversionPattern","%d{MM-dd HH:mm:ss} - %m%n");
        defaultProperties.put("log4j.appender.D.Append", "true");
    }

    public static void initLog() {
        if (initOK) {
            return;
        }
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        Thread.currentThread().setContextClassLoader(Log4jInit.class.getClassLoader());
        try {
            PropertyConfigurator.configure(defaultProperties);
            FileAppender bizFileAppender = new FileAppender();
            bizFileAppender.setFile("/app/weblogic/logs/log-demo/log4j.log");
            setFileAppender(bizFileAppender, LOG_NAME);
            initOK = true;
        }
        finally {
            Thread.currentThread().setContextClassLoader(cl);
        }
    }

    private static void setFileAppender(FileAppender bizFileAppender, String logName) {
        FileAppender fileAppender = getFileAppender(Logger.getLogger(logName));
        String bizLogDir = new File(bizFileAppender.getFile()).getParent();
        File newLogFile = new File(bizLogDir, fileAppender.getFile());
        fileAppender.setFile(newLogFile.getAbsolutePath());
        fileAppender.activateOptions();
        logger.info(logName + ",appender-path:" + newLogFile.getAbsolutePath());
    }
}



import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Log4jTest {
    static {
        Log4jInit.initLog();
    }

    //LOG_NAME在Log4jInit.initLog()中配置
    private static final Log log4j = LogFactory.getLog(Log4jInit.LOG_NAME);

    public void printLog() {
        log4j.info("log4j.info");
    }
}

应用使用sdk-a,如果想要特殊处理Logger("log4jLog"),可以自定义file、appender。

    <appender name="otherAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_DIR}/other.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_BAK_DIR}/other.%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>${LOG_MAX_HISTORY}</maxHistory>
            <totalSizeCap>${LOG_TOTAL_SIZE_CAP}</totalSizeCap>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] %logger{50}\(%file:%line\) - %msg%n</pattern>
        </encoder>
    </appender>    
<!--可以重新配置log4jLog,若不配置,使用root输出也可以-->
    <logger name="log4jLog" level="info" additivity="false">
        <appender-ref ref="otherAppender"/>
    </logger>

    <root level="INFO">
        <appender-ref ref="consoleAppender"/>
        <appender-ref ref="appAppender"/>
    </root>

启动应用,打印sdk-a的Logger(log4jLog),查看日志,可以看出:

1)确实输出了sdk-a中定义的/app/weblogic/logs/log-demo/log4j.log,并且内容为空。

2)Logger(log4jLog)由应用配置的logback,输出到了otherAppender定义的file中。

package com.ls.demo.log.logdemo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.sdk.a.Log4jTest;

@SpringBootApplication
public class LogDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(LogDemoApplication.class, args);

        //使用sdk-a
        Log4jTest log4jTest = new Log4jTest();
        log4jTest.printLog();

        Logger logger = LoggerFactory.getLogger(LogDemoApplication.class);
        logger.info("logback.info");

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值