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