All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.logging.metadata.LoggingMetaDataHelper Maven / Gradle / Ivy

There is a newer version: 1.0.0.CR10
Show newest version
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2009, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.logging.metadata;

import org.jboss.beans.metadata.spi.BeanMetaData;
import org.jboss.beans.metadata.spi.ValueMetaData;
import org.jboss.beans.metadata.spi.ParameterMetaData;
import org.jboss.beans.metadata.spi.PropertyMetaData;
import org.jboss.beans.metadata.spi.builder.BeanMetaDataBuilder;
import org.jboss.beans.metadata.plugins.AbstractValueFactoryMetaData;
import org.jboss.beans.metadata.plugins.AbstractParameterMetaData;
import org.jboss.beans.metadata.plugins.AbstractInjectionValueMetaData;
import org.jboss.beans.metadata.plugins.AbstractValueMetaData;
import org.jboss.logmanager.Logger;
import org.jboss.logmanager.formatters.PatternFormatter;
import org.jboss.logmanager.filters.AllFilter;
import org.jboss.logmanager.filters.AnyFilter;
import org.jboss.logmanager.filters.AcceptAllFilter;
import org.jboss.logmanager.filters.DenyAllFilter;
import org.jboss.logmanager.filters.InvertFilter;
import org.jboss.logmanager.filters.RegexFilter;
import org.jboss.logmanager.filters.SubstituteFilter;
import org.jboss.logmanager.filters.LevelFilter;
import org.jboss.logmanager.filters.LevelRangeFilter;
import org.jboss.logmanager.filters.LevelChangingFilter;
import org.jboss.logmanager.errormanager.OnlyOnceErrorManager;
import org.jboss.logmanager.log4j.handlers.Log4jAppenderHandler;
import org.jboss.logmanager.handlers.AsyncHandler;
import org.jboss.logmanager.handlers.ConsoleHandler;
import org.jboss.logmanager.handlers.FileHandler;
import org.jboss.logmanager.handlers.NullHandler;
import org.jboss.logmanager.handlers.PeriodicRotatingFileHandler;
import org.jboss.logmanager.handlers.SizeRotatingFileHandler;
import org.jboss.dependency.spi.ControllerMode;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.EnumMap;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import java.util.concurrent.atomic.AtomicInteger;

import java.util.logging.Handler;
import java.util.logging.Filter;
import java.util.logging.Level;

public final class LoggingMetaDataHelper {

    private LoggingMetaDataHelper() {
    }

    private static final AtomicInteger sequence = new AtomicInteger();

    public static void createBeanMetaData(final List beanMetaDataList, final LoggingMetaData loggingMetaData) {
        final String context = loggingMetaData.getContext();
        if (context == null) {
            // context should be "system" by default
            throw new NullPointerException("context is null");
        }
        final List abstractLoggerMetaDataList = loggingMetaData.getLoggerMetaDataList();
        if (abstractLoggerMetaDataList != null) for (AbstractLoggerMetaData abstractLoggerMetaData : abstractLoggerMetaDataList) {
            createLoggerBeanMetaData(beanMetaDataList, abstractLoggerMetaData, context);
        }
        final List handlerMetaDataList = loggingMetaData.getHandlerMetaDataList();
        if (handlerMetaDataList != null) for (AbstractHandlerMetaData abstractHandlerMetaData : handlerMetaDataList) {
            getValue(beanMetaDataList, abstractHandlerMetaData, context);
        }
        final List installHandlerMetaDataList = loggingMetaData.getInstallHandlerMetaDataList();
        if (installHandlerMetaDataList != null) for (InstallHandlerMetaData installMetaData : installHandlerMetaDataList) {
            final String installerName = getInstallerName(context, "*");
            final RefMetaData handlerRef = installMetaData.getHandlerRef();
            final List loggerRefs = installMetaData.getLoggerRefList();
            BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(installerName, HandlerInstallerHelper.class.getName());
            final List handlerList = builder.createList();
            final List targetList = builder.createList();
            handlerList.add(builder.createInject(getName(context, Kind.HANDLER, handlerRef.getName())));
            for (AbstractLoggerRefMetaData loggerRef : loggerRefs) {
                final String refContext = loggerRef.getContext();
                final String refName;
                if (loggerRef instanceof LoggerRefMetaData) {
                    refName = ((LoggerRefMetaData)loggerRef).getCategory();
                } else {
                    refName = "";
                }
                targetList.add(getLoggerInjectValue(refContext == null ? context : refContext, refName));
            }
            builder.addPropertyMetaData("handlerList", (ValueMetaData) handlerList);
            builder.addPropertyMetaData("targetList", (ValueMetaData) targetList);
            beanMetaDataList.add(builder.getBeanMetaData());
        }
    }

