    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    }