logback源码分析-3.logger element

源码基于logback 1.1.7

logback.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://www.padual.com/java/logback.xsd">

    <appender name="WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/Users/apple/Documents/UNKONESERVER/warn.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 按天回滚 daily -->
            <fileNamePattern>/Users/apple/Documents/UNKONESERVER/warn.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 日志最大的保存天数 -->
            <maxHistory>2</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%msg%n</pattern>
        </encoder>
    </appender>

    <logger name="com.logback.test" level="debug"
            additivity="false">
        <appender-ref ref="WARN" />
    </logger>

    <root level="debug">
    </root>

</configuration>

下面分析loaback是如何解析logger元素的:

1.当解析到[configuration][logger]的时候会触发[configuration][logger]的startEvent方法,最终调用LoggerAction的begin方法:

public void begin(InterpretationContext ec, String name, Attributes attributes) {
        // Let us forget about previous errors (in this object)
        inError = false;
        logger = null;

        LoggerContext loggerContext = (LoggerContext) this.context;
        //获取logger name,这里是com.logback.test
        String loggerName = ec.subst(attributes.getValue(NAME_ATTRIBUTE));

        if (OptionHelper.isEmpty(loggerName)) {
            inError = true;
            String aroundLine = getLineColStr(ec);
            String errorMsg = "No 'name' attribute in element " + name + ", around " + aroundLine;
            addError(errorMsg);
            return;
        }
        //根据loggerName获取logger,下面会详细分析
        logger = loggerContext.getLogger(loggerName);

        String levelStr = ec.subst(attributes.getValue(LEVEL_ATTRIBUTE));

        if (!OptionHelper.isEmpty(levelStr)) {
            if (ActionConst.INHERITED.equalsIgnoreCase(levelStr) || ActionConst.NULL.equalsIgnoreCase(levelStr)) {
                addInfo("Setting level of logger [" + loggerName + "] to null, i.e. INHERITED");
                logger.setLevel(null);
            } else {
                Level level = Level.toLevel(levelStr);
                addInfo("Setting level of logger [" + loggerName + "] to " + level);
                //设置logger级别,没有设置的话默认用debug
                logger.setLevel(level);
            }
        }

        String additivityStr = ec.subst(attributes.getValue(ActionConst.ADDITIVITY_ATTRIBUTE));
        if (!OptionHelper.isEmpty(additivityStr)) {
            boolean additive = OptionHelper.toBoolean(additivityStr, true);
            addInfo("Setting additivity of logger [" + loggerName + "] to " + additive);
            //在本文中例子中,如果是false,那只输出com.logback.test对应logger的日志
            //如果是true,不仅会输出com.logback.test对应logger的日志,还是输出com.logback对应logger的日志
            //如果com.logback对应的logger的additive也是true,那也会输出上级logger日志
            logger.setAdditive(additive);
        }
        ec.pushObject(logger);
    }
    

loggerContext.getLogger(loggerName):

public final Logger getLogger(final String name) {

        if (name == null) {
            throw new IllegalArgumentException("name argument cannot be null");
        }

        // if we are asking for the root logger, then let us return it without
        // wasting time
        if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
            return root;
        }

        int i = 0;
        Logger logger = root;

        // check if the desired logger exists, if it does, return it
        // without further ado.
        //从缓存中根据name获取logger对象,首次是没有值的
        Logger childLogger = (Logger) loggerCache.get(name);
        // if we have the child, then let us return it without wasting time
        if (childLogger != null) {
            return childLogger;
        }

        // if the desired logger does not exist, them create all the loggers
        // in between as well (if they don't already exist)
        //将loggerName按照.进行层级拆分,比如com.logback.test,会被查分成com, com.logback ,com.logback.test三个childName。
        //然后根据这个三个childName去缓存中获取对应的logger,没有就创建,然后保存到缓存中。
        //该方法最后返回childName为com.logback.test的logger。
        //每个logger会保存它的父级logger。
        //每个logger又会保存它的child logger,比如com对应的logger会保存com.logback对应的logger。
        //ROOT logger是最顶级logger,保存所有一级logger,比如com对应的logger,也是所有一级logger的父级logger。
        String childName;
        while (true) {
            int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
            if (h == -1) {
                childName = name;
            } else {
                childName = name.substring(0, h);
            }
            // move i left of the last point
            i = h + 1;
            synchronized (logger) {
                childLogger = logger.getChildByName(childName);
                if (childLogger == null) {
                    childLogger = logger.createChildByName(childName);
                    loggerCache.put(childName, childLogger);
                    incSize();
                }
            }
            logger = childLogger;
            if (h == -1) {
                return childLogger;
            }
        }
    }