    private static void createLoggerBeanMetaData(final List beanMetaDataList, final AbstractLoggerMetaData abstractLoggerMetaData, final String context) {
        final String name;
        final String humanName;
        if (abstractLoggerMetaData instanceof LoggerMetaData) {
            name = humanName = ((LoggerMetaData) abstractLoggerMetaData).getCategory();
        } else {
            name = "";
            humanName = "";
        }
        final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(getName(context, Kind.LOGGER, humanName), Logger.class.getName());
        builder.setFactory(builder.createInject(getContextName(context)));
        builder.setFactoryMethod("getLogger");
        builder.addConstructorParameter(String.class.getName(), name);
        if (abstractLoggerMetaData instanceof LoggerMetaData) {
            builder.addPropertyMetaData("useParentHandlers", Boolean.valueOf(((LoggerMetaData) abstractLoggerMetaData).isUseParentHandlers()));
        }
        final RefMetaData levelRef = abstractLoggerMetaData.getLevelMetaData();
        if (levelRef != null) {
            builder.addPropertyMetaData("level", getLevelInjectValue(context, levelRef.getName()));
        }
        final FilterMetaData filterMetaData = abstractLoggerMetaData.getFilterMetaData();
        if (filterMetaData != null) {
            builder.addPropertyMetaData("filter", getValue(beanMetaDataList, context, filterMetaData));
        }
        final BeanMetaData loggerBeanMetaData = builder.getBeanMetaData();
        // now install handlers
        final List handlerMetaDataList = abstractLoggerMetaData.getHandlerMetaDataList();
        if (handlerMetaDataList != null) {
            final BeanMetaDataBuilder installerBuilder = BeanMetaDataBuilder.createBuilder(getInstallerName(context, name), HandlerInstallerHelper.class.getName());
            final List handlerList = builder.createList();
            for (Object handlerMetaData : handlerMetaDataList) {
                if (handlerMetaData instanceof AbstractHandlerMetaData) {
                    handlerList.add(getValue(beanMetaDataList, (AbstractHandlerMetaData) handlerMetaData, context));
                } else if (handlerMetaData instanceof ValueMetaData) {
                    handlerList.add((ValueMetaData) handlerMetaData);
                } else {
                    handlerList.add(builder.createInject(getName(context, Kind.HANDLER, ((RefMetaData) handlerMetaData).getName())));
                }
            }
            final List targetList = builder.createList();
            targetList.add(loggerBeanMetaData);
            installerBuilder.addPropertyMetaData("handlerList", (ValueMetaData) handlerList);
            installerBuilder.addPropertyMetaData("targetList", (ValueMetaData) targetList);
            beanMetaDataList.add(installerBuilder.getBeanMetaData());
        }
        beanMetaDataList.add(loggerBeanMetaData);
    }

    private static final Map targetMap = new EnumMap(ConsoleHandlerMetaData.Target.class);

    static {
        targetMap.put(ConsoleHandlerMetaData.Target.SYSTEM_ERR, ConsoleHandler.Target.SYSTEM_ERR);
        targetMap.put(ConsoleHandlerMetaData.Target.SYSTEM_OUT, ConsoleHandler.Target.SYSTEM_OUT);
    }

