001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2022, QOS.ch. All rights reserved.
004 * <p>
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 * <p>
009 * or (per the licensee's choosing)
010 * <p>
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.core.joran.sanity;
015
016import ch.qos.logback.core.model.AppenderModel;
017import ch.qos.logback.core.model.Model;
018import ch.qos.logback.core.spi.ContextAwareBase;
019
020import java.util.ArrayList;
021import java.util.List;
022import java.util.stream.Collectors;
023
024public class AppenderWithinAppenderSanityChecker extends ContextAwareBase implements SanityChecker  {
025
026    static public String NESTED_APPENDERS_WARNING = "As of logback version 1.3, nested appenders are not allowed.";
027
028    @Override
029    public void check(Model model) {
030        if (model == null)
031            return;
032
033        List<Model> appenderModels = new ArrayList<>();
034        deepFindAllModelsOfType(AppenderModel.class, appenderModels, model);
035
036        List<Pair<Model, Model>> nestedPairs = deepFindNestedSubModelsOfType(AppenderModel.class, appenderModels);
037
038        List<Pair<Model, Model>> filteredNestedPairs = nestedPairs.stream().filter(pair -> !isSiftingAppender(pair.first)).collect(Collectors.toList());
039
040        if(filteredNestedPairs.isEmpty()) {
041            return;
042        }
043        addWarn(NESTED_APPENDERS_WARNING);
044        for(Pair<Model, Model> pair: filteredNestedPairs) {
045            addWarn("Appender at line "+pair.first.getLineNumber() + " contains a nested appender at line "+pair.second.getLineNumber());
046        }
047    }
048
049    private boolean isSiftingAppender(Model first) {
050        if(first instanceof  AppenderModel) {
051            AppenderModel appenderModel = (AppenderModel) first;
052            String classname = appenderModel.getClassName();
053            if(classname == null)
054                return false;
055            return appenderModel.getClassName().contains("SiftingAppender");
056        }
057        return false;
058    }
059
060}