View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.log4j.lf5;
19  
20  import org.apache.log4j.lf5.util.Resource;
21  import org.apache.log4j.lf5.viewer.LogBrokerMonitor;
22  import org.apache.log4j.AppenderSkeleton;
23  import org.apache.log4j.spi.LocationInfo;
24  import org.apache.log4j.spi.LoggingEvent;
25  
26  import java.awt.*;
27  
28  /***
29   * <code>LF5Appender</code> logs events to a swing based logging
30   * console. The swing console supports turning categories on and off,
31   * multiple detail level views, as well as full text searching and many
32   * other capabilties.
33   *
34   * @author Brent Sprecher
35   */
36  
37  // Contributed by ThoughtWorks Inc.
38  
39  public class LF5Appender extends AppenderSkeleton {
40    //--------------------------------------------------------------------------
41    // Constants:
42    //--------------------------------------------------------------------------
43  
44    //--------------------------------------------------------------------------
45    // Protected Variables:
46    //--------------------------------------------------------------------------
47  
48    protected LogBrokerMonitor _logMonitor;
49    protected static LogBrokerMonitor _defaultLogMonitor;
50    protected static AppenderFinalizer _finalizer;
51  
52    //--------------------------------------------------------------------------
53    // Private Variables:
54    //--------------------------------------------------------------------------
55  
56    //--------------------------------------------------------------------------
57    // Constructors:
58    //--------------------------------------------------------------------------
59  
60    /***
61     * Constructs a <code>LF5Appender</code> using the default instance of
62     * the <code>LogBrokerMonitor</code>. This constructor should <bold>always
63     * </bold> be  preferred over the
64     * <code>LF5Appender(LogBrokerMonitor monitor)</code>
65     * constructor, unless you need to spawn additional log monitoring
66     * windows.
67     */
68    public LF5Appender() {
69      this(getDefaultInstance());
70    }
71  
72    /***
73     * Constructs a <code>LF5Appender<code> using an instance of
74     * a <code>LogBrokerMonitor<code> supplied by the user. This
75     * constructor should only be used when you need to spawn
76     * additional log monitoring windows.
77     *
78     * @param monitor An instance of a <code>LogBrokerMonitor<code>
79     * created by the user.
80     */
81    public LF5Appender(LogBrokerMonitor monitor) {
82  
83      if (monitor != null) {
84        _logMonitor = monitor;
85      }
86    }
87  
88    //--------------------------------------------------------------------------
89    // Public Methods:
90    //--------------------------------------------------------------------------
91  
92    /***
93     * Appends a <code>LoggingEvent</code> record to the
94     * <code>LF5Appender</code>.
95     * @param event The <code>LoggingEvent</code>
96     * to be appended.
97     */
98    public void append(LoggingEvent event) {
99      // Retrieve the information from the log4j LoggingEvent.
100     String category = event.getLoggerName();
101     String logMessage = event.getRenderedMessage();
102     String nestedDiagnosticContext = event.getNDC();
103     String threadDescription = event.getThreadName();
104     String level = event.getLevel().toString();
105     long time = event.timeStamp;
106     LocationInfo locationInfo = event.getLocationInformation();
107 
108     // Add the logging event information to a LogRecord
109     Log4JLogRecord record = new Log4JLogRecord();
110 
111     record.setCategory(category);
112     record.setMessage(logMessage);
113     record.setLocation(locationInfo.fullInfo);
114     record.setMillis(time);
115     record.setThreadDescription(threadDescription);
116 
117     if (nestedDiagnosticContext != null) {
118       record.setNDC(nestedDiagnosticContext);
119     } else {
120       record.setNDC("");
121     }
122 
123     if (event.getThrowableInformation() != null) {
124       record.setThrownStackTrace(event.getThrowableInformation());
125     }
126 
127     try {
128       record.setLevel(LogLevel.valueOf(level));
129     } catch (LogLevelFormatException e) {
130       // If the priority level doesn't match one of the predefined
131       // log levels, then set the level to warning.
132       record.setLevel(LogLevel.WARN);
133     }
134 
135     if (_logMonitor != null) {
136       _logMonitor.addMessage(record);
137     }
138   }
139 
140   /***
141    * This method is an empty implementation of the close() method inherited
142    * from the <code>org.apache.log4j.Appender</code> interface.
143    */
144   public void close() {
145   }
146 
147   /***
148    * Returns a value that indicates whether this appender requires a
149    * <code>Layout</code>. This method always returns false.
150    * No layout is required for the <code>LF5Appender</code>.
151    */
152   public boolean requiresLayout() {
153     return false;
154   }
155 
156   /***
157    * This method is used to set the property that controls whether
158    * the <code>LogBrokerMonitor</code> is hidden or closed when a user
159    * exits
160    * the monitor. By default, the <code>LogBrokerMonitor</code> will hide
161    * itself when the log window is exited, and the swing thread will
162    * continue to run in the background. If this property is
163    * set to true, the <code>LogBrokerMonitor</code> will call System.exit(0)
164    * and will shut down swing thread and the virtual machine.
165    *
166    * @param callSystemExitOnClose A boolean value indicating whether
167    * to call System.exit(0) when closing the log window.
168    */
169   public void setCallSystemExitOnClose(boolean callSystemExitOnClose) {
170     _logMonitor.setCallSystemExitOnClose(callSystemExitOnClose);
171   }
172 
173   /***
174    * The equals method compares two LF5Appenders and determines whether
175    * they are equal. Two <code>Appenders</code> will be considered equal
176    * if, and only if, they both contain references to the same <code>
177    * LogBrokerMonitor</code>.
178    *
179    * @param compareTo A boolean value indicating whether
180    * the two LF5Appenders are equal.
181    */
182   public boolean equals(LF5Appender compareTo) {
183     // If both reference the same LogBrokerMonitor, they are equal.
184     return _logMonitor == compareTo.getLogBrokerMonitor();
185   }
186 
187   public LogBrokerMonitor getLogBrokerMonitor() {
188     return _logMonitor;
189   }
190 
191   public static void main(String[] args) {
192     new LF5Appender();
193   }
194 
195   public void setMaxNumberOfRecords(int maxNumberOfRecords) {
196     _defaultLogMonitor.setMaxNumberOfLogRecords(maxNumberOfRecords);
197   }
198   //--------------------------------------------------------------------------
199   // Protected Methods:
200   //--------------------------------------------------------------------------
201 
202   /***
203    * @return The default instance of the <code>LogBrokerMonitor</code>.
204    */
205   protected static synchronized LogBrokerMonitor getDefaultInstance() {
206     if (_defaultLogMonitor == null) {
207       try {
208         _defaultLogMonitor =
209             new LogBrokerMonitor(LogLevel.getLog4JLevels());
210         _finalizer = new AppenderFinalizer(_defaultLogMonitor);
211 
212         _defaultLogMonitor.setFrameSize(getDefaultMonitorWidth(),
213             getDefaultMonitorHeight());
214         _defaultLogMonitor.setFontSize(12);
215         _defaultLogMonitor.show();
216 
217       } catch (SecurityException e) {
218         _defaultLogMonitor = null;
219       }
220     }
221 
222     return _defaultLogMonitor;
223   }
224 
225   /***
226    * @return the screen width from Toolkit.getScreenSize()
227    * if possible, otherwise returns 800
228    * @see java.awt.Toolkit
229    */
230   protected static int getScreenWidth() {
231     try {
232       return Toolkit.getDefaultToolkit().getScreenSize().width;
233     } catch (Throwable t) {
234       return 800;
235     }
236   }
237 
238   /***
239    * @return the screen height from Toolkit.getScreenSize()
240    * if possible, otherwise returns 600
241    * @see java.awt.Toolkit
242    */
243   protected static int getScreenHeight() {
244     try {
245       return Toolkit.getDefaultToolkit().getScreenSize().height;
246     } catch (Throwable t) {
247       return 600;
248     }
249   }
250 
251   protected static int getDefaultMonitorWidth() {
252     return (3 * getScreenWidth()) / 4;
253   }
254 
255   protected static int getDefaultMonitorHeight() {
256     return (3 * getScreenHeight()) / 4;
257   }
258   //--------------------------------------------------------------------------
259   // Private Methods:
260   //--------------------------------------------------------------------------
261 
262 
263   //--------------------------------------------------------------------------
264   // Nested Top-Level Classes or Interfaces:
265   //--------------------------------------------------------------------------
266 
267 }