2.当[configuration][logger]的startEvent结束后,会触发[configuration][logger][appender-ref]的startEvent,最终会调用AppenderRefAction的begin方法:

public void begin(InterpretationContext ec, String tagName, Attributes attributes) {
        // Let us forget about previous errors (in this object)
        inError = false;

        // logger.debug("begin called");
        //获取[configuraion][logger]对应的logger实例
        Object o = ec.peekObject();

        if (!(o instanceof AppenderAttachable)) {
            String errMsg = "Could not find an AppenderAttachable at the top of execution stack. Near [" + tagName + "] line " + getLineNumber(ec);
            inError = true;
            addError(errMsg);
            return;
        }

        AppenderAttachable<E> appenderAttachable = (AppenderAttachable<E>) o;
        //获取appender name,本文例子的appender name为WARN
        String appenderName = ec.subst(attributes.getValue(ActionConst.REF_ATTRIBUTE));

        if (OptionHelper.isEmpty(appenderName)) {
            // print a meaningful error message and return
            String errMsg = "Missing appender ref attribute in <appender-ref> tag.";
            inError = true;
            addError(errMsg);

            return;
        }
        //根据appender name获取对应的appender实例
        HashMap<String, Appender<E>> appenderBag = (HashMap<String, Appender<E>>) ec.getObjectMap().get(ActionConst.APPENDER_BAG);
        Appender<E> appender = (Appender<E>) appenderBag.get(appenderName);

        if (appender == null) {
            String msg = "Could not find an appender named [" + appenderName + "]. Did you define it below instead of above in the configuration file?";
            inError = true;
            addError(msg);
            addError("See " + CoreConstants.CODES_URL + "#appender_order for more details.");
            return;
        }

        addInfo("Attaching appender named [" + appenderName + "] to " + appenderAttachable);
        //将appender实例存入logger中
        appenderAttachable.addAppender(appender);
    }

3.[configuration][logger][appender-ref]的startEvent结束后,触发[configuration][logger][appender-ref]的endEvent,没做任何事情。 4.接下来就是[configuration][logger]的endEvent了,但LoggerAction的end方法也没做什么事情。

转载于:https://my.oschina.net/u/913896/blog/916694

### 下载或获取 logback-classic-1.2.11.jar 文件的方法 在 Maven 项目中,如果需要使用 `logback-classic` 的特定版本(如 1.2.11),可以通过以下方法下载或获取 `logback-classic-1.2.11.jar` 文件。 #### 方法一:通过 Maven 自动下载 将以下依赖配置添加到项目的 `pom.xml` 文件中: ```xml <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.11</version> </dependency> ``` 运行以下命令以确保依赖被正确解析并下载到本地仓库: ```bash mvn clean install ``` Maven 会自动从中央仓库下载 `logback-classic-1.2.11.jar` 文件及其传递性依赖[^1]。下载完成后,可以在本地 Maven 仓库中找到该文件,路径通常为: ``` ~/.m2/repository/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar ``` #### 方法二:手动下载 如果不想通过 Maven 自动下载,可以直接从 Maven 中央仓库手动下载 `logback-classic-1.2.11.jar` 文件。访问以下链接: [https://repo.maven.apache.org/maven2/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar](https://repo.maven.apache.org/maven2/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar) 点击链接即可下载 `.jar` 文件。将其保存到项目的 `lib` 目录或其他合适的位置,并在构建工具中配置为依赖项。 #### 方法三:解决可能的认证问题 如果在下载过程中遇到认证错误(如引用中的描述),请检查 `${user.home}/.m2/settings.xml` 文件是否正确配置了服务器凭证[^3]。例如: ```xml <servers> <server> <id>central</id> <username>your-username</username> <password>your-password</password> </server> </servers> ``` 确保 `<id>` 值与远程仓库的 `<id>` 匹配。如果未正确配置,Maven 将无法提供必要的认证信息,导致下载失败。 ### 注意事项 - 如果使用的是公司内部私服(如 Nexus 或 Artifactory),需要确保私服已同步 `logback-classic-1.2.11` 版本。 - 在某些情况下,可能需要额外配置代理或网络设置以访问外部仓库。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值