AppenderWithinAppenderSanityChecker.java

/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2022, QOS.ch. All rights reserved.
 * <p>
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 * <p>
 * or (per the licensee's choosing)
 * <p>
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.core.joran.sanity;

import ch.qos.logback.core.model.AppenderModel;
import ch.qos.logback.core.model.Model;
import ch.qos.logback.core.spi.ContextAwareBase;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class AppenderWithinAppenderSanityChecker extends ContextAwareBase implements SanityChecker  {

    static public String NESTED_APPENDERS_WARNING = "As of logback version 1.3, nested appenders are not allowed.";

    @Override
    public void check(Model model) {
        if (model == null)
            return;

        List<Model> appenderModels = new ArrayList<>();
        deepFindAllModelsOfType(AppenderModel.class, appenderModels, model);

        List<Pair<Model, Model>> nestedPairs = deepFindNestedSubModelsOfType(AppenderModel.class, appenderModels);

        List<Pair<Model, Model>> filteredNestedPairs = nestedPairs.stream().filter(pair -> !isSiftingAppender(pair.first)).collect(Collectors.toList());

        if(filteredNestedPairs.isEmpty()) {
            return;
        }
        addWarn(NESTED_APPENDERS_WARNING);
        for(Pair<Model, Model> pair: filteredNestedPairs) {
            addWarn("Appender at line "+pair.first.getLineNumber() + " contains a nested appender at line "+pair.second.getLineNumber());
        }
    }

    private boolean isSiftingAppender(Model first) {
        if(first instanceof  AppenderModel) {
            AppenderModel appenderModel = (AppenderModel) first;
            String classname = appenderModel.getClassName();
            if(classname == null)
                return false;
            return appenderModel.getClassName().contains("SiftingAppender");
        }
        return false;
    }

}