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    }