KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > server > logging > UniformLogFormatter


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.server.logging;
25
26 import java.util.logging.Formatter JavaDoc;
27 import java.util.logging.LogRecord JavaDoc;
28 import java.util.logging.LogManager JavaDoc;
29 import java.util.logging.Logger JavaDoc;
30 import java.util.logging.Level JavaDoc;
31 import java.util.logging.ErrorManager JavaDoc;
32 import java.util.ResourceBundle JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Date JavaDoc;
35 import java.util.Map JavaDoc;
36 import java.util.Collection JavaDoc;
37 import java.util.Iterator JavaDoc;
38 import java.text.SimpleDateFormat JavaDoc;
39 import java.text.MessageFormat JavaDoc;
40 import java.text.FieldPosition JavaDoc;
41 import java.io.StringWriter JavaDoc;
42 import java.io.PrintWriter JavaDoc;
43
44 import com.sun.enterprise.Switch;
45 import com.sun.enterprise.admin.monitor.callflow.Agent;
46 import com.sun.enterprise.admin.monitor.callflow.ThreadLocalData;
47
48 /**
49  * UniformLogFormatter conforms to the logging format defined by the
50  * Log Working Group in Java Webservices Org.
51  * The specified format is
52  * "[#|DATETIME|LOG_LEVEL|PRODUCT_ID|LOGGER NAME|OPTIONAL KEY VALUE PAIRS|
53  * MESSAGE|#]\n"
54  *
55  * @author Hemanth Puttaswamy
56  *
57  * TODO:
58  * 1. Performance improvement. We can Cache the LOG_LEVEL|PRODUCT_ID strings
59  * and minimize the concatenations and revisit for more performance
60  * improvements
61  * 2. Need to use Product Name and Version based on the version string
62  * that is part of the product.
63  * 3. Stress testing
64  * 4. If there is a Map as the last element, need to scan the message to
65  * distinguish key values with the message argument.
66  */

