001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 *     Benoit Delbosc
019 */
020package org.nuxeo.common.logging;
021
022import java.util.Map;
023import java.util.concurrent.ConcurrentHashMap;
024import java.util.logging.Handler;
025import java.util.logging.Level;
026import java.util.logging.LogManager;
027import java.util.logging.LogRecord;
028import java.util.logging.Logger;
029
030import org.apache.commons.logging.Log;
031import org.apache.commons.logging.LogFactory;
032
033/**
034 * Helper that can redirect all {@code java.util.logging} messages to the Apache Commons Logging implementation.
035 *
036 * @author Florent Guillaume
037 */
038public class JavaUtilLoggingHelper {
039
040    private static final Log log = LogFactory.getLog(JavaUtilLoggingHelper.class);
041
042    private static LogHandler activeHandler;
043
044    // Utility class.
045    private JavaUtilLoggingHelper() {
046    }
047
048    /**
049     * Redirects {@code java.util.logging} to Apache Commons Logging do not log below INFO level.
050     */
051    public static synchronized void redirectToApacheCommons() {
052        redirectToApacheCommons(Level.INFO);
053    }
054
055    /**
056     * Redirects {@code java.util.logging} to Apache Commons Logging do not log below the threshold level.
057     *
058     * @since 5.4.2
059     */
060    public static synchronized void redirectToApacheCommons(Level threshold) {
061        if (activeHandler != null) {
062            return;
063        }
064        try {
065            Logger rootLogger = LogManager.getLogManager().getLogger("");
066            for (Handler handler : rootLogger.getHandlers()) {
067                rootLogger.removeHandler(handler);
068            }
069            activeHandler = new LogHandler();
070            activeHandler.setLevel(threshold);
071            rootLogger.addHandler(activeHandler);
072            rootLogger.setLevel(threshold);
073            log.info("Redirecting java.util.logging to Apache Commons Logging, threshold is " + threshold.toString());
074        } catch (SecurityException e) {
075            log.error("Handler setup failed", e);
076        }
077    }
078
079    /**
080     * Resets {@code java.util.logging} redirections.
081     */
082    public static synchronized void reset() {
083        if (activeHandler == null) {
084            return;
085        }
086        try {
087            Logger rootLogger = LogManager.getLogManager().getLogger("");
088            rootLogger.removeHandler(activeHandler);
089        } catch (SecurityException e) {
090            log.error("Handler removal failed", e);
091        }
092        activeHandler = null;
093    }
094
095    public static class LogHandler extends Handler {
096
097        final ThreadLocal<LogRecord> holder = new ThreadLocal<>();
098
099        private final Map<String, Log> cache = new ConcurrentHashMap<>();
100
101        protected void doPublish(LogRecord record) {
102            Level level = record.getLevel();
103            if (level == Level.FINER || level == Level.FINEST) {
104                // don't log, too fine
105                return;
106            }
107            String name = record.getLoggerName();
108            if (name == null) {
109                return;
110            }
111            Log log = cache.get(name);
112            if (log == null) {
113                log = LogFactory.getLog(name);
114                cache.put(name, log);
115            }
116            if (level == Level.FINE) {
117                log.trace(record.getMessage(), record.getThrown());
118            } else if (level == Level.CONFIG) {
119                log.debug(record.getMessage(), record.getThrown());
120            } else if (level == Level.INFO) {
121                log.info(record.getMessage(), record.getThrown());
122            } else if (level == Level.WARNING) {
123                log.warn(record.getMessage(), record.getThrown());
124            } else if (level == Level.SEVERE) {
125                log.error(record.getMessage(), record.getThrown());
126            }
127
128        }
129
130        @Override
131        public void publish(LogRecord record) {
132            if (holder.get() != null) {
133                return;
134            }
135            holder.set(record);
136            try {
137                doPublish(record);
138            } finally {
139                holder.remove();
140            }
141        }
142
143        @Override
144        public void flush() {
145        }
146
147        @Override
148        public void close() {
149        }
150    }
151
152}