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