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 */ 017package org.apache.logging.slf4j; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Iterator; 022import java.util.concurrent.ConcurrentHashMap; 023import java.util.concurrent.ConcurrentMap; 024 025import org.apache.logging.log4j.Logger; 026import org.apache.logging.log4j.MarkerManager; 027import org.apache.logging.log4j.status.StatusLogger; 028import org.slf4j.IMarkerFactory; 029import org.slf4j.Marker; 030 031/** 032 * Log4j/SLF4J bridge to create SLF4J Markers based on name or based on existing SLF4J Markers. 033 */ 034public class Log4jMarkerFactory implements IMarkerFactory { 035 036 private static final Logger LOGGER = StatusLogger.getLogger(); 037 038 private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<>(); 039 040 /** 041 * Returns a Log4j Marker that is compatible with SLF4J. 042 * @param name The name of the Marker. 043 * @return A Marker. 044 */ 045 @Override 046 public Marker getMarker(final String name) { 047 if (name == null) { 048 throw new IllegalArgumentException("Marker name must not be null"); 049 } 050 final Marker marker = markerMap.get(name); 051 if (marker != null) { 052 return marker; 053 } 054 final org.apache.logging.log4j.Marker log4jMarker = MarkerManager.getMarker(name); 055 return addMarkerIfAbsent(name, log4jMarker); 056 } 057 058 private Marker addMarkerIfAbsent(final String name, final org.apache.logging.log4j.Marker log4jMarker) { 059 final Marker marker = new Log4jMarker(log4jMarker); 060 final Marker existing = markerMap.putIfAbsent(name, marker); 061 return existing == null ? marker : existing; 062 } 063 064 /** 065 * Returns a Log4j Marker converted from an existing custom SLF4J Marker. 066 * @param marker The SLF4J Marker to convert. 067 * @return A converted Log4j/SLF4J Marker. 068 * @since 2.1 069 */ 070 public Marker getMarker(final Marker marker) { 071 if (marker == null) { 072 throw new IllegalArgumentException("Marker must not be null"); 073 } 074 final Marker m = markerMap.get(marker.getName()); 075 if (m != null) { 076 return m; 077 } 078 return addMarkerIfAbsent(marker.getName(), convertMarker(marker)); 079 } 080 081 private static org.apache.logging.log4j.Marker convertMarker(final Marker original) { 082 if (original == null) { 083 throw new IllegalArgumentException("Marker must not be null"); 084 } 085 return convertMarker(original, new ArrayList<Marker>()); 086 } 087 088 private static org.apache.logging.log4j.Marker convertMarker(final Marker original, 089 final Collection<Marker> visited) { 090 final org.apache.logging.log4j.Marker marker = MarkerManager.getMarker(original.getName()); 091 if (original.hasReferences()) { 092 final Iterator<Marker> it = original.iterator(); 093 while (it.hasNext()) { 094 final Marker next = it.next(); 095 if (visited.contains(next)) { 096 LOGGER.warn("Found a cycle in Marker [{}]. Cycle will be broken.", next.getName()); 097 } else { 098 visited.add(next); 099 marker.addParents(convertMarker(next, visited)); 100 } 101 } 102 } 103 return marker; 104 } 105 106 /** 107 * Returns true if the Marker exists. 108 * @param name The Marker name. 109 * @return {@code true} if the Marker exists, {@code false} otherwise. 110 */ 111 @Override 112 public boolean exists(final String name) { 113 return markerMap.containsKey(name); 114 } 115 116 /** 117 * Log4j does not support detached Markers. This method always returns false. 118 * @param name The Marker name. 119 * @return {@code false} 120 */ 121 @Override 122 public boolean detachMarker(final String name) { 123 return false; 124 } 125 126 /** 127 * Log4j does not support detached Markers for performance reasons. The returned Marker is attached. 128 * @param name The Marker name. 129 * @return The named Marker (unmodified). 130 */ 131 @Override 132 public Marker getDetachedMarker(final String name) { 133 LOGGER.warn("Log4j does not support detached Markers. Returned Marker [{}] will be unchanged.", name); 134 return getMarker(name); 135 } 136 137 138}