001package org.apache.commons.jcs3.log;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache license, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the license for the specific language governing permissions and
017 * limitations under the license.
018 */
019
020import java.util.ArrayList;
021import java.util.Iterator;
022import java.util.List;
023import java.util.ServiceConfigurationError;
024import java.util.ServiceLoader;
025
026/**
027 * This is a borrowed and stripped-down version of the log4j2 LogManager class.
028 *
029 * The anchor point for the JCS logging system. The most common usage of this
030 * class is to obtain a named {@link Log}.
031 */
032public class LogManager
033{
034    /**
035     * The name of log subsystem
036     */
037    private static String logSystem;
038
039    /** Log systems currently known */
040    public static final String LOGSYSTEM_JAVA_UTIL_LOGGING = "jul";
041    public static final String LOGSYSTEM_LOG4J2 = "log4j2";
042
043    /**
044     * The SPI LogFactory
045     */
046    private static class LogFactoryHolder
047    {
048        static final LogFactory INSTANCE = createLogFactory();
049
050        /**
051         * Scans the classpath to find a logging implementation.
052         *
053         * @return the LogFactory
054         * @throws RuntimeException, if no factory implementation could be found
055         */
056        private static LogFactory createLogFactory()
057        {
058            final ServiceLoader<LogFactory> factories = ServiceLoader.load(LogFactory.class);
059            if (LogManager.logSystem == null)
060            {
061                LogManager.logSystem = System.getProperty("jcs.logSystem",
062                        LOGSYSTEM_JAVA_UTIL_LOGGING);
063            }
064
065            // Store errors that may occur until log system is available
066            List<ServiceConfigurationError> errors = new ArrayList<>();
067            Iterator<LogFactory> itr = factories.iterator();
068            LogFactory factory = null;
069            while (itr.hasNext())
070            {
071                try
072                {
073                    LogFactory instance = itr.next();
074                    if (logSystem.equalsIgnoreCase(instance.getName()))
075                    {
076                        factory = instance;
077                        break;
078                    }
079                }
080                catch (ServiceConfigurationError e)
081                {
082                    errors.add(e);
083                }
084            }
085            if (factory != null)
086            {
087                if (!errors.isEmpty())
088                {
089                    Log log = factory.getLog(LogFactoryHolder.class);
090
091                    for (ServiceConfigurationError error : errors)
092                    {
093                        log.debug("Error loading LogFactory", error);
094                    }
095                    log.debug("Found LogFactory for " + logSystem);
096                }
097                return factory;
098            }
099
100            // No log system could be found --> report errors to stderr
101            errors.forEach(e -> System.err.println(e.getMessage()));
102            throw new RuntimeException("Could not find factory implementation for log subsystem " + logSystem);
103        }
104    }
105
106    /**
107     * Set the log system. Must be called before getLog is called
108     *
109     * @param logSystem the logSystem to set
110     */
111    public static void setLogSystem(final String logSystem)
112    {
113        LogManager.logSystem = logSystem;
114    }
115
116    /**
117     * Return the LogFactory
118     */
119    private static LogFactory getLogFactory()
120    {
121        return LogFactoryHolder.INSTANCE;
122    }
123
124    /**
125     * Prevents instantiation
126     */
127    protected LogManager()
128    {
129    }
130
131    /**
132     * Shutdown the logging system if the logging system supports it.
133     */
134    public static void shutdown()
135    {
136        getLogFactory().shutdown();
137    }
138
139    /**
140     * Returns a Log using the fully qualified name of the Class as the Log
141     * name.
142     *
143     * @param clazz
144     *            The Class whose name should be used as the Log name.
145     * @return The Log.
146     * @throws UnsupportedOperationException
147     *             if {@code clazz} is {@code null}
148     */
149    public static Log getLog(final Class<?> clazz)
150    {
151        return getLogFactory().getLog(clazz);
152    }
153
154    /**
155     * Returns a Log with the specified name.
156     *
157     * @param name
158     *            The logger name.
159     * @return The Log.
160     * @throws UnsupportedOperationException
161     *             if {@code name} is {@code null}
162     */
163    public static Log getLog(final String name)
164    {
165        return getLogFactory().getLog(name);
166    }
167
168    /**
169     * Returns the root logger.
170     *
171     * @return the root logger, named {@link LogFactory#ROOT_LOGGER_NAME}.
172     */
173    public static Log getRootLogger()
174    {
175        return getLog(LogFactory.ROOT_LOGGER_NAME);
176    }
177}