You are viewing a plain text version of this content. The canonical link for it is here.
Posted to log4j-dev@logging.apache.org by "Gary Gregory (JIRA)" <ji...@apache.org> on 2014/11/18 07:11:33 UTC

[jira] [Comment Edited] (LOG4J2-895) Specify the SyslogAppender connect timeout value as part of the configuration

    [ https://issues.apache.org/jira/browse/LOG4J2-895?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14215756#comment-14215756 ] 

Gary Gregory edited comment on LOG4J2-895 at 11/18/14 6:11 AM:
---------------------------------------------------------------

In git master. 

The new appender takes a new parameter {{connectTimeoutMillis}}.


was (Author: garydgregory):
In git master.

> Specify the SyslogAppender connect timeout value as part of the configuration
> -----------------------------------------------------------------------------
>
>                 Key: LOG4J2-895
>                 URL: https://issues.apache.org/jira/browse/LOG4J2-895
>             Project: Log4j 2
>          Issue Type: New Feature
>    Affects Versions: 2.1
>         Environment: All
>            Reporter: Sam Beroz
>            Assignee: Gary Gregory
>            Priority: Minor
>             Fix For: 2.2
>
>
> I was testing the use case of taking the logserver down for maintenance and noticed that the SyslogAppender doesn't provide a way to override the default socket timeout.  This resulted in my application noticeably hanging on startup when waiting for the socket to timeout.
> As a short term fix I created an extension largely based on the SyslogAppender that includes the connection timeout as a configurable parameter (timeoutMillis).  I'd like something like this to be added in a future revision so I don't have to maintain this extension.  Here's my version:
> {code:title=FailFastSyslogAppender.java|borderStyle=solid}
> import java.io.ByteArrayOutputStream;
> import java.io.IOException;
> import java.io.OutputStream;
> import java.io.Serializable;
> import java.net.InetAddress;
> import java.net.InetSocketAddress;
> import java.net.Socket;
> import java.net.UnknownHostException;
> import java.nio.charset.Charset;
> import javax.net.ssl.SSLSocket;
> import javax.net.ssl.SSLSocketFactory;
> import org.apache.logging.log4j.Level;
> import org.apache.logging.log4j.core.Filter;
> import org.apache.logging.log4j.core.Layout;
> import org.apache.logging.log4j.core.appender.ManagerFactory;
> import org.apache.logging.log4j.core.appender.SocketAppender;
> import org.apache.logging.log4j.core.config.Configuration;
> import org.apache.logging.log4j.core.config.plugins.Plugin;
> import org.apache.logging.log4j.core.config.plugins.PluginAliases;
> import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
> import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
> import org.apache.logging.log4j.core.config.plugins.PluginElement;
> import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> import org.apache.logging.log4j.core.layout.LoggerFields;
> import org.apache.logging.log4j.core.layout.Rfc5424Layout;
> import org.apache.logging.log4j.core.layout.SyslogLayout;
> import org.apache.logging.log4j.core.net.AbstractSocketManager;
> import org.apache.logging.log4j.core.net.Advertiser;
> import org.apache.logging.log4j.core.net.Facility;
> import org.apache.logging.log4j.core.net.Protocol;
> import org.apache.logging.log4j.core.net.SslSocketManager;
> import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
> import org.apache.logging.log4j.util.EnglishEnums;
> /**
>  * The FailFastSyslog Appender.
>  * I created this because the Syslog Appender doesn't currently allow you to set a connection timeout value.
>  * Other then allowing a timeout it's basically identical to the SSL Syslog Appender.
>  */
> @Plugin(name = "FailFastSyslog", category = "Core", elementType = "appender", printObject = true)
> public class FailFastSyslogAppender extends SocketAppender {
>     private static final long serialVersionUID = 1L;
>     protected static final String RFC5424 = "RFC5424";
>     protected FailFastSyslogAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
>                              final boolean ignoreExceptions, final boolean immediateFlush,
>                              final AbstractSocketManager manager, final Advertiser advertiser) {
>         super(name, layout, filter, manager, ignoreExceptions, immediateFlush, advertiser);
>     }
>     /**
>      * Create a FailFastSyslogAppender.
>      * @param host The name of the host to connect to.
>      * @param port The port to connect to on the target host.
>      * @param protocolStr The Protocol to use.
>      * @param sslConfig TODO
>      * @param reconnectionDelayMillis The interval in which failed writes should be retried.
>      * @param immediateFail True if the write should fail if no socket is immediately available.
>      * @param name The name of the Appender.
>      * @param immediateFlush "true" if data should be flushed on each write.
>      * @param ignoreExceptions If {@code "true"} (default) exceptions encountered when appending events are logged;
>      *                         otherwise they are propagated to the caller.
>      * @param facility The Facility is used to try to classify the message.
>      * @param id The default structured data id to use when formatting according to RFC 5424.
>      * @param enterpriseNumber The IANA enterprise number.
>      * @param includeMdc Indicates whether data from the ThreadContextMap will be included in the RFC 5424 Syslog
>      * record. Defaults to "true:.
>      * @param mdcId The id to use for the MDC Structured Data Element.
>      * @param mdcPrefix The prefix to add to MDC key names.
>      * @param eventPrefix The prefix to add to event key names.
>      * @param newLine If true, a newline will be appended to the end of the syslog record. The default is false.
>      * @param escapeNL String that should be used to replace newlines within the message text.
>      * @param appName The value to use as the APP-NAME in the RFC 5424 syslog record.
>      * @param msgId The default value to be used in the MSGID field of RFC 5424 syslog records.
>      * @param excludes A comma separated list of mdc keys that should be excluded from the LogEvent.
>      * @param includes A comma separated list of mdc keys that should be included in the FlumeEvent.
>      * @param required A comma separated list of mdc keys that must be present in the MDC.
>      * @param format If set to "RFC5424" the data will be formatted in accordance with RFC 5424. Otherwise,
>      * it will be formatted as a BSD Syslog record.
>      * @param filter A Filter to determine if the event should be handled by this Appender.
>      * @param config The Configuration.
>      * @param charsetName The character set to use when converting the syslog String to a byte array.
>      * @param exceptionPattern The converter pattern to use for formatting exceptions.
>      * @param loggerFields The logger fields
>      * @param advertise Whether to advertise
>      * @return A FailFastSyslogAppender.
>      */
>     @PluginFactory
>     public static FailFastSyslogAppender createAppender(
>             // @formatter:off
>             @PluginAttribute("host") final String host,
>             @PluginAttribute(value = "port", defaultInt = 0) final int port,
>             @PluginAttribute("protocol") final String protocolStr,
>             @PluginElement("SSL") final SslConfiguration sslConfig,
>             @PluginAliases("reconnectionDelay") // deprecated
>             @PluginAttribute(value = "reconnectionDelayMillis", defaultInt = 0) final int reconnectionDelayMillis,
>             @PluginAttribute(value = "timeoutMillis", defaultInt = 2000) final int timeoutMillis,
>             @PluginAttribute(value = "immediateFail", defaultBoolean = true) final boolean immediateFail,
>             @PluginAttribute("name") final String name,
>             @PluginAttribute(value = "immediateFlush", defaultBoolean = true) final boolean immediateFlush,
>             @PluginAttribute(value = "ignoreExceptions", defaultBoolean = true) final boolean ignoreExceptions,
>             @PluginAttribute(value = "facility", defaultString = "LOCAL0") final Facility facility,
>             @PluginAttribute("id") final String id,
>             @PluginAttribute(value = "enterpriseNumber", defaultInt = Rfc5424Layout.DEFAULT_ENTERPRISE_NUMBER) final int enterpriseNumber,
>             @PluginAttribute(value = "includeMdc", defaultBoolean = true) final boolean includeMdc,
>             @PluginAttribute("mdcId") final String mdcId,
>             @PluginAttribute("mdcPrefix") final String mdcPrefix,
>             @PluginAttribute("eventPrefix") final String eventPrefix,
>             @PluginAttribute(value = "newLine", defaultBoolean = false) final boolean newLine,
>             @PluginAttribute("newLineEscape") final String escapeNL,
>             @PluginAttribute("appName") final String appName,
>             @PluginAttribute("messageId") final String msgId,
>             @PluginAttribute("mdcExcludes") final String excludes,
>             @PluginAttribute("mdcIncludes") final String includes,
>             @PluginAttribute("mdcRequired") final String required,
>             @PluginAttribute("format") final String format,
>             @PluginElement("Filter") final Filter filter,
>             @PluginConfiguration final Configuration config,
>             @PluginAttribute(value = "charset", defaultString = "UTF-8") final Charset charsetName,
>             @PluginAttribute("exceptionPattern") final String exceptionPattern,
>             @PluginElement("LoggerFields") final LoggerFields[] loggerFields,
>             @PluginAttribute(value = "advertise", defaultBoolean = false) final boolean advertise) {
>         // @formatter:on
>         // TODO: add Protocol to TypeConverters
>         final Protocol protocol = EnglishEnums.valueOf(Protocol.class, protocolStr);
>         final boolean useTlsMessageFormat = sslConfig != null || protocol == Protocol.SSL;
>         final Layout<? extends Serializable> layout = RFC5424.equalsIgnoreCase(format) ?
>             Rfc5424Layout.createLayout(facility, id, enterpriseNumber, includeMdc, mdcId, mdcPrefix, eventPrefix, newLine,
>                 escapeNL, appName, msgId, excludes, includes, required, exceptionPattern, useTlsMessageFormat, loggerFields,
>                 config) :
>             SyslogLayout.createLayout(facility, newLine, escapeNL, charsetName);
>         if (name == null) {
>             LOGGER.error("No name provided for FailFastSyslogAppender");
>             return null;
>         }
>         
>         SslSocketManagerFactory factory = new SslSocketManagerFactory();
>         AbstractSocketManager manager = factory.createManager("TLS:" + host + ':' + port, new SslFactoryData(sslConfig, host, port, reconnectionDelayMillis, timeoutMillis, immediateFail, layout));
>         
>         return new FailFastSyslogAppender(name, layout, filter, ignoreExceptions, immediateFlush, manager,
>                 advertise ? config.getAdvertiser() : null);
>     }
>     
>     
>     private static SSLSocketFactory createSslSocketFactory(final SslConfiguration sslConf) {
>         SSLSocketFactory socketFactory;
>         if (sslConf != null) {
>             socketFactory = sslConf.getSslSocketFactory();
>         } else {
>             socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
>         }
>         return socketFactory;
>     }
>     private static class SslSocketManagerFactory implements ManagerFactory<SslSocketManager, SslFactoryData> {
>         private class TlsSocketManagerFactoryException extends Exception {
>             private static final long serialVersionUID = 1L;
>         }
>     @Override
>     public SslSocketManager createManager(final String name, final SslFactoryData data) {
>         InetAddress inetAddress = null;
>         OutputStream os = null;
>         Socket socket = null;
>         try {
>             inetAddress = resolveAddress(data.host);
>             socket = createSocket(data);
>             os = socket.getOutputStream();
>             checkDelay(data.delayMillis, os);
>         }
>         catch (final IOException e) {
>             LOGGER.error("SslSocketManager ({})", name, e);
>             os = new ByteArrayOutputStream();
>         }
>         catch (final TlsSocketManagerFactoryException e) {
>             LOGGER.catching(Level.DEBUG, e);
>             return null;
>         }
>         return createManager(name, os, socket, data.sslConfig, inetAddress, data.host, data.port, data.delayMillis, data.immediateFail, data.layout);
>     }
>     private InetAddress resolveAddress(final String hostName) throws TlsSocketManagerFactoryException {
>         InetAddress address;
>         try {
>             address = InetAddress.getByName(hostName);
>         } catch (final UnknownHostException ex) {
>             LOGGER.error("Could not find address of {}", hostName, ex);
>             throw new TlsSocketManagerFactoryException();
>         }
>         return address;
>     }
>     private void checkDelay(final int delay, final OutputStream os) throws TlsSocketManagerFactoryException {
>         if (delay == 0 && os == null) {
>             throw new TlsSocketManagerFactoryException();
>         }
>     }
>     private Socket createSocket(final SslFactoryData data) throws IOException {
>         SSLSocketFactory socketFactory;
>         SSLSocket socket;
>         socketFactory = createSslSocketFactory(data.sslConfig);
> //      **********************************************************************************
> //        This is the changed part
>         socket = (SSLSocket) socketFactory.createSocket();
>         socket.connect(new InetSocketAddress(data.host, data.port), data.timeoutMillis);
> //      **********************************************************************************
>         return socket;
>     }
>     private SslSocketManager createManager(final String name, final OutputStream os, final Socket socket,
>             final SslConfiguration sslConfig, final InetAddress inetAddress, final String host, final int port,
>             final int delay, final boolean immediateFail, final Layout<? extends Serializable> layout) {
>         return new SslSocketManager(name, os, socket, sslConfig, inetAddress, host, port, delay, immediateFail,
>                 layout);
>     }
> }
>     
>     private static class SslFactoryData {
>         protected SslConfiguration sslConfig;
>         private final String host;
>         private final int port;
>         private final int delayMillis;
>         private final int timeoutMillis;
>         private final boolean immediateFail;
>         private final Layout<? extends Serializable> layout;
>         public SslFactoryData(final SslConfiguration sslConfig, final String host, final int port, final int delayMillis, 
>         		final int timeoutMillis, final boolean immediateFail, final Layout<? extends Serializable> layout) {
>             this.host = host;
>             this.port = port;
>             this.delayMillis = delayMillis;
>             this.timeoutMillis = timeoutMillis;
>             this.immediateFail = immediateFail;
>             this.layout = layout;
>             this.sslConfig = sslConfig;
>         }
>     }
> }
> {code}
> Thanks - Sam



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

---------------------------------------------------------------------
To unsubscribe, e-mail: log4j-dev-unsubscribe@logging.apache.org
For additional commands, e-mail: log4j-dev-help@logging.apache.org