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