1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.chainsaw;
18
19 import org.apache.log4j.AppenderSkeleton;
20 import org.apache.log4j.LogManager;
21 import org.apache.log4j.helpers.Constants;
22 import org.apache.log4j.rule.ExpressionRule;
23 import org.apache.log4j.rule.Rule;
24 import org.apache.log4j.spi.LoggerRepositoryEx;
25 import org.apache.log4j.spi.LoggingEvent;
26 import org.apache.log4j.spi.LoggingEventFieldResolver;
27
28 import javax.swing.event.EventListenerList;
29 import java.beans.PropertyChangeListener;
30 import java.beans.PropertyChangeSupport;
31 import java.util.*;
32
33
34
35
36
37
38
39
40
41 public class ChainsawAppenderHandler extends AppenderSkeleton {
42 private static final String DEFAULT_IDENTIFIER = "Unknown";
43 private final Object mutex = new Object();
44 private int sleepInterval = 1000;
45 private EventListenerList listenerList = new EventListenerList();
46 private double dataRate = 0.0;
47 private String identifierExpression;
48 private final LoggingEventFieldResolver resolver = LoggingEventFieldResolver
49 .getInstance();
50 private PropertyChangeSupport propertySupport = new PropertyChangeSupport(
51 this);
52 private Map<String, Rule> customExpressionRules = new HashMap<>();
53
54
55
56
57
58
59
60
61 private WorkQueue worker = new WorkQueue();
62
63 public ChainsawAppenderHandler(final ChainsawAppender appender) {
64 super(true);
65 appender.setAppender(this);
66 }
67
68 public ChainsawAppenderHandler() {
69 super(true);
70 }
71
72 public void setIdentifierExpression(String identifierExpression) {
73 synchronized (mutex) {
74 this.identifierExpression = identifierExpression;
75 mutex.notify();
76 }
77 }
78
79 public String getIdentifierExpression() {
80 return identifierExpression;
81 }
82
83 public void addCustomEventBatchListener(String identifier,
84 EventBatchListener l) throws IllegalArgumentException {
85 customExpressionRules.put(identifier, ExpressionRule.getRule(identifier));
86 listenerList.add(EventBatchListener.class, l);
87 }
88
89 public void addEventBatchListener(EventBatchListener l) {
90 listenerList.add(EventBatchListener.class, l);
91 }
92
93 public void removeEventBatchListener(EventBatchListener l) {
94 listenerList.remove(EventBatchListener.class, l);
95 }
96
97 public void append(LoggingEvent event) {
98 worker.enqueue(event);
99 }
100
101 public void close() {
102 }
103
104 public boolean requiresLayout() {
105 return false;
106 }
107
108 public int getQueueInterval() {
109 return sleepInterval;
110 }
111
112 public void setQueueInterval(int interval) {
113 sleepInterval = interval;
114 }
115
116
117
118
119
120
121
122
123 String getTabIdentifier(LoggingEvent e) {
124 String ident = resolver.applyFields(identifierExpression, e);
125 return ((ident != null) ? ident : DEFAULT_IDENTIFIER);
126 }
127
128
129
130
131
132
133
134
135
136
137
138 public double getDataRate() {
139 return dataRate;
140 }
141
142
143
144
145 void setDataRate(double dataRate) {
146 double oldValue = this.dataRate;
147 this.dataRate = dataRate;
148 propertySupport.firePropertyChange("dataRate", oldValue,
149 this.dataRate);
150 }
151
152
153
154
155 public synchronized void addPropertyChangeListener(
156 PropertyChangeListener listener) {
157 propertySupport.addPropertyChangeListener(listener);
158 }
159
160
161
162
163
164 public synchronized void addPropertyChangeListener(String propertyName,
165 PropertyChangeListener listener) {
166 propertySupport.addPropertyChangeListener(propertyName, listener);
167 }
168
169
170
171
172 public synchronized void removePropertyChangeListener(
173 PropertyChangeListener listener) {
174 propertySupport.removePropertyChangeListener(listener);
175 }
176
177
178
179
180
181 public synchronized void removePropertyChangeListener(String propertyName,
182 PropertyChangeListener listener) {
183 propertySupport.removePropertyChangeListener(propertyName, listener);
184 }
185
186
187
188
189
190
191 class WorkQueue {
192 final ArrayList<LoggingEvent> queue = new ArrayList<>();
193 Thread workerThread;
194
195 protected WorkQueue() {
196 workerThread = new WorkerThread();
197 workerThread.start();
198 }
199
200 public final void enqueue(LoggingEvent event) {
201 synchronized (mutex) {
202 queue.add(event);
203 mutex.notify();
204 }
205 }
206
207 public final void stop() {
208 synchronized (mutex) {
209 workerThread.interrupt();
210 }
211 }
212
213
214
215
216
217 private class WorkerThread extends Thread {
218 public WorkerThread() {
219 super("Chainsaw-WorkerThread");
220 setDaemon(true);
221 setPriority(Thread.NORM_PRIORITY - 1);
222 }
223
224 public void run() {
225 List<LoggingEvent> innerList = new ArrayList<>();
226 while (true) {
227 long timeStart = System.currentTimeMillis();
228 synchronized (mutex) {
229 try {
230 while ((queue.size() == 0) || (identifierExpression == null)) {
231 setDataRate(0);
232 mutex.wait();
233 }
234 if (queue.size() > 0) {
235 innerList.addAll(queue);
236 queue.clear();
237 }
238 } catch (InterruptedException ie) {
239 }
240 }
241 int size = innerList.size();
242 if (size > 0) {
243 Iterator<LoggingEvent> iter = innerList.iterator();
244 ChainsawEventBatch eventBatch = new ChainsawEventBatch();
245 while (iter.hasNext()) {
246 LoggingEvent e = iter.next();
247
248
249
250 if (e.getProperty(Constants.HOSTNAME_KEY) == null) {
251 String remoteHost = e
252 .getProperty(ChainsawConstants.LOG4J_REMOTEHOST_KEY);
253 if (remoteHost != null) {
254 int colonIndex = remoteHost.indexOf(":");
255 if (colonIndex == -1) {
256 colonIndex = remoteHost.length();
257 }
258 e.setProperty(Constants.HOSTNAME_KEY, remoteHost.substring(0,
259 colonIndex));
260 }
261 }
262 for (Object o : customExpressionRules.entrySet()) {
263 Map.Entry entry = (Map.Entry) o;
264 Rule rule = (Rule) entry.getValue();
265 if (rule.evaluate(e, null)) {
266 eventBatch.addEvent((String) entry.getKey(), e);
267 }
268 }
269 eventBatch.addEvent(getTabIdentifier(e), e);
270 }
271 dispatchEventBatch(eventBatch);
272 innerList.clear();
273 }
274 if (getQueueInterval() > 1000) {
275 try {
276 synchronized (this) {
277 wait(getQueueInterval());
278 }
279 } catch (InterruptedException ie) {
280 }
281 } else {
282 Thread.yield();
283 }
284 if (size == 0) {
285 setDataRate(0.0);
286 } else {
287 long timeEnd = System.currentTimeMillis();
288 long diffInSeconds = (timeEnd - timeStart) / 1000;
289 double rate = (((double) size) / diffInSeconds);
290 setDataRate(rate);
291 }
292 }
293 }
294
295
296
297
298
299
300
301
302 private void dispatchEventBatch(ChainsawEventBatch eventBatch) {
303 EventBatchListener[] listeners = listenerList
304 .getListeners(EventBatchListener.class);
305 for (Iterator<String> iter = eventBatch.identifierIterator(); iter.hasNext(); ) {
306 String identifier = iter.next();
307 List<LoggingEvent> eventList = null;
308 for (EventBatchListener listener : listeners) {
309 if ((listener.getInterestedIdentifier() == null)
310 || listener.getInterestedIdentifier().equals(identifier)) {
311 if (eventList == null) {
312 eventList = eventBatch.entrySet(identifier);
313 }
314 listener.receiveEventBatch(identifier, eventList);
315 }
316 }
317 }
318 }
319 }
320 }
321 }