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 package org.apache.log4j.gui; 18 19 20 import java.awt.Color; 21 import java.awt.Image; 22 import java.awt.Toolkit; 23 import java.io.*; 24 import java.net.URL; 25 import java.util.Enumeration; 26 import java.util.StringTokenizer; 27 import java.util.Hashtable; 28 import java.util.ArrayList; 29 30 import javax.swing.JPanel; 31 32 import org.apache.log4j.*; 33 34 import org.apache.log4j.spi.LoggingEvent; 35 import org.apache.log4j.helpers.Loader; 36 import org.apache.log4j.helpers.QuietWriter; 37 import org.apache.log4j.helpers.TracerPrintWriter; 38 import org.apache.log4j.helpers.OptionConverter; 39 40 41 /** 42 * 43 * @author James House 44 */ 45 46 public class TextPanelAppender extends AppenderSkeleton { 47 48 TracerPrintWriter tp; 49 StringWriter sw; 50 QuietWriter qw; 51 LogTextPanel logTextPanel; 52 LogPublishingThread logPublisher; 53 54 final String COLOR_OPTION_FATAL = "Color.Fatal"; 55 final String COLOR_OPTION_ERROR = "Color.Error"; 56 final String COLOR_OPTION_WARN = "Color.Warn"; 57 final String COLOR_OPTION_INFO = "Color.Info"; 58 final String COLOR_OPTION_DEBUG = "Color.Debug"; 59 final String COLOR_OPTION_BACKGROUND = "Color.Background"; 60 final String FONT_NAME_OPTION = "Font.Name"; 61 final String FONT_SIZE_OPTION = "Font.Size"; 62 final String EVENT_BUFFER_SIZE_OPTION = "EventBuffer.Size"; 63 TextPanelAppender(Layout layout, String name)64 public TextPanelAppender(Layout layout, String name) { 65 this.layout = layout; 66 this.name = name; 67 this.sw = new StringWriter(); 68 this.qw = new QuietWriter(sw, errorHandler); 69 this.tp = new TracerPrintWriter(qw); 70 setLogTextPanel(new LogTextPanel()); 71 logPublisher = new LogPublishingThread(logTextPanel, Priority.ERROR, 500); 72 //logPublisher = new LogPublishingThread(logTextPanel, null, 500); 73 } 74 75 public close()76 void close() { 77 } 78 append(LoggingEvent event)79 public void append(LoggingEvent event) { 80 81 String text = this.layout.format(event); 82 83 // Print Stacktrace 84 // Quick Hack maybe there is a better/faster way? 85 if (event.throwable!=null) { 86 event.throwable.printStackTrace(tp); 87 for (int i=0; i< sw.getBuffer().length(); i++) { 88 if (sw.getBuffer().charAt(i)=='\t') 89 sw.getBuffer().replace(i,i+1," "); 90 } 91 text += sw.toString(); 92 sw.getBuffer().delete(0,sw.getBuffer().length()); 93 } 94 else 95 if(!text.endsWith("\n")) 96 text += "\n"; 97 98 logPublisher.publishEvent(event.priority, text); 99 } 100 101 public getLogTextPanel()102 JPanel getLogTextPanel() { 103 return logTextPanel; 104 } 105 106 public getOptionStrings()107 String[] getOptionStrings() { 108 return new String[] { COLOR_OPTION_FATAL, COLOR_OPTION_ERROR, 109 COLOR_OPTION_WARN, COLOR_OPTION_INFO, COLOR_OPTION_DEBUG, 110 COLOR_OPTION_BACKGROUND, FONT_NAME_OPTION, FONT_SIZE_OPTION}; 111 } 112 113 114 public setName(String name)115 void setName(String name) { 116 this.name = name; 117 } 118 119 protected setLogTextPanel(LogTextPanel logTextPanel)120 void setLogTextPanel(LogTextPanel logTextPanel) { 121 this.logTextPanel = logTextPanel; 122 logTextPanel.setTextBackground(Color.white); 123 } 124 125 public setOption(String option, String value)126 void setOption(String option, String value) { 127 if (option.equalsIgnoreCase(COLOR_OPTION_FATAL)) 128 logTextPanel.setTextColor(Priority.FATAL,value); 129 if (option.equalsIgnoreCase(COLOR_OPTION_ERROR)) 130 logTextPanel.setTextColor(Priority.ERROR,value); 131 if (option.equalsIgnoreCase(COLOR_OPTION_WARN)) 132 logTextPanel.setTextColor(Priority.WARN,value); 133 if (option.equalsIgnoreCase(COLOR_OPTION_INFO)) 134 logTextPanel.setTextColor(Priority.INFO,value); 135 if (option.equalsIgnoreCase(COLOR_OPTION_DEBUG)) 136 logTextPanel.setTextColor(Priority.DEBUG,value); 137 if (option.equalsIgnoreCase(COLOR_OPTION_BACKGROUND)) 138 logTextPanel.setTextBackground(value); 139 if (option.equalsIgnoreCase(FONT_SIZE_OPTION)) 140 logTextPanel.setTextFontSize(Integer.parseInt(value)); 141 if (option.equalsIgnoreCase(FONT_NAME_OPTION)) 142 logTextPanel.setTextFontName(value); 143 if (option.equalsIgnoreCase(EVENT_BUFFER_SIZE_OPTION)) 144 logTextPanel.setEventBufferSize(Integer.parseInt(value)); 145 return; 146 } 147 148 public requiresLayout()149 boolean requiresLayout() { 150 return true; 151 } 152 153 154 155 class LogPublishingThread extends Thread { 156 157 LogTextPanel logTextPanel; 158 ArrayList evts; 159 Priority triggerPrio; 160 long pubInterval; 161 LogPublishingThread(LogTextPanel logTextPanel, Priority triggerPrio, long pubInterval)162 public LogPublishingThread(LogTextPanel logTextPanel, Priority triggerPrio, long pubInterval) { 163 this.logTextPanel = logTextPanel; 164 this.evts = new ArrayList(1000); 165 this.triggerPrio = triggerPrio; 166 this.pubInterval = pubInterval; 167 //this.setPriority(Thread.NORM_PRIORITY - 1); 168 this.start(); 169 } 170 run()171 public void run() { 172 while(true) { 173 synchronized(evts) { 174 try { 175 evts.wait(pubInterval); 176 } 177 catch(InterruptedException e) {} 178 179 logTextPanel.newEvents((EventBufferElement[])evts.toArray(new EventBufferElement[evts.size()])); 180 181 evts.clear(); 182 } 183 } 184 185 } 186 publishEvent(Priority prio, String text)187 public void publishEvent(Priority prio, String text) { 188 synchronized(evts) { 189 evts.add(new EventBufferElement(prio, text)); 190 if(triggerPrio != null && prio.isGreaterOrEqual(triggerPrio)) 191 evts.notify(); 192 } 193 } 194 } 195 196 } // TextPaneAppender 197 198 class EventBufferElement { 199 200 public String text; 201 public Priority prio; 202 public int numLines; 203 EventBufferElement(Priority prio, String text)204 EventBufferElement(Priority prio, String text) { 205 this.prio = prio; 206 this.text = text; 207 numLines = 1; 208 int pos = pos = text.indexOf('\n', 0); 209 int len = text.length() - 1; 210 211 while( (pos > 0) && (pos < len) ) 212 numLines++; 213 pos = text.indexOf('\n', pos + 1); 214 } 215 } 216 217 218