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 }