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.util.HashMap; 021import java.util.Map; 022 023import org.apache.logging.log4j.core.Filter; 024import org.apache.logging.log4j.core.Layout; 025import org.apache.logging.log4j.core.LogEvent; 026import org.apache.logging.log4j.core.config.Configuration; 027import org.apache.logging.log4j.core.config.plugins.Plugin; 028import org.apache.logging.log4j.core.config.plugins.PluginAliases; 029import org.apache.logging.log4j.core.config.plugins.PluginAttribute; 030import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 031import org.apache.logging.log4j.core.config.plugins.PluginElement; 032import org.apache.logging.log4j.core.config.plugins.PluginFactory; 033import org.apache.logging.log4j.core.layout.SerializedLayout; 034import org.apache.logging.log4j.core.net.AbstractSocketManager; 035import org.apache.logging.log4j.core.net.Advertiser; 036import org.apache.logging.log4j.core.net.DatagramSocketManager; 037import org.apache.logging.log4j.core.net.Protocol; 038import org.apache.logging.log4j.core.net.SslSocketManager; 039import org.apache.logging.log4j.core.net.TcpSocketManager; 040import org.apache.logging.log4j.core.net.ssl.SslConfiguration; 041import org.apache.logging.log4j.core.util.Booleans; 042 043/** 044 * An Appender that delivers events over socket connections. Supports both TCP and UDP. 045 */ 046@Plugin(name = "Socket", category = "Core", elementType = "appender", printObject = true) 047public class SocketAppender extends AbstractOutputStreamAppender<AbstractSocketManager> { 048 049 private final Object advertisement; 050 private final Advertiser advertiser; 051 052 protected SocketAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, 053 final AbstractSocketManager manager, final boolean ignoreExceptions, final boolean immediateFlush, 054 final Advertiser advertiser) { 055 super(name, layout, filter, ignoreExceptions, immediateFlush, manager); 056 if (advertiser != null) { 057 final Map<String, String> configuration = new HashMap<>(layout.getContentFormat()); 058 configuration.putAll(manager.getContentFormat()); 059 configuration.put("contentType", layout.getContentType()); 060 configuration.put("name", name); 061 this.advertisement = advertiser.advertise(configuration); 062 } else { 063 this.advertisement = null; 064 } 065 this.advertiser = advertiser; 066 } 067 068 @Override 069 public void stop() { 070 super.stop(); 071 if (this.advertiser != null) { 072 this.advertiser.unadvertise(this.advertisement); 073 } 074 } 075 076 /** 077 * Creates a socket appender. 078 * 079 * @param host 080 * The name of the host to connect to. 081 * @param port 082 * The port to connect to on the target host. 083 * @param protocol 084 * The Protocol to use. 085 * @param sslConfig 086 * The SSL configuration file for TCP/SSL, ignored for UPD. 087 * @param connectTimeoutMillis 088 * the connect timeout in milliseconds. 089 * @param reconnectDelayMillis 090 * The interval in which failed writes should be retried. 091 * @param immediateFail 092 * True if the write should fail if no socket is immediately available. 093 * @param name 094 * The name of the Appender. 095 * @param immediateFlush 096 * "true" if data should be flushed on each write. 097 * @param ignoreExceptions 098 * If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise they 099 * are propagated to the caller. 100 * @param layout 101 * The layout to use (defaults to SerializedLayout). 102 * @param filter 103 * The Filter or null. 104 * @param advertise 105 * "true" if the appender configuration should be advertised, "false" otherwise. 106 * @param config 107 * The Configuration 108 * @return A SocketAppender. 109 */ 110 @PluginFactory 111 public static SocketAppender createAppender( 112 // @formatter:off 113 @PluginAttribute("host") final String host, 114 @PluginAttribute(value = "port", defaultInt = 0) final int port, 115 @PluginAttribute("protocol") final Protocol protocol, 116 @PluginElement("SSL") final SslConfiguration sslConfig, 117 @PluginAttribute(value = "connectTimeoutMillis", defaultInt = 0) final int connectTimeoutMillis, 118 @PluginAliases("reconnectionDelay") // deprecated 119 @PluginAttribute(value = "reconnectionDelayMillis", defaultInt = 0) final int reconnectDelayMillis, 120 @PluginAttribute(value = "immediateFail", defaultBoolean = true) final boolean immediateFail, 121 @PluginAttribute("name") final String name, 122 @PluginAttribute(value = "immediateFlush", defaultBoolean = true) boolean immediateFlush, 123 @PluginAttribute(value = "ignoreExceptions", defaultBoolean = true) final boolean ignoreExceptions, 124 @PluginElement("Layout") Layout<? extends Serializable> layout, 125 @PluginElement("Filter") final Filter filter, 126 @PluginAttribute(value = "advertise", defaultBoolean = false) final boolean advertise, 127 @PluginConfiguration final Configuration config) { 128 // @formatter:on 129 130 if (layout == null) { 131 layout = SerializedLayout.createLayout(); 132 } 133 134 if (name == null) { 135 LOGGER.error("No name provided for SocketAppender"); 136 return null; 137 } 138 139 final Protocol actualProtocol = protocol != null ? protocol : Protocol.TCP; 140 if (actualProtocol == Protocol.UDP) { 141 immediateFlush = true; 142 } 143 144 final AbstractSocketManager manager = createSocketManager(name, actualProtocol, host, port, connectTimeoutMillis, 145 sslConfig, reconnectDelayMillis, immediateFail, layout); 146 147 return new SocketAppender(name, layout, filter, manager, ignoreExceptions, immediateFlush, 148 advertise ? config.getAdvertiser() : null); 149 } 150 151 /** 152 * Creates a socket appender. 153 * 154 * @param host 155 * The name of the host to connect to. 156 * @param portNum 157 * The port to connect to on the target host. 158 * @param protocolIn 159 * The Protocol to use. 160 * @param sslConfig 161 * The SSL configuration file for TCP/SSL, ignored for UPD. 162 * @param connectTimeoutMillis 163 * the connect timeout in milliseconds. 164 * @param delayMillis 165 * The interval in which failed writes should be retried. 166 * @param immediateFail 167 * True if the write should fail if no socket is immediately available. 168 * @param name 169 * The name of the Appender. 170 * @param immediateFlush 171 * "true" if data should be flushed on each write. 172 * @param ignore 173 * If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise they 174 * are propagated to the caller. 175 * @param layout 176 * The layout to use (defaults to {@link SerializedLayout}). 177 * @param filter 178 * The Filter or null. 179 * @param advertise 180 * "true" if the appender configuration should be advertised, "false" otherwise. 181 * @param config 182 * The Configuration 183 * @return A SocketAppender. 184 * @deprecated Deprecated in 2.5; use 185 * {@link #createAppender(String, int, Protocol, SslConfiguration, int, int, boolean, String, boolean, boolean, Layout, Filter, boolean, Configuration)} 186 * . 187 */ 188 @Deprecated 189 public static SocketAppender createAppender( 190 // @formatter:off 191 final String host, 192 final String portNum, 193 final String protocolIn, 194 final SslConfiguration sslConfig, 195 final int connectTimeoutMillis, 196 // deprecated 197 final String delayMillis, 198 final String immediateFail, 199 final String name, 200 final String immediateFlush, 201 final String ignore, 202 Layout<? extends Serializable> layout, 203 final Filter filter, 204 final String advertise, 205 final Configuration config) { 206 // @formatter:on 207 boolean isFlush = Booleans.parseBoolean(immediateFlush, true); 208 final boolean isAdvertise = Boolean.parseBoolean(advertise); 209 final boolean ignoreExceptions = Booleans.parseBoolean(ignore, true); 210 final boolean fail = Booleans.parseBoolean(immediateFail, true); 211 final int reconnectDelayMillis = AbstractAppender.parseInt(delayMillis, 0); 212 final int port = AbstractAppender.parseInt(portNum, 0); 213 final Protocol p = protocolIn == null ? Protocol.UDP : Protocol.valueOf(protocolIn); 214 return createAppender(host, port, p, sslConfig, connectTimeoutMillis, reconnectDelayMillis, fail, name, isFlush, 215 ignoreExceptions, layout, filter, isAdvertise, config); 216 } 217 218 /** 219 * Creates an AbstractSocketManager for TCP, UDP, and SSL. 220 * 221 * @throws IllegalArgumentException 222 * if the protocol cannot be handled. 223 */ 224 protected static AbstractSocketManager createSocketManager(final String name, Protocol protocol, final String host, 225 final int port, final int connectTimeoutMillis, final SslConfiguration sslConfig, final int delayMillis, 226 final boolean immediateFail, final Layout<? extends Serializable> layout) { 227 if (protocol == Protocol.TCP && sslConfig != null) { 228 // Upgrade TCP to SSL if an SSL config is specified. 229 protocol = Protocol.SSL; 230 } 231 if (protocol != Protocol.SSL && sslConfig != null) { 232 LOGGER.info("Appender {} ignoring SSL configuration for {} protocol", name, protocol); 233 } 234 switch (protocol) { 235 case TCP: 236 return TcpSocketManager.getSocketManager(host, port, connectTimeoutMillis, delayMillis, immediateFail, 237 layout); 238 case UDP: 239 return DatagramSocketManager.getSocketManager(host, port, layout); 240 case SSL: 241 return SslSocketManager.getSocketManager(sslConfig, host, port, connectTimeoutMillis, delayMillis, 242 immediateFail, layout); 243 default: 244 throw new IllegalArgumentException(protocol.toString()); 245 } 246 } 247 248 @Override 249 protected void directEncodeEvent(final LogEvent event) { 250 // Disable garbage-free logging for now: 251 // problem with UDP: 8K buffer size means that largish messages get broken up into chunks 252 writeByteArrayToManager(event); // revert to classic (non-garbage free) logging 253 } 254}