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