1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.appender;
18
19 import java.io.Serializable;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.concurrent.TimeUnit;
23
24 import org.apache.logging.log4j.core.AbstractLifeCycle;
25 import org.apache.logging.log4j.core.Appender;
26 import org.apache.logging.log4j.core.Core;
27 import org.apache.logging.log4j.core.Filter;
28 import org.apache.logging.log4j.core.Layout;
29 import org.apache.logging.log4j.core.LogEvent;
30 import org.apache.logging.log4j.core.config.Configuration;
31 import org.apache.logging.log4j.core.config.plugins.Plugin;
32 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
33 import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
34 import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
35 import org.apache.logging.log4j.core.config.plugins.PluginElement;
36 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
37 import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
38 import org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
39 import org.apache.logging.log4j.core.net.AbstractSocketManager;
40 import org.apache.logging.log4j.core.net.Advertiser;
41 import org.apache.logging.log4j.core.net.DatagramSocketManager;
42 import org.apache.logging.log4j.core.net.Protocol;
43 import org.apache.logging.log4j.core.net.SocketOptions;
44 import org.apache.logging.log4j.core.net.SslSocketManager;
45 import org.apache.logging.log4j.core.net.TcpSocketManager;
46 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
47 import org.apache.logging.log4j.core.util.Booleans;
48
49
50
51
52 @Plugin(name = "Socket", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
53 public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketManager> {
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 public static abstract class AbstractBuilder<B extends AbstractBuilder<B>> extends AbstractOutputStreamAppender.Builder<B> {
72
73 @PluginBuilderAttribute
74 private boolean advertise;
75
76 @PluginBuilderAttribute
77 private int connectTimeoutMillis;
78
79 @PluginBuilderAttribute
80 @ValidHost
81 private String host = "localhost";
82
83 @PluginBuilderAttribute
84 private boolean immediateFail = true;
85
86 @PluginBuilderAttribute
87 @ValidPort
88 private int port;
89
90 @PluginBuilderAttribute
91 private Protocol protocol = Protocol.TCP;
92
93 @PluginBuilderAttribute
94 @PluginAliases({ "reconnectDelay", "reconnectionDelay", "delayMillis", "reconnectionDelayMillis" })
95 private int reconnectDelayMillis;
96
97 @PluginElement("SocketOptions")
98 private SocketOptions socketOptions;
99
100 @PluginElement("SslConfiguration")
101 @PluginAliases({ "SslConfig" })
102 private SslConfiguration sslConfiguration;
103
104 public boolean getAdvertise() {
105 return advertise;
106 }
107
108 public int getConnectTimeoutMillis() {
109 return connectTimeoutMillis;
110 }
111
112 public String getHost() {
113 return host;
114 }
115
116 public int getPort() {
117 return port;
118 }
119
120 public Protocol getProtocol() {
121 return protocol;
122 }
123
124 public SslConfiguration getSslConfiguration() {
125 return sslConfiguration;
126 }
127
128 public boolean getImmediateFail() {
129 return immediateFail;
130 }
131
132 public B withAdvertise(final boolean advertise) {
133 this.advertise = advertise;
134 return asBuilder();
135 }
136
137 public B withConnectTimeoutMillis(final int connectTimeoutMillis) {
138 this.connectTimeoutMillis = connectTimeoutMillis;
139 return asBuilder();
140 }
141
142 public B withHost(final String host) {
143 this.host = host;
144 return asBuilder();
145 }
146
147 public B withImmediateFail(final boolean immediateFail) {
148 this.immediateFail = immediateFail;
149 return asBuilder();
150 }
151
152 public B withPort(final int port) {
153 this.port = port;
154 return asBuilder();
155 }
156
157 public B withProtocol(final Protocol protocol) {
158 this.protocol = protocol;
159 return asBuilder();
160 }
161
162 public B withReconnectDelayMillis(final int reconnectDelayMillis) {
163 this.reconnectDelayMillis = reconnectDelayMillis;
164 return asBuilder();
165 }
166
167 public B withSocketOptions(final SocketOptions socketOptions) {
168 this.socketOptions = socketOptions;
169 return asBuilder();
170 }
171
172 public B withSslConfiguration(final SslConfiguration sslConfiguration) {
173 this.sslConfiguration = sslConfiguration;
174 return asBuilder();
175 }
176
177 public int getReconnectDelayMillis() {
178 return reconnectDelayMillis;
179 }
180
181 public SocketOptions getSocketOptions() {
182 return socketOptions;
183 }
184
185 }
186
187
188
189
190
191
192
193
194 public static class Builder extends AbstractBuilder<Builder>
195 implements org.apache.logging.log4j.core.util.Builder<SocketAppender> {
196
197 @SuppressWarnings("resource")
198 @Override
199 public SocketAppender build() {
200 boolean immediateFlush = isImmediateFlush();
201 final boolean bufferedIo = isBufferedIo();
202 final Layout<? extends Serializable> layout = getLayout();
203 if (layout == null) {
204 AbstractLifeCycle.LOGGER.error("No layout provided for SocketAppender");
205 return null;
206 }
207
208 final String name = getName();
209 if (name == null) {
210 AbstractLifeCycle.LOGGER.error("No name provided for SocketAppender");
211 return null;
212 }
213
214 final Protocol protocol = getProtocol();
215 final Protocol actualProtocol = protocol != null ? protocol : Protocol.TCP;
216 if (actualProtocol == Protocol.UDP) {
217 immediateFlush = true;
218 }
219
220 final AbstractSocketManager manager = SocketAppender.createSocketManager(name, actualProtocol, getHost(), getPort(),
221 getConnectTimeoutMillis(), getSslConfiguration(), getReconnectDelayMillis(), getImmediateFail(), layout, getBufferSize(), getSocketOptions());
222
223 return new SocketAppender(name, layout, getFilter(), manager, isIgnoreExceptions(),
224 !bufferedIo || immediateFlush, getAdvertise() ? getConfiguration().getAdvertiser() : null);
225 }
226 }
227
228 @PluginBuilderFactory
229 public static Builder newBuilder() {
230 return new Builder();
231 }
232
233 private final Object advertisement;
234 private final Advertiser advertiser;
235
236 protected SocketAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
237 final AbstractSocketManager manager, final boolean ignoreExceptions, final boolean immediateFlush,
238 final Advertiser advertiser) {
239 super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
240 if (advertiser != null) {
241 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
242 configuration.putAll(manager.getContentFormat());
243 configuration.put("contentType", layout.getContentType());
244 configuration.put("name", name);
245 this.advertisement = advertiser.advertise(configuration);
246 } else {
247 this.advertisement = null;
248 }
249 this.advertiser = advertiser;
250 }
251
252 @Override
253 public boolean stop(final long timeout, final TimeUnit timeUnit) {
254 setStopping();
255 super.stop(timeout, timeUnit, false);
256 if (this.advertiser != null) {
257 this.advertiser.unadvertise(this.advertisement);
258 }
259 setStopped();
260 return true;
261 }
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298 @Deprecated
299 @PluginFactory
300 public static SocketAppender createAppender(
301
302 final String host,
303 final int port,
304 final Protocol protocol,
305 final SslConfiguration sslConfig,
306 final int connectTimeoutMillis,
307 final int reconnectDelayMillis,
308 final boolean immediateFail,
309 final String name,
310 final boolean immediateFlush,
311 final boolean ignoreExceptions,
312 final Layout<? extends Serializable> layout,
313 final Filter filter,
314 final boolean advertise,
315 final Configuration configuration) {
316
317
318
319 return newBuilder()
320 .withAdvertise(advertise)
321 .setConfiguration(configuration)
322 .withConnectTimeoutMillis(connectTimeoutMillis)
323 .withFilter(filter)
324 .withHost(host)
325 .withIgnoreExceptions(ignoreExceptions)
326 .withImmediateFail(immediateFail)
327 .withLayout(layout)
328 .withName(name)
329 .withPort(port)
330 .withProtocol(protocol)
331 .withReconnectDelayMillis(reconnectDelayMillis)
332 .withSslConfiguration(sslConfig)
333 .build();
334
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 @Deprecated
373 public static SocketAppender createAppender(
374
375 final String host,
376 final String portNum,
377 final String protocolIn,
378 final SslConfiguration sslConfig,
379 final int connectTimeoutMillis,
380
381 final String delayMillis,
382 final String immediateFail,
383 final String name,
384 final String immediateFlush,
385 final String ignore,
386 final Layout<? extends Serializable> layout,
387 final Filter filter,
388 final String advertise,
389 final Configuration config) {
390
391 final boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
392 final boolean isAdvertise = Boolean.parseBoolean(advertise);
393 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
394 final boolean fail = Booleans.parseBoolean(immediateFail, true);
395 final int reconnectDelayMillis = AbstractAppender.parseInt(delayMillis, 0);
396 final int port = AbstractAppender.parseInt(portNum, 0);
397 final Protocol p = protocolIn == null ? Protocol.UDP : Protocol.valueOf(protocolIn);
398 return createAppender(host, port, p, sslConfig, connectTimeoutMillis, reconnectDelayMillis, fail, name, isFlush,
399 ignoreExceptions, layout, filter, isAdvertise, config);
400 }
401
402
403
404
405
406
407
408
409 @Deprecated
410 protected static AbstractSocketManager createSocketManager(final String name, final Protocol protocol, final String host,
411 final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig, final int reconnectDelayMillis,
412 final boolean immediateFail, final Layout<? extends Serializable> layout, final int bufferSize) {
413 return createSocketManager(name, protocol, host, port, connectTimeoutMillis, sslConfig, reconnectDelayMillis, immediateFail, layout, bufferSize, null);
414 }
415
416
417
418
419
420
421
422 protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host,
423 final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig,
424 final int reconnectDelayMillis, final boolean immediateFail, final Layout<? extends Serializable> layout,
425 final int bufferSize, final SocketOptions socketOptions) {
426 if (protocol == Protocol.TCP && sslConfig != null) {
427
428 protocol = Protocol.SSL;
429 }
430 if (protocol != Protocol.SSL && sslConfig != null) {
431 LOGGER.info("Appender {} ignoring SSL configuration for {} protocol", name, protocol);
432 }
433 switch (protocol) {
434 case TCP:
435 return TcpSocketManager.getSocketManager(host, port, connectTimeoutMillis, reconnectDelayMillis,
436 immediateFail, layout, bufferSize, socketOptions);
437 case UDP:
438 return DatagramSocketManager.getSocketManager(host, port, layout, bufferSize);
439 case SSL:
440 return SslSocketManager.getSocketManager(sslConfig, host, port, connectTimeoutMillis, reconnectDelayMillis,
441 immediateFail, layout, bufferSize, socketOptions);
442 default:
443 throw new IllegalArgumentException(protocol.toString());
444 }
445 }
446
447 @Override
448 protected void directEncodeEvent(final LogEvent event) {
449
450
451 writeByteArrayToManager(event);
452 }
453 }