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; 041import org.apache.logging.log4j.util.EnglishEnums; 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 static final long serialVersionUID = 1L; 050 051 private Object advertisement; 052 private final Advertiser advertiser; 053 054 protected SocketAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, 055 final AbstractSocketManager manager, final boolean ignoreExceptions, final boolean immediateFlush, 056 final Advertiser advertiser) { 057 super(name, layout, filter, ignoreExceptions, immediateFlush, manager); 058 if (advertiser != null) { 059 final Map<String, String> configuration = new HashMap<String, String>(layout.getContentFormat()); 060 configuration.putAll(manager.getContentFormat()); 061 configuration.put("contentType", layout.getContentType()); 062 configuration.put("name", name); 063 this.advertisement = advertiser.advertise(configuration); 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 * 078 * @param host 079 * The name of the host to connect to. 080 * @param portNum 081 * The port to connect to on the target host. 082 * @param protocolStr 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 delayMillis 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 ignore 097 * If {@code "true"} (default) exceptions encountered when appending events are logged; otherwise they are 098 * 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("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, 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}