1 /**
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  *      http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */

14 package net.logstash.logback.composite;
15
16 import java.io.IOException;
17 import java.util.TimeZone;
18
19 import net.logstash.logback.fieldnames.LogstashCommonFieldNames;
20
21 import org.apache.commons.lang3.time.FastDateFormat;
22
23 import ch.qos.logback.core.spi.DeferredProcessingAware;
24
25 import com.fasterxml.jackson.core.JsonGenerator;
26
27 /**
28  * Writes the timestamp field as either:
29  * <ul>
30  *      <li>A string value formatted by a {@link FastDateFormat} pattern</li>
31  *      <li>A string value representing the number of milliseconds since unix epoch  (designated by specifying the pattern value as {@value #UNIX_TIMESTAMP_AS_STRING})</li>
32  *      <li>A number value of the milliseconds since unix epoch  (designated by specifying the pattern value as {@value #UNIX_TIMESTAMP_AS_NUMBER})</li>
33  * </ul>
34  */

35 public abstract class FormattedTimestampJsonProvider<Event extends DeferredProcessingAware, FieldNames extends LogstashCommonFieldNames> extends AbstractFieldJsonProvider<Event> implements FieldNamesAware<FieldNames> {
36     
37     public static final String FIELD_TIMESTAMP = "@timestamp";
38     
39     /**
40      * Setting the {@link #pattern} as this value will make it so that the timestamp
41      * is written as a number value of the milliseconds since unix epoch.
42      */

43     public static final String UNIX_TIMESTAMP_AS_NUMBER = "[UNIX_TIMESTAMP_AS_NUMBER]";
44     
45     /**
46      * Setting the {@link #pattern} as this value will make it so that the timestamp
47      * is written as a string value representing the number of milliseconds since unix epoch
48      */

49     public static final String UNIX_TIMESTAMP_AS_STRING = "[UNIX_TIMESTAMP_AS_STRING]";
50     
51     private static final String DEFAULT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
52     private static final TimeZone DEFAULT_TIMEZONE = null;
53     
54     /**
55      * The pattern in which to format the timestamp.
56      * Setting this value to {@value #UNIX_TIMESTAMP_AS_NUMBER} will cause the timestamp to be written as a number value of the milliseconds since unix epoch. 
57      * Setting this value to {@value #UNIX_TIMESTAMP_AS_STRING} will cause the timestamp to be written as a string value representing the number value of the milliseconds since unix epoch.
58      * Any other value will be used as a pattern for formatting the timestamp by a {@link FastDateFormat} 
59      */

60     private String pattern = DEFAULT_PATTERN;
61     
62     /**
63      * The timezone for which to write the timestamp.
64      * Only applicable if the pattern is not {@value #UNIX_TIMESTAMP_AS_NUMBER} or {@value #UNIX_TIMESTAMP_AS_STRING} 
65      */

66     private TimeZone timeZone = DEFAULT_TIMEZONE;
67     
68     /**
69      * Writes the timestamp to the JsonGenerator.
70      */

71     private TimestampWriter timestampWriter = new PatternTimestampWriter(FastDateFormat.getInstance(pattern, timeZone));
72     
73     /**
74      * Writes the timestamp to the JsonGenerator
75      */

76     private static interface TimestampWriter {
77         void writeTo(JsonGenerator generator, String fieldName, long timestampInMillis) throws IOException;
78         
79         String getTimestampAsString(long timestampInMillis);
80     }
81     
82     /**
83      * Writes the timestamp to the JsonGenerator as a string formatted by the pattern.
84      */

85     private static class PatternTimestampWriter implements TimestampWriter {
86
87         private final FastDateFormat formatter;
88         
89         public PatternTimestampWriter(FastDateFormat formatter) {
90             this.formatter = formatter;
91         }
92
93         
94         @Override
95         public void writeTo(JsonGenerator generator, String fieldName, long timestampInMillis) throws IOException {
96             JsonWritingUtils.writeStringField(generator, fieldName, getTimestampAsString(timestampInMillis));
97         }
98
99         @Override
100         public String getTimestampAsString(long timestampInMillis) {
101             return formatter.format(timestampInMillis);
102         }
103     }
104     
105     /**
106      * Writes the timestamp to the JsonGenerator as a number of milliseconds since unix epoch.
107      */

108     private static class NumberTimestampWriter implements TimestampWriter {
109
110         @Override
111         public void writeTo(JsonGenerator generator, String fieldName, long timestampInMillis) throws IOException {
112             JsonWritingUtils.writeNumberField(generator, fieldName, timestampInMillis);
113         }
114         
115         @Override
116         public String getTimestampAsString(long timestampInMillis) {
117             return Long.toString(timestampInMillis);
118         }
119     }
120     
121     /**
122      * Writes the timestamp to the JsonGenerator as a string representation of the of milliseconds since unix epoch.
123      */

124     private static class StringTimestampWriter implements TimestampWriter {
125
126         @Override
127         public void writeTo(JsonGenerator generator, String fieldName, long timestampInMillis) throws IOException {
128             JsonWritingUtils.writeStringField(generator, fieldName, getTimestampAsString(timestampInMillis));
129         }
130         
131         @Override
132         public String getTimestampAsString(long timestampInMillis) {
133             return Long.toString(timestampInMillis);
134         }
135         
136     }
137     
138     public FormattedTimestampJsonProvider() {
139         setFieldName(FIELD_TIMESTAMP);
140     }
141     
142     @Override
143     public void setFieldNames(FieldNames fieldNames) {
144         setFieldName(fieldNames.getTimestamp());
145     }
146     
147     @Override
148     public void writeTo(JsonGenerator generator, Event event) throws IOException {
149         timestampWriter.writeTo(generator, getFieldName(), getTimestampAsMillis(event));
150     }
151
152     protected String getFormattedTimestamp(Event event) {
153         return timestampWriter.getTimestampAsString(getTimestampAsMillis(event));
154     }
155
156     protected abstract long getTimestampAsMillis(Event event);
157     
158     /**
159      * Updates the {@link #timestampWriter} value based on the current pattern and timeZone.
160      */

161     private void updateTimestampWriter() {
162         if (UNIX_TIMESTAMP_AS_NUMBER.equals(pattern)) {
163             timestampWriter = new NumberTimestampWriter();
164         } else if (UNIX_TIMESTAMP_AS_STRING.equals(pattern)) {
165             timestampWriter = new StringTimestampWriter();
166         } else {
167             timestampWriter = new PatternTimestampWriter(FastDateFormat.getInstance(pattern, timeZone));
168         }
169     }
170     
171     public String getPattern() {
172         return pattern;
173     }
174     public void setPattern(String pattern) {
175         this.pattern = pattern;
176         updateTimestampWriter();
177     }
178     public String getTimeZone() {
179         return timeZone.getID();
180     }
181     public void setTimeZone(String timeZoneId) {
182         this.timeZone = TimeZone.getTimeZone(timeZoneId);
183         updateTimestampWriter();
184     }
185 }
186