1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.log4j.net;
21
22 import java.io.IOException;
23 import java.io.ObjectOutputStream;
24 import java.io.InterruptedIOException;
25 import java.net.InetAddress;
26 import java.net.Socket;
27
28 import org.apache.log4j.AppenderSkeleton;
29 import org.apache.log4j.helpers.LogLog;
30 import org.apache.log4j.spi.ErrorCode;
31 import org.apache.log4j.spi.LoggingEvent;
32
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 public class SocketAppender extends AppenderSkeleton {
103
104
105
106
107
108 static public final int DEFAULT_PORT = 4560;
109
110
111
112
113 static final int DEFAULT_RECONNECTION_DELAY = 30000;
114
115
116
117
118
119 String remoteHost;
120
121
122
123
124 public static final String ZONE = "_log4j_obj_tcpconnect_appender.local.";
125
126 InetAddress address;
127 int port = DEFAULT_PORT;
128 ObjectOutputStream oos;
129 int reconnectionDelay = DEFAULT_RECONNECTION_DELAY;
130 boolean locationInfo = false;
131 private String application;
132
133 private Connector connector;
134
135 int counter = 0;
136
137
138
139 private static final int RESET_FREQUENCY = 1;
140 private boolean advertiseViaMulticastDNS;
141 private ZeroConfSupport zeroConf;
142
143 public SocketAppender() {
144 }
145
146
147
148
149 public SocketAppender(InetAddress address, int port) {
150 this.address = address;
151 this.remoteHost = address.getHostName();
152 this.port = port;
153 connect(address, port);
154 }
155
156
157
158
159 public SocketAppender(String host, int port) {
160 this.port = port;
161 this.address = getAddressByName(host);
162 this.remoteHost = host;
163 connect(address, port);
164 }
165
166
167
168
169 public void activateOptions() {
170 if (advertiseViaMulticastDNS) {
171 zeroConf = new ZeroConfSupport(ZONE, port, getName());
172 zeroConf.advertise();
173 }
174 connect(address, port);
175 }
176
177
178
179
180
181
182
183 synchronized public void close() {
184 if(closed)
185 return;
186
187 this.closed = true;
188 if (advertiseViaMulticastDNS) {
189 zeroConf.unadvertise();
190 }
191
192 cleanUp();
193 }
194
195
196
197
198
199 public void cleanUp() {
200 if(oos != null) {
201 try {
202 oos.close();
203 } catch(IOException e) {
204 if (e instanceof InterruptedIOException) {
205 Thread.currentThread().interrupt();
206 }
207 LogLog.error("Could not close oos.", e);
208 }
209 oos = null;
210 }
211 if(connector != null) {
212
213 connector.interrupted = true;
214 connector = null;
215 }
216 }
217
218 void connect(InetAddress address, int port) {
219 if(this.address == null)
220 return;
221 try {
222
223 cleanUp();
224 oos = new ObjectOutputStream(new Socket(address, port).getOutputStream());
225 } catch(IOException e) {
226 if (e instanceof InterruptedIOException) {
227 Thread.currentThread().interrupt();
228 }
229 String msg = "Could not connect to remote log4j server at ["
230 +address.getHostName()+"].";
231 if(reconnectionDelay > 0) {
232 msg += " We will try again later.";
233 fireConnector();
234 } else {
235 msg += " We are not retrying.";
236 errorHandler.error(msg, e, ErrorCode.GENERIC_FAILURE);
237 }
238 LogLog.error(msg);
239 }
240 }
241
242
243 public void append(LoggingEvent event) {
244 if(event == null)
245 return;
246
247 if(address==null) {
248 errorHandler.error("No remote host is set for SocketAppender named \""+
249 this.name+"\".");
250 return;
251 }
252
253 if(oos != null) {
254 try {
255
256 if(locationInfo) {
257 event.getLocationInformation();
258 }
259 if (application != null) {
260 event.setProperty("application", application);
261 }
262 event.getNDC();
263 event.getThreadName();
264 event.getMDCCopy();
265 event.getRenderedMessage();
266 event.getThrowableStrRep();
267
268 oos.writeObject(event);
269
270 oos.flush();
271 if(++counter >= RESET_FREQUENCY) {
272 counter = 0;
273
274
275
276 oos.reset();
277 }
278 } catch(IOException e) {
279 if (e instanceof InterruptedIOException) {
280 Thread.currentThread().interrupt();
281 }
282 oos = null;
283 LogLog.warn("Detected problem with connection: "+e);
284 if(reconnectionDelay > 0) {
285 fireConnector();
286 } else {
287 errorHandler.error("Detected problem with connection, not reconnecting.", e,
288 ErrorCode.GENERIC_FAILURE);
289 }
290 }
291 }
292 }
293
294 public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
295 this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
296 }
297
298 public boolean isAdvertiseViaMulticastDNS() {
299 return advertiseViaMulticastDNS;
300 }
301
302 void fireConnector() {
303 if(connector == null) {
304 LogLog.debug("Starting a new connector thread.");
305 connector = new Connector();
306 connector.setDaemon(true);
307 connector.setPriority(Thread.MIN_PRIORITY);
308 connector.start();
309 }
310 }
311
312 static
313 InetAddress getAddressByName(String host) {
314 try {
315 return InetAddress.getByName(host);
316 } catch(Exception e) {
317 if (e instanceof InterruptedIOException || e instanceof InterruptedException) {
318 Thread.currentThread().interrupt();
319 }
320 LogLog.error("Could not find address of ["+host+"].", e);
321 return null;
322 }
323 }
324
325
326
327
328
329 public boolean requiresLayout() {
330 return false;
331 }
332
333
334
335
336
337
338 public void setRemoteHost(String host) {
339 address = getAddressByName(host);
340 remoteHost = host;
341 }
342
343
344
345
346 public String getRemoteHost() {
347 return remoteHost;
348 }
349
350
351
352
353
354 public void setPort(int port) {
355 this.port = port;
356 }
357
358
359
360
361 public int getPort() {
362 return port;
363 }
364
365
366
367
368
369
370 public void setLocationInfo(boolean locationInfo) {
371 this.locationInfo = locationInfo;
372 }
373
374
375
376
377 public boolean getLocationInfo() {
378 return locationInfo;
379 }
380
381
382
383
384
385
386
387 public void setApplication(String lapp) {
388 this.application = lapp;
389 }
390
391
392
393
394
395 public String getApplication() {
396 return application;
397 }
398
399
400
401
402
403
404
405
406
407
408 public void setReconnectionDelay(int delay) {
409 this.reconnectionDelay = delay;
410 }
411
412
413
414
415 public int getReconnectionDelay() {
416 return reconnectionDelay;
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430
431 class Connector extends Thread {
432
433 boolean interrupted = false;
434
435 public
436 void run() {
437 Socket socket;
438 while(!interrupted) {
439 try {
440 sleep(reconnectionDelay);
441 LogLog.debug("Attempting connection to "+address.getHostName());
442 socket = new Socket(address, port);
443 synchronized(this) {
444 oos = new ObjectOutputStream(socket.getOutputStream());
445 connector = null;
446 LogLog.debug("Connection established. Exiting connector thread.");
447 break;
448 }
449 } catch(InterruptedException e) {
450 LogLog.debug("Connector interrupted. Leaving loop.");
451 return;
452 } catch(java.net.ConnectException e) {
453 LogLog.debug("Remote host "+address.getHostName()
454 +" refused connection.");
455 } catch(IOException e) {
456 if (e instanceof InterruptedIOException) {
457 Thread.currentThread().interrupt();
458 }
459 LogLog.debug("Could not connect to " + address.getHostName()+
460 ". Exception is " + e);
461 }
462 }
463
464 }
465
466
467
468
469
470
471
472 }
473
474 }