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.util.HashMap;
21  import java.util.Map;
22  
23  import org.apache.logging.log4j.core.Filter;
24  import org.apache.logging.log4j.core.Layout;
25  import org.apache.logging.log4j.core.config.Configuration;
26  import org.apache.logging.log4j.core.config.plugins.Plugin;
27  import org.apache.logging.log4j.core.config.plugins.PluginAliases;
28  import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
29  import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
30  import org.apache.logging.log4j.core.config.plugins.PluginElement;
31  import org.apache.logging.log4j.core.config.plugins.PluginFactory;
32  import org.apache.logging.log4j.core.layout.SerializedLayout;
33  import org.apache.logging.log4j.core.net.AbstractSocketManager;
34  import org.apache.logging.log4j.core.net.Advertiser;
35  import org.apache.logging.log4j.core.net.DatagramSocketManager;
36  import org.apache.logging.log4j.core.net.Protocol;
37  import org.apache.logging.log4j.core.net.SslSocketManager;
38  import org.apache.logging.log4j.core.net.TcpSocketManager;
39  import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
40  import org.apache.logging.log4j.core.util.Booleans;
41  import org.apache.logging.log4j.util.EnglishEnums;
42  
43  /**
44   * An Appender that delivers events over socket connections. Supports both TCP and UDP.
45   */
46  @Plugin(name = "Socket", category = "Core", elementType = "appender", printObject = true)
47  public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketManager> {
48  
49      private static final long serialVersionUID = 1L;
50  
51      private Object advertisement;
52      private final Advertiser advertiser;
53  
54      protected SocketAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter,
55              final AbstractSocketManager manager, final boolean ignoreExceptions, final boolean immediateFlush,
56              final Advertiser advertiser) {
57          super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
58          if (advertiser != null) {
59              final Map<String, String> configuration = new HashMap<>(layout.getContentFormat());
60              configuration.putAll(manager.getContentFormat());
61              configuration.put("contentType", layout.getContentType());
62              configuration.put("name", name);
63              this.advertisement = advertiser.advertise(configuration);
64          }
65          this.advertiser = advertiser;
66      }
67  
68      @Override
69      public void stop() {
70          super.stop();
71          if (this.advertiser != null) {
72              this.advertiser.unadvertise(this.advertisement);
73          }
74      }
75  
76      /**
77       * 
78       * @param host
79       *        The name of the host to connect to.
80       * @param portNum
81       *        The port to connect to on the target host.
82       * @param protocolStr
83       *        The Protocol to use.
84       * @param sslConfig
85       *        The SSL configuration file for TCP/SSL, ignored for UPD.
86       * @param connectTimeoutMillis
87       *        the connect timeout in milliseconds.
88       * @param delayMillis
89       *        The interval in which failed writes should be retried.
90       * @param immediateFail
91       *        True if the write should fail if no socket is immediately available.
92       * @param name
93       *        The name of the Appender.
94       * @param immediateFlush
95       *        "true" if data should be flushed on each write.
96       * @param ignore
97       *        If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise they are
98       *        propagated to the caller.
99       * @param layout
100      *        The layout to use (defaults to SerializedLayout).
101      * @param filter
102      *        The Filter or null.
103      * @param advertise
104      *        "true" if the appender configuration should be advertised, "false" otherwise.
105      * @param config
106      *        The Configuration
107      * @return A SocketAppender.
108      */
109     @PluginFactory
110     public static SocketAppender createAppender(
111             // @formatter:off
112             @PluginAttribute("host") final String host,
113             @PluginAttribute("port") final String portNum,
114             @PluginAttribute("protocol") final String protocolStr,
115             @PluginElement("SSL") final SslConfiguration sslConfig,
116             @PluginAttribute(value = "connectTimeoutMillis", defaultInt = 0) final int connectTimeoutMillis,
117             @PluginAliases("reconnectionDelay") // deprecated
118             @PluginAttribute("reconnectionDelayMillis") final String delayMillis,
119             @PluginAttribute("immediateFail") final String immediateFail,
120             @PluginAttribute("name") final String name,
121             @PluginAttribute("immediateFlush") final String immediateFlush,
122             @PluginAttribute("ignoreExceptions") final String ignore,
123             @PluginElement("Layout") Layout<? extends Serializable> layout,
124             @PluginElement("Filter") final Filter filter, 
125             @PluginAttribute("advertise") final String advertise, @PluginConfiguration final Configuration config) {
126             // @formatter:on
127         boolean isFlush = Booleans.parseBoolean(immediateFlush, true);
128         final boolean isAdvertise = Boolean.parseBoolean(advertise);
129         final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true);
130         final boolean fail = Booleans.parseBoolean(immediateFail, true);
131         final int reconnectDelayMillis = AbstractAppender.parseInt(delayMillis, 0);
132         final int port = AbstractAppender.parseInt(portNum, 0);
133         if (layout == null) {
134             layout = SerializedLayout.createLayout();
135         }
136 
137         if (name == null) {
138             LOGGER.error("No name provided for SocketAppender");
139             return null;
140         }
141 
142         final Protocol protocol = EnglishEnums.valueOf(Protocol.class,
143                 protocolStr != null ? protocolStr : Protocol.TCP.name());
144         if (protocol == Protocol.UDP) {
145             isFlush = true;
146         }
147 
148         final AbstractSocketManager manager = createSocketManager(name, protocol, host, port, connectTimeoutMillis,
149                 sslConfig, reconnectDelayMillis, fail, layout);
150 
151         return new SocketAppender(name, layout, filter, manager, ignoreExceptions, isFlush,
152                 isAdvertise ? config.getAdvertiser() : null);
153     }
154 
155     /**
156      * Creates an AbstractSocketManager for TCP, UDP, and SSL.
157      * 
158      * @throws IllegalArgumentException
159      *         if the protocol cannot be handled.
160      */
161     protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host,
162             final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig, final int delayMillis,
163             final boolean immediateFail, final Layout<? extends Serializable> layout) {
164         if (protocol == Protocol.TCP && sslConfig != null) {
165             // Upgrade TCP to SSL if an SSL config is specified.
166             protocol = Protocol.SSL;
167         }
168         if (protocol != Protocol.SSL && sslConfig != null) {
169             LOGGER.info("Appender {} ignoring SSL configuration for {} protocol", name, protocol);
170         }
171         switch (protocol) {
172         case TCP:
173             return TcpSocketManager.getSocketManager(host, port, connectTimeoutMillis, delayMillis, immediateFail,
174                     layout);
175         case UDP:
176             return DatagramSocketManager.getSocketManager(host, port, layout);
177         case SSL:
178             return SslSocketManager.getSocketManager(sslConfig, host, port, connectTimeoutMillis, delayMillis,
179                     immediateFail, layout);
180         default:
181             throw new IllegalArgumentException(protocol.toString());
182         }
183     }
184 }