    private static ValueMetaData getValue(final List beanMetaDataList, final AbstractHandlerMetaData handlerMetaData, final String context) {
        final String name = handlerMetaData.getName();
        final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(name == null ? getAnonymousName(context, Kind.HANDLER) : getName(context, Kind.HANDLER, name), null);
        if (handlerMetaData instanceof HandlerMetaData) {
            builder.setBean(((HandlerMetaData)handlerMetaData).getClassName());
        } else if (handlerMetaData instanceof AsyncHandlerMetaData) {
            builder.setBean(AsyncHandler.class.getName());
        } else if (handlerMetaData instanceof ConsoleHandlerMetaData) {
            final ConsoleHandlerMetaData consoleHandlerMetaData = (ConsoleHandlerMetaData) handlerMetaData;
            builder.setBean(ConsoleHandler.class.getName());
            builder.addPropertyMetaData("target", targetMap.get(consoleHandlerMetaData.getTarget()));
        } else if (handlerMetaData instanceof FileHandlerMetaData) {
            final FileHandlerMetaData fileHandlerMetaData = (FileHandlerMetaData) handlerMetaData;
            if (handlerMetaData instanceof PeriodicRotatingFileHandlerMetaData) {
                final PeriodicRotatingFileHandlerMetaData periodicRotatingFileHandlerMetaData = (PeriodicRotatingFileHandlerMetaData) handlerMetaData;
                builder.setBean(PeriodicRotatingFileHandler.class.getName());
                builder.addPropertyMetaData("suffix", periodicRotatingFileHandlerMetaData.getSuffix());
            } else if (handlerMetaData instanceof SizeRotatingFileHandlerMetaData) {
                final SizeRotatingFileHandlerMetaData sizeRotatingFileHandlerMetaData = (SizeRotatingFileHandlerMetaData) handlerMetaData;
                builder.setBean(SizeRotatingFileHandler.class.getName());
                builder.addPropertyMetaData("maxBackupIndex", Integer.valueOf(sizeRotatingFileHandlerMetaData.getMaxBackupIndex()));
                final String sizeString = sizeRotatingFileHandlerMetaData.getRotateSizeString();
                builder.addPropertyMetaData("rotateSize", Long.valueOf(parseSizeString(sizeString)));
            } else {
                builder.setBean(FileHandler.class.getName());
            }
            builder.addConstructorParameter(String.class.getName(), fileHandlerMetaData.getFileName());
            builder.addConstructorParameter(boolean.class.getName(), Boolean.valueOf(fileHandlerMetaData.isAppend()));
        } else if (handlerMetaData instanceof Log4jAppenderMetaData) {
            builder.setBean(Log4jAppenderHandler.class.getName());
        } else if (handlerMetaData instanceof NullHandlerMetaData) {
            builder.setBean(NullHandler.class.getName());
        }
        builder.setStop("close");
        builder.setMode(ControllerMode.ON_DEMAND);
        // autoflush
        builder.addPropertyMetaData("autoFlush", Boolean.valueOf(handlerMetaData.isAutoflush()));
        // encoding
        final String encoding = handlerMetaData.getEncoding();
        if (encoding != null) {
            builder.addPropertyMetaData("encoding", builder.createValue(encoding));
        }
        // properties
        final List properties = handlerMetaData.getPropertyMetaDataList();
        if (properties != null) for (PropertyMetaData property : properties) {
            builder.addPropertyMetaData(property.getName(), property.getValue());
        }
        // error-manager
        final ErrorManagerMetaData errorManager = handlerMetaData.getErrorManagerMetaData();
        if (errorManager != null) {
            if (errorManager.isOnlyOnce()) {
                builder.addPropertyMetaData("errorManager", builder.createValue(new OnlyOnceErrorManager()));
            } else {
                builder.addPropertyMetaData("errorManager", errorManager.getValueMetaData());
            }
        }
        // level
        final RefMetaData levelRef = handlerMetaData.getLevelMetaData();
        if (levelRef != null) {
            builder.addPropertyMetaData("level", getLevelInjectValue(context, levelRef.getName()));
        }
        // filter
        final FilterMetaData filter = handlerMetaData.getFilterMetaData();
        if (filter != null) {
            builder.addPropertyMetaData("filter", getValue(beanMetaDataList, context, filter));
        }
        // formatter
        final FormatterMetaData formatter = handlerMetaData.getFormatterMetaData();
        if (formatter != null) {
            builder.addPropertyMetaData("formatter", getValue(beanMetaDataList, formatter, context));
        }
        // sub-handlers
        final List subHandlers = handlerMetaData.getSubHandlerMetaDataList();
        if (subHandlers != null) {
            final List subHandlerValueList = builder.createArray(Handler[].class.getName(), Handler.class.getName());
            for (AbstractHandlerMetaData subHandler : subHandlers) {
                subHandlerValueList.add(getValue(beanMetaDataList, subHandler, context));
            }
            builder.addPropertyMetaData("handlers", (ValueMetaData) subHandlerValueList);
        }
        final BeanMetaData handlerBeanMetaData = builder.getBeanMetaData();
        beanMetaDataList.add(handlerBeanMetaData);
        // loggers
        final List loggers = handlerMetaData.getLoggerMetaDataList();
        if (loggers != null) {
            final String installerName = getInstallerName(context, "*");
            final BeanMetaDataBuilder installerBuilder = BeanMetaDataBuilder.createBuilder(installerName, HandlerInstallerHelper.class.getName());
            final List targetList = installerBuilder.createList();
            for (AbstractLoggerRefMetaData loggerRef : loggers) {
                final String refContext = loggerRef.getContext();
                final String refName;
                if (loggerRef instanceof LoggerRefMetaData) {
                    refName = ((LoggerRefMetaData)loggerRef).getCategory();
                } else {
                    refName = "";
                }
                targetList.add(getLoggerInjectValue(refContext == null ? context : refContext, refName));
            }
            final List handlerList = installerBuilder.createList();
            handlerList.add(handlerBeanMetaData);
            installerBuilder.addPropertyMetaData("handlerList", (ValueMetaData) handlerList);
            installerBuilder.addPropertyMetaData("targetList", (ValueMetaData) targetList);
            beanMetaDataList.add(installerBuilder.getBeanMetaData());
        }
        return handlerBeanMetaData;
    }

