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.log4j.core.pattern;
18  
19  import java.util.HashMap;
20  import java.util.Locale;
21  import java.util.Map;
22  
23  import org.apache.logging.log4j.Level;
24  import org.apache.logging.log4j.core.LogEvent;
25  import org.apache.logging.log4j.core.config.plugins.Plugin;
26  import org.apache.logging.log4j.core.util.Patterns;
27  import org.apache.logging.log4j.util.PerformanceSensitive;
28  
29  /**
30   * Returns the event's level in a StringBuilder.
31   */
32  @Plugin(name = "LevelPatternConverter", category = PatternConverter.CATEGORY)
33  @ConverterKeys({ "p", "level" })
34  @PerformanceSensitive("allocation")
35  public final class LevelPatternConverter extends LogEventPatternConverter {
36      private static final String OPTION_LENGTH = "length";
37      private static final String OPTION_LOWER = "lowerCase";
38  
39      /**
40       * Singleton.
41       */
42      private static final LevelPatternConverter INSTANCE = new LevelPatternConverter(null);
43  
44      private final Map<Level, String> levelMap;
45  
46      /**
47       * Private constructor.
48       */
49      private LevelPatternConverter(final Map<Level, String> map) {
50          super("Level", "level");
51          this.levelMap = map;
52      }
53  
54      /**
55       * Obtains an instance of pattern converter.
56       *
57       * @param options
58       *            options, may be null. May contain a list of level names and The value that should be displayed for the
59       *            Level.
60       * @return instance of pattern converter.
61       */
62      public static LevelPatternConverter newInstance(final String[] options) {
63          if (options == null || options.length == 0) {
64              return INSTANCE;
65          }
66          final Map<Level, String> levelMap = new HashMap<>();
67          int length = Integer.MAX_VALUE; // More than the longest level name.
68          boolean lowerCase = false;
69          final String[] definitions = options[0].split(Patterns.COMMA_SEPARATOR);
70          for (final String def : definitions) {
71              final String[] pair = def.split("=");
72              if (pair == null || pair.length != 2) {
73                  LOGGER.error("Invalid option {}", def);
74                  continue;
75              }
76              final String key = pair[0].trim();
77              final String value = pair[1].trim();
78              if (OPTION_LENGTH.equalsIgnoreCase(key)) {
79                  length = Integer.parseInt(value);
80              } else if (OPTION_LOWER.equalsIgnoreCase(key)) {
81                  lowerCase = Boolean.parseBoolean(value);
82              } else {
83                  final Level level = Level.toLevel(key, null);
84                  if (level == null) {
85                      LOGGER.error("Invalid Level {}", key);
86                  } else {
87                      levelMap.put(level, value);
88                  }
89              }
90          }
91          if (levelMap.isEmpty() && length == Integer.MAX_VALUE && !lowerCase) {
92              return INSTANCE;
93          }
94          for (final Level level : Level.values()) {
95              if (!levelMap.containsKey(level)) {
96                  final String left = left(level, length);
97                  levelMap.put(level, lowerCase ? left.toLowerCase(Locale.US) : left);
98              }
99          }
100         return new LevelPatternConverter(levelMap);
101     }
102 
103     /**
104      * Returns the leftmost chars of the level name for the given level.
105      *
106      * @param level
107      *            The level
108      * @param length
109      *            How many chars to return
110      * @return The abbreviated level name, or the whole level name if the {@code length} is greater than the level name
111      *         length,
112      */
113     private static String left(final Level level, final int length) {
114         final String string = level.toString();
115         if (length >= string.length()) {
116             return string;
117         }
118         return string.substring(0, length);
119     }
120 
121     /**
122      * {@inheritDoc}
123      */
124     @Override
125     public void format(final LogEvent event, final StringBuilder output) {
126         output.append(levelMap == null ? event.getLevel().toString() : levelMap.get(event.getLevel()));
127     }
128 
129     /**
130      * {@inheritDoc}
131      */
132     @Override
133     public String getStyleClass(final Object e) {
134         if (e instanceof LogEvent) {
135             return "level " + ((LogEvent) e).getLevel().name().toLowerCase(Locale.ENGLISH);
136         }
137 
138         return "level";
139     }
140 }