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