修改logback日志框架默认文件路径(附修改思路)

如果配置过logback的同学肯定都清楚,在resource下创建一个logback.xml文件即可,但是今天遇到了一个需求,需要在生产环境和开发环境进行区分,因为生产环境下的路径是work用户的而我们开发环境是dev用户,默认权限运维也只给到home目录下,如果配置文件只有一套的话,在开发时需要调整地址,而发布代码的时候又要改回去。容易出错也麻烦,那么以这个背景为前提,研究一下如何配置。
之前也没有详细的了解过slf4j和logback是如何实现的,整好跟下代码看一下。如果没兴趣了解细节的同学,可以直接拉到底部

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Test.class);

引用sl4j一般都是上面的办法,没有什么特别的,那么如何加载框架肯定是在LoggerFactory.getLogger(Test.class)中了,LoggerFactory点进去看了一下没有静态块,明显的一个工厂方法,那么看看getLogger

public static Logger getLogger(Class<?> clazz) {
		// 返回的就是这个logger
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
            Class<?> autoComputedCallingClass = Util.getCallingClass();
            if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
                                autoComputedCallingClass.getName()));
                Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
            }
        }
        return logger;
    }

继续进入到getLogger

 public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

跟到getILoggerFactory

public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == UNINITIALIZED) {
            INITIALIZATION_STATE = ONGOING_INITIALIZATION;
            //方法命很明显,执行初始化操作
            performInitialization();
        }
        switch (INITIALIZATION_STATE) {
        case SUCCESSFUL_INITIALIZATION:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
        case NOP_FALLBACK_INITIALIZATION:
            return NOP_FALLBACK_FACTORY;
        case FAILED_INITIALIZATION:
            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
        case ONGOING_INITIALIZATION:
            // support re-entrant behavior.
            // See also http://jira.qos.ch/browse/SLF4J-97
            return TEMP_FACTORY;
        }
        throw new IllegalStateException("Unreachable code");
    }

中间方法就不粘贴了performInitialization->bind()->StaticLoggerBinder.getSingleton()
下面是重点,看注释

 private final static void bind() {
        try {
            Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
            reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            // the next line does the binding  
            /*
            *  这个StaticLoggerBinder类是在ch.qos.logback-classic包了,我猜测log4j应该也是这么实现的。
            *  那么然后在StaticLoggerBinder中的静态块初始化logbck的实现
            *   下面是调用栈StaticLoggerBinder.init()->new ContextInitializer(defaultLoggerContext).autoConfig()->findURLOfDefaultConfigurationFile(true)
            */
            StaticLoggerBinder.getSingleton();
            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
            reportActualBinding(staticLoggerBinderPathSet);
            fixSubstitutedLoggers();
        } catch (NoClassDefFoundError ncde) {
            String msg = ncde.getMessage();
            if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
                INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
                Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
                Util.report("Defaulting to no-operation (NOP) logger implementation");
                Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
            } else {
                failedBinding(ncde);
                throw ncde;
            }
        } catch (java.lang.NoSuchMethodError nsme) {
            String msg = nsme.getMessage();
            if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
                INITIALIZATION_STATE = FAILED_INITIALIZATION;
                Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
                Util.report("Your binding is version 1.5.5 or earlier.");
                Util.report("Upgrade your binding to version 1.6.x.");
            }
            throw nsme;
        } catch (Exception e) {
            failedBinding(e);
            throw new IllegalStateException("Unexpected initialization failure", e);
        }
    }

下面是findURLOfDefaultConfigurationFile(boolean updateStatus)

final public static String GROOVY_AUTOCONFIG_FILE = "logback.groovy";
final public static String AUTOCONFIG_FILE = "logback.xml";
final public static String TEST_AUTOCONFIG_FILE = "logback-test.xml";
final public static String CONFIG_FILE_PROPERTY = "logback.configurationFile";
 public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
        //这个方法里就是通过SystemProperties来改变logback配置文件的地方了
        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
		//如果没有设置那么优先用TEST_AUTOCONFIG_FILE的配置
        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
		
        url = getResource(GROOVY_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }

        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
    }

下面是findConfigFileURLFromSystemProperties

 private URL findConfigFileURLFromSystemProperties(ClassLoader classLoader, boolean updateStatus) {
 	   //在这里获取配置
        String logbackConfigFile = OptionHelper.getSystemProperty(CONFIG_FILE_PROPERTY);
        if (logbackConfigFile != null) {
            URL result = null;
            try {
                result = new URL(logbackConfigFile);
                return result;
            } catch (MalformedURLException e) {
                // so, resource is not a URL:
                // attempt to get the resource from the class path
                result = Loader.getResource(logbackConfigFile, classLoader);
                if (result != null) {
                    return result;
                }
                File f = new File(logbackConfigFile);
                if (f.exists() && f.isFile()) {
                    try {
                        result = f.toURI().toURL();
                        return result;
                    } catch (MalformedURLException e1) {
                    }
                }
            } finally {
                if (updateStatus) {
                    statusOnResourceSearch(logbackConfigFile, classLoader, result);
                }
            }
        }
        return null;
    }

总结

  1. 在jvm参数中添加-Dlogback.configurationFile=logback-product.xml,logback-product.xml文件在编译后保证在classes下即可
  2. 综上分析得知logback配置文件的优先级是SystemProperties>logback-test.xml>logback.groovy>logback.xml
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot应用程序中,可以通过配置日志框架日志输出到文件中。以下是一些常用的日志框架以及如何将日志输出到文件中的配置示例: 1. Logback Logback是Spring Boot默认日志框架。要将日志输出到文件中,可以在application.properties文件中添加以下配置: ``` logging.file.name=mylog.log ``` 这将在应用程序的根目录下创建一个名为mylog.log的文件,并将所有日志输出到该文件中。 2. Log4j2 要在Log4j2中将日志输出到文件中,可以在application.properties文件中添加以下配置: ``` logging.file.name=mylog.log ``` 这将在应用程序的根目录下创建一个名为mylog.log的文件,并将所有日志输出到该文件中。 3. JUL (java.util.logging) 要在JUL中将日志输出到文件中,可以在application.properties文件中添加以下配置: ``` logging.file.name=mylog.log ``` 这将在应用程序的根目录下创建一个名为mylog.log的文件,并将所有日志输出到该文件中。 注意:以上示例中使用的是logging.file.name属性。如果要使用完整路径而不是在应用程序的根目录下创建日志文件,则可以使用logging.file.path属性。例如: ``` logging.file.path=/var/log/myapp/ logging.file.name=mylog.log ``` 这将在/var/log/myapp/目录下创建一个名为mylog.log的日志文件。 另外,还可以使用logging.pattern.console属性和logging.pattern.file属性来配置日志输出的格式。例如: ``` logging.pattern.console=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n logging.pattern.file=%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n ``` 这将在控制台和日志文件中以相同的格式输出日志

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值