1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.pattern;
18
19 import java.util.Date;
20 import java.util.Objects;
21 import java.util.TimeZone;
22 import java.util.concurrent.atomic.AtomicReference;
23
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.datetime.FastDateFormat;
27 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat;
28 import org.apache.logging.log4j.core.util.datetime.FixedDateFormat.FixedFormat;
29
30
31
32
33 @Plugin(name = "DatePatternConverter", category = PatternConverter.CATEGORY)
34 @ConverterKeys({ "d", "date" })
35 public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter {
36
37 private final class CachedTime {
38 public long timestampMillis;
39 public String formatted;
40
41 public CachedTime(final long timestampMillis) {
42 this.timestampMillis = timestampMillis;
43 this.formatted = formatter.format(this.timestampMillis);
44 }
45 }
46
47 private final AtomicReference<CachedTime> cachedTime;
48
49 private abstract static class Formatter {
50 abstract String format(long timeMillis);
51
52 public String toPattern() {
53 return null;
54 }
55 }
56
57 private static final class PatternFormatter extends Formatter {
58 private final FastDateFormat fastDateFormat;
59
60 PatternFormatter(final FastDateFormat fastDateFormat) {
61 this.fastDateFormat = fastDateFormat;
62 }
63
64 @Override
65 String format(final long timeMillis) {
66 return fastDateFormat.format(timeMillis);
67 }
68
69 @Override
70 public String toPattern() {
71 return fastDateFormat.toPattern();
72 }
73 }
74
75 private static final class FixedFormatter extends Formatter {
76 private final FixedDateFormat fixedDateFormat;
77
78 FixedFormatter(final FixedDateFormat fixedDateFormat) {
79 this.fixedDateFormat = fixedDateFormat;
80 }
81
82 @Override
83 String format(final long timeMillis) {
84 return fixedDateFormat.format(timeMillis);
85 }
86
87 @Override
88 public String toPattern() {
89 return fixedDateFormat.getFormat();
90 }
91 }
92
93 private static final class UnixFormatter extends Formatter {
94
95 @Override
96 String format(final long timeMillis) {
97 return Long.toString(timeMillis / 1000);
98 }
99 }
100
101 private static final class UnixMillisFormatter extends Formatter {
102
103 @Override
104 String format(final long timeMillis) {
105 return Long.toString(timeMillis);
106 }
107 }
108
109
110
111
112 private static final String UNIX_FORMAT = "UNIX";
113
114
115
116
117 private static final String UNIX_MILLIS_FORMAT = "UNIX_MILLIS";
118
119
120
121
122
123
124
125
126 public static DatePatternConverter newInstance(final String[] options) {
127 return new DatePatternConverter(options);
128 }
129
130 private final Formatter formatter;
131
132
133
134
135
136
137
138 private DatePatternConverter(final String[] options) {
139 super("Date", "date");
140
141 final FixedDateFormat fixedDateFormat = FixedDateFormat.createIfSupported(options);
142 if (fixedDateFormat != null) {
143 formatter = createFormatter(fixedDateFormat);
144 } else {
145 formatter = createFormatter(options);
146 }
147 cachedTime = new AtomicReference<>(new CachedTime(System.currentTimeMillis()));
148 }
149
150 private static Formatter createFormatter(final FixedDateFormat fixedDateFormat) {
151 return new FixedFormatter(fixedDateFormat);
152 }
153
154 private static Formatter createFormatter(final String[] options) {
155
156 Objects.requireNonNull(options);
157 if (options.length == 0) {
158 throw new IllegalArgumentException("options array must have at least one element");
159 }
160 Objects.requireNonNull(options[0]);
161 final String patternOption = options[0];
162 if (UNIX_FORMAT.equals(patternOption)) {
163 return new UnixFormatter();
164 }
165 if (UNIX_MILLIS_FORMAT.equals(patternOption)) {
166 return new UnixMillisFormatter();
167 }
168
169
170 TimeZone tz = null;
171 if (options != null && options.length > 1) {
172 tz = TimeZone.getTimeZone(options[1]);
173 }
174
175 try {
176 final FastDateFormat tempFormat = FastDateFormat.getInstance(patternOption, tz);
177 return new PatternFormatter(tempFormat);
178 } catch (final IllegalArgumentException e) {
179 LOGGER.warn("Could not instantiate FastDateFormat with pattern " + patternOption, e);
180
181
182 return createFormatter(FixedDateFormat.create(FixedFormat.DEFAULT));
183 }
184 }
185
186
187
188
189
190
191
192
193
194 public void format(final Date date, final StringBuilder toAppendTo) {
195 format(date.getTime(), toAppendTo);
196 }
197
198
199
200
201 @Override
202 public void format(final LogEvent event, final StringBuilder output) {
203 format(event.getTimeMillis(), output);
204 }
205
206 public void format(final long timestampMillis, final StringBuilder output) {
207 CachedTime cached = cachedTime.get();
208 if (timestampMillis != cached.timestampMillis) {
209 final CachedTime newTime = new CachedTime(timestampMillis);
210 if (cachedTime.compareAndSet(cached, newTime)) {
211 cached = newTime;
212 } else {
213 cached = cachedTime.get();
214 }
215 }
216 output.append(cached.formatted);
217 }
218
219
220
221
222 @Override
223 public void format(final Object obj, final StringBuilder output) {
224 if (obj instanceof Date) {
225 format((Date) obj, output);
226 }
227 super.format(obj, output);
228 }
229
230 @Override
231 public void format(final StringBuilder toAppendTo, final Object... objects) {
232 for (final Object obj : objects) {
233 if (obj instanceof Date) {
234 format(obj, toAppendTo);
235 break;
236 }
237 }
238 }
239
240
241
242
243
244
245 public String getPattern() {
246 return formatter.toPattern();
247 }
248
249 }