    private static final Pattern SIZE_PATTERN = Pattern.compile("(\\d+)([bBkKmMgGtT]?)");

    private static long parseSizeString(final String sizeString) {
        final Matcher matcher = SIZE_PATTERN.matcher(sizeString);
        if (matcher.matches()) {
            final long size = Long.parseLong(matcher.group(1));
            final String multStr = matcher.group(2);
            final char multChar;
            if (multStr.length() == 0) {
                multChar = 'b';
            } else {
                multChar = Character.toLowerCase(multStr.charAt(0));
            }
            switch (multChar) {
                case 'b': break;
                case 'k': return size * 1024L;
                case 'm': return size * 1024L * 1024L;
                case 'g': return size * 1024L * 1024L * 1024L;
                case 't': return size * 1024L * 1024L * 1024L * 1024L;
            }
            throw new IllegalStateException();
        } else {
            throw new IllegalArgumentException("Invalid size string \"" + sizeString + "\"");
        }
    }

    private static ValueMetaData getLevelInjectValue(final String context, final String name) {
        if (context == null) {
            throw new NullPointerException("context is null");
        }
        if (name == null) {
            throw new NullPointerException("name is null");
        }
        final AbstractValueFactoryMetaData avfmd = new AbstractValueFactoryMetaData(getContextName(context), "getLevelForName");
        final List parameterList = new ArrayList(1);
        avfmd.setParameters(parameterList);
        parameterList.add(new AbstractParameterMetaData(String.class.getName(), name));
        return avfmd;
    }

    private static ValueMetaData getLoggerInjectValue(final String context, final String category) {
        if (context == null) {
            throw new NullPointerException("context is null");
        }
        if (category == null) {
            throw new NullPointerException("category is null");
        }
        final AbstractValueFactoryMetaData avfmd = new AbstractValueFactoryMetaData(getContextName(context), "getLogger");
        final List parameterList = new ArrayList(1);
        avfmd.setParameters(parameterList);
        parameterList.add(new AbstractParameterMetaData(String.class.getName(), category));
        return avfmd;
    }

    private static ValueMetaData getValue(final List beanMetaDataList, final String context, final FilterMetaData filterMetaData) {
        final String name = filterMetaData.getName();
        final String beanName = name == null ? getAnonymousName(context, Kind.FILTER) : getName(context, Kind.FILTER, name);
        final Object value = filterMetaData.getValue();
        return getFilterValue(beanMetaDataList, beanName, context, value);
    }

