001/*
002 * Copyright 2012-2017 the original author or authors.
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
017package org.springframework.boot.logging.java;
018
019import java.io.ByteArrayInputStream;
020import java.io.InputStreamReader;
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.Enumeration;
024import java.util.List;
025import java.util.Set;
026import java.util.logging.Level;
027import java.util.logging.LogManager;
028import java.util.logging.Logger;
029
030import org.springframework.boot.logging.AbstractLoggingSystem;
031import org.springframework.boot.logging.LogFile;
032import org.springframework.boot.logging.LogLevel;
033import org.springframework.boot.logging.LoggerConfiguration;
034import org.springframework.boot.logging.LoggingInitializationContext;
035import org.springframework.boot.logging.LoggingSystem;
036import org.springframework.util.Assert;
037import org.springframework.util.FileCopyUtils;
038import org.springframework.util.ResourceUtils;
039import org.springframework.util.StringUtils;
040
041/**
042 * {@link LoggingSystem} for {@link Logger java.util.logging}.
043 *
044 * @author Phillip Webb
045 * @author Dave Syer
046 * @author Andy Wilkinson
047 * @author Ben Hale
048 */
049public class JavaLoggingSystem extends AbstractLoggingSystem {
050
051        private static final LogLevels<Level> LEVELS = new LogLevels<>();
052
053        static {
054                LEVELS.map(LogLevel.TRACE, Level.FINEST);
055                LEVELS.map(LogLevel.DEBUG, Level.FINE);
056                LEVELS.map(LogLevel.INFO, Level.INFO);
057                LEVELS.map(LogLevel.WARN, Level.WARNING);
058                LEVELS.map(LogLevel.ERROR, Level.SEVERE);
059                LEVELS.map(LogLevel.FATAL, Level.SEVERE);
060                LEVELS.map(LogLevel.OFF, Level.OFF);
061        }
062
063        public JavaLoggingSystem(ClassLoader classLoader) {
064                super(classLoader);
065        }
066
067        @Override
068        protected String[] getStandardConfigLocations() {
069                return new String[] { "logging.properties" };
070        }
071
072        @Override
073        public void beforeInitialize() {
074                super.beforeInitialize();
075                Logger.getLogger("").setLevel(Level.SEVERE);
076        }
077
078        @Override
079        protected void loadDefaults(LoggingInitializationContext initializationContext,
080                        LogFile logFile) {
081                if (logFile != null) {
082                        loadConfiguration(getPackagedConfigFile("logging-file.properties"), logFile);
083                }
084                else {
085                        loadConfiguration(getPackagedConfigFile("logging.properties"), logFile);
086                }
087        }
088
089        @Override
090        protected void loadConfiguration(LoggingInitializationContext initializationContext,
091                        String location, LogFile logFile) {
092                loadConfiguration(location, logFile);
093        }
094
095        protected void loadConfiguration(String location, LogFile logFile) {
096                Assert.notNull(location, "Location must not be null");
097                try {
098                        String configuration = FileCopyUtils.copyToString(
099                                        new InputStreamReader(ResourceUtils.getURL(location).openStream()));
100                        if (logFile != null) {
101                                configuration = configuration.replace("${LOG_FILE}",
102                                                StringUtils.cleanPath(logFile.toString()));
103                        }
104                        LogManager.getLogManager().readConfiguration(
105                                        new ByteArrayInputStream(configuration.getBytes()));
106                }
107                catch (Exception ex) {
108                        throw new IllegalStateException(
109                                        "Could not initialize Java logging from " + location, ex);
110                }
111        }
112
113        @Override
114        public Set<LogLevel> getSupportedLogLevels() {
115                return LEVELS.getSupported();
116        }
117
118        @Override
119        public void setLogLevel(String loggerName, LogLevel level) {
120                if (loggerName == null || ROOT_LOGGER_NAME.equals(loggerName)) {
121                        loggerName = "";
122                }
123                Logger logger = Logger.getLogger(loggerName);
124                if (logger != null) {
125                        logger.setLevel(LEVELS.convertSystemToNative(level));
126                }
127        }
128
129        @Override
130        public List<LoggerConfiguration> getLoggerConfigurations() {
131                List<LoggerConfiguration> result = new ArrayList<>();
132                Enumeration<String> names = LogManager.getLogManager().getLoggerNames();
133                while (names.hasMoreElements()) {
134                        result.add(getLoggerConfiguration(names.nextElement()));
135                }
136                result.sort(CONFIGURATION_COMPARATOR);
137                return Collections.unmodifiableList(result);
138        }
139
140        @Override
141        public LoggerConfiguration getLoggerConfiguration(String loggerName) {
142                Logger logger = Logger.getLogger(loggerName);
143                if (logger == null) {
144                        return null;
145                }
146                LogLevel level = LEVELS.convertNativeToSystem(logger.getLevel());
147                LogLevel effectiveLevel = LEVELS.convertNativeToSystem(getEffectiveLevel(logger));
148                String name = (StringUtils.hasLength(logger.getName()) ? logger.getName()
149                                : ROOT_LOGGER_NAME);
150                return new LoggerConfiguration(name, level, effectiveLevel);
151        }
152
153        private Level getEffectiveLevel(Logger root) {
154                Logger logger = root;
155                while (logger.getLevel() == null) {
156                        logger = logger.getParent();
157                }
158                return logger.getLevel();
159        }
160
161        @Override
162        public Runnable getShutdownHandler() {
163                return new ShutdownHandler();
164        }
165
166        private final class ShutdownHandler implements Runnable {
167
168                @Override
169                public void run() {
170                        LogManager.getLogManager().reset();
171                }
172
173        }
174
175}