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 }