View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.slf4j.helpers;
18  
19  import java.util.Map;
20  import java.util.WeakHashMap;
21  import java.util.concurrent.ConcurrentHashMap;
22  import java.util.concurrent.ConcurrentMap;
23  
24  import org.apache.logging.log4j.LogManager;
25  import org.apache.logging.log4j.spi.AbstractLogger;
26  import org.apache.logging.log4j.spi.LoggerContext;
27  import org.apache.logging.slf4j.SLF4JLoggingException;
28  import org.slf4j.ILoggerFactory;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  import org.slf4j.impl.SLF4JLogger;
32  
33  /**
34   *
35   */
36  public class Log4jLoggerFactory implements ILoggerFactory {
37  
38      private static final String FQCN = Log4jLoggerFactory.class.getName();
39      private static final String PACKAGE = "org.slf4j";
40  
41      private final Map<LoggerContext, ConcurrentMap<String, Logger>> contextMap =
42          new WeakHashMap<LoggerContext, ConcurrentMap<String, Logger>>();
43  
44      @Override
45      public Logger getLogger(final String name) {
46          final LoggerContext context = getContext();
47          final ConcurrentMap<String, Logger> loggers = getLoggersMap(context);
48  
49          if (loggers.containsKey(name)) {
50              return loggers.get(name);
51          }
52          final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name;
53          final org.apache.logging.log4j.Logger logger = context.getLogger(key);
54          if (logger instanceof AbstractLogger) {
55              loggers.putIfAbsent(name, new SLF4JLogger((AbstractLogger) logger, name));
56              return loggers.get(name);
57          }
58          throw new SLF4JLoggingException("SLF4J Adapter requires base logging system to extend Log4j AbstractLogger");
59      }
60  
61      private ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) {
62          synchronized (contextMap) {
63              ConcurrentMap<String, Logger> map = contextMap.get(context);
64              if (map == null) {
65                  map = new ConcurrentHashMap<String, Logger>();
66                  contextMap.put(context, map);
67              }
68              return map;
69          }
70      }
71      private LoggerContext getContext() {
72          final Throwable t = new Throwable();
73          boolean next = false;
74          boolean pkg = false;
75          String fqcn = LoggerFactory.class.getName();
76          for (final StackTraceElement element : t.getStackTrace()) {
77              if (FQCN.equals(element.getClassName())) {
78                  next = true;
79                  continue;
80              }
81              if (next && element.getClassName().startsWith(PACKAGE)) {
82                  fqcn = element.getClassName();
83                  pkg = true;
84                  continue;
85              }
86              if (pkg) {
87                  break;
88              }
89          }
90          return PrivateManager.getContext(fqcn);
91      }
92  
93      /**
94       * The real bridge between SLF4J and Log4j.
95       */
96      private static class PrivateManager extends LogManager {
97          private static final String FQCN = LoggerFactory.class.getName();
98  
99          public static LoggerContext getContext() {
100             return getContext(FQCN, false);
101         }
102 
103         public static LoggerContext getContext(final String fqcn) {
104             return getContext(fqcn, false);
105         }
106 
107         public static org.apache.logging.log4j.Logger getLogger(final String name) {
108             return getLogger(FQCN, name);
109         }
110     }
111 
112 }