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