001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.pattern; 018 019 import java.text.SimpleDateFormat; 020 import java.util.Date; 021 import java.util.TimeZone; 022 023 import org.apache.logging.log4j.core.LogEvent; 024 import org.apache.logging.log4j.core.config.plugins.Plugin; 025 026 /** 027 * Convert and format the event's date in a StringBuilder. 028 */ 029 @Plugin(name = "DatePatternConverter", category = "Converter") 030 @ConverterKeys({ "d", "date" }) 031 public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter { 032 033 private abstract static class Formatter { 034 abstract String format(long time); 035 036 public String toPattern() { 037 return null; 038 } 039 } 040 041 private static class PatternFormatter extends Formatter { 042 private final SimpleDateFormat simpleDateFormat; 043 044 PatternFormatter(final SimpleDateFormat simpleDateFormat) { 045 this.simpleDateFormat = simpleDateFormat; 046 } 047 048 @Override 049 String format(final long time) { 050 return simpleDateFormat.format(Long.valueOf(time)); 051 } 052 053 @Override 054 public String toPattern() { 055 return simpleDateFormat.toPattern(); 056 } 057 } 058 059 private static class UnixFormatter extends Formatter { 060 061 @Override 062 String format(final long time) { 063 return Long.toString(time / 1000); 064 } 065 066 } 067 068 private static class UnixMillisFormatter extends Formatter { 069 070 @Override 071 String format(final long time) { 072 return Long.toString(time); 073 } 074 075 } 076 077 /** 078 * ABSOLUTE string literal. 079 */ 080 private static final String ABSOLUTE_FORMAT = "ABSOLUTE"; 081 082 /** 083 * SimpleTimePattern for ABSOLUTE. 084 */ 085 private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS"; 086 087 /** 088 * COMPACT string literal. 089 */ 090 private static final String COMPACT_FORMAT = "COMPACT"; 091 092 /** 093 * SimpleTimePattern for COMPACT. 094 */ 095 private static final String COMPACT_PATTERN = "yyyyMMddHHmmssSSS"; 096 097 /** 098 * DATE string literal. 099 */ 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 * ISO8601_BASIC string literal. 109 */ 110 private static final String ISO8601_BASIC_FORMAT = "ISO8601_BASIC"; 111 112 /** 113 * SimpleTimePattern for ISO8601_BASIC. 114 */ 115 private static final String ISO8601_BASIC_PATTERN = "yyyyMMdd HHmmss,SSS"; 116 117 /** 118 * ISO8601 string literal. 119 */ 120 private static final String ISO8601_FORMAT = "ISO8601"; 121 122 /** 123 * SimpleTimePattern for ISO8601. 124 */ 125 private static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS"; 126 127 /** 128 * UNIX formatter in seconds (standard). 129 */ 130 private static final String UNIX_FORMAT = "UNIX"; 131 132 /** 133 * UNIX formatter in milliseconds 134 */ 135 private static final String UNIX_MILLIS_FORMAT = "UNIX_MILLIS"; 136 137 /** 138 * Obtains an instance of pattern converter. 139 * 140 * @param options 141 * options, may be null. 142 * @return instance of pattern converter. 143 */ 144 public static DatePatternConverter newInstance(final String[] options) { 145 return new DatePatternConverter(options); 146 } 147 148 /** 149 * Date format. 150 */ 151 private String cachedDateString; 152 153 private final Formatter formatter; 154 155 private long lastTimestamp; 156 157 /** 158 * Private constructor. 159 * 160 * @param options 161 * options, may be null. 162 */ 163 private DatePatternConverter(final String[] options) { 164 super("Date", "date"); 165 166 // null patternOption is OK. 167 final String patternOption = options != null && options.length > 0 ? options[0] : null; 168 169 String pattern = null; 170 Formatter tempFormatter = null; 171 172 if (patternOption == null || patternOption.equalsIgnoreCase(ISO8601_FORMAT)) { 173 pattern = ISO8601_PATTERN; 174 } else if (patternOption.equalsIgnoreCase(ISO8601_BASIC_FORMAT)) { 175 pattern = ISO8601_BASIC_PATTERN; 176 } else if (patternOption.equalsIgnoreCase(ABSOLUTE_FORMAT)) { 177 pattern = ABSOLUTE_TIME_PATTERN; 178 } else if (patternOption.equalsIgnoreCase(DATE_AND_TIME_FORMAT)) { 179 pattern = DATE_AND_TIME_PATTERN; 180 } else if (patternOption.equalsIgnoreCase(COMPACT_FORMAT)) { 181 pattern = COMPACT_PATTERN; 182 } else if (patternOption.equalsIgnoreCase(UNIX_FORMAT)) { 183 tempFormatter = new UnixFormatter(); 184 } else if (patternOption.equalsIgnoreCase(UNIX_MILLIS_FORMAT)) { 185 tempFormatter = new UnixMillisFormatter(); 186 } else { 187 pattern = patternOption; 188 } 189 190 if (pattern != null) { 191 SimpleDateFormat tempFormat; 192 193 try { 194 tempFormat = new SimpleDateFormat(pattern); 195 } catch (final IllegalArgumentException e) { 196 LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e); 197 198 // default to the ISO8601 format 199 tempFormat = new SimpleDateFormat(ISO8601_PATTERN); 200 } 201 202 // if the option list contains a TZ option, then set it. 203 if (options != null && options.length > 1) { 204 final TimeZone tz = TimeZone.getTimeZone(options[1]); 205 tempFormat.setTimeZone(tz); 206 } 207 tempFormatter = new PatternFormatter(tempFormat); 208 } 209 formatter = tempFormatter; 210 } 211 212 /** 213 * Append formatted date to string buffer. 214 * 215 * @param date 216 * date 217 * @param toAppendTo 218 * buffer to which formatted date is appended. 219 */ 220 public void format(final Date date, final StringBuilder toAppendTo) { 221 synchronized (this) { 222 toAppendTo.append(formatter.format(date.getTime())); 223 } 224 } 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override 230 public void format(final LogEvent event, final StringBuilder output) { 231 final long timestamp = event.getTimeMillis(); 232 233 synchronized (this) { 234 if (timestamp != lastTimestamp) { 235 lastTimestamp = timestamp; 236 cachedDateString = formatter.format(timestamp); 237 } 238 } 239 output.append(cachedDateString); 240 } 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override 246 public void format(final Object obj, final StringBuilder output) { 247 if (obj instanceof Date) { 248 format((Date) obj, output); 249 } 250 super.format(obj, output); 251 } 252 253 @Override 254 public void format(final StringBuilder toAppendTo, final Object... objects) { 255 for (final Object obj : objects) { 256 if (obj instanceof Date) { 257 format(obj, toAppendTo); 258 break; 259 } 260 } 261 } 262 263 /** 264 * Gets the pattern string describing this date format. 265 * 266 * @return the pattern string describing this date format. 267 */ 268 public String getPattern() { 269 return formatter.toPattern(); 270 } 271 272 }