1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.net;
19
20 import java.io.IOException;
21 import java.io.InterruptedIOException;
22 import java.io.ObjectOutputStream;
23 import java.net.InetAddress;
24 import java.net.ServerSocket;
25 import java.net.Socket;
26 import java.net.SocketException;
27 import java.util.Vector;
28
29 import org.apache.log4j.AppenderSkeleton;
30 import org.apache.log4j.helpers.CyclicBuffer;
31 import org.apache.log4j.helpers.LogLog;
32 import org.apache.log4j.spi.LoggingEvent;
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 public class SocketHubAppender extends AppenderSkeleton {
109
110
111
112 static final int DEFAULT_PORT = 4560;
113
114 private int port = DEFAULT_PORT;
115 private Vector oosList = new Vector();
116 private ServerMonitor serverMonitor = null;
117 private boolean locationInfo = false;
118 private CyclicBuffer buffer = null;
119 private String application;
120 private boolean advertiseViaMulticastDNS;
121 private ZeroConfSupport zeroConf;
122
123
124
125
126 public static final String ZONE = "_log4j_obj_tcpaccept_appender.local.";
127
128
129 public SocketHubAppender() { }
130
131
132
133 public
134 SocketHubAppender(int _port) {
135 port = _port;
136 startServer();
137 }
138
139
140
141 public
142 void activateOptions() {
143 if (advertiseViaMulticastDNS) {
144 zeroConf = new ZeroConfSupport(ZONE, port, getName());
145 zeroConf.advertise();
146 }
147 startServer();
148 }
149
150
151
152
153
154 synchronized
155 public
156 void close() {
157 if(closed)
158 return;
159
160 LogLog.debug("closing SocketHubAppender " + getName());
161 this.closed = true;
162 if (advertiseViaMulticastDNS) {
163 zeroConf.unadvertise();
164 }
165 cleanUp();
166
167 LogLog.debug("SocketHubAppender " + getName() + " closed");
168 }
169
170
171
172
173 public
174 void cleanUp() {
175
176 LogLog.debug("stopping ServerSocket");
177 serverMonitor.stopMonitor();
178 serverMonitor = null;
179
180
181 LogLog.debug("closing client connections");
182 while (oosList.size() != 0) {
183 ObjectOutputStream oos = (ObjectOutputStream)oosList.elementAt(0);
184 if(oos != null) {
185 try {
186 oos.close();
187 } catch(InterruptedIOException e) {
188 Thread.currentThread().interrupt();
189 LogLog.error("could not close oos.", e);
190 } catch(IOException e) {
191 LogLog.error("could not close oos.", e);
192 }
193
194 oosList.removeElementAt(0);
195 }
196 }
197 }
198
199
200
201 public
202 void append(LoggingEvent event) {
203 if (event != null) {
204
205 if (locationInfo) {
206 event.getLocationInformation();
207 }
208 if (application != null) {
209 event.setProperty("application", application);
210 }
211 event.getNDC();
212 event.getThreadName();
213 event.getMDCCopy();
214 event.getRenderedMessage();
215 event.getThrowableStrRep();
216
217 if (buffer != null) {
218 buffer.add(event);
219 }
220 }
221
222
223 if ((event == null) || (oosList.size() == 0)) {
224 return;
225 }
226
227
228 for (int streamCount = 0; streamCount < oosList.size(); streamCount++) {
229
230 ObjectOutputStream oos = null;
231 try {
232 oos = (ObjectOutputStream)oosList.elementAt(streamCount);
233 }
234 catch (ArrayIndexOutOfBoundsException e) {
235
236
237
238 }
239
240
241 if (oos == null)
242 break;
243
244 try {
245 oos.writeObject(event);
246 oos.flush();
247
248
249
250 oos.reset();
251 }
252 catch(IOException e) {
253 if (e instanceof InterruptedIOException) {
254 Thread.currentThread().interrupt();
255 }
256
257 oosList.removeElementAt(streamCount);
258 LogLog.debug("dropped connection");
259
260
261 streamCount--;
262 }
263 }
264 }
265
266
267
268
269 public
270 boolean requiresLayout() {
271 return false;
272 }
273
274
275
276
277 public
278 void setPort(int _port) {
279 port = _port;
280 }
281
282
283
284
285
286 public
287 void setApplication(String lapp) {
288 this.application = lapp;
289 }
290
291
292
293
294 public
295 String getApplication() {
296 return application;
297 }
298
299
300
301 public
302 int getPort() {
303 return port;
304 }
305
306
307
308
309
310 public
311 void setBufferSize(int _bufferSize) {
312 buffer = new CyclicBuffer(_bufferSize);
313 }
314
315
316
317
318 public
319 int getBufferSize() {
320 if (buffer == null) {
321 return 0;
322 } else {
323 return buffer.getMaxSize();
324 }
325 }
326
327
328
329
330
331 public
332 void setLocationInfo(boolean _locationInfo) {
333 locationInfo = _locationInfo;
334 }
335
336
337
338 public
339 boolean getLocationInfo() {
340 return locationInfo;
341 }
342
343 public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
344 this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
345 }
346
347 public boolean isAdvertiseViaMulticastDNS() {
348 return advertiseViaMulticastDNS;
349 }
350
351
352
353 private
354 void startServer() {
355 serverMonitor = new ServerMonitor(port, oosList);
356 }
357
358
359
360
361
362
363
364 protected ServerSocket createServerSocket(final int socketPort) throws IOException {
365 return new ServerSocket(socketPort);
366 }
367
368
369
370
371
372 private
373 class ServerMonitor implements Runnable {
374 private int port;
375 private Vector oosList;
376 private boolean keepRunning;
377 private Thread monitorThread;
378
379
380
381 public
382 ServerMonitor(int _port, Vector _oosList) {
383 port = _port;
384 oosList = _oosList;
385 keepRunning = true;
386 monitorThread = new Thread(this);
387 monitorThread.setDaemon(true);
388 monitorThread.setName("SocketHubAppender-Monitor-" + port);
389 monitorThread.start();
390 }
391
392
393
394
395 public
396 synchronized
397 void stopMonitor() {
398 if (keepRunning) {
399 LogLog.debug("server monitor thread shutting down");
400 keepRunning = false;
401 try {
402 monitorThread.join();
403 }
404 catch (InterruptedException e) {
405 Thread.currentThread().interrupt();
406
407 }
408
409
410 monitorThread = null;
411 LogLog.debug("server monitor thread shut down");
412 }
413 }
414
415 private
416 void sendCachedEvents(ObjectOutputStream stream) throws IOException {
417 if (buffer != null) {
418 for (int i = 0; i < buffer.length(); i++) {
419 stream.writeObject(buffer.get(i));
420 }
421 stream.flush();
422 stream.reset();
423 }
424 }
425
426
427
428
429 public
430 void run() {
431 ServerSocket serverSocket = null;
432 try {
433 serverSocket = createServerSocket(port);
434 serverSocket.setSoTimeout(1000);
435 }
436 catch (Exception e) {
437 if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
438 Thread.currentThread().interrupt();
439 }
440 LogLog.error("exception setting timeout, shutting down server socket.", e);
441 keepRunning = false;
442 return;
443 }
444
445 try {
446 try {
447 serverSocket.setSoTimeout(1000);
448 }
449 catch (SocketException e) {
450 LogLog.error("exception setting timeout, shutting down server socket.", e);
451 return;
452 }
453
454 while (keepRunning) {
455 Socket socket = null;
456 try {
457 socket = serverSocket.accept();
458 }
459 catch (InterruptedIOException e) {
460
461 }
462 catch (SocketException e) {
463 LogLog.error("exception accepting socket, shutting down server socket.", e);
464 keepRunning = false;
465 }
466 catch (IOException e) {
467 LogLog.error("exception accepting socket.", e);
468 }
469
470
471 if (socket != null) {
472 try {
473 InetAddress remoteAddress = socket.getInetAddress();
474 LogLog.debug("accepting connection from " + remoteAddress.getHostName()
475 + " (" + remoteAddress.getHostAddress() + ")");
476
477
478 ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
479 if (buffer != null && buffer.length() > 0) {
480 sendCachedEvents(oos);
481 }
482
483
484 oosList.addElement(oos);
485 } catch (IOException e) {
486 if (e instanceof InterruptedIOException) {
487 Thread.currentThread().interrupt();
488 }
489 LogLog.error("exception creating output stream on socket.", e);
490 }
491 }
492 }
493 }
494 finally {
495
496 try {
497 serverSocket.close();
498 } catch(InterruptedIOException e) {
499 Thread.currentThread().interrupt();
500 } catch (IOException e) {
501
502 }
503 }
504 }
505 }
506 }
507