Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: er/extensions/ERXPatternLayout.java


1   /*
2    * Copyright (C) NetStruxr, Inc. All rights reserved.
3    *
4    * This software is published under the terms of the NetStruxr
5    * Public Software License version 0.5, a copy of which has been
6    * included with this distribution in the LICENSE.NPL file.  */
7   package er.extensions;
8   
9   import org.apache.log4j.PatternLayout;
10  import org.apache.log4j.helpers.FormattingInfo;
11  import org.apache.log4j.helpers.PatternConverter;
12  import org.apache.log4j.helpers.PatternParser;
13  import org.apache.log4j.spi.LoggingEvent;
14  import java.util.Enumeration;
15  import com.webobjects.appserver.WOApplication;
16  import com.webobjects.appserver.WOAdaptor;
17  import com.webobjects.foundation.NSArray;
18  import com.webobjects.foundation.NSMutableArray;
19  import com.webobjects.foundation.NSDictionary;
20  import com.webobjects.foundation.NSMutableDictionary;
21  
22  /**
23   * The ERXPatternLayout adds some additional (and needed) layout options. The
24   * first is by specifing an '@' character a full backtrace will be logged as part
25   * of the log event. The second is by specifing an '$' char the current application
26   * name of the WOApplication will be logged as part of the log event.
27   * Finally by specifing an '#' char the current port number on which the  
28   * primary adaptor listens to will be logged as part of the log event. 
29   * 
30   * <pre>
31   * WebObjects Applicaion Info Patterns
32   * Example: %W{n[i:p s]} -- MyApp[9300:2001 28] 
33   * 
34   * n: application name
35   * i: pid (process ID, provided through Java system property "com.webobjects.pid") 
36   * p: primary adaptor's port number
37   * s: active session count
38   * 
39   * Java VM (Virtual Machine) Info Patterns
40   * Example: %V{u used/f free} -- 75.22 MB used/12.86 MB free
41   * 
42   * t: total memory
43   * u: used memory 
44   * f: free memory in the current heap size (not max)
45   * 
46   * </pre>
47   * 
48   */
49  // ENHANCEME: Need access to ERXThreadStorage, also need more WO stuff, could opt for a WO char
50  //        and then specify all of the things to log as formatting info for that converter.
51  public class ERXPatternLayout extends PatternLayout {
52  
53      /**
54       * Default constructor. Uses the default conversion
55       * pattern.
56       */
57      public ERXPatternLayout() {
58          this(DEFAULT_CONVERSION_PATTERN);
59      }
60  
61      /**
62       * Default constructor. Uses the specified conversion
63       * pattern.
64       * @param pattern layout to be used.
65       */
66      public ERXPatternLayout(String pattern) {
67          super(pattern);
68      }
69  
70      /**
71       * Creates a pattern parser for the given pattern.
72       * This method is called implicitly by the log4j
73       * logging system.
74       * @param pattern to create the pattern parser for
75       * @return an ERXPatternParser for the given pattern
76       */
77      public PatternParser createPatternParser(String pattern) {
78          return new ERXPatternParser(pattern == null ? DEFAULT_CONVERSION_PATTERN : pattern);
79    }
80  }
81  
82  /**
83   * Pattern parser extension that adds support for WebObjects
84   * specific patterns.
85   */
86  class ERXPatternParser extends PatternParser {
87  
88      /**
89       * Default constructor for a given pattern
90       * @param pattern to construct the parser for
91       */
92      public ERXPatternParser(String pattern) {
93          super(pattern);
94      }
95  
96      /**
97       * Creates a converter for a particular
98       * character. This is the method that
99       * adds the custom converters for WO.
100      * @param c char to add the converter for
101      */
102     public void finalizeConverter(char c) {
103         switch (c) {
104             case '$': 
105                 addConverter(new AppNamePatternConverter(formattingInfo));
106                 currentLiteral.setLength(0);
107                 break;
108             case '#': 
109                 addConverter(new AdaptorPortNumberConverter(formattingInfo));
110                 currentLiteral.setLength(0);
111                 break;
112             case '@':
113                 addConverter(new StackTracePatternConverter(formattingInfo));
114                 currentLiteral.setLength(0);
115                 break;
116             case 'W':
117                 addConverter(new AppInfoPatternConverter(formattingInfo, extractOption()));
118                 currentLiteral.setLength(0);
119                 break;
120             case 'V':
121                 addConverter(new JavaVMInfoPatternConverter(formattingInfo, extractOption()));
122                 currentLiteral.setLength(0);
123                 break;
124             default: 
125                 super.finalizeConverter(c);            
126                 break;
127         }
128     }
129 
130     /**
131      * The stack trace pattern is useful for logging full stack traces
132      * when a log event occurs.
133      */
134     private class StackTracePatternConverter extends PatternConverter {
135         /**
136          * Package access level constructor.
137          * @param formattingInfo that is currently being used for this
138          *    pattern converter.
139          */
140         StackTracePatternConverter(FormattingInfo formattingInfo) {
141             super(formattingInfo);
142         }
143 
144         /**
145          * For a given log event returns the string representation
146          * of a stack trace for the current logging call minus all
147          * of the log4j stack.
148          * @param event current logging event
149          * @return string representation of the current backtrace.
150          */
151         public String convert(LoggingEvent event) {
152             NSArray parts = NSArray.componentsSeparatedByString(ERXUtilities.stackTrace(), "\n\t");
153             NSMutableArray subParts = new NSMutableArray();
154             boolean first = true;
155             for (Enumeration e = parts.reverseObjectEnumerator(); e.hasMoreElements();) {
156                 String element = (String)e.nextElement();
157                 if (element.indexOf("org.apache.log4j") != -1)
158                     break;
159                 if (!first)
160                     subParts.insertObjectAtIndex(element, 0);
161                 else
162                     first = false;                    
163             }
164             return "\t" + subParts.componentsJoinedByString("\n\t") + "\n";
165         }        
166     }
167 
168     /**
169      * The application name pattern converter is useful for logging
170      * the current application name in log statements.
171      * 
172      * @deprecated 
173      */
174     private class AppNamePatternConverter extends PatternConverter {
175         /** holds a reference to the app name */
176         String _appName;
177 
178         /**
179          * Default package level constructor
180          * @param formattingInfo current pattern formatting information
181          */
182         AppNamePatternConverter(FormattingInfo formattingInfo) {
183             super(formattingInfo);
184         }
185 
186         /**
187          * Returns the current application name for the
188          * current logging event. If the application instance
189          * has not been created yet then "N/A" is logged.
190          * @param event a given logging event
191          * @return the current application name
192          */
193         public String convert(LoggingEvent event) {
194             if (_appName == null) {
195                 if (WOApplication.application() != null)
196                     _appName = WOApplication.application().name();
197             }
198             return _appName != null ? _appName : "N/A";
199         }
200     }
201     
202     /**
203      * The adaptor port number pattern converter is useful for logging
204      * the current primary adaptor port in log statements.
205      *
206      * @deprecated 
207      */
208     private class AdaptorPortNumberConverter extends PatternConverter {
209         /** holds a reference to the primary adaptor port */
210         String _portNumber;
211         
212         /**
213          * Default package level constructor
214          * @param formattingInfo current pattern formatting information
215          */
216         AdaptorPortNumberConverter(FormattingInfo formattingInfo) {
217             super(formattingInfo);
218         }
219         
220         /**
221          * Returns the current port number on which the  
222          * primary adaptor listens to. 
223          * This will be the same number specified
224          * by WOPort launch argument.
225          * <p> 
226          * If the application or adapter instance 
227          * has not been created yet then "N/A" is logged.
228          * @param event a given logging event
229          * @return the current application name
230          */
231         public String convert(LoggingEvent event) {
232             if (_portNumber == null) {
233                 if (WOApplication.application() != null) {
234                     //_portNumber = WOApplication.application().port().toString();
235 
236                     // WO 5.1.x -- Apple Ref# 2260519
237                     NSArray adaptors = WOApplication.application().adaptors();
238                     if (adaptors != null  &&  adaptors.count() > 0) {
239                         WOAdaptor primaryAdaptor = (WOAdaptor)adaptors.objectAtIndex(0);
240                         _portNumber = String.valueOf(primaryAdaptor.port()); 
241                     }
242                 }
243             }
244             return _portNumber != null ? _portNumber : "N/A";
245         }
246     }
247 
248     /**
249      * The <code>AppInfoPatternConverter</code> is useful for logging
250      * various info about the WebObjects applicaiton instance. 
251      * See {@link ERXPatternLayout} for example/supported partterns. 
252      */
253     private class AppInfoPatternConverter extends PatternConverter {
254 
255         /** Template parser to format logging events */
256         private ERXSimpleTemplateParser _templateParser;
257 
258         /** Template used by _templateParser */
259         private String _template;
260         
261         /** 
262          * Flag to indicate if the constant values are set. 
263          * The constant values are the part of application info that 
264          * shouldn't change during the application's life span. 
265          */
266         private boolean _constantsInitialized = false;
267         
268         /** Holds the values for the application info. Used by the template parser */ 
269         private NSMutableDictionary _appInfo;
270         
271         /** 
272          * Holds the default labels for the values. 
273          * Note that the template parser will put "-" for undefined 
274          * values by defauilt. 
275          */
276         private final NSDictionary _defaultLabels = 
277             ERXDictionaryUtilities.dictionaryWithObjectsAndKeys(new Object[] {"@sessionCount@", "sessionCount"});
278         
279         /**
280          * Default package level constructor
281          * 
282          * @param  formattingInfo current pattern formatting information
283          * @param  format  string for the logging event format 
284          */
285         // FIXME: Work in progress - fixed template; format parameter will be ignored for now. 
286         AppInfoPatternConverter(FormattingInfo formattingInfo, String format) {
287             super(formattingInfo);
288             _templateParser = new ERXSimpleTemplateParser("-");
289             // This will prevent the convert method to get into an infinite loop 
290             // when debug level logging is enabled for the perser. 
291             _templateParser.isLoggingDisabled = true;
292             _appInfo = new NSMutableDictionary();
293             // work in progress; this is the fixed template.
294             _template = "@appName@[@pid@:@portNumber@ @sessionCount@]";
295         }
296         
297         /**
298          * Returns ...
299          * <p> 
300          * 
301          * ... has not been created yet then "-" is logged.
302          * 
303          * @param event a given logging event
304          * @return the current application name
305          */
306         public String convert(LoggingEvent event) {
307             WOApplication app = WOApplication.application();
308             if (app != null) {
309                 
310                 if (! _constantsInitialized) {
311                     String pid = System.getProperty("com.webobjects.pid");
312                     if (pid != null)
313                         _appInfo.setObjectForKey(pid, "pid");
314 
315                     String appName = app.name();
316                     if (appName != null) 
317                         _appInfo.setObjectForKey(appName, "appName");
318 
319                     if (app.port() != null && app.port().intValue() > 0) {
320                         _appInfo.setObjectForKey(app.port().toString(), "portNumber");
321                     } else {
322                         // WO 5.1.x -- Apple Ref# 2260519
323                         NSArray adaptors = app.adaptors();
324                         if (adaptors != null  &&  adaptors.count() > 0) {
325                             WOAdaptor primaryAdaptor = (WOAdaptor)adaptors.objectAtIndex(0);
326                             String portNumber = String.valueOf(primaryAdaptor.port());
327                             if (portNumber != null)
328                                 _appInfo.setObjectForKey(portNumber, "portNumber");
329                         }                        
330                     }
331                     
332                     _template = _templateParser.parseTemplateWithObject(_template, "@", _appInfo, _defaultLabels);
333                     _constantsInitialized = true;
334                 }
335                 
336                 _appInfo.setObjectForKey(String.valueOf(app.activeSessionsCount()), "sessionCount");
337             }
338             return _templateParser.parseTemplateWithObject(_template, "@", _appInfo);
339         }
340     }
341 
342     /**
343      * The <code>JavaVMInfoPatternConverter</code> is useful for logging
344      * various info about the Java runtime and Virtual Machine that 
345      * is running the application instance. 
346      * See {@link ERXPatternLayout} for example/supported partterns. 
347      */
348     private class JavaVMInfoPatternConverter extends PatternConverter {
349 
350         /** */
351         private Runtime _runtime;
352 
353         /** */
354         private ERXUnitAwareDecimalFormat _decimalFormatter;
355 
356         /** Template parser to format logging events */
357         private ERXSimpleTemplateParser _templateParser;
358 
359         /** Template used by _templateParser */
360         private String _template;
361         
362         /** 
363          * Flag to indicate if the constant values are set. 
364          * The constant values are the part of application info that 
365          * shouldn't change during the application's life span. 
366          */
367         private boolean _constantsInitialized = false;
368         
369         /** Holds the values for the JavaVM info. Used by the template parser */ 
370         private NSMutableDictionary _jvmInfo;
371         
372         /** 
373          * Holds the default labels for the values. 
374          * Note that the template parser will put "-" for undefined 
375          * values by defauilt. 
376          */
377         private final NSDictionary _defaultLabels = null;
378         
379         /**
380          * Default package level constructor
381          * 
382          * @param  formattingInfo current pattern formatting information
383          * @param  format  string for the logging event format 
384          */
385         // FIXME: Work in progress - fixed template; format parameter will be ignored for now. 
386         JavaVMInfoPatternConverter(FormattingInfo formattingInfo, String format) {
387             super(formattingInfo);
388             _runtime = Runtime.getRuntime();
389             _decimalFormatter = new ERXUnitAwareDecimalFormat(ERXUnitAwareDecimalFormat.BYTE);
390             _decimalFormatter.setMaximumFractionDigits(2);
391             _templateParser = new ERXSimpleTemplateParser("-");
392             // This will prevent the convert method to get into an infinite loop 
393             // when debug level logging is enabled for the perser. 
394             _templateParser.isLoggingDisabled = true;
395             _jvmInfo = new NSMutableDictionary();
396             // work in progress; this is the fixed template.
397             _template = "@usedMemory@ used/@freeMemory@ free";
398         }
399         
400         /**
401          * Returns ...
402          * <p> 
403          * 
404          * ... has not been created yet then "-" is logged.
405          * 
406          * @param event a given logging event
407          * @return the current application name
408          */
409         public String convert(LoggingEvent event) {
410             if (! _constantsInitialized) {
411                 // Initialize constants here
412                 _constantsInitialized = true;
413             }
414             
415             long totalMemory = _runtime.totalMemory();
416             long freeMemory  = _runtime.freeMemory();
417             long usedMemory  = totalMemory - freeMemory;
418             _jvmInfo.setObjectForKey(_decimalFormatter.format(totalMemory), "totalMemory");
419             _jvmInfo.setObjectForKey(_decimalFormatter.format(freeMemory),  "freeMemory" );
420             _jvmInfo.setObjectForKey(_decimalFormatter.format(usedMemory),  "usedMemory" );
421 
422             return _templateParser.parseTemplateWithObject(_template, "@", _jvmInfo);
423         }
424     }
425 
426 }