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 package org.apache.logging.slf4j; 018 019 import java.util.Map; 020 import java.util.WeakHashMap; 021 import java.util.concurrent.ConcurrentHashMap; 022 import java.util.concurrent.ConcurrentMap; 023 024 import org.apache.logging.log4j.LogManager; 025 import org.apache.logging.log4j.spi.LoggerContext; 026 import org.apache.logging.log4j.spi.ExtendedLogger; 027 import org.slf4j.ILoggerFactory; 028 import org.slf4j.Logger; 029 import org.slf4j.LoggerFactory; 030 031 /** 032 * 033 */ 034 public class Log4jLoggerFactory implements ILoggerFactory { 035 036 private static final String FQCN = Log4jLoggerFactory.class.getName(); 037 private static final String PACKAGE = "org.slf4j"; 038 039 private final Map<LoggerContext, ConcurrentMap<String, Logger>> contextMap = 040 new WeakHashMap<LoggerContext, ConcurrentMap<String, Logger>>(); 041 042 @Override 043 public Logger getLogger(final String name) { 044 final LoggerContext context = getContext(); 045 final ConcurrentMap<String, Logger> loggers = getLoggersMap(context); 046 047 if (loggers.containsKey(name)) { 048 return loggers.get(name); 049 } 050 final String key = Logger.ROOT_LOGGER_NAME.equals(name) ? LogManager.ROOT_LOGGER_NAME : name; 051 loggers.putIfAbsent(name, new Log4jLogger(context.getLogger(key), name)); 052 return loggers.get(name); 053 } 054 055 private ConcurrentMap<String, Logger> getLoggersMap(final LoggerContext context) { 056 synchronized (contextMap) { 057 ConcurrentMap<String, Logger> map = contextMap.get(context); 058 if (map == null) { 059 map = new ConcurrentHashMap<String, Logger>(); 060 contextMap.put(context, map); 061 } 062 return map; 063 } 064 } 065 private LoggerContext getContext() { 066 final Throwable t = new Throwable(); 067 boolean next = false; 068 boolean pkg = false; 069 String fqcn = LoggerFactory.class.getName(); 070 for (final StackTraceElement element : t.getStackTrace()) { 071 if (FQCN.equals(element.getClassName())) { 072 next = true; 073 continue; 074 } 075 if (next && element.getClassName().startsWith(PACKAGE)) { 076 fqcn = element.getClassName(); 077 pkg = true; 078 continue; 079 } 080 if (pkg) { 081 break; 082 } 083 } 084 return PrivateManager.getContext(fqcn); 085 } 086 087 /** 088 * The real bridge between SLF4J and Log4j. 089 */ 090 private static class PrivateManager extends LogManager { 091 private static final String FQCN = LoggerFactory.class.getName(); 092 093 public static LoggerContext getContext() { 094 return getContext(FQCN, false); 095 } 096 097 public static LoggerContext getContext(final String fqcn) { 098 return getContext(fqcn, false); 099 } 100 101 public static ExtendedLogger getLogger(final String name) { 102 return getContext(FQCN).getLogger(name); 103 } 104 } 105 }