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 */ 017 018package org.apache.logging.log4j.core.appender; 019 020import java.io.Serializable; 021import java.net.URL; 022import java.util.Objects; 023import java.util.concurrent.TimeUnit; 024 025import org.apache.logging.log4j.core.Appender; 026import org.apache.logging.log4j.core.Filter; 027import org.apache.logging.log4j.core.Layout; 028import org.apache.logging.log4j.core.LogEvent; 029import org.apache.logging.log4j.core.config.Node; 030import org.apache.logging.log4j.core.config.Property; 031import org.apache.logging.log4j.core.config.plugins.Plugin; 032import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute; 033import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory; 034import org.apache.logging.log4j.core.config.plugins.PluginElement; 035import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required; 036import org.apache.logging.log4j.core.net.ssl.SslConfiguration; 037 038/** 039 * Sends log events over HTTP. 040 */ 041@Plugin(name = "Http", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true) 042public final class HttpAppender extends AbstractAppender { 043 044 /** 045 * Builds HttpAppender instances. 046 * @param <B> The type to build 047 */ 048 public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B> 049 implements org.apache.logging.log4j.core.util.Builder<HttpAppender> { 050 051 @PluginBuilderAttribute 052 @Required(message = "No URL provided for HttpAppender") 053 private URL url; 054 055 @PluginBuilderAttribute 056 private String method = "POST"; 057 058 @PluginBuilderAttribute 059 private int connectTimeoutMillis = 0; 060 061 @PluginBuilderAttribute 062 private int readTimeoutMillis = 0; 063 064 @PluginElement("Headers") 065 private Property[] headers; 066 067 @PluginElement("SslConfiguration") 068 private SslConfiguration sslConfiguration; 069 070 @PluginBuilderAttribute 071 private boolean verifyHostname = true; 072 073 @Override 074 public HttpAppender build() { 075 final HttpManager httpManager = new HttpURLConnectionManager(getConfiguration(), 076 getConfiguration().getLoggerContext(), getName(), url, method, connectTimeoutMillis, 077 readTimeoutMillis, headers, sslConfiguration, verifyHostname); 078 return new HttpAppender(getName(), getLayout(), getFilter(), isIgnoreExceptions(), httpManager, 079 getPropertyArray()); 080 } 081 082 public URL getUrl() { 083 return url; 084 } 085 086 public String getMethod() { 087 return method; 088 } 089 090 public int getConnectTimeoutMillis() { 091 return connectTimeoutMillis; 092 } 093 094 public int getReadTimeoutMillis() { 095 return readTimeoutMillis; 096 } 097 098 public Property[] getHeaders() { 099 return headers; 100 } 101 102 public SslConfiguration getSslConfiguration() { 103 return sslConfiguration; 104 } 105 106 public boolean isVerifyHostname() { 107 return verifyHostname; 108 } 109 110 public B setUrl(final URL url) { 111 this.url = url; 112 return asBuilder(); 113 } 114 115 public B setMethod(final String method) { 116 this.method = method; 117 return asBuilder(); 118 } 119 120 public B setConnectTimeoutMillis(final int connectTimeoutMillis) { 121 this.connectTimeoutMillis = connectTimeoutMillis; 122 return asBuilder(); 123 } 124 125 public B setReadTimeoutMillis(final int readTimeoutMillis) { 126 this.readTimeoutMillis = readTimeoutMillis; 127 return asBuilder(); 128 } 129 130 public B setHeaders(final Property[] headers) { 131 this.headers = headers; 132 return asBuilder(); 133 } 134 135 public B setSslConfiguration(final SslConfiguration sslConfiguration) { 136 this.sslConfiguration = sslConfiguration; 137 return asBuilder(); 138 } 139 140 public B setVerifyHostname(final boolean verifyHostname) { 141 this.verifyHostname = verifyHostname; 142 return asBuilder(); 143 } 144 } 145 146 /** 147 * @return a builder for a HttpAppender. 148 */ 149 @PluginBuilderFactory 150 public static <B extends Builder<B>> B newBuilder() { 151 return new Builder<B>().asBuilder(); 152 } 153 154 private final HttpManager manager; 155 156 private HttpAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, 157 final boolean ignoreExceptions, final HttpManager manager, final Property[] properties) { 158 super(name, filter, layout, ignoreExceptions, properties); 159 Objects.requireNonNull(layout, "layout"); 160 this.manager = Objects.requireNonNull(manager, "manager"); 161 } 162 163 @Override 164 public void start() { 165 super.start(); 166 manager.startup(); 167 } 168 169 @Override 170 public void append(final LogEvent event) { 171 try { 172 manager.send(getLayout(), event); 173 } catch (final Exception e) { 174 error("Unable to send HTTP in appender [" + getName() + "]", event, e); 175 } 176 } 177 178 @Override 179 public boolean stop(final long timeout, final TimeUnit timeUnit) { 180 setStopping(); 181 boolean stopped = super.stop(timeout, timeUnit, false); 182 stopped &= manager.stop(timeout, timeUnit); 183 setStopped(); 184 return stopped; 185 } 186 187 @Override 188 public String toString() { 189 return "HttpAppender{" + 190 "name=" + getName() + 191 ", state=" + getState() + 192 '}'; 193 } 194}