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