    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.text.SimpleDateFormat;
    020    import java.util.Date;
    021    import java.util.TimeZone;
    022
    023    import org.apache.logging.log4j.core.LogEvent;
    024    import org.apache.logging.log4j.core.config.plugins.Plugin;
    025
    026    /**
    027     * Convert and format the event's date in a StringBuilder.
    028     */
    029    @Plugin(name = "DatePatternConverter", category = PatternConverter.CATEGORY)
    030    @ConverterKeys({ "d", "date" })
    031    public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter {
    032
    033        private abstract static class Formatter {
    034            abstract String format(long time);
    035
    036            public String toPattern() {
    037                return null;
    038            }
    039        }
    040
    041        private static class PatternFormatter extends Formatter {
    042            private final SimpleDateFormat simpleDateFormat;
    043
    044            PatternFormatter(final SimpleDateFormat simpleDateFormat) {
    045                this.simpleDateFormat = simpleDateFormat;
    046            }
    047
    048            @Override
    049            String format(final long time) {
    050                return simpleDateFormat.format(Long.valueOf(time));
    051            }
    052
    053            @Override
    054            public String toPattern() {
    055                return simpleDateFormat.toPattern();
    056            }
    057        }
    058
    059        private static class UnixFormatter extends Formatter {
    060
    061            @Override
    062            String format(final long time) {
    063                return Long.toString(time / 1000);
    064            }
    065
    066        }
    067
    068        private static class UnixMillisFormatter extends Formatter {
    069
    070            @Override
    071            String format(final long time) {
    072                return Long.toString(time);
    073            }
    074
    075        }
    076
    077        /**
    078         * ABSOLUTE string literal.
    079         */
    080        private static final String ABSOLUTE_FORMAT = "ABSOLUTE";
    081
    082        /**
    083         * SimpleTimePattern for ABSOLUTE.
    084         */
    085        private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS";
    086
    087        /**
    088         * COMPACT string literal.
    089         */
    090        private static final String COMPACT_FORMAT = "COMPACT";
    091
    092        /**
    093         * SimpleTimePattern for COMPACT.
    094         */
    095        private static final String COMPACT_PATTERN = "yyyyMMddHHmmssSSS";
    096
    097        /**
    098         * DATE string literal.
    099         */
    100        private static final String DATE_AND_TIME_FORMAT = "DATE";
    101
    102        /**
    103         * SimpleTimePattern for DATE.
    104         */
    105        private static final String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS";
    106
    107        /**
    108         * DEFAULT string literal.
    109         */
    110        private static final String DEFAULT_FORMAT = "DEFAULT";
    111
    112        /**
    113         * SimpleTimePattern for DEFAULT.
    114         */
    115        // package private for unit tests
    116        static final String DEFAULT_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
    117
    118        /**
    119         * ISO8601_BASIC string literal.
    120         */
    121        private static final String ISO8601_BASIC_FORMAT = "ISO8601_BASIC";
    122
    123        /**
    124         * SimpleTimePattern for ISO8601_BASIC.
    125         */
    126        private static final String ISO8601_BASIC_PATTERN = "yyyyMMdd'T'HHmmss,SSS";
    127
    128        /**
    129         * ISO8601 string literal.
    130         */
    131        // package private for unit tests
    132        static final String ISO8601_FORMAT = "ISO8601";
    133
    134        /**
    135         * SimpleTimePattern for ISO8601.
    136         */
    137        // package private for unit tests
    138        static final String ISO8601_PATTERN = "yyyy-MM-dd'T'HH:mm:ss,SSS";
    139
    140        /**
    141         * UNIX formatter in seconds (standard).
    142         */
    143        private static final String UNIX_FORMAT = "UNIX";
    144
    145        /**
    146         * UNIX formatter in milliseconds
    147         */
    148        private static final String UNIX_MILLIS_FORMAT = "UNIX_MILLIS";
    149
    150        /**
    151         * Obtains an instance of pattern converter.
    152         *
    153         * @param options
    154         *            options, may be null.
    155         * @return instance of pattern converter.
    156         */
    157        public static DatePatternConverter newInstance(final String[] options) {
    158            return new DatePatternConverter(options);
    159        }
    160
    161        /**
    162         * Date format.
    163         */
    164        private String cachedDateString;
    165
    166        private final Formatter formatter;
    167
    168        private long lastTimestamp;
    169
    170        /**
    171         * Private constructor.
    172         *
    173         * @param options
    174         *            options, may be null.
    175         */
    176        private DatePatternConverter(final String[] options) {
    177            super("Date", "date");
    178
    179            // null patternOption is OK.
    180            final String patternOption = options != null && options.length > 0 ? options[0] : null;
    181
    182            String pattern = null;
    183            Formatter tempFormatter = null;
    184
    185            if (patternOption == null || patternOption.equalsIgnoreCase(DEFAULT_FORMAT)) {
    186                pattern = DEFAULT_PATTERN;
    187            } else if (patternOption.equalsIgnoreCase(ISO8601_FORMAT)) {
    188                pattern = ISO8601_PATTERN;
    189            } else if (patternOption.equalsIgnoreCase(ISO8601_BASIC_FORMAT)) {
    190                pattern = ISO8601_BASIC_PATTERN;
    191            } else if (patternOption.equalsIgnoreCase(ABSOLUTE_FORMAT)) {
    192                pattern = ABSOLUTE_TIME_PATTERN;
    193            } else if (patternOption.equalsIgnoreCase(DATE_AND_TIME_FORMAT)) {
    194                pattern = DATE_AND_TIME_PATTERN;
    195            } else if (patternOption.equalsIgnoreCase(COMPACT_FORMAT)) {
    196                pattern = COMPACT_PATTERN;
    197            } else if (patternOption.equalsIgnoreCase(UNIX_FORMAT)) {
    198                tempFormatter = new UnixFormatter();
    199            } else if (patternOption.equalsIgnoreCase(UNIX_MILLIS_FORMAT)) {
    200                tempFormatter = new UnixMillisFormatter();
    201            } else {
    202                pattern = patternOption;
    203            }
    204
    205            if (pattern != null) {
    206                SimpleDateFormat tempFormat;
    207
    208                try {
    209                    tempFormat = new SimpleDateFormat(pattern);
    210                } catch (final IllegalArgumentException e) {
    211                    LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e);
    212
    213                    // default to the DEFAULT format
    214                    tempFormat = new SimpleDateFormat(DEFAULT_PATTERN);
    215                }
    216
    217                // if the option list contains a TZ option, then set it.
    218                if (options != null && options.length > 1) {
    219                    final TimeZone tz = TimeZone.getTimeZone(options[1]);
    220                    tempFormat.setTimeZone(tz);
    221                }
    222                tempFormatter = new PatternFormatter(tempFormat);
    223            }
    224            formatter = tempFormatter;
    225        }
    226
    227        /**
    228         * Append formatted date to string buffer.
    229         *
    230         * @param date
    231         *            date
    232         * @param toAppendTo
    233         *            buffer to which formatted date is appended.
    234         */
    235        public void format(final Date date, final StringBuilder toAppendTo) {
    236            synchronized (this) {
    237                toAppendTo.append(formatter.format(date.getTime()));
    238            }
    239        }
    240
    241        /**
    242         * {@inheritDoc}
    243         */
    244        @Override
    245        public void format(final LogEvent event, final StringBuilder output) {
    246            final long timestamp = event.getTimeMillis();
    247
    248            synchronized (this) {
    249                if (timestamp != lastTimestamp) {
    250                    lastTimestamp = timestamp;
    251                    cachedDateString = formatter.format(timestamp);
    252                }
    253            }
    254            output.append(cachedDateString);
    255        }
    256
    257        /**
    258         * {@inheritDoc}
    259         */
    260        @Override
    261        public void format(final Object obj, final StringBuilder output) {
    262            if (obj instanceof Date) {
    263                format((Date) obj, output);
    264            }
    265            super.format(obj, output);
    266        }
    267
    268        @Override
    269        public void format(final StringBuilder toAppendTo, final Object... objects) {
    270            for (final Object obj : objects) {
    271                if (obj instanceof Date) {
    272                    format(obj, toAppendTo);
    273                    break;
    274                }
    275            }
    276        }
    277
    278        /**
    279         * Gets the pattern string describing this date format.
    280         *
    281         * @return the pattern string describing this date format.
    282         */
    283        public String getPattern() {
    284            return formatter.toPattern();
    285        }
    286
    287    }