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.LoggerContext;
010import ch.qos.logback.core.util.StatusPrinter;
011import hm.binkley.util.logging.Level;
012import org.slf4j.LoggerFactory;
013import org.slf4j.bridge.SLF4JBridgeHandler;
014
015import javax.annotation.Nonnull;
016import javax.annotation.Nullable;
017import java.util.Objects;
018
019import static hm.binkley.util.logging.osi.OSI.SystemProperty.LOGBACK_CONFIGURATION_FILE;
020import static hm.binkley.util.logging.osi.OSI.SystemProperty.LOGBACK_CONTEXT_NAME;
021import static hm.binkley.util.logging.osi.OSI.SystemProperty.LOGBACK_DEBUG;
022import static java.lang.String.format;
023import static java.lang.System.clearProperty;
024import static java.lang.System.getProperty;
025import static java.lang.System.out;
026import static java.lang.System.setProperty;
027
028/**
029 * {@code OSI} enable OSI logging for simple cases.
030 *
031 * @author <a href="mailto:binkley@alumni.rice.edu">B. K. Oxley (binkley)</a>
032 */
033public final class OSI {
034    /**
035     * Enable OSI logging using the default configuration resource, "osi-logback.xml" as found on
036     * the class path, and the default application name.  Control configuration through use of other
037     * {@link SystemProperty OSI system properties}.
038     * <p>
039     * Must be called before first use of logback.
040     * <p>
041     * Do not show status of the logging system.
042     */
043    @SuppressWarnings({"ConstantConditions", "Annotator"})
044    public static void enable() {
045        enable(null, false); // Publically applicationName is non-null
046    }
047
048    /**
049     * Enable OSI logging using the default configuration resource, "osi-logback.xml" as found on
050     * the class path, and the default application name.  Control configuration through use of other
051     * {@link SystemProperty OSI system properties}.
052     * <p>
053     * Must be called before first use of logback.
054     *
055     * @param showDetail if {@code true} log the status of the logging system including setup
056     * details.
057     */
058    @SuppressWarnings({"ConstantConditions", "Annotator"})
059    public static void enable(final boolean showDetail) {
060        enable(null, showDetail); // Publically applicationName is non-null
061    }
062
063    /**
064     * Enable OSI logging using the default configuration resource, "osi-logback.xml" as found on
065     * the class path, and the given <var>applicationName</var>.  Control configuration through use
066     * of other {@link SystemProperty OSI system properties}.
067     * <p>
068     * Must be called before first use of logback.
069     * <p>
070     * Do not show status of the logging system.
071     *
072     * @param applicationName the logback context name, never missing
073     */
074    public static void enable(@Nonnull final String applicationName) {
075        enable(applicationName, false);
076    }
077
078    /**
079     * Enable OSI logging using the default configuration resource, "osi-logback.xml" as found on
080     * the class path, and the given <var>applicationName</var>.  Control configuration through use
081     * of other {@link SystemProperty OSI system properties}.
082     * <p>
083     * Must be called before first use of logback.
084     *
085     * @param applicationName the logback context name, never missing
086     * @param showDetail if {@code true} log the status of the logging system including setup
087     * details.
088     *
089     * @see #enable(boolean)
090     */
091    @SuppressWarnings("ConstantConditions")
092    public static void enable(@Nonnull final String applicationName, final boolean showDetail) {
093        SLF4JBridgeHandler.install();
094        LOGBACK_CONFIGURATION_FILE.set("osi-logback.xml");
095        if (null != applicationName) // Publically non-null, internally nullable
096            LOGBACK_CONTEXT_NAME.set(applicationName);
097        if (!showDetail)
098            return;
099        for (final SystemProperty property : SystemProperty.values())
100            out.println(property);
101        // No point duplicating the status messages
102        if (Boolean.valueOf(LOGBACK_DEBUG.get()))
103            return;
104        StatusPrinter.print((LoggerContext) LoggerFactory.getILoggerFactory());
105    }
106
107    /** {@code SystemProperty} defines system properties used by OSI. */
108    public enum SystemProperty {
109        /**
110         * Sets the logback configuration resource, rarely changed except for testing.  Default is
111         * "osi-logback.xml".
112         * <p>
113         * Note this is defined by logback.  Although looked for on the classpath, logback names
114         * this "configurationFile".
115         *
116         * @see #enable()
117         */
118        LOGBACK_CONFIGURATION_FILE("logback.configurationFile"),
119        /**
120         * Sets the logback context name, equivalently, a short tag identifying the application.
121         * Default is "default".
122         * <p>
123         * Use this to distinguish merging of logging from multiple application.
124         *
125         * @see <a href="http://logback.qos.ch/manual/configuration.html#contextName">Setting the
126         * context name</a>
127         */
128        LOGBACK_CONTEXT_NAME("logback.contextName"),
129        /**
130         * As an alternative to setting system properties, put properties here.  Default is
131         * "osi-logback.properties" in the classpath root.
132         * <p>
133         * These cannot, however, override these system properties which are used before the
134         * properties resource is loaded: <ul><li>logback.configurationFile</li>
135         * <li>logback.propertiesResource</li> <li>logback.debug</li></ul>
136         */
137        LOGBACK_PROPERTIES_RESOURCE("logback.propertiesResource"),
138        /**
139         * Sets a custom style file for logging, rarely changed.  Default is
140         * "osi-logback-style.properties".
141         *
142         * @see #LOGBACK_STYLES_RESOURCE
143         */
144        LOGBACK_STYLES_RESOURCE("logback.stylesResource"),
145        /**
146         * Sets the default logging style. Default is "standard".
147         * <p>
148         * See {@code osi-logback-styles.properties} for help and details.
149         *
150         * @see #LOGBACK_STYLES_RESOURCE
151         */
152        LOGBACK_STYLE("logback.style"),
153        /**
154         * Sets the resource for additional included logging directives.  Default is
155         * "osi-logback-included.xml".
156         * <p>
157         * This is often changed (or one named {@code osi-logback-included.xml} is provided in the
158         * application class path) to control logging such as changing log levels.
159         *
160         * @see #LOGBACK_INCLUDED_RESOURCE
161         */
162        LOGBACK_INCLUDED_RESOURCE("logback.includedResource"),
163        /** Enables JMX support for logback.  Default is "true". */
164        LOGBACK_JMX("logback.jmx"),
165        /**
166         * Enables logback debugging.  Default is "false".
167         * <p>
168         * Enabling logback debugging sets {@code log.level} to "DEBUG".
169         *
170         * @see #LOG_LEVEL
171         */
172        LOGBACK_DEBUG("logback.debug"),
173        /**
174         * Adjusts the general logging level when no more specific level is configured for a logger.
175         * Default is "WARN".
176         *
177         * @see Level
178         */
179        LOG_LEVEL("log.level"),
180        /**
181         * Sets the root appender.  Default is "console".
182         * <p>
183         * Use in combination with a custom appender defined in {@code osi-logback-included.xml}.
184         *
185         * @see #LOGBACK_INCLUDED_RESOURCE
186         */
187        LOGBACK_ROOT_APPENDER("logback.rootAppender"),
188        /** Enables ANSI color codes for logging, including Windows.  Default is "false". */
189        LOGBACK_JANSI("logback.jansi");
190
191        @Nonnull
192        private final String key;
193
194        SystemProperty(@Nonnull final String key) {
195            this.key = key;
196        }
197
198        /**
199         * Gets the key string used with system properties.
200         *
201         * @return the key string, never missing
202         */
203        @Nonnull
204        public final String key() {
205            return key;
206        }
207
208        /**
209         * Gets the value of the corresponding system property.
210         *
211         * @return the system property value or {@code null} if undefined
212         */
213        @Nullable
214        public final String get() {
215            return getProperty(key);
216        }
217
218        /**
219         * Sets the value of the corresponding system property, or clears it if {@code null}.
220         *
221         * @param value the system property value or {@code null} to clear
222         */
223        public final void set(@Nullable final String value) {
224            if (null == value)
225                clearProperty(key);
226            else
227                setProperty(key, value);
228        }
229
230        /** Clears the value to the corresponding system property. */
231        public final void clear() {
232            clearProperty(key);
233        }
234
235        @Nonnull
236        @Override
237        public final String toString() {
238            return format("%s(%s)=%s", name(), key,
239                    Objects.toString(getProperty(key), "<default>"));
240        }
241    }
242}