001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017
018package org.apache.logging.log4j.jul;
019
020import java.security.AccessController;
021import java.security.PrivilegedAction;
022import java.util.logging.Filter;
023import java.util.logging.Level;
024import java.util.logging.LogRecord;
025import java.util.logging.Logger;
026
027import org.apache.logging.log4j.message.Message;
028import org.apache.logging.log4j.message.MessageFactory;
029import org.apache.logging.log4j.spi.ExtendedLogger;
030
031/**
032 * Log4j API implementation of the JUL {@link Logger} class. <strong>Note that this implementation does
033 * <em>not</em> use the {@link java.util.logging.Handler} class.</strong> Instead, logging is delegated to the
034 * underlying Log4j {@link org.apache.logging.log4j.Logger} which may be implemented in one of many different ways.
035 * Consult the documentation for your Log4j Provider for more details.
036 * <p>Note that the methods {@link #getParent()} and {@link #setLevel(java.util.logging.Level)} are not supported by
037 * this implementation. If you need support for these methods, then you'll need to use log4j-core. The
038 * {@link #getParent()} method will not fail (thanks to JUL API limitations), but it won't necessarily be
039 * accurate!</p>
040 * <p>Also note that {@link #setParent(java.util.logging.Logger)} is explicitly unsupported. Parent loggers are
041 * determined using the syntax of the logger name; not through an arbitrary graph of loggers.</p>
042 *
043 * @since 2.1
044 */
045public class ApiLogger extends Logger {
046
047    private final WrappedLogger logger;
048    private static final String FQCN = ApiLogger.class.getName();
049
050    ApiLogger(final ExtendedLogger logger) {
051        super(logger.getName(), null);
052        final Level javaLevel = LevelTranslator.toJavaLevel(logger.getLevel());
053        // "java.util.logging.LoggingPermission" "control"
054        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
055            ApiLogger.super.setLevel(javaLevel);
056            return null;
057        });
058        this.logger = new WrappedLogger(logger);
059    }
060
061    @Override
062    public void log(final LogRecord record) {
063        if (isFiltered(record)) {
064            return;
065        }
066        final org.apache.logging.log4j.Level level = LevelTranslator.toLevel(record.getLevel());
067        final Object[] parameters = record.getParameters();
068        final MessageFactory messageFactory = logger.getMessageFactory();
069        final Message message = parameters == null ?
070            messageFactory.newMessage(record.getMessage()) /* LOG4J2-1251: not formatted case */ :
071            messageFactory.newMessage(record.getMessage(), parameters);
072        final Throwable thrown = record.getThrown();
073        logger.logIfEnabled(FQCN, level, null, message, thrown);
074    }
075
076    // support for Logger.getFilter()/Logger.setFilter()
077    boolean isFiltered(final LogRecord logRecord) {
078        final Filter filter = getFilter();
079        return filter != null && !filter.isLoggable(logRecord);
080    }
081
082    @Override
083    public boolean isLoggable(final Level level) {
084        return logger.isEnabled(LevelTranslator.toLevel(level));
085    }
086
087    @Override
088    public String getName() {
089        return logger.getName();
090    }
091
092    @Override
093    public void setLevel(final Level newLevel) throws SecurityException {
094        throw new UnsupportedOperationException("Cannot set level through log4j-api");
095    }
096
097    /**
098     * Provides access to {@link Logger#setLevel(java.util.logging.Level)}. This method should only be used by child
099     * classes.
100     *
101     * @see Logger#setLevel(java.util.logging.Level)
102     */
103    protected void doSetLevel(final Level newLevel) throws SecurityException {
104        super.setLevel(newLevel);
105    }
106
107    /**
108     * Unsupported operation.
109     *
110     * @throws UnsupportedOperationException always
111     */
112    @Override
113    public void setParent(final Logger parent) {
114        throw new UnsupportedOperationException("Cannot set parent logger");
115    }
116
117    @Override
118    public void log(final Level level, final String msg) {
119        if (getFilter() == null) {
120            logger.log(LevelTranslator.toLevel(level), msg);
121        } else {
122            super.log(level, msg);
123        }
124    }
125
126    @Override
127    public void log(final Level level, final String msg, final Object param1) {
128        if (getFilter() == null) {
129            logger.log(LevelTranslator.toLevel(level), msg, param1);
130        } else {
131            super.log(level, msg, param1);
132        }
133    }
134
135    @Override
136    public void log(final Level level, final String msg, final Object[] params) {
137        if (getFilter() == null) {
138            logger.log(LevelTranslator.toLevel(level), msg, params);
139        } else {
140            super.log(level, msg, params);
141        }
142    }
143
144    @Override
145    public void log(final Level level, final String msg, final Throwable thrown) {
146        if (getFilter() == null) {
147            logger.log(LevelTranslator.toLevel(level), msg, thrown);
148        } else {
149            super.log(level, msg, thrown);
150        }
151    }
152
153    @Override
154    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg) {
155        log(level, msg);
156    }
157
158    @Override
159    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg,
160                     final Object param1) {
161        log(level, msg, param1);
162    }
163
164    @Override
165    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg,
166                     final Object[] params) {
167        log(level, msg, params);
168    }
169
170    @Override
171    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg,
172                     final Throwable thrown) {
173        log(level, msg, thrown);
174    }
175
176    @Override
177    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName,
178                      final String msg) {
179        log(level, msg);
180    }
181
182    @Override
183    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName,
184                      final String msg, final Object param1) {
185        log(level, msg, param1);
186    }
187
188    @Override
189    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName,
190                      final String msg, final Object[] params) {
191        log(level, msg, params);
192    }
193
194    @Override
195    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName,
196                      final String msg, final Throwable thrown) {
197        log(level, msg, thrown);
198    }
199
200    @Override
201    public void entering(final String sourceClass, final String sourceMethod) {
202        logger.entry();
203    }
204
205    @Override
206    public void entering(final String sourceClass, final String sourceMethod, final Object param1) {
207        logger.entry(param1);
208    }
209
210    @Override
211    public void entering(final String sourceClass, final String sourceMethod, final Object[] params) {
212        logger.entry(params);
213    }
214
215    @Override
216    public void exiting(final String sourceClass, final String sourceMethod) {
217        logger.exit();
218    }
219
220    @Override
221    public void exiting(final String sourceClass, final String sourceMethod, final Object result) {
222        logger.exit(result);
223    }
224
225    @Override
226    public void throwing(final String sourceClass, final String sourceMethod, final Throwable thrown) {
227        logger.throwing(thrown);
228    }
229
230    @Override
231    public void severe(final String msg) {
232        if (getFilter() == null) {
233            logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.ERROR, null, msg);
234        } else {
235            super.severe(msg);
236        }
237    }
238
239    @Override
240    public void warning(final String msg) {
241        if (getFilter() == null) {
242            logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.WARN, null, msg);
243        } else {
244            super.warning(msg);
245        }
246    }
247
248    @Override
249    public void info(final String msg) {
250        if (getFilter() == null) {
251            logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.INFO, null, msg);
252        } else {
253            super.info(msg);
254        }
255    }
256
257    @Override
258    public void config(final String msg) {
259        if (getFilter() == null) {
260            logger.logIfEnabled(FQCN, LevelTranslator.CONFIG, null, msg);
261        } else {
262            super.config(msg);
263        }
264    }
265
266    @Override
267    public void fine(final String msg) {
268        if (getFilter() == null) {
269            logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.DEBUG, null, msg);
270        } else {
271            super.fine(msg);
272        }
273    }
274
275    @Override
276    public void finer(final String msg) {
277        if (getFilter() == null) {
278            logger.logIfEnabled(FQCN, org.apache.logging.log4j.Level.TRACE, null, msg);
279        } else {
280            super.finer(msg);
281        }
282    }
283
284    @Override
285    public void finest(final String msg) {
286        if (getFilter() == null) {
287            logger.logIfEnabled(FQCN, LevelTranslator.FINEST, null, msg);
288        } else {
289            super.finest(msg);
290        }
291    }
292}