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 org.apache.logging.log4j.core.LogEvent; 020 import org.apache.logging.log4j.core.config.plugins.Plugin; 021 022 import java.text.SimpleDateFormat; 023 import java.util.Date; 024 import java.util.TimeZone; 025 026 027 /** 028 * Convert and format the event's date in a StringBuffer. 029 */ 030 @Plugin(name = "DatePatternConverter", category = "Converter") 031 @ConverterKeys({"d", "date" }) 032 public final class DatePatternConverter extends LogEventPatternConverter implements ArrayPatternConverter { 033 034 /** 035 * ABSOLUTE string literal. 036 */ 037 private static final String ABSOLUTE_FORMAT = "ABSOLUTE"; 038 039 /** 040 * COMPACT string literal. 041 */ 042 private static final String COMPACT_FORMAT = "COMPACT"; 043 044 /** 045 * SimpleTimePattern for ABSOLUTE. 046 */ 047 private static final String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS"; 048 049 /** 050 * DATE string literal. 051 */ 052 private static final String DATE_AND_TIME_FORMAT = "DATE"; 053 054 /** 055 * SimpleTimePattern for DATE. 056 */ 057 private static final String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS"; 058 059 /** 060 * ISO8601 string literal. 061 */ 062 private static final String ISO8601_FORMAT = "ISO8601"; 063 064 /** 065 * ISO8601_BASIC string literal. 066 */ 067 private static final String ISO8601_BASIC_FORMAT = "ISO8601_BASIC"; 068 069 /** 070 * SimpleTimePattern for ISO8601. 071 */ 072 private static final String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS"; 073 074 /** 075 * SimpleTimePattern for ISO8601_BASIC. 076 */ 077 private static final String ISO8601_BASIC_PATTERN = "yyyyMMdd HHmmss,SSS"; 078 079 /** 080 * SimpleTimePattern for COMPACT. 081 */ 082 private static final String COMPACT_PATTERN = "yyyyMMddHHmmssSSS"; 083 084 /** 085 * Date format. 086 */ 087 private String cachedDate; 088 089 private long lastTimestamp; 090 091 private final SimpleDateFormat simpleFormat; 092 093 /** 094 * Private constructor. 095 * 096 * @param options options, may be null. 097 */ 098 private DatePatternConverter(final String[] options) { 099 super("Date", "date"); 100 101 String patternOption; 102 103 if (options == null || options.length == 0) { 104 // the branch could be optimized, but here we are making explicit 105 // that null values for patternOption are allowed. 106 patternOption = null; 107 } else { 108 patternOption = options[0]; 109 } 110 111 String pattern; 112 113 if (patternOption == null || patternOption.equalsIgnoreCase(ISO8601_FORMAT)) { 114 pattern = ISO8601_PATTERN; 115 } else if (patternOption.equalsIgnoreCase(ISO8601_BASIC_FORMAT)) { 116 pattern = ISO8601_BASIC_PATTERN; 117 } else if (patternOption.equalsIgnoreCase(ABSOLUTE_FORMAT)) { 118 pattern = ABSOLUTE_TIME_PATTERN; 119 } else if (patternOption.equalsIgnoreCase(DATE_AND_TIME_FORMAT)) { 120 pattern = DATE_AND_TIME_PATTERN; 121 } else if (patternOption.equalsIgnoreCase(COMPACT_FORMAT)) { 122 pattern = COMPACT_PATTERN; 123 } else { 124 pattern = patternOption; 125 } 126 127 SimpleDateFormat tempFormat; 128 129 try { 130 tempFormat = new SimpleDateFormat(pattern); 131 } catch (final IllegalArgumentException e) { 132 LOGGER.warn("Could not instantiate SimpleDateFormat with pattern " + patternOption, e); 133 134 // default to the ISO8601 format 135 tempFormat = new SimpleDateFormat(ISO8601_PATTERN); 136 } 137 138 // if the option list contains a TZ option, then set it. 139 if (options != null && options.length > 1) { 140 final TimeZone tz = TimeZone.getTimeZone(options[1]); 141 tempFormat.setTimeZone(tz); 142 } 143 simpleFormat = tempFormat; 144 } 145 146 /** 147 * Obtains an instance of pattern converter. 148 * 149 * @param options options, may be null. 150 * @return instance of pattern converter. 151 */ 152 public static DatePatternConverter newInstance(final String[] options) { 153 return new DatePatternConverter(options); 154 } 155 156 /** 157 * {@inheritDoc} 158 */ 159 @Override 160 public void format(final LogEvent event, final StringBuilder output) { 161 final long timestamp = event.getMillis(); 162 163 synchronized (this) { 164 if (timestamp != lastTimestamp) { 165 lastTimestamp = timestamp; 166 cachedDate = simpleFormat.format(timestamp); 167 } 168 } 169 output.append(cachedDate); 170 } 171 172 @Override 173 public void format(final StringBuilder toAppendTo, final Object... objects) { 174 for (final Object obj : objects) { 175 if (obj instanceof Date) { 176 format(obj, toAppendTo); 177 break; 178 } 179 } 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 public void format(final Object obj, final StringBuilder output) { 187 if (obj instanceof Date) { 188 format((Date) obj, output); 189 } 190 191 super.format(obj, output); 192 } 193 194 /** 195 * Append formatted date to string buffer. 196 * 197 * @param date date 198 * @param toAppendTo buffer to which formatted date is appended. 199 */ 200 public void format(final Date date, final StringBuilder toAppendTo) { 201 synchronized (this) { 202 toAppendTo.append(simpleFormat.format(date.getTime())); 203 } 204 } 205 206 public String getPattern() { 207 return simpleFormat.toPattern(); 208 } 209 210 }