    private static ValueMetaData getFilterValue(final List beanMetaDataList, final String beanName, final String context, final Object value) {
        if (value instanceof ValueMetaData) {
            return (ValueMetaData) value;
        } else if (value instanceof RefMetaData) {
            return new AbstractInjectionValueMetaData(((RefMetaData)value).getName());
        } else if (value instanceof AbstractMultiFilterMetaData) {
            final AbstractMultiFilterMetaData metaData = (AbstractMultiFilterMetaData) value;
            final BeanMetaDataBuilder builder;
            if (metaData instanceof AllFilterMetaData) {
                builder = BeanMetaDataBuilder.createBuilder(beanName, AllFilter.class.getName());
            } else {
                builder = BeanMetaDataBuilder.createBuilder(beanName, AnyFilter.class.getName());
            }
            final List filterList = builder.createArray();
            for (Object filterValue : metaData.getFilterMetaDataList()) {
                filterList.add(getFilterValue(beanMetaDataList, getAnonymousName(context, Kind.FILTER), context, filterValue));
            }
            builder.addConstructorParameter(Filter[].class.getName(), (ValueMetaData) filterList);
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        } else if (value instanceof AcceptFilterMetaData) {
            return new AbstractValueMetaData(AcceptAllFilter.getInstance());
        } else if (value instanceof DenyFilterMetaData) {
            return new AbstractValueMetaData(DenyAllFilter.getInstance());
        } else if (value instanceof NotFilterMetaData) {
            final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(beanName, InvertFilter.class.getName());
            builder.addPropertyMetaData("target", getFilterValue(beanMetaDataList, getAnonymousName(context, Kind.FILTER), context, ((NotFilterMetaData)value).getValue()));
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        } else if (value instanceof PatternFormatterMetaData) {
            final PatternFormatterMetaData metaData = (PatternFormatterMetaData) value;
            final String pattern = metaData.getPattern();
            final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(beanName, RegexFilter.class.getName());
            builder.addConstructorParameter(String.class.getName(), pattern);
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        } else if (value instanceof ReplaceFilterMetaData) {
            final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(beanName, SubstituteFilter.class.getName());
            final ReplaceFilterMetaData metaData = (ReplaceFilterMetaData) value;
            builder.addConstructorParameter(String.class.getName(), metaData.getPattern());
            builder.addConstructorParameter(String.class.getName(), metaData.getReplacement());
            builder.addConstructorParameter(boolean.class.getName(), Boolean.valueOf(metaData.isReplaceAll()));
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        } else if (value instanceof LevelFilterMetaData) {
            final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(beanName, LevelFilter.class.getName());
            final LevelFilterMetaData metaData = (LevelFilterMetaData) value;
            builder.addConstructorParameter(Level.class.getName(), getLevelInjectValue(context, metaData.getLevel()));
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        } else if (value instanceof LevelRangeFilterMetaData) {
            final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(beanName, LevelRangeFilter.class.getName());
            final LevelRangeFilterMetaData metaData = (LevelRangeFilterMetaData) value;
            builder.addConstructorParameter(Level.class.getName(), getLevelInjectValue(context, metaData.getMinLevel()));
            builder.addConstructorParameter(boolean.class.getName(), Boolean.valueOf(metaData.isMinInclusive()));
            builder.addConstructorParameter(Level.class.getName(), getLevelInjectValue(context, metaData.getMaxLevel()));
            builder.addConstructorParameter(boolean.class.getName(), Boolean.valueOf(metaData.isMaxInclusive()));
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        } else if (value instanceof LevelChangeFilterMetaData) {
            final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(beanName, LevelChangingFilter.class.getName());
            final LevelChangeFilterMetaData metaData = (LevelChangeFilterMetaData) value;
            builder.addConstructorParameter(Level.class.getName(), getLevelInjectValue(context, metaData.getLevel()));
            final BeanMetaData beanMetaData = builder.getBeanMetaData();
            beanMetaDataList.add(beanMetaData);
            return beanMetaData;
        }
        throw new IllegalStateException();
    }

    private static ValueMetaData getValue(final List beanMetaDataList, final FormatterMetaData formatter, final String context) {
        final RefMetaData refMetaData = formatter.getFormatterRefMetaData();
        if (refMetaData != null) {
            return new AbstractInjectionValueMetaData(refMetaData.getName());
        }
        final ValueMetaData valueMetaData = formatter.getValueMetaData();
        if (valueMetaData != null) {
            return valueMetaData;
        }
        final PatternFormatterMetaData metaData = formatter.getPatternFormatterMetaData();
        if (metaData == null) {
            return null;
        }
        final BeanMetaDataBuilder builder = BeanMetaDataBuilder.createBuilder(getAnonymousName(context, Kind.FORMATTER), PatternFormatter.class.getName());
        builder.addConstructorParameter(String.class.getName(), metaData.getPattern());
        final BeanMetaData beanMetaData = builder.getBeanMetaData();
        beanMetaDataList.add(beanMetaData);
        return beanMetaData;
    }

    public static String getName(String context, Kind kind, String name) {
        StringBuilder b = new StringBuilder(64);
        b.append("Logging:");
        b.append(kind);
        b.append(':');
        b.append(context);
        b.append(':');
        b.append(name);
        return b.toString();
    }

    public static String getAnonymousName(String context, Kind kind) {
        StringBuilder b = new StringBuilder(64);
        b.append("Logging:");
        b.append(kind);
        b.append(':');
        b.append(context);
        b.append(':');
        b.append("Anonymous-");
        b.append(sequence.getAndIncrement());
        return b.toString();
    }

    public static String getInstallerName(String context, String category) {
        StringBuilder b = new StringBuilder(64);
        b.append("Logging:HANDLER_INSTALLER:");
        b.append(context);
        b.append(':');
        b.append(category);
        b.append(':');
        b.append(sequence.getAndIncrement());
        return b.toString();
    }

    public static String getContextName(String name) {
        StringBuilder b = new StringBuilder(64);
        b.append("Logging:CONTEXT:");
        b.append(name);
        return b.toString();
    }

    public enum Kind {
        FORMATTER,
        HANDLER,
        FILTER,
        LOGGER,
    }
}