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  
18  package org.apache.logging.log4j.jul;
19  
20  import java.io.Serializable;
21  import java.util.ArrayList;
22  import java.util.Collections;
23  import java.util.Comparator;
24  import java.util.IdentityHashMap;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.concurrent.ConcurrentHashMap;
28  import java.util.concurrent.ConcurrentMap;
29  
30  import org.apache.logging.log4j.Level;
31  
32  /**
33   * Default implementation of LevelConverter strategy.
34   * <p>
35   * Since 2.4, supports custom JUL levels by mapping them to their closest mapped neighbour.
36   * </p>
37   *
38   * @since 2.1
39   */
40  public class DefaultLevelConverter implements LevelConverter {
41  
42      static final class JulLevelComparator implements Comparator<java.util.logging.Level>, Serializable {
43          private static final long serialVersionUID = 1L;
44          @Override
45          public int compare(final java.util.logging.Level level1, final java.util.logging.Level level2) {
46              return Integer.compare(level1.intValue(), level2.intValue());
47          }
48      }
49  
50      private final ConcurrentMap<java.util.logging.Level, Level> julToLog4j = new ConcurrentHashMap<>(9);
51      private final Map<Level, java.util.logging.Level> log4jToJul = new IdentityHashMap<>(10);
52      private final List<java.util.logging.Level> sortedJulLevels = new ArrayList<>(9);
53  
54      public DefaultLevelConverter() {
55          // Map JUL to Log4j
56          mapJulToLog4j(java.util.logging.Level.ALL, Level.ALL);
57          mapJulToLog4j(java.util.logging.Level.FINEST, LevelTranslator.FINEST);
58          mapJulToLog4j(java.util.logging.Level.FINER, Level.TRACE);
59          mapJulToLog4j(java.util.logging.Level.FINE, Level.DEBUG);
60          mapJulToLog4j(java.util.logging.Level.CONFIG, LevelTranslator.CONFIG);
61          mapJulToLog4j(java.util.logging.Level.INFO, Level.INFO);
62          mapJulToLog4j(java.util.logging.Level.WARNING, Level.WARN);
63          mapJulToLog4j(java.util.logging.Level.SEVERE, Level.ERROR);
64          mapJulToLog4j(java.util.logging.Level.OFF, Level.OFF);
65          // Map Log4j to JUL
66          mapLog4jToJul(Level.ALL, java.util.logging.Level.ALL);
67          mapLog4jToJul(LevelTranslator.FINEST, java.util.logging.Level.FINEST);
68          mapLog4jToJul(Level.TRACE, java.util.logging.Level.FINER);
69          mapLog4jToJul(Level.DEBUG, java.util.logging.Level.FINE);
70          mapLog4jToJul(LevelTranslator.CONFIG, java.util.logging.Level.CONFIG);
71          mapLog4jToJul(Level.INFO, java.util.logging.Level.INFO);
72          mapLog4jToJul(Level.WARN, java.util.logging.Level.WARNING);
73          mapLog4jToJul(Level.ERROR, java.util.logging.Level.SEVERE);
74          mapLog4jToJul(Level.FATAL, java.util.logging.Level.SEVERE);
75          mapLog4jToJul(Level.OFF, java.util.logging.Level.OFF);
76          // Sorted Java levels
77          sortedJulLevels.addAll(julToLog4j.keySet());
78          Collections.sort(sortedJulLevels, new JulLevelComparator());
79  
80      }
81  
82      private long distance(final java.util.logging.Level javaLevel, final java.util.logging.Level customJavaLevel) {
83          return Math.abs((long) customJavaLevel.intValue() - (long) javaLevel.intValue());
84      }
85  
86      /*
87       * TODO consider making public for advanced configuration.
88       */
89      private void mapJulToLog4j(final java.util.logging.Level julLevel, final Level level) {
90          julToLog4j.put(julLevel, level);
91      }
92  
93      /*
94       * TODO consider making public for advanced configuration.
95       */
96      private void mapLog4jToJul(final Level level, final java.util.logging.Level julLevel) {
97          log4jToJul.put(level, julLevel);
98      }
99  
100     private Level nearestLevel(final java.util.logging.Level customJavaLevel) {
101         long prevDist = Long.MAX_VALUE;
102         java.util.logging.Level prevLevel = null;
103         for (final java.util.logging.Level mappedJavaLevel : sortedJulLevels) {
104             final long distance = distance(customJavaLevel, mappedJavaLevel);
105             if (distance > prevDist) {
106                 return julToLog4j.get(prevLevel);
107             }
108             prevDist = distance;
109             prevLevel = mappedJavaLevel;
110         }
111         return julToLog4j.get(prevLevel);
112     }
113 
114     @Override
115     public java.util.logging.Level toJavaLevel(final Level level) {
116         return log4jToJul.get(level);
117     }
118 
119     @Override
120     public Level toLevel(final java.util.logging.Level javaLevel) {
121         if (javaLevel == null) {
122             return null;
123         }
124         final Level level = julToLog4j.get(javaLevel);
125         if (level != null) {
126             return level;
127         }
128         final Level nearestLevel = nearestLevel(javaLevel);
129         julToLog4j.put(javaLevel, nearestLevel);
130         return nearestLevel;
131     }
132 }