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(), getConfiguration().getLoggerContext(), 076 getName(), url, method, connectTimeoutMillis, readTimeoutMillis, headers, sslConfiguration, verifyHostname); 077 return new HttpAppender(getName(), getLayout(), getFilter(), isIgnoreExceptions(), httpManager); 078 } 079 080 public URL getUrl() { 081 return url; 082 } 083 084 public String getMethod() { 085 return method; 086 } 087 088 public int getConnectTimeoutMillis() { 089 return connectTimeoutMillis; 090 } 091 092 public int getReadTimeoutMillis() { 093 return readTimeoutMillis; 094 } 095 096 public Property[] getHeaders() { 097 return headers; 098 } 099 100 public SslConfiguration getSslConfiguration() { 101 return sslConfiguration; 102 } 103 104 public boolean isVerifyHostname() { 105 return verifyHostname; 106 } 107 108 public B setUrl(final URL url) { 109 this.url = url; 110 return asBuilder(); 111 } 112 113 public B setMethod(final String method) { 114 this.method = method; 115 return asBuilder(); 116 } 117 118 public B setConnectTimeoutMillis(final int connectTimeoutMillis) { 119 this.connectTimeoutMillis = connectTimeoutMillis; 120 return asBuilder(); 121 } 122 123 public B setReadTimeoutMillis(final int readTimeoutMillis) { 124 this.readTimeoutMillis = readTimeoutMillis; 125 return asBuilder(); 126 } 127 128 public B setHeaders(final Property[] headers) { 129 this.headers = headers; 130 return asBuilder(); 131 } 132 133 public B setSslConfiguration(final SslConfiguration sslConfiguration) { 134 this.sslConfiguration = sslConfiguration; 135 return asBuilder(); 136 } 137 138 public B setVerifyHostname(final boolean verifyHostname) { 139 this.verifyHostname = verifyHostname; 140 return asBuilder(); 141 } 142 } 143 144 /** 145 * @return a builder for a HttpAppender. 146 */ 147 @PluginBuilderFactory 148 public static <B extends Builder<B>> B newBuilder() { 149 return new Builder<B>().asBuilder(); 150 } 151 152 private final HttpManager manager; 153 154 private HttpAppender(final String name, final Layout<? extends Serializable> layout, final Filter filter, 155 final boolean ignoreExceptions, final HttpManager manager) { 156 super(name, filter, layout, ignoreExceptions); 157 Objects.requireNonNull(layout, "layout"); 158 this.manager = Objects.requireNonNull(manager, "manager"); 159 } 160 161 @Override 162 public void start() { 163 super.start(); 164 manager.startup(); 165 } 166 167 @Override 168 public void append(final LogEvent event) { 169 try { 170 manager.send(getLayout(), event); 171 } catch (final Exception e) { 172 error("Unable to send HTTP in appender [" + getName() + "]", event, e); 173 } 174 } 175 176 @Override 177 public boolean stop(final long timeout, final TimeUnit timeUnit) { 178 setStopping(); 179 boolean stopped = super.stop(timeout, timeUnit, false); 180 stopped &= manager.stop(timeout, timeUnit); 181 setStopped(); 182 return stopped; 183 } 184 185 @Override 186 public String toString() { 187 return "HttpAppender{" + 188 "name=" + getName() + 189 ", state=" + getState() + 190 '}'; 191 } 192}