001 /**
002 * Source code taken from {@link http://wiki.eclipse.org/EclipseLink/Foundation/Logging}.
003 * Supports use of log4j with eclipselink.
004 */
005 /*******************************************************************************
006 * Copyright (c) 1998, 2008 Oracle. All rights reserved.
007 * This program and the accompanying materials are made available under the
008 * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
009 * which accompanies this distribution.
010 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
011 * and the Eclipse Distribution License is available at
012 * http://www.eclipse.org/org/documents/edl-v10.php.
013 *
014 * Contributors:
015 * Oracle - initial API and implementation from Oracle TopLink
016 ******************************************************************************/
017 package org.eclipse.persistence.logging;
018
019 import java.io.PrintWriter;
020 import java.io.StringWriter;
021 import java.text.MessageFormat;
022 import java.util.Date;
023 import java.util.logging.Level;
024 import java.util.logging.LogRecord;
025 import java.util.logging.SimpleFormatter;
026
027 import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
028 import org.eclipse.persistence.logging.AbstractSessionLog;
029 import org.eclipse.persistence.logging.EclipseLinkLogRecord;
030
031 /**
032 * <p>
033 * Print a brief summary of a TopLink LogRecord in a human readable
034 * format. The summary will typically be 1 or 2 lines.
035 * </p>
036 *
037 * @author laurent bourges (voparis) : bourges.laurent@gmail.com
038 */
039 public final class FastLogFormatter extends SimpleFormatter {
040
041 //~ Constants --------------------------------------------------------------------------------------------------------
042 /**
043 * undefined capacity
044 */
045 private final static int UNDEFINED_CAPACITY = -1;
046 /**
047 * initial buffer capacity = 256 chars
048 */
049 private final static int INITIAL_BUFFER_CAPACITY = 256;
050 /**
051 * date format
052 */
053 private final static String format = "{0,date} {0,time}";
054 /**
055 * '(' character
056 */
057 public final static char PAR_OPEN_CHAR = '(';
058 /**
059 * ')' character
060 */
061 public final static char PAR_CLOSE_CHAR = ')';
062 /**
063 * ' ' character
064 */
065 public final static char SPACE_CHAR = ' ';
066 /**
067 * Line separator string. This is the value of the line.separator
068 * property at the moment that the SimpleFormatter was created.
069 */
070 private final static String LINE_SEPARATOR = PrivilegedAccessHelper.getLineSeparator();
071
072 //~ Members ----------------------------------------------------------------------------------------------------------
073 /**
074 * computed buffer capacity
075 */
076 private int adaptedBufferCapacity = UNDEFINED_CAPACITY;
077 /**
078 * date formatter
079 */
080 private MessageFormat dateFormatter;
081 /**
082 * cached date instance
083 */
084 private final Date dateInstance = new Date();
085 /**
086 * buffer to store formatted date
087 */
088 private final StringBuffer dateBuffer = new StringBuffer(64);
089 /**
090 * date formatter args
091 */
092 private Object[] dateFormatterArgs = new Object[1];
093
094 /**
095 * Format the given LogRecord.
096 * @param pRecord the log record to be formatted.
097 * @return a formatted log record
098 */
099 @Override
100 public String format(LogRecord pRecord) {
101 if (!(pRecord instanceof EclipseLinkLogRecord)) {
102 return super.format(pRecord);
103 } else {
104 final EclipseLinkLogRecord record = (EclipseLinkLogRecord) pRecord;
105
106 final String message = formatMessage(record);
107
108 final int capacity = (adaptedBufferCapacity == UNDEFINED_CAPACITY) ? INITIAL_BUFFER_CAPACITY : adaptedBufferCapacity + message.length();
109 /*
110 * Unsynchronized & sized character buffer to avoid too much array resize operations :
111 */
112 final StringBuilder sb = new StringBuilder(capacity);
113
114 // local variable for performance :
115 final char space = SPACE_CHAR;
116
117 if (record.shouldPrintDate()) {
118 synchronized (dateInstance) {
119 // Minimize memory allocations here.
120 dateInstance.setTime(record.getMillis());
121 dateFormatterArgs[0] = dateInstance;
122 if (dateFormatter == null) {
123 dateFormatter = new MessageFormat(format);
124 }
125 dateFormatter.format(dateFormatterArgs, dateBuffer, null);
126 sb.append(dateBuffer);
127 // reset dateBuffer content :
128 dateBuffer.setLength(0);
129 }
130 sb.append(space);
131 }
132
133 if (record.getSourceClassName() != null) {
134 sb.append(record.getSourceClassName());
135 } else {
136 sb.append(record.getLoggerName());
137 }
138
139 if (record.getSourceMethodName() != null) {
140 sb.append(space);
141 sb.append(record.getSourceMethodName());
142 }
143
144 if (record.getSessionString() != null) {
145 sb.append(space);
146 sb.append(record.getSessionString());
147 }
148
149 if (record.getConnection() != null) {
150 sb.append(space);
151 sb.append(AbstractSessionLog.CONNECTION_STRING).append(PAR_OPEN_CHAR);
152 sb.append(String.valueOf(System.identityHashCode(record.getConnection()))).append(PAR_CLOSE_CHAR);
153 }
154
155 if (record.shouldPrintThread()) {
156 sb.append(space);
157 sb.append(AbstractSessionLog.THREAD_STRING).append(PAR_OPEN_CHAR);
158 sb.append(String.valueOf(record.getThreadID())).append(PAR_CLOSE_CHAR);
159 }
160
161 sb.append(LINE_SEPARATOR);
162
163 sb.append(record.getLevel().getLocalizedName());
164 sb.append(": ");
165 sb.append(message);
166
167 // first time, compute initial capacity :
168 if (adaptedBufferCapacity == UNDEFINED_CAPACITY) {
169 adaptedBufferCapacity = sb.length() + 4 - message.length();
170
171 if (CommonsLoggingSessionLog.FORCE_INTERNAL_DEBUG) {
172 sb.append(LINE_SEPARATOR);
173 sb.append("adaptedBufferCapacity : ");
174 sb.append(adaptedBufferCapacity);
175 }
176 }
177
178 /*
179 * Log4J : not necessary :
180 * sb.append(LINE_SEPARATOR);
181 */
182 if (record.getThrown() != null) {
183 final StringWriter sw = new StringWriter(INITIAL_BUFFER_CAPACITY);
184 final PrintWriter pw = new PrintWriter(sw);
185 try {
186 if (record.getLevel().intValue() == Level.SEVERE.intValue()) {
187 record.getThrown().printStackTrace(pw);
188 } else if (record.getLevel().intValue() <= Level.WARNING.intValue()) {
189 if (record.shouldLogExceptionStackTrace()) {
190 record.getThrown().printStackTrace(pw);
191 } else {
192 pw.write(record.getThrown().toString());
193 /*
194 * Log4J : not necessary :
195 * pw.write(LINE_SEPARATOR);
196 */
197 }
198 }
199 } catch (Exception e) {
200 CommonsLoggingSessionLog.error(e);
201 } finally {
202 pw.close();
203 sb.append(sw.toString());
204 }
205 }
206
207 if (CommonsLoggingSessionLog.FORCE_INTERNAL_DEBUG) {
208 final int len = sb.length();
209 final int cap = sb.capacity();
210 sb.append(LINE_SEPARATOR);
211 sb.append("sb-Length : ");
212 sb.append(len);
213 sb.append(" - initial capacity : ");
214 sb.append(capacity);
215 sb.append(" - capacity : ");
216 sb.append(cap);
217 sb.append(" - resized : ");
218 sb.append(cap > capacity);
219 sb.append(" - overhead : ");
220 sb.append(cap - len);
221 }
222
223 return sb.toString();
224 }
225 }
226 }