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