001/*
002 * This is free and unencumbered software released into the public domain.
003 *
004 * Please see https://github.com/binkley/binkley/blob/master/LICENSE.md.
005 */
006
007package hm.binkley.util.logging.osi;
008
009import ch.qos.logback.classic.Level;
010import hm.binkley.util.logging.MarkedLogger;
011import hm.binkley.util.logging.MinimumLogger;
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014import org.slf4j.ext.XLogger;
015import org.slf4j.ext.XLoggerFactory;
016
017import javax.annotation.Nonnull;
018
019import static ch.qos.logback.classic.Level.ALL;
020import static ch.qos.logback.classic.Level.INFO;
021import static ch.qos.logback.classic.Level.WARN;
022import static org.slf4j.MarkerFactory.getMarker;
023
024/**
025 * {@code SupportLoggers} are custom {@link MarkedLogger}s for specialized use. Methods create new
026 * marked loggers with the enum names as markers. <p> There is one factory method variant for each
027 * style of logger creation: <dl> <dt>{@link #getLogger(Class)}</dt> <dd>Creates a new underlying
028 * logger from a class</dd> <dt>{@link #getLogger(String)}</dt> <dd>Creates a new underlying logger
029 * from a logger name</dd> <dt>{@link #getLogger(Logger)}</dt> <dd>Reuses an existing underlying
030 * logger</dd> </dl> <p> Applications should configure logback or other logging system by marker:
031 * <dl><dt>{@link #ALERT}</dt> <dd>Send alerts for system issues</dd> <dt>{@link #APPLICATION}</dt>
032 * <dd>Logs normally following logback configuration</dd> <dt>{@link #AUDIT}</dt> <dd>Records an
033 * audit trail, typically to a database</dd> <dt>{@link #TRACE}</dt> <dd>A tracing logger for method
034 * entry and exit</dd></dl>
035 *
036 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
037 */
038public enum SupportLoggers {
039    /**
040     * Marks "ALERT" loggers for system issues.  Rejects logging at less than {@code WARN} level
041     * (throws {@code IllegalStateException}).
042     */
043    ALERT(WARN),
044    /** Unmarked loggers for normal logging. */
045    APPLICATION(ALL) {
046        @Nonnull
047        @Override
048        public Logger getLogger(@Nonnull final Class<?> logger) {
049            return LoggerFactory.getLogger(logger);
050        }
051
052        @Nonnull
053        @Override
054        public Logger getLogger(@Nonnull final String logger) {
055            return LoggerFactory.getLogger(logger);
056        }
057
058        @Nonnull
059        @Override
060        public Logger getLogger(@Nonnull final Logger logger) {
061            return logger;
062        }
063    },
064    /**
065     * Marks "AUDIT" loggers to record an audit trail, typically to a database.  Rejects logging
066     * less than {@code INFO} level (throws {@code IllegalStateException}).
067     */
068    AUDIT(INFO),
069    /** Trace loggers ({@link XLogger} for debugging. */
070    TRACE(ALL) {
071        @Nonnull
072        @Override
073        public XLogger getLogger(@Nonnull final Class<?> logger) {
074            return XLoggerFactory.getXLogger(logger);
075        }
076
077        @Nonnull
078        @Override
079        public XLogger getLogger(@Nonnull final String logger) {
080            return XLoggerFactory.getXLogger(logger);
081        }
082
083        @Nonnull
084        @Override
085        public XLogger getLogger(@Nonnull final Logger logger) {
086            return (XLogger) logger;
087        }
088    };
089    @Nonnull
090    private final Level minimum;
091
092    SupportLoggers(@Nonnull final Level minimum) {
093        this.minimum = minimum;
094    }
095
096    /**
097     * Redundant method for {@link #TRACE} returning {@code XLogger}.
098     *
099     * @param logger the logger class, never missing
100     *
101     * @return the XLogger, never missing
102     *
103     * @todo Java needs anonymous instance covariant returns to avoid casting
104     */
105    @Nonnull
106    public static XLogger trace(@Nonnull final Class<?> logger) {
107        return trace(logger.getName());
108    }
109
110    /**
111     * Redundant method for {@link #TRACE} returning {@code XLogger}.
112     *
113     * @param logger the logger name, never missing
114     *
115     * @return the XLogger, never missing
116     *
117     * @todo Java needs anonymous instance covariant returns to avoid casting
118     */
119    @Nonnull
120    public static XLogger trace(@Nonnull final String logger) {
121        return (XLogger) TRACE.getLogger(logger);
122    }
123
124    /**
125     * Creates a new marked logger for the given <var>logger</var>.
126     *
127     * @param logger the underlying class, never missing
128     *
129     * @return the wrapping marked logger, never missing
130     */
131    @Nonnull
132    public Logger getLogger(@Nonnull final Class<?> logger) {
133        return getLogger(LoggerFactory.getLogger(logger));
134    }
135
136    /**
137     * Creates a new marked logger for the given <var>logger</var>.
138     *
139     * @param logger the underlying logger name, never missing
140     *
141     * @return the wrapping marked logger, never missing
142     */
143    @Nonnull
144    public Logger getLogger(@Nonnull final String logger) {
145        return getLogger(LoggerFactory.getLogger(logger));
146    }
147
148    /**
149     * Creates a new marked logger for the given <var>logger</var>.
150     *
151     * @param logger the underlying SLF4j logger, never missing
152     *
153     * @return the wrapping marked logger, never missing
154     */
155    @Nonnull
156    public Logger getLogger(@Nonnull final Logger logger) {
157        return ALL == minimum ? new MarkedLogger(logger, getMarker(name())) : new MinimumLogger(
158                new MarkedLogger(logger, MinimumLogger.class.getName(), getMarker(name())),
159                minimum);
160    }
161}