View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.core.appender;
18  
19  import java.io.Serializable;
20  import java.nio.charset.Charset;
21  import java.nio.charset.StandardCharsets;
22  
23  import org.apache.logging.log4j.core.Appender;
24  import org.apache.logging.log4j.core.Core;
25  import org.apache.logging.log4j.core.Filter;
26  import org.apache.logging.log4j.core.Layout;
27  import org.apache.logging.log4j.core.config.Configuration;
28  import org.apache.logging.log4j.core.config.Property;
29  import org.apache.logging.log4j.core.config.plugins.Plugin;
30  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
31  import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
32  import org.apache.logging.log4j.core.config.plugins.PluginElement;
33  import org.apache.logging.log4j.core.layout.LoggerFields;
34  import org.apache.logging.log4j.core.layout.Rfc5424Layout;
35  import org.apache.logging.log4j.core.layout.SyslogLayout;
36  import org.apache.logging.log4j.core.net.AbstractSocketManager;
37  import org.apache.logging.log4j.core.net.Advertiser;
38  import org.apache.logging.log4j.core.net.Facility;
39  import org.apache.logging.log4j.core.net.Protocol;
40  import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
41  import org.apache.logging.log4j.core.util.Constants;
42  import org.apache.logging.log4j.util.EnglishEnums;
43  
44  /**
45   * The Syslog Appender.
46   */
47  @Plugin(name = "Syslog", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true)
48  public class SyslogAppender extends SocketAppender {
49  
50      public static class Builder<B extends Builder<B>> extends AbstractBuilder<B>
51              implements org.apache.logging.log4j.core.util.Builder<SocketAppender> {
52  
53          @PluginBuilderAttribute(value = "facility")
54          private Facility facility = Facility.LOCAL0;
55  
56          @PluginBuilderAttribute("id")
57          private String id;
58  
59          @PluginBuilderAttribute(value = "enterpriseNumber")
60          private int enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER;
61  
62          @PluginBuilderAttribute(value = "includeMdc")
63          private boolean includeMdc = true;
64  
65          @PluginBuilderAttribute("mdcId")
66          private String mdcId;
67  
68          @PluginBuilderAttribute("mdcPrefix")
69          private String mdcPrefix;
70  
71          @PluginBuilderAttribute("eventPrefix")
72          private String eventPrefix;
73  
74          @PluginBuilderAttribute(value = "newLine")
75          private boolean newLine;
76  
77          @PluginBuilderAttribute("newLineEscape")
78          private String escapeNL;
79  
80          @PluginBuilderAttribute("appName")
81          private String appName;
82  
83          @PluginBuilderAttribute("messageId")
84          private String msgId;
85  
86          @PluginBuilderAttribute("mdcExcludes")
87          private String excludes;
88  
89          @PluginBuilderAttribute("mdcIncludes")
90          private String includes;
91  
92          @PluginBuilderAttribute("mdcRequired")
93          private String required;
94  
95          @PluginBuilderAttribute("format")
96          private String format;
97  
98          @PluginBuilderAttribute("charset")
99          private Charset charsetName = StandardCharsets.UTF_8;
100 
101         @PluginBuilderAttribute("exceptionPattern")
102         private String exceptionPattern;
103 
104         @PluginElement("LoggerFields")
105         private LoggerFields[] loggerFields;
106 
107         @SuppressWarnings({"resource", "unchecked"})
108         @Override
109         public SyslogAppender build() {
110             final Protocol protocol = getProtocol();
111             final SslConfiguration sslConfiguration = getSslConfiguration();
112             final boolean useTlsMessageFormat = sslConfiguration != null || protocol == Protocol.SSL;
113             final Configuration configuration = getConfiguration();
114             Layout<? extends Serializable> layout = getLayout();
115             if (layout == null) {
116                 layout = RFC5424.equalsIgnoreCase(format)
117                         ? Rfc5424Layout.createLayout(facility, id, enterpriseNumber, includeMdc, mdcId, mdcPrefix,
118                                 eventPrefix, newLine, escapeNL, appName, msgId, excludes, includes, required,
119                                 exceptionPattern, useTlsMessageFormat, loggerFields, configuration)
120                         :
121                         // @formatter:off
122                         SyslogLayout.newBuilder()
123                             .setFacility(facility)
124                             .setIncludeNewLine(newLine)
125                             .setEscapeNL(escapeNL)
126                             .setCharset(charsetName)
127                             .build();
128                         // @formatter:on
129             }
130             final String name = getName();
131             if (name == null) {
132                 LOGGER.error("No name provided for SyslogAppender");
133                 return null;
134             }
135             final AbstractSocketManager manager = createSocketManager(name, protocol, getHost(), getPort(), getConnectTimeoutMillis(),
136                     sslConfiguration, getReconnectDelayMillis(), getImmediateFail(), layout, Constants.ENCODER_BYTE_BUFFER_SIZE, null);
137 
138             return new SyslogAppender(name, layout, getFilter(), isIgnoreExceptions(), isImmediateFlush(), manager,
139                     getAdvertise() ? configuration.getAdvertiser() : null, null);
140         }
141 
142         public Facility getFacility() {
143             return facility;
144         }
145 
146         public String getId() {
147             return id;
148         }
149 
150         public int getEnterpriseNumber() {
151             return enterpriseNumber;
152         }
153 
154         public boolean isIncludeMdc() {
155             return includeMdc;
156         }
157 
158         public String getMdcId() {
159             return mdcId;
160         }
161 
162         public String getMdcPrefix() {
163             return mdcPrefix;
164         }
165 
166         public String getEventPrefix() {
167             return eventPrefix;
168         }
169 
170         public boolean isNewLine() {
171             return newLine;
172         }
173 
174         public String getEscapeNL() {
175             return escapeNL;
176         }
177 
178         public String getAppName() {
179             return appName;
180         }
181 
182         public String getMsgId() {
183             return msgId;
184         }
185 
186         public String getExcludes() {
187             return excludes;
188         }
189 
190         public String getIncludes() {
191             return includes;
192         }
193 
194         public String getRequired() {
195             return required;
196         }
197 
198         public String getFormat() {
199             return format;
200         }
201 
202         public Charset getCharsetName() {
203             return charsetName;
204         }
205 
206         public String getExceptionPattern() {
207             return exceptionPattern;
208         }
209 
210         public LoggerFields[] getLoggerFields() {
211             return loggerFields;
212         }
213 
214         public B setFacility(final Facility facility) {
215             this.facility = facility;
216             return asBuilder();
217         }
218 
219         public B setId(final String id) {
220             this.id = id;
221             return asBuilder();
222         }
223 
224         public B setEnterpriseNumber(final int enterpriseNumber) {
225             this.enterpriseNumber = enterpriseNumber;
226             return asBuilder();
227         }
228 
229         public B setIncludeMdc(final boolean includeMdc) {
230             this.includeMdc = includeMdc;
231             return asBuilder();
232         }
233 
234         public B setMdcId(final String mdcId) {
235             this.mdcId = mdcId;
236             return asBuilder();
237         }
238 
239         public B setMdcPrefix(final String mdcPrefix) {
240             this.mdcPrefix = mdcPrefix;
241             return asBuilder();
242         }
243 
244         public B setEventPrefix(final String eventPrefix) {
245             this.eventPrefix = eventPrefix;
246             return asBuilder();
247         }
248 
249         public B setNewLine(final boolean newLine) {
250             this.newLine = newLine;
251             return asBuilder();
252         }
253 
254         public B setEscapeNL(final String escapeNL) {
255             this.escapeNL = escapeNL;
256             return asBuilder();
257         }
258 
259         public B setAppName(final String appName) {
260             this.appName = appName;
261             return asBuilder();
262         }
263 
264         public B setMsgId(final String msgId) {
265             this.msgId = msgId;
266             return asBuilder();
267         }
268 
269         public B setExcludes(final String excludes) {
270             this.excludes = excludes;
271             return asBuilder();
272         }
273 
274         public B setIncludes(final String includes) {
275             this.includes = includes;
276             return asBuilder();
277         }
278 
279         public B setRequired(final String required) {
280             this.required = required;
281             return asBuilder();
282         }
283 
284         public B setFormat(final String format) {
285             this.format = format;
286             return asBuilder();
287         }
288 
289         public B setCharsetName(final Charset charset) {
290             this.charsetName = charset;
291             return asBuilder();
292         }
293 
294         public B setExceptionPattern(final String exceptionPattern) {
295             this.exceptionPattern = exceptionPattern;
296             return asBuilder();
297         }
298 
299         public B setLoggerFields(final LoggerFields[] loggerFields) {
300             this.loggerFields = loggerFields;
301             return asBuilder();
302         }
303     }
304 
305     protected static final String RFC5424 = "RFC5424";
306 
307     protected SyslogAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
308                              final boolean ignoreExceptions, final boolean immediateFlush,
309                              final AbstractSocketManager manager, final Advertiser advertiser, final Property[] properties) {
310         super(name, layout, filter, manager, ignoreExceptions, immediateFlush, advertiser, properties);
311     }
312 
313     /**
314      * @deprecated Use
315      * {@link #SyslogAppender(String, Layout, Filter, boolean, boolean, AbstractSocketManager, Advertiser, Property[])}.
316      */
317     @Deprecated
318     protected SyslogAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
319             final boolean ignoreExceptions, final boolean immediateFlush, final AbstractSocketManager manager,
320             final Advertiser advertiser) {
321         super(name, layout, filter, manager, ignoreExceptions, immediateFlush, advertiser, Property.EMPTY_ARRAY);
322     }
323 
324     /**
325      * Creates a SyslogAppender.
326      * @param host The name of the host to connect to.
327      * @param port The port to connect to on the target host.
328      * @param protocolStr The Protocol to use.
329      * @param sslConfiguration TODO
330      * @param connectTimeoutMillis the connect timeout in milliseconds.
331      * @param reconnectDelayMillis The interval in which failed writes should be retried.
332      * @param immediateFail True if the write should fail if no socket is immediately available.
333      * @param name The name of the Appender.
334      * @param immediateFlush "true" if data should be flushed on each write.
335      * @param ignoreExceptions If {@code "true"} (default) exceptions encountered when appending events are logged;
336      *                         otherwise they are propagated to the caller.
337      * @param facility The Facility is used to try to classify the message.
338      * @param id The default structured data id to use when formatting according to RFC 5424.
339      * @param enterpriseNumber The IANA enterprise number.
340      * @param includeMdc Indicates whether data from the ThreadContextMap will be included in the RFC 5424 Syslog
341      * record. Defaults to "true:.
342      * @param mdcId The id to use for the MDC Structured Data Element.
343      * @param mdcPrefix The prefix to add to MDC key names.
344      * @param eventPrefix The prefix to add to event key names.
345      * @param newLine If true, a newline will be appended to the end of the syslog record. The default is false.
346      * @param escapeNL String that should be used to replace newlines within the message text.
347      * @param appName The value to use as the APP-NAME in the RFC 5424 syslog record.
348      * @param msgId The default value to be used in the MSGID field of RFC 5424 syslog records.
349      * @param excludes A comma separated list of mdc keys that should be excluded from the LogEvent.
350      * @param includes A comma separated list of mdc keys that should be included in the FlumeEvent.
351      * @param required A comma separated list of mdc keys that must be present in the MDC.
352      * @param format If set to "RFC5424" the data will be formatted in accordance with RFC 5424. Otherwise,
353      * it will be formatted as a BSD Syslog record.
354      * @param filter A Filter to determine if the event should be handled by this Appender.
355      * @param configuration The Configuration.
356      * @param charset The character set to use when converting the syslog String to a byte array.
357      * @param exceptionPattern The converter pattern to use for formatting exceptions.
358      * @param loggerFields The logger fields
359      * @param advertise Whether to advertise
360      * @return A SyslogAppender.
361      * @deprecated Use {@link #newSyslogAppenderBuilder()}.
362      */
363     @Deprecated
364     public static <B extends Builder<B>> SyslogAppender createAppender(
365             // @formatter:off
366             final String host,
367             final int port,
368             final String protocolStr,
369             final SslConfiguration sslConfiguration,
370             final int connectTimeoutMillis,
371             final int reconnectDelayMillis,
372             final boolean immediateFail,
373             final String name,
374             final boolean immediateFlush,
375             final boolean ignoreExceptions,
376             final Facility facility,
377             final String id,
378             final int enterpriseNumber,
379             final boolean includeMdc,
380             final String mdcId,
381             final String mdcPrefix,
382             final String eventPrefix,
383             final boolean newLine,
384             final String escapeNL,
385             final String appName,
386             final String msgId,
387             final String excludes,
388             final String includes,
389             final String required,
390             final String format,
391             final Filter filter,
392             final Configuration configuration,
393             final Charset charset,
394             final String exceptionPattern,
395             final LoggerFields[] loggerFields,
396             final boolean advertise) {
397         // @formatter:on
398 
399         // @formatter:off
400         return SyslogAppender.<B>newSyslogAppenderBuilder()
401         .withHost(host)
402         .withPort(port)
403         .withProtocol(EnglishEnums.valueOf(Protocol.class, protocolStr))
404         .withSslConfiguration(sslConfiguration)
405         .withConnectTimeoutMillis(connectTimeoutMillis)
406         .withReconnectDelayMillis(reconnectDelayMillis)
407         .withImmediateFail(immediateFail).setName(appName)
408         .withImmediateFlush(immediateFlush).setIgnoreExceptions(ignoreExceptions).setFilter(filter)
409                 .setConfiguration(configuration)
410                 .withAdvertise(advertise)
411                 .setFacility(facility)
412                 .setId(id)
413                 .setEnterpriseNumber(enterpriseNumber)
414                 .setIncludeMdc(includeMdc)
415                 .setMdcId(mdcId)
416                 .setMdcPrefix(mdcPrefix)
417                 .setEventPrefix(eventPrefix)
418                 .setNewLine(newLine)
419                 .setAppName(appName)
420                 .setMsgId(msgId)
421                 .setExcludes(excludes)
422                 .setIncludeMdc(includeMdc)
423                 .setRequired(required)
424                 .setFormat(format)
425                 .setCharsetName(charset)
426                 .setExceptionPattern(exceptionPattern)
427                 .setLoggerFields(loggerFields)
428                 .build();
429         // @formatter:on
430     }
431 
432     // Calling this method newBuilder() does not compile
433     @PluginBuilderFactory
434     public static <B extends Builder<B>> B newSyslogAppenderBuilder() {
435         return new Builder<B>().asBuilder();
436     }
437 
438 }