View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  
18  package org.apache.logging.log4j.core.appender;
19  
20  import java.io.Serializable;
21  import java.net.URL;
22  import java.util.Objects;
23  import java.util.concurrent.TimeUnit;
24  
25  import org.apache.logging.log4j.core.Appender;
26  import org.apache.logging.log4j.core.Filter;
27  import org.apache.logging.log4j.core.Layout;
28  import org.apache.logging.log4j.core.LogEvent;
29  import org.apache.logging.log4j.core.config.Node;
30  import org.apache.logging.log4j.core.config.Property;
31  import org.apache.logging.log4j.core.config.plugins.Plugin;
32  import org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
33  import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
34  import org.apache.logging.log4j.core.config.plugins.PluginElement;
35  import org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
36  import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
37  
38  /**
39   * Sends log events over HTTP.
40   */
41  @Plugin(name = "Http", category = Node.CATEGORY, elementType = Appender.ELEMENT_TYPE, printObject = true)
42  public final class HttpAppender extends AbstractAppender {
43  
44      /**
45       * Builds HttpAppender instances.
46       * @param <B> The type to build
47       */
48      public static class Builder<B extends Builder<B>> extends AbstractAppender.Builder<B>
49              implements org.apache.logging.log4j.core.util.Builder<HttpAppender> {
50  
51          @PluginBuilderAttribute
52          @Required(message = "No URL provided for HttpAppender")
53          private URL url;
54  
55          @PluginBuilderAttribute
56          private String method = "POST";
57  
58          @PluginBuilderAttribute
59          private int connectTimeoutMillis = 0;
60  
61          @PluginBuilderAttribute
62          private int readTimeoutMillis = 0;
63  
64          @PluginElement("Headers")
65          private Property[] headers;
66  
67          @PluginElement("SslConfiguration")
68          private SslConfiguration sslConfiguration;
69  
70          @PluginBuilderAttribute
71          private boolean verifyHostname = true;
72  
73          @Override
74          public HttpAppender build() {
75              final HttpManager httpManager = new HttpURLConnectionManager(getConfiguration(),
76                      getConfiguration().getLoggerContext(), getName(), url, method, connectTimeoutMillis,
77                      readTimeoutMillis, headers, sslConfiguration, verifyHostname);
78              return new HttpAppender(getName(), getLayout(), getFilter(), isIgnoreExceptions(), httpManager,
79                      getPropertyArray());
80          }
81  
82          public URL getUrl() {
83              return url;
84          }
85  
86          public String getMethod() {
87              return method;
88          }
89  
90          public int getConnectTimeoutMillis() {
91              return connectTimeoutMillis;
92          }
93  
94          public int getReadTimeoutMillis() {
95              return readTimeoutMillis;
96          }
97  
98          public Property[] getHeaders() {
99              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 }