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.text.SimpleDateFormat;
    20  import java.util.Date;
    21  import java.util.TimeZone;
    22
    23  import org.apache.logging.log4j.core.LogEvent;
    24  import org.apache.logging.log4j.core.config.plugins.Plugin;
    25
    26  /**
    27   * Convert and format the event's date in a StringBuilder.
    28   */
    29  @Plugin(name = "DatePatternConverter", category = PatternConverter.CATEGORY)
    30  @ConverterKeys({ "d", "date" })
    31  public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter {
    32
    33      private abstract static class Formatter {
    34          abstract String format(long time);
    35
    36          public String toPattern() {
    37              return null;
    38          }
    39      }
    40
    41      private static class PatternFormatter extends Formatter {
    42          private final SimpleDateFormat simpleDateFormat;
    43
    44          PatternFormatter(final SimpleDateFormat simpleDateFormat) {
    45              this.simpleDateFormat = simpleDateFormat;
    46          }
    47
    48          @Override
    49          String format(final long time) {
    50              return simpleDateFormat.format(Long.valueOf(time));
    51          }
    52
    53          @Override
    54          public String toPattern() {
    55              return simpleDateFormat.toPattern();
    56          }
    57      }
    58
    59      private static class UnixFormatter extends Formatter {
    60
    61          @Override
    62          String format(final long time) {
    63              return Long.toString(time / 1000);
    64          }
    65
    66      }
    67
    68      private static class UnixMillisFormatter extends Formatter {
    69
    70          @Override
    71          String format(final long time) {
    72              return Long.toString(time);
    73          }
    74
    75      }
    76
    77      /**
    78       * ABSOLUTE string literal.
    79       */
    80      private static final String ABSOLUTE_FORMAT = "ABSOLUTE";
    81
    82      /**
    83       * SimpleTimePattern for ABSOLUTE.
    84       */
    85      private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS";
    86
    87      /**
    88       * COMPACT string literal.
    89       */
    90      private static final String COMPACT_FORMAT = "COMPACT";
    91
    92      /**
    93       * SimpleTimePattern for COMPACT.
    94       */
    95      private static final String COMPACT_PATTERN = "yyyyMMddHHmmssSSS";
    96
    97      /**
    98       * DATE string literal.
    99       */
    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 }