67 public class UniformLogFormatter extends Formatter JavaDoc {
68     // loggerResourceBundleTable caches references to all the ResourceBundle
69
// and can be searched using the LoggerName as the key
70
private HashMap JavaDoc loggerResourceBundleTable;
71     private LogManager JavaDoc logManager;
72     // A Dummy Container Date Object is used to format the date
73
private Date JavaDoc date = new Date JavaDoc( );
74     private static String JavaDoc PRODUCTID_CONTEXTID = null;
75     // This is temporary, in the next phase of implementation the product Id
76
// will be obtained from the version object that is part of Sun One AppServ
77
// Bug 4882896: string initialized using Version.java
78
private static final String JavaDoc PRODUCT_VERSION =
79             com.sun.appserv.server.util.Version.getAbbreviatedVersion();
80     private static final int FINE_LEVEL_INT_VALUE = Level.FINE.intValue();
81
82     private static boolean LOG_SOURCE_IN_KEY_VALUE = false;
83
84     private static boolean RECORD_NUMBER_IN_KEY_VALUE = false;
85
86     static {
87         String JavaDoc logSource = System.getProperty(
88             "com.sun.aas.logging.keyvalue.logsource");
89         if( (logSource != null )
90           &&(logSource.equals( "true" ) ) )
91         {
92             LOG_SOURCE_IN_KEY_VALUE = true;
93         }
94
95         String JavaDoc recordCount = System.getProperty(
96             "com.sun.aas.logging.keyvalue.recordnumber");
97         if( (recordCount != null )
98           &&(recordCount.equals( "true" ) ) )
99         {
100             RECORD_NUMBER_IN_KEY_VALUE = true;
101         }
102     }
103
104     private long recordNumber = 0;
105
106     private static final String JavaDoc LINE_SEPARATOR =
107         (String JavaDoc) java.security.AccessController.doPrivileged(
108             new sun.security.action.GetPropertyAction("line.separator"));
109
110     private static final String JavaDoc RECORD_BEGIN_MARKER = "[#|";
111     private static final String JavaDoc RECORD_END_MARKER = "|#]" + LINE_SEPARATOR +
112         LINE_SEPARATOR;
113     private static final char FIELD_SEPARATOR = '|';
114     private static final char NVPAIR_SEPARATOR = ';';
115     private static final char NV_SEPARATOR = '=';
116     
117     private static final String JavaDoc RFC_3339_DATE_FORMAT =
118         "yyyy-MM-dd'T'HH:mm:ss.SSSZ";
119
120     private static final SimpleDateFormat JavaDoc dateFormatter =
121         new SimpleDateFormat JavaDoc( RFC_3339_DATE_FORMAT );
122
123     public UniformLogFormatter( ) {
124         super( );
125         loggerResourceBundleTable = new HashMap JavaDoc( );
126         logManager = LogManager.getLogManager( );
127     }
128
129
130     /**
131      * _REVISIT_: Replace the String Array with an HashMap and do some
132      * benchmark to determine whether StringCat is faster or Hashlookup for
133      * the template is faster.
134      */

135             
136
137     public String JavaDoc format( LogRecord JavaDoc record ) {
138         return uniformLogFormat( record );
139     }
140
141     public String JavaDoc formatMessage( LogRecord JavaDoc record ) {
142         return uniformLogFormat( record );
143     }
144
145
146     /**
147      * Sun One AppServer SE/EE can override to specify their product version
148      */

149     protected String JavaDoc getProductId( ) {
150         return PRODUCT_VERSION;
151     }
152
153     
154     /**
155      * Sun One Appserver SE/EE? can override to specify their product specific
156      * key value pairs.
157      */

158     protected void getNameValuePairs(StringBuilder JavaDoc buf, LogRecord JavaDoc record) {
159         
160         Object JavaDoc[] parameters = record.getParameters();
161         if ((parameters == null) || (parameters.length == 0)) {
162             return;
163         }
164         
165         try {
166             for (Object JavaDoc obj : parameters) {
167                 if (obj == null) {
168                     continue;
169                 }
170                 if (obj instanceof Map JavaDoc) {
171                     Map JavaDoc map = (Map JavaDoc) obj;
172                     for (Object JavaDoc key : map.keySet()) {
173                         buf.append(key.toString()).append(NV_SEPARATOR).
174                             append(map.get(key).toString()).
175                             append(NVPAIR_SEPARATOR);
176                     }
177                 } else if (obj instanceof java.util.Collection JavaDoc) {
178                     for (Object JavaDoc entry : ((Collection JavaDoc)obj)) {
179                         buf.append(entry.toString()).append(NVPAIR_SEPARATOR);
180                     }
181                 } else {
182                     buf.append(obj.toString()).append(NVPAIR_SEPARATOR);
183                 }
184             }
185         } catch( Exception JavaDoc e ) {
186             new ErrorManager JavaDoc().error(
187                 "Error in extracting Name Value Pairs", e,
188                 ErrorManager.FORMAT_FAILURE );
189         }
190     }
191     
192     private void uniformLogFormat(
193             StringBuilder JavaDoc buf, ThreadLocalData tld, Level JavaDoc level) {
194         
195         if (level.equals(Level.INFO) || level.equals(Level.CONFIG)) {
196             
197             if (tld.getApplicationName() != null) {
198                 buf.append("_ApplicationName").append(NV_SEPARATOR).
199                         append(tld.getApplicationName()).
200                         append(NVPAIR_SEPARATOR);
201             }
202             
203         } else {
204             
205             if (tld.getRequestId() != null) {
206                 buf.append("_RequestID").append(NV_SEPARATOR).
207                         append(tld.getRequestId()).append(NVPAIR_SEPARATOR);
208             }
209             
210             if (tld.getApplicationName() != null) {
211                 buf.append("_ApplicationName").append(NV_SEPARATOR).
212                         append(tld.getApplicationName()).
213                         append(NVPAIR_SEPARATOR);
214             }
215             
216             if (tld.getModuleName() != null) {
217                 buf.append("_ModuleName").append(NV_SEPARATOR).
218                         append(tld.getModuleName()).append(NVPAIR_SEPARATOR);
219             }
220             
221             if (tld.getComponentName() != null) {
222                 buf.append("_ComponentName").append(NV_SEPARATOR).
223                         append(tld.getComponentName()).append(NVPAIR_SEPARATOR);
224             }
225             
226             if (tld.getComponentType() != null) {
227                 buf.append("_ComponentType").append(NV_SEPARATOR).
228                         append(tld.getComponentType()).append(NVPAIR_SEPARATOR);
229             }
230             
231             if (tld.getMethodName() != null) {
232                 buf.append("_MethodName").append(NV_SEPARATOR).
233                         append(tld.getMethodName()).append(NVPAIR_SEPARATOR);
234             }
235             
236             if (tld.getTransactionId() != null) {
237                 buf.append("_TransactionId").append(NV_SEPARATOR).
238                         append(tld.getTransactionId()).append(NVPAIR_SEPARATOR);
239             }
240             
241             if (tld.getSecurityId() != null) {
242                 buf.append("_CallerId").append(NV_SEPARATOR).
243                         append(tld.getSecurityId()).append(NVPAIR_SEPARATOR);
244             }
245         }
246     }
247
248     /**
249      * Note: This method is not synchronized, we are assuming that the
250      * synchronization will happen at the Log Handler.publish( ) method.
251      */

252     private String JavaDoc uniformLogFormat(LogRecord JavaDoc record) {
253         
254         try {
255             
256             StringBuilder JavaDoc recordBuffer = new StringBuilder JavaDoc(RECORD_BEGIN_MARKER);
257             // The following operations are to format the date and time in a
258
// human readable format.
259
// _REVISIT_: Use HiResolution timer to analyze the number of
260
// Microseconds spent on formatting date object
261
date.setTime(record.getMillis());
262             recordBuffer.append(dateFormatter.format(date));
263             recordBuffer.append(FIELD_SEPARATOR);
264
265             recordBuffer.append(record.getLevel()).append(FIELD_SEPARATOR);
266             recordBuffer.append(getProductId()).append(FIELD_SEPARATOR);
267             recordBuffer.append(record.getLoggerName()).append(FIELD_SEPARATOR);
268             
269             recordBuffer.append("_ThreadID").append(NV_SEPARATOR);
270             recordBuffer.append(record.getThreadID()).append(NVPAIR_SEPARATOR);
271             
272             recordBuffer.append("_ThreadName").append(NV_SEPARATOR);
273             recordBuffer.append(Thread.currentThread().getName());
274             recordBuffer.append(NVPAIR_SEPARATOR);
275             
276             // See 6316018. ClassName and MethodName information should be
277
// included for FINER and FINEST log levels.
278
Level JavaDoc level = record.getLevel();
279             if (LOG_SOURCE_IN_KEY_VALUE ||
280                     (level.intValue() <= Level.FINE.intValue())) {
281                 recordBuffer.append("ClassName").append(NV_SEPARATOR);
282                 recordBuffer.append(record.getSourceClassName());
283                 recordBuffer.append(NVPAIR_SEPARATOR);
284                 recordBuffer.append("MethodName").append(NV_SEPARATOR);
285                 recordBuffer.append(record.getSourceMethodName());
286                 recordBuffer.append(NVPAIR_SEPARATOR);
287             }
288
289             if (RECORD_NUMBER_IN_KEY_VALUE) {
290                 recordBuffer.append("RecordNumber").append(NV_SEPARATOR);
291                 recordBuffer.append(recordNumber++).append(NVPAIR_SEPARATOR);
292             }
293             
294             getNameValuePairs(recordBuffer, record);
295             
296             Agent callFlowAgent = Switch.getSwitch().getCallFlowAgent();
297             if (callFlowAgent != null) {
298                 // Since it is possible that a log call may happen before
299
// the Switch class's callflow agent is initialized during
300
// server startup, we perform the null check above.
301
ThreadLocalData tld = callFlowAgent.getThreadLocalData();
302                 if (tld != null) {
303                     uniformLogFormat(recordBuffer, tld, level);
304                 }
305             }
306             
307             recordBuffer.append(FIELD_SEPARATOR);
308             
309             String JavaDoc logMessage = record.getMessage();
310         if (logMessage == null) {
311             logMessage = "The log message is null.";
312         }
313             if( logMessage.indexOf("{0}") >= 0 ) {
314                 // If we find {0} or {1} etc., in the message, then it's most
315
// likely finer level messages for Method Entry, Exit etc.,
316
logMessage = java.text.MessageFormat.format(
317                     logMessage, record.getParameters() );
318             } else {
319                 ResourceBundle JavaDoc rb = getResourceBundle(record.getLoggerName( ) );
320                 if( rb != null ) {
321                     try {
322                         logMessage = MessageFormat.format(
323                             rb.getString( logMessage ),
324                             record.getParameters( ) );
325                     } catch ( java.util.MissingResourceException JavaDoc e ) {
326                         // If we don't find an entry, then we are covered
327
// because the logMessage is intialized already
328
}
329                 }
330             }
331             recordBuffer.append(logMessage);
332
333             if (record.getThrown() != null) {
334                 recordBuffer.append(LINE_SEPARATOR);
335                 StringWriter JavaDoc sw = new StringWriter JavaDoc();
336                 PrintWriter JavaDoc pw = new PrintWriter JavaDoc(sw);
337                 record.getThrown().printStackTrace(pw);
338                 pw.close();
339                 recordBuffer.append(sw.toString());
340             }
341             
342             recordBuffer.append(RECORD_END_MARKER);
343             return recordBuffer.toString();
344             
345         } catch( Exception JavaDoc ex ) {
346             new ErrorManager JavaDoc().error(
347                 "Error in formatting Logrecord", ex,
348                 ErrorManager.FORMAT_FAILURE );
349             // We've already notified the exception, the following
350
// return is to keep javac happy
351
return new String JavaDoc("");
352         }
353     }
354  
355     private synchronized ResourceBundle JavaDoc getResourceBundle( String JavaDoc loggerName ) {
356         if( loggerName == null ) {
357             return null;
358         }
359         ResourceBundle JavaDoc rb = (ResourceBundle JavaDoc) loggerResourceBundleTable.get(
360             loggerName );
361  
362         if( rb == null ) {
363             rb = logManager.getLogger( loggerName ).getResourceBundle( );
364             loggerResourceBundleTable.put( loggerName, rb );
365         }
366         return rb;
367     }
368 }
369
Popular Tags