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.apache.logging.log4j.core.pattern;
018
019 import java.util.HashMap;
020 import java.util.Locale;
021 import java.util.Map;
022
023 import org.apache.logging.log4j.Level;
024 import org.apache.logging.log4j.core.LogEvent;
025 import org.apache.logging.log4j.core.config.plugins.Plugin;
026 import org.apache.logging.log4j.core.util.Patterns;
027
028 /**
029 * Returns the event's level in a StringBuilder.
030 */
031 @Plugin(name = "LevelPatternConverter", category = PatternConverter.CATEGORY)
032 @ConverterKeys({ "p", "level" })
033 public final class LevelPatternConverter extends LogEventPatternConverter {
034 private static final String OPTION_LENGTH = "length";
035 private static final String OPTION_LOWER = "lowerCase";
036
037 /**
038 * Singleton.
039 */
040 private static final LevelPatternConverter INSTANCE = new LevelPatternConverter(null);
041
042 private final Map<Level, String> levelMap;
043
044 /**
045 * Private constructor.
046 */
047 private LevelPatternConverter(final Map<Level, String> map) {
048 super("Level", "level");
049 this.levelMap = map;
050 }
051
052 /**
053 * Obtains an instance of pattern converter.
054 *
055 * @param options
056 * options, may be null. May contain a list of level names and The value that should be displayed for the
057 * Level.
058 * @return instance of pattern converter.
059 */
060 public static LevelPatternConverter newInstance(final String[] options) {
061 if (options == null || options.length == 0) {
062 return INSTANCE;
063 }
064 final Map<Level, String> levelMap = new HashMap<Level, String>();
065 int length = Integer.MAX_VALUE; // More than the longest level name.
066 boolean lowerCase = false;
067 final String[] definitions = options[0].split(Patterns.COMMA_SEPARATOR);
068 for (final String def : definitions) {
069 final String[] pair = def.split("=");
070 if (pair == null || pair.length != 2) {
071 LOGGER.error("Invalid option {}", def);
072 continue;
073 }
074 final String key = pair[0].trim();
075 final String value = pair[1].trim();
076 if (OPTION_LENGTH.equalsIgnoreCase(key)) {
077 length = Integer.parseInt(value);
078 } else if (OPTION_LOWER.equalsIgnoreCase(key)) {
079 lowerCase = Boolean.parseBoolean(value);
080 } else {
081 final Level level = Level.toLevel(key, null);
082 if (level == null) {
083 LOGGER.error("Invalid Level {}", key);
084 } else {
085 levelMap.put(level, value);
086 }
087 }
088 }
089 if (levelMap.isEmpty() && length == Integer.MAX_VALUE && !lowerCase) {
090 return INSTANCE;
091 }
092 for (final Level level : Level.values()) {
093 if (!levelMap.containsKey(level)) {
094 final String left = left(level, length);
095 levelMap.put(level, lowerCase ? left.toLowerCase(Locale.US) : left);
096 }
097 }
098 return new LevelPatternConverter(levelMap);
099 }
100
101 /**
102 * Returns the leftmost chars of the level name for the given level.
103 *
104 * @param level
105 * The level
106 * @param length
107 * How many chars to return
108 * @return The abbreviated level name, or the whole level name if the {@code length} is greater than the level name
109 * length,
110 */
111 private static String left(final Level level, final int length) {
112 final String string = level.toString();
113 if (length >= string.length()) {
114 return string;
115 }
116 return string.substring(0, length);
117 }
118
119 /**
120 * {@inheritDoc}
121 */
122 @Override
123 public void format(final LogEvent event, final StringBuilder output) {
124 output.append(levelMap == null ? event.getLevel().toString() : levelMap.get(event.getLevel()));
125 }
126
127 /**
128 * {@inheritDoc}
129 */
130 @Override
131 public String getStyleClass(final Object e) {
132 if (e instanceof LogEvent) {
133 return "level " + ((LogEvent) e).getLevel().name().toLowerCase(Locale.ENGLISH);
134 }
135
136 return "level";
137 }
138 }