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.apache.logging.slf4j;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Iterator;
22  import java.util.concurrent.ConcurrentHashMap;
23  import java.util.concurrent.ConcurrentMap;
24  
25  import org.apache.logging.log4j.Logger;
26  import org.apache.logging.log4j.MarkerManager;
27  import org.apache.logging.log4j.status.StatusLogger;
28  import org.slf4j.IMarkerFactory;
29  import org.slf4j.Marker;
30  
31  /**
32   * Log4j/SLF4J bridge to create SLF4J Markers based on name or based on existing SLF4J Markers.
33   */
34  public class Log4jMarkerFactory implements IMarkerFactory {
35  
36      private static final Logger LOGGER = StatusLogger.getLogger();
37  
38      private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<>();
39  
40      /**
41       * Returns a Log4j Marker that is compatible with SLF4J.
42       * @param name The name of the Marker.
43       * @return A Marker.
44       */
45      @Override
46      public Marker getMarker(final String name) {
47          if (name == null) {
48              throw new IllegalArgumentException("Marker name must not be null");
49          }
50          final Marker marker = markerMap.get(name);
51          if (marker != null) {
52              return marker;
53          }
54          final org.apache.logging.log4j.Marker log4jMarker = MarkerManager.getMarker(name);
55          return addMarkerIfAbsent(name, log4jMarker);
56      }
57  
58      private Marker addMarkerIfAbsent(final String name, final org.apache.logging.log4j.Marker log4jMarker) {
59          final Marker marker = new Log4jMarker(log4jMarker);
60          final Marker existing = markerMap.putIfAbsent(name, marker);
61          return existing == null ? marker : existing;
62      }
63  
64      /**
65       * Returns a Log4j Marker converted from an existing custom SLF4J Marker.
66       * @param marker The SLF4J Marker to convert.
67       * @return A converted Log4j/SLF4J Marker.
68       * @since 2.1
69       */
70      public Marker getMarker(final Marker marker) {
71          if (marker == null) {
72              throw new IllegalArgumentException("Marker must not be null");
73          }
74          final Marker m = markerMap.get(marker.getName());
75          if (m != null) {
76              return m;
77          }
78          return addMarkerIfAbsent(marker.getName(), convertMarker(marker));
79      }
80  
81      private static org.apache.logging.log4j.Marker convertMarker(final Marker original) {
82          if (original == null) {
83              throw new IllegalArgumentException("Marker must not be null");
84          }
85          return convertMarker(original, new ArrayList<Marker>());
86      }
87  
88      private static org.apache.logging.log4j.Marker convertMarker(final Marker original,
89                                                                   final Collection<Marker> visited) {
90          final org.apache.logging.log4j.Marker marker = MarkerManager.getMarker(original.getName());
91          if (original.hasReferences()) {
92              final Iterator<Marker> it = original.iterator();
93              while (it.hasNext()) {
94                  final Marker next = it.next();
95                  if (visited.contains(next)) {
96                      LOGGER.warn("Found a cycle in Marker [{}]. Cycle will be broken.", next.getName());
97                  } else {
98                      visited.add(next);
99                      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 }