001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.log4j.lf5; 019 020import java.awt.Toolkit; 021 022import org.apache.log4j.AppenderSkeleton; 023import org.apache.log4j.lf5.viewer.LogBrokerMonitor; 024import org.apache.log4j.spi.LocationInfo; 025import org.apache.log4j.spi.LoggingEvent; 026 027/** 028 * <code>LF5Appender</code> logs events to a swing based logging 029 * console. The swing console supports turning categories on and off, 030 * multiple detail level views, as well as full text searching and many 031 * other capabilties. 032 * 033 * @author Brent Sprecher 034 */ 035 036// Contributed by ThoughtWorks Inc. 037 038public class LF5Appender extends AppenderSkeleton { 039 //-------------------------------------------------------------------------- 040 // Constants: 041 //-------------------------------------------------------------------------- 042 043 //-------------------------------------------------------------------------- 044 // Protected Variables: 045 //-------------------------------------------------------------------------- 046 047 protected LogBrokerMonitor _logMonitor; 048 protected static LogBrokerMonitor _defaultLogMonitor; 049 protected static AppenderFinalizer _finalizer; 050 051 //-------------------------------------------------------------------------- 052 // Private Variables: 053 //-------------------------------------------------------------------------- 054 055 //-------------------------------------------------------------------------- 056 // Constructors: 057 //-------------------------------------------------------------------------- 058 059 /** 060 * Constructs a <code>LF5Appender</code> using the default instance of 061 * the <code>LogBrokerMonitor</code>. This constructor should <bold>always 062 * </bold> be preferred over the 063 * <code>LF5Appender(LogBrokerMonitor monitor)</code> 064 * constructor, unless you need to spawn additional log monitoring 065 * windows. 066 */ 067 public LF5Appender() { 068 this(getDefaultInstance()); 069 } 070 071 /** 072 * Constructs a <code>LF5Appender<code> using an instance of 073 * a <code>LogBrokerMonitor<code> supplied by the user. This 074 * constructor should only be used when you need to spawn 075 * additional log monitoring windows. 076 * 077 * @param monitor An instance of a <code>LogBrokerMonitor<code> 078 * created by the user. 079 */ 080 public LF5Appender(LogBrokerMonitor monitor) { 081 082 if (monitor != null) { 083 _logMonitor = monitor; 084 } 085 } 086 087 //-------------------------------------------------------------------------- 088 // Public Methods: 089 //-------------------------------------------------------------------------- 090 091 /** 092 * Appends a <code>LoggingEvent</code> record to the 093 * <code>LF5Appender</code>. 094 * @param event The <code>LoggingEvent</code> 095 * to be appended. 096 */ 097 public void append(LoggingEvent event) { 098 // Retrieve the information from the log4j LoggingEvent. 099 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}