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 018package org.apache.logging.log4j.jul; 019 020import java.io.Serializable; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.Comparator; 024import java.util.IdentityHashMap; 025import java.util.List; 026import java.util.Map; 027import java.util.concurrent.ConcurrentHashMap; 028import java.util.concurrent.ConcurrentMap; 029 030import org.apache.logging.log4j.Level; 031 032/** 033 * Default implementation of LevelConverter strategy. 034 * <p> 035 * Since 2.4, supports custom JUL levels by mapping them to their closest mapped neighbour. 036 * </p> 037 * 038 * @since 2.1 039 */ 040public class DefaultLevelConverter implements LevelConverter { 041 042 static final class JulLevelComparator implements Comparator<java.util.logging.Level>, Serializable { 043 private static final long serialVersionUID = 1L; 044 @Override 045 public int compare(final java.util.logging.Level level1, final java.util.logging.Level level2) { 046 return Integer.compare(level1.intValue(), level2.intValue()); 047 } 048 } 049 050 private final ConcurrentMap<java.util.logging.Level, Level> julToLog4j = new ConcurrentHashMap<>(9); 051 private final Map<Level, java.util.logging.Level> log4jToJul = new IdentityHashMap<>(10); 052 private final List<java.util.logging.Level> sortedJulLevels = new ArrayList<>(9); 053 054 public DefaultLevelConverter() { 055 // Map JUL to Log4j 056 mapJulToLog4j(java.util.logging.Level.ALL, Level.ALL); 057 mapJulToLog4j(java.util.logging.Level.FINEST, LevelTranslator.FINEST); 058 mapJulToLog4j(java.util.logging.Level.FINER, Level.TRACE); 059 mapJulToLog4j(java.util.logging.Level.FINE, Level.DEBUG); 060 mapJulToLog4j(java.util.logging.Level.CONFIG, LevelTranslator.CONFIG); 061 mapJulToLog4j(java.util.logging.Level.INFO, Level.INFO); 062 mapJulToLog4j(java.util.logging.Level.WARNING, Level.WARN); 063 mapJulToLog4j(java.util.logging.Level.SEVERE, Level.ERROR); 064 mapJulToLog4j(java.util.logging.Level.OFF, Level.OFF); 065 // Map Log4j to JUL 066 mapLog4jToJul(Level.ALL, java.util.logging.Level.ALL); 067 mapLog4jToJul(LevelTranslator.FINEST, java.util.logging.Level.FINEST); 068 mapLog4jToJul(Level.TRACE, java.util.logging.Level.FINER); 069 mapLog4jToJul(Level.DEBUG, java.util.logging.Level.FINE); 070 mapLog4jToJul(LevelTranslator.CONFIG, java.util.logging.Level.CONFIG); 071 mapLog4jToJul(Level.INFO, java.util.logging.Level.INFO); 072 mapLog4jToJul(Level.WARN, java.util.logging.Level.WARNING); 073 mapLog4jToJul(Level.ERROR, java.util.logging.Level.SEVERE); 074 mapLog4jToJul(Level.FATAL, java.util.logging.Level.SEVERE); 075 mapLog4jToJul(Level.OFF, java.util.logging.Level.OFF); 076 // Sorted Java levels 077 sortedJulLevels.addAll(julToLog4j.keySet()); 078 Collections.sort(sortedJulLevels, new JulLevelComparator()); 079 080 } 081 082 private long distance(final java.util.logging.Level javaLevel, final java.util.logging.Level customJavaLevel) { 083 return Math.abs((long) customJavaLevel.intValue() - (long) javaLevel.intValue()); 084 } 085 086 /* 087 * TODO consider making public for advanced configuration. 088 */ 089 private void mapJulToLog4j(final java.util.logging.Level julLevel, final Level level) { 090 julToLog4j.put(julLevel, level); 091 } 092 093 /* 094 * TODO consider making public for advanced configuration. 095 */ 096 private void mapLog4jToJul(final Level level, final java.util.logging.Level julLevel) { 097 log4jToJul.put(level, julLevel); 098 } 099 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}