001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017package org.apache.logging.log4j.core.appender; 018 019import java.io.Serializable; 020import java.nio.charset.Charset; 021import java.nio.charset.StandardCharsets; 022 023import org.apache.logging.log4j.core.Appender; 024import org.apache.logging.log4j.core.Core; 025import org.apache.logging.log4j.core.Filter; 026import org.apache.logging.log4j.core.Layout; 027import org.apache.logging.log4j.core.config.Configuration; 028import org.apache.logging.log4j.core.config.plugins.Plugin; 029import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 030import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 031import org.apache.logging.log4j.core.config.plugins.PluginElement; 032import org.apache.logging.log4j.core.layout.LoggerFields; 033import org.apache.logging.log4j.core.layout.Rfc5424Layout; 034import org.apache.logging.log4j.core.layout.SyslogLayout; 035import org.apache.logging.log4j.core.net.AbstractSocketManager; 036import org.apache.logging.log4j.core.net.Advertiser; 037import org.apache.logging.log4j.core.net.Facility; 038import org.apache.logging.log4j.core.net.Protocol; 039import org.apache.logging.log4j.core.net.ssl.SslConfiguration; 040import org.apache.logging.log4j.core.util.Constants; 041import org.apache.logging.log4j.util.EnglishEnums; 042 043/** 044 * The Syslog Appender. 045 */ 046@Plugin(name = "Syslog", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true) 047public class SyslogAppender extends SocketAppender { 048 049 public static class Builder<B extends Builder<B>> extends AbstractBuilder<B> 050 implements org.apache.logging.log4j.core.util.Builder<SocketAppender> { 051 052 @PluginBuilderAttribute(value = "facility") 053 private Facility facility = Facility.LOCAL0; 054 055 @PluginBuilderAttribute("id") 056 private String id; 057 058 @PluginBuilderAttribute(value = "enterpriseNumber") 059 private int enterpriseNumber = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER; 060 061 @PluginBuilderAttribute(value = "includeMdc") 062 private boolean includeMdc = true; 063 064 @PluginBuilderAttribute("mdcId") 065 private String mdcId; 066 067 @PluginBuilderAttribute("mdcPrefix") 068 private String mdcPrefix; 069 070 @PluginBuilderAttribute("eventPrefix") 071 private String eventPrefix; 072 073 @PluginBuilderAttribute(value = "newLine") 074 private boolean newLine; 075 076 @PluginBuilderAttribute("newLineEscape") 077 private String escapeNL; 078 079 @PluginBuilderAttribute("appName") 080 private String appName; 081 082 @PluginBuilderAttribute("messageId") 083 private String msgId; 084 085 @PluginBuilderAttribute("mdcExcludes") 086 private String excludes; 087 088 @PluginBuilderAttribute("mdcIncludes") 089 private String includes; 090 091 @PluginBuilderAttribute("mdcRequired") 092 private String required; 093 094 @PluginBuilderAttribute("format") 095 private String format; 096 097 @PluginBuilderAttribute("charset") 098 private Charset charsetName = StandardCharsets.UTF_8; 099 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}