├── .gitignore
├── .travis.yml
├── HTTP Monitor Screenshot.png
├── LICENSE
├── LICENSE.md
├── README.md
├── graylog2-plugin-input-httpmonitor.iml
├── pom.xml
└── src
└── main
├── java
└── org
│ └── graylog2
│ └── plugin
│ └── httpmonitor
│ ├── HttpMonitorInput.java
│ ├── HttpMonitorInputMetaData.java
│ ├── HttpMonitorInputModule.java
│ ├── HttpMonitorInputPlugin.java
│ ├── HttpMonitorTransport.java
│ └── URLMonitorConfig.java
└── resources
└── META-INF
└── services
└── org.graylog2.plugin.Plugin
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | pom.xml.tag
3 | pom.xml.releaseBackup
4 | pom.xml.versionsBackup
5 | pom.xml.next
6 | release.properties
7 | dependency-reduced-pom.xml
8 | buildNumber.properties
9 | .mvn/timing.properties
10 | .idea/
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 |
3 |
--------------------------------------------------------------------------------
/HTTP Monitor Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sivasamyk/graylog2-plugin-input-httpmonitor/129c723236aca7f8ecc255236077e715e66b2777/HTTP Monitor Screenshot.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Sivasamy Kaliappan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) [year] [fullname]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Graylog HTTP Monitor Input Plugin (DEPRECATED)
2 |
3 | 
4 |
5 | An input monitor plugin for monitoring HTTP URLs (websites and REST APIs).
6 | Works by periodically polling the URLs and recording the responses as messages.
7 |
8 | This plugin provides support for monitoring following parameters
9 |
10 | * Response time in milliseconds
11 | * HTTP Status Code
12 | * HTTP Status Text
13 | * HTTP Response Body
14 | * HTTP Response size in bytes
15 | * Timeouts and connection failures
16 | * Custom Response Headers
17 |
18 | Getting started
19 | ---------------
20 | For Graylog v2.0 and above download this [jar](https://github.com/sivasamyk/graylog2-plugin-input-httpmonitor/releases/download/v1.0.5/graylog2-plugin-input-httpmonitor-1.0.5.jar)
21 | (Please note this version will break (due to changes in graylog field naming restrictions) HTTP monitor dashboard created in older versions)
22 |
23 | For Graylog v1.2 and above download this [jar](https://github.com/sivasamyk/graylog2-plugin-input-httpmonitor/releases/download/v1.0.2/graylog2-plugin-input-httpmonitor-1.0.2.jar)
24 |
25 | For Graylog v1.1 and below download this [jar](https://github.com/sivasamyk/graylog2-plugin-input-httpmonitor/releases/download/v1.0.0/graylog2-plugin-input-httpmonitor-1.0.0.jar)
26 |
27 | * Shutdown the graylog server.
28 | * Place the plugin jar in the Graylog plugins directory.
29 | * Restart the server.
30 | * In the graylog web UI, goto System->Inputs to launch new input of type 'HTTP Monitor'
31 |
32 |
33 | Following parameters can be configured while launching the plugin
34 |
35 | * URL to monitor ( supports HTTPS URLs with self-signed certificates also)
36 | * Polling interval - Interval to execute the HTTP methods (poll the URL)
37 | * Timeout - Time to wait before declaring the request as timed out.
38 | * HTTP Method - GET/POST/PUT method to be executed
39 | * Additional HTTP headers to send - Comma separated list of HTTP request headers to be sent as part of request. e.g. CAccept:application/json, X-Requester:Graylog2
40 | * Additional HTTP headers to log - Command separated list of HTTP response headers to log as part of message. e.g. Expires,Date
41 | * HTTP Basic Authentication username and password
42 | * HTTP Proxy URI
43 |
44 | The status code will be 999 on connection failures, 998 on connection timeouts and 997 for others errors.
45 |
46 | Polling interval and timeout can be configured in milliseconds/seconds/minutes/hours/days
47 |
48 | You can import the [content pack](https://github.com/sivasamyk/graylog-contentpack-httpmonitor) for HTTP Monitor for prebuilt dashboard and streams.
49 |
50 | Sample Dashboard
51 | ----------------
52 |
53 | 
54 |
--------------------------------------------------------------------------------
/graylog2-plugin-input-httpmonitor.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.graylog2
8 | graylog2-plugin-input-httpmonitor
9 | 1.0.5
10 | jar
11 |
12 | ${project.artifactId}
13 | Graylog ${project.artifactId} plugin.
14 | https://www.graylog.org
15 |
16 |
17 | UTF-8
18 | 1.7
19 | 1.7
20 | 1.0.0
21 | /usr/share/graylog-server/plugin
22 |
23 |
24 |
25 |
26 | org.graylog2
27 | graylog2-plugin
28 | ${graylog2.version}
29 | provided
30 |
31 |
32 | com.ning
33 | async-http-client
34 | 1.9.40
35 |
36 |
37 | org.graylog2
38 | graylog2-inputs
39 | ${graylog2.version}
40 | provided
41 |
42 |
43 | log4j
44 | log4j
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | org.apache.maven.plugins
54 | maven-shade-plugin
55 | 2.3
56 |
57 | false
58 |
59 |
60 |
61 | package
62 |
63 | shade
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | jdeb
76 | org.vafer
77 | 1.3
78 |
79 | ${project.build.directory}/${project.artifactId}-${project.version}.deb
80 |
81 |
82 | ${project.build.directory}/${project.build.finalName}.jar
83 | file
84 |
85 | perm
86 | ${graylog2.plugin-dir}
87 | 644
88 | root
89 | root
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | org.codehaus.mojo
98 | rpm-maven-plugin
99 | 2.1.2
100 |
101 | Application/Internet
102 |
103 | /usr
104 |
105 |
106 | _unpackaged_files_terminate_build 0
107 | _binaries_in_noarch_packages_terminate_build 0
108 |
109 | 644
110 | 755
111 | root
112 | root
113 |
114 |
115 | ${graylog2.plugin-dir}
116 |
117 |
118 | ${project.build.directory}/
119 |
120 | ${project.build.finalName}.jar
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
--------------------------------------------------------------------------------
/src/main/java/org/graylog2/plugin/httpmonitor/HttpMonitorInput.java:
--------------------------------------------------------------------------------
1 | package org.graylog2.plugin.httpmonitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.google.inject.assistedinject.Assisted;
5 | import com.google.inject.assistedinject.AssistedInject;
6 | import org.graylog2.plugin.LocalMetricRegistry;
7 | import org.graylog2.plugin.ServerStatus;
8 | import org.graylog2.plugin.configuration.Configuration;
9 | import org.graylog2.plugin.inputs.MessageInput;
10 | import org.graylog2.plugin.inputs.codecs.Codec;
11 | import org.graylog2.plugin.inputs.transports.Transport;
12 | import org.graylog2.inputs.codecs.GelfCodec;
13 |
14 | import javax.inject.Inject;
15 |
16 | /**
17 | * This is the plugin. Your class should implement one of the existing plugin
18 | * interfaces. (i.e. AlarmCallback, MessageInput, MessageOutput)
19 | */
20 | public class HttpMonitorInput extends MessageInput {
21 |
22 | private static final String NAME = "HTTP Monitor";
23 |
24 | @AssistedInject
25 | public HttpMonitorInput(MetricRegistry metricRegistry, @Assisted Configuration configuration,
26 | HttpMonitorTransport.Factory factory, LocalMetricRegistry localRegistry,
27 | GelfCodec.Factory codecFactory,
28 | Config config, Descriptor descriptor, ServerStatus serverStatus) {
29 | super(metricRegistry, configuration, factory.create(configuration),
30 | localRegistry, codecFactory.create(configuration), config, descriptor, serverStatus);
31 | }
32 |
33 | public interface Factory extends MessageInput.Factory {
34 | @Override
35 | HttpMonitorInput create(Configuration configuration);
36 |
37 | @Override
38 | Config getConfig();
39 |
40 | @Override
41 | Descriptor getDescriptor();
42 | }
43 |
44 | public static class Descriptor extends MessageInput.Descriptor {
45 | @Inject
46 | public Descriptor() {
47 | super(NAME, false, "");
48 | }
49 | }
50 |
51 | public static class Config extends MessageInput.Config {
52 | @Inject
53 | public Config(HttpMonitorTransport.Factory transport, GelfCodec.Factory codec) {
54 | super(transport.getConfig(), codec.getConfig());
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/org/graylog2/plugin/httpmonitor/HttpMonitorInputMetaData.java:
--------------------------------------------------------------------------------
1 | package org.graylog2.plugin.httpmonitor;
2 |
3 | import org.graylog2.plugin.PluginMetaData;
4 | import org.graylog2.plugin.ServerStatus;
5 | import org.graylog2.plugin.Version;
6 |
7 | import java.net.URI;
8 | import java.util.Collections;
9 | import java.util.Set;
10 |
11 | /**
12 | * Implement the PluginMetaData interface here.
13 | */
14 | public class HttpMonitorInputMetaData implements PluginMetaData {
15 | @Override
16 | public String getUniqueId() {
17 | return "org.graylog2.plugin.httpmonitor.HttpMonitorInputPlugin";
18 | }
19 |
20 | @Override
21 | public String getName() {
22 | return "HttpMonitorInput";
23 | }
24 |
25 | @Override
26 | public String getAuthor() {
27 | return "Sivasamy Kaliappan";
28 | }
29 |
30 | @Override
31 | public URI getURL() {
32 | return URI.create("https://www.graylog.org/");
33 | }
34 |
35 | @Override
36 | public Version getVersion() {
37 | return new Version(1, 0, 5);
38 | }
39 |
40 | @Override
41 | public String getDescription() {
42 | return "HTTP Monitor Plugin";
43 | }
44 |
45 | @Override
46 | public Version getRequiredVersion() {
47 | return new Version(2, 0, 0);
48 | }
49 |
50 | @Override
51 | public Set getRequiredCapabilities() {
52 | return Collections.emptySet();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/org/graylog2/plugin/httpmonitor/HttpMonitorInputModule.java:
--------------------------------------------------------------------------------
1 | package org.graylog2.plugin.httpmonitor;
2 |
3 | import org.graylog2.plugin.PluginConfigBean;
4 | import org.graylog2.plugin.PluginModule;
5 |
6 | import java.util.Collections;
7 | import java.util.Set;
8 |
9 | /**
10 | * Extend the PluginModule abstract class here to add you plugin to the system.
11 | */
12 | public class HttpMonitorInputModule extends PluginModule {
13 | /**
14 | * Returns all configuration beans required by this plugin.
15 | *
16 | * Implementing this method is optional. The default method returns an empty {@link Set}.
17 | */
18 | // @Override
19 | // public Set extends PluginConfigBean> getConfigBeans() {
20 | // return Collections.emptySet();
21 | // }
22 |
23 | @Override
24 | protected void configure() {
25 | installTransport(transportMapBinder(),"http-monitor-transport",HttpMonitorTransport.class);
26 | installInput(inputsMapBinder(), HttpMonitorInput.class, HttpMonitorInput.Factory.class);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/graylog2/plugin/httpmonitor/HttpMonitorInputPlugin.java:
--------------------------------------------------------------------------------
1 | package org.graylog2.plugin.httpmonitor;
2 |
3 | import org.graylog2.plugin.Plugin;
4 | import org.graylog2.plugin.PluginMetaData;
5 | import org.graylog2.plugin.PluginModule;
6 |
7 | import java.util.Arrays;
8 | import java.util.Collection;
9 |
10 | /**
11 | * Implement the Plugin interface here.
12 | */
13 | public class HttpMonitorInputPlugin implements Plugin {
14 | @Override
15 | public PluginMetaData metadata() {
16 | return new HttpMonitorInputMetaData();
17 | }
18 |
19 | @Override
20 | public Collection modules () {
21 | return Arrays.asList(new HttpMonitorInputModule());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/org/graylog2/plugin/httpmonitor/HttpMonitorTransport.java:
--------------------------------------------------------------------------------
1 | package org.graylog2.plugin.httpmonitor;
2 |
3 | import com.codahale.metrics.MetricRegistry;
4 | import com.codahale.metrics.MetricSet;
5 | import com.fasterxml.jackson.databind.ObjectMapper;
6 | import com.google.common.collect.Maps;
7 | import com.google.inject.assistedinject.Assisted;
8 | import com.google.inject.assistedinject.AssistedInject;
9 | import com.ning.http.client.*;
10 | import org.apache.commons.lang3.StringUtils;
11 | import org.graylog2.plugin.ServerStatus;
12 | import org.graylog2.plugin.configuration.Configuration;
13 | import org.graylog2.plugin.configuration.ConfigurationRequest;
14 | import org.graylog2.plugin.configuration.fields.*;
15 | import org.graylog2.plugin.inputs.MessageInput;
16 | import org.graylog2.plugin.inputs.MisfireException;
17 | import org.graylog2.plugin.inputs.annotations.ConfigClass;
18 | import org.graylog2.plugin.inputs.annotations.FactoryClass;
19 | import org.graylog2.plugin.inputs.codecs.CodecAggregator;
20 | import org.graylog2.plugin.inputs.transports.Transport;
21 | import org.graylog2.plugin.journal.RawMessage;
22 | import org.slf4j.Logger;
23 | import org.slf4j.LoggerFactory;
24 |
25 | import javax.net.ssl.SSLContext;
26 | import javax.net.ssl.TrustManager;
27 | import javax.net.ssl.X509TrustManager;
28 | import java.io.ByteArrayOutputStream;
29 | import java.io.IOException;
30 | import java.net.ConnectException;
31 | import java.net.URI;
32 | import java.net.URL;
33 | import java.security.GeneralSecurityException;
34 | import java.security.KeyManagementException;
35 | import java.security.cert.CertificateException;
36 | import java.security.cert.X509Certificate;
37 | import java.util.HashMap;
38 | import java.util.Map;
39 | import java.util.concurrent.*;
40 |
41 | /**
42 | * Created on 17/6/15.
43 | */
44 | public class HttpMonitorTransport implements Transport {
45 |
46 | private static final Logger LOGGER = LoggerFactory.getLogger(HttpMonitorTransport.class.getName());
47 | private static final String CK_CONFIG_URL = "configURL";
48 | private static final String CK_CONFIG_LABEL = "configLabel";
49 | private static final String CK_CONFIG_METHOD = "configMethod";
50 | private static final String CK_CONFIG_REQUEST_BODY = "configRequestBody";
51 | private static final String CK_CONFIG_HEADERS_TO_SEND = "configHeadersToSend";
52 | private static final String CK_CONFIG_USER_NAME = "configUsername";
53 | private static final String CK_CONFIG_PASSWORD = "configPassword";
54 | private static final String CK_CONFIG_TIMEOUT = "configTimeout";
55 | private static final String CK_CONFIG_TIMEOUT_UNIT = "configTimeoutUnit";
56 | private static final String CK_CONFIG_INTERVAL = "configInterval";
57 | private static final String CK_CONFIG_INTERVAL_UNIT = "configIntervalUnit";
58 | private static final String CK_CONFIG_HEADERS_TO_RECORD = "configHeadersToRecord";
59 | private static final String CK_CONFIG_LOG_RESPONSE_BODY = "configLogResponseBody";
60 | private static final String CK_CONFIG_HTTP_PROXY = "configHttpProxy";
61 |
62 | private static final String METHOD_POST = "POST";
63 | private static final String METHOD_HEAD = "HEAD";
64 | private static final String METHOD_PUT = "PUT";
65 | private static final String METHOD_GET = "GET";
66 | private final Configuration configuration;
67 | private final MetricRegistry metricRegistry;
68 | private ServerStatus serverStatus;
69 | private ScheduledExecutorService executorService;
70 | private ScheduledFuture future;
71 | private MessageInput messageInput;
72 |
73 | @AssistedInject
74 | public HttpMonitorTransport(@Assisted Configuration configuration,
75 | MetricRegistry metricRegistry,
76 | ServerStatus serverStatus) {
77 | this.configuration = configuration;
78 | this.metricRegistry = metricRegistry;
79 | this.serverStatus = serverStatus;
80 | }
81 |
82 |
83 | @Override
84 | public void setMessageAggregator(CodecAggregator codecAggregator) {
85 |
86 | }
87 |
88 | @Override
89 | public void launch(MessageInput messageInput) throws MisfireException {
90 | this.messageInput = messageInput;
91 | URLMonitorConfig urlMonitorConfig = new URLMonitorConfig();
92 | urlMonitorConfig.setUrl(configuration.getString(CK_CONFIG_URL));
93 | urlMonitorConfig.setLabel(configuration.getString(CK_CONFIG_LABEL));
94 | urlMonitorConfig.setMethod(configuration.getString(CK_CONFIG_METHOD));
95 |
96 | String proxyUri = configuration.getString(CK_CONFIG_HTTP_PROXY);
97 | if (proxyUri != null && !proxyUri.isEmpty()) {
98 | urlMonitorConfig.setHttpProxyUri(URI.create(proxyUri));
99 | }
100 |
101 | String requestHeaders = configuration.getString(CK_CONFIG_HEADERS_TO_SEND);
102 | if (StringUtils.isNotEmpty(requestHeaders)) {
103 | urlMonitorConfig.setRequestHeadersToSend(
104 | requestHeaders.split(","));
105 | }
106 | urlMonitorConfig.setUsername(configuration.getString(CK_CONFIG_USER_NAME));
107 | urlMonitorConfig.setPassword(configuration.getString(CK_CONFIG_PASSWORD));
108 | urlMonitorConfig.setExecutionInterval(configuration.getInt(CK_CONFIG_INTERVAL));
109 | urlMonitorConfig.setTimeout(configuration.getInt(CK_CONFIG_TIMEOUT));
110 | urlMonitorConfig.setTimeoutUnit(TimeUnit.valueOf(configuration.getString(CK_CONFIG_TIMEOUT_UNIT)));
111 | urlMonitorConfig.setIntervalUnit(TimeUnit.valueOf(configuration.getString(CK_CONFIG_INTERVAL_UNIT)));
112 |
113 | // long timoutInMs = TimeUnit.MILLISECONDS.convert(urlMonitorConfig.getTimeout(), urlMonitorConfig.getTimeoutUnit());
114 | // long intervalInMs = TimeUnit.MILLISECONDS.convert(urlMonitorConfig.getExecutionInterval(), urlMonitorConfig.getIntervalUnit());
115 | //
116 | // if (intervalInMs <= timoutInMs) {
117 | // String message = MessageFormat.format("Timeout {0} {1} should be smaller than interval {2} {3}",
118 | // urlMonitorConfig.getTimeout(),urlMonitorConfig.getTimeoutUnit(),
119 | // urlMonitorConfig.getExecutionInterval(), urlMonitorConfig.getIntervalUnit());
120 | // throw new MisfireException(message);
121 | // }
122 |
123 | urlMonitorConfig.setRequestBody(configuration.getString(CK_CONFIG_REQUEST_BODY));
124 | urlMonitorConfig.setLogResponseBody(configuration.getBoolean(CK_CONFIG_LOG_RESPONSE_BODY));
125 |
126 | String responseHeaders = configuration.getString(CK_CONFIG_HEADERS_TO_RECORD);
127 | if (StringUtils.isNotEmpty(responseHeaders)) {
128 | urlMonitorConfig.setResponseHeadersToRecord(
129 | responseHeaders.split(","));
130 | }
131 |
132 | startMonitoring(urlMonitorConfig);
133 | }
134 |
135 | @Override
136 | public void stop() {
137 |
138 | if (future != null) {
139 | future.cancel(true);
140 | }
141 |
142 | if (executorService != null) {
143 | executorService.shutdownNow();
144 | }
145 | }
146 |
147 | private void startMonitoring(URLMonitorConfig config) {
148 | executorService = Executors.newSingleThreadScheduledExecutor();
149 | long initalDelayMs = TimeUnit.MILLISECONDS.convert(Math.round(Math.random() * 60), TimeUnit.SECONDS);
150 | long executionIntervalMs = TimeUnit.MILLISECONDS.convert(config.getExecutionInterval(), config.getIntervalUnit());
151 | future = executorService.scheduleAtFixedRate(new MonitorTask(config, messageInput), initalDelayMs,
152 | executionIntervalMs, TimeUnit.MILLISECONDS);
153 | }
154 |
155 |
156 | @Override
157 | public MetricSet getMetricSet() {
158 | return null;
159 | }
160 |
161 | private static class MonitorTask implements Runnable {
162 | private URLMonitorConfig config;
163 | private MessageInput messageInput;
164 | private ObjectMapper mapper;
165 | private AsyncHttpClient httpClient;
166 | private AsyncHttpClient.BoundRequestBuilder requestBuilder;
167 |
168 | public MonitorTask(URLMonitorConfig config, MessageInput messageInput) {
169 | this.config = config;
170 | this.messageInput = messageInput;
171 | this.mapper = new ObjectMapper();
172 | AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder();
173 | configBuilder.setEnabledProtocols(new String[] {"TLSv1.2", "TLSv1.1", "TLSv1"});
174 | configBuilder.setSSLContext(getSSLContext());
175 | httpClient = new AsyncHttpClient(configBuilder.build());
176 | buildRequest();
177 | }
178 |
179 | //Accept all certficates
180 | private SSLContext getSSLContext() {
181 | try {
182 | SSLContext context = SSLContext.getInstance("SSL");
183 | context.init(null, new TrustManager[]{
184 | new X509TrustManager() {
185 |
186 | @Override
187 | public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
188 |
189 | }
190 |
191 | @Override
192 | public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
193 |
194 | }
195 |
196 | @Override
197 | public X509Certificate[] getAcceptedIssuers() {
198 | return null;
199 | }
200 | }
201 | }, null);
202 | return context;
203 | } catch (GeneralSecurityException e) {
204 | LOGGER.debug("Exception while creating certs ",e);
205 | }
206 | return null;
207 | }
208 |
209 | @Override
210 | public void run() {
211 | //send to http server
212 | try {
213 |
214 | long startTime = System.currentTimeMillis();
215 | long time;
216 | Map eventdata = Maps.newHashMap();
217 | eventdata.put("version", "1.1");
218 | eventdata.put("_http_monitor_url", config.getUrl());
219 | eventdata.put("_label", config.getLabel());
220 | try {
221 | Response response = requestBuilder.execute().get();
222 | long endTime = System.currentTimeMillis();
223 | time = endTime - startTime;
224 | eventdata.put("host", response.getUri().getHost());
225 | eventdata.put("_http_monitor_status", response.getStatusCode());
226 | eventdata.put("_http_monitor_statusLine", response.getStatusText());
227 | String responseBodyStr = new String(response.getResponseBodyAsBytes());
228 | eventdata.put("_http_monitor_responseSize", responseBodyStr.length());
229 | if (config.isLogResponseBody()) {
230 | eventdata.put("full_message", responseBodyStr);
231 | }
232 | String shortMessage = responseBodyStr.length() > 50 ? responseBodyStr.substring(0, 50) :
233 | responseBodyStr;
234 | if (shortMessage.isEmpty()) {
235 | shortMessage = "no_response";
236 | }
237 | eventdata.put("short_message", shortMessage);
238 |
239 |
240 | if (config.getResponseHeadersToRecord() != null) {
241 | for (String header : config.getResponseHeadersToRecord()) {
242 | eventdata.put("_" + header, response.getHeader(header));
243 | }
244 | }
245 | } catch (ExecutionException e) {
246 | eventdata.put("host", new URL(config.getUrl()).getHost());
247 | eventdata.put("short_message", "Request failed :" + e.getMessage());
248 | eventdata.put("_http_monitor_responseSize", 0);
249 | long endTime = System.currentTimeMillis();
250 | time = endTime - startTime;
251 | //In case of connection timeout we get an execution exception with root cause as timeoutexception
252 | if (e.getCause() instanceof TimeoutException) {
253 | LOGGER.debug("Timeout while executing request for URL " + config.getUrl(), e);
254 | eventdata.put("_http_monitor_status", 998);
255 | } else if (e.getCause() instanceof ConnectException) {
256 | //In case of connect exception we get an execution exception with root cause as connectexception
257 | LOGGER.debug("Exception while executing request for URL " + config.getUrl(), e);
258 | eventdata.put("_http_monitor_status", 999);
259 | } else {
260 | //Any other exception..
261 | LOGGER.debug("Exception while executing request for URL " + config.getUrl(), e);
262 | eventdata.put("_http_monitor_status", 997);
263 | }
264 | }
265 | eventdata.put("_http_monitor_responseTime", time);
266 |
267 | //publish to graylog server
268 | ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
269 | mapper.writeValue(byteStream, eventdata);
270 | messageInput.processRawMessage(new RawMessage(byteStream.toByteArray()));
271 | byteStream.close();
272 |
273 | } catch (InterruptedException | IOException e) {
274 | LOGGER.error("Exception while executing request for URL " + config.getUrl(), e);
275 | }
276 | }
277 |
278 | private void buildRequest() {
279 |
280 | //Build request object
281 | if (METHOD_POST.equals(config.getMethod())) {
282 | requestBuilder = httpClient.preparePost(config.getUrl());
283 | } else if (METHOD_PUT.equals(config.getMethod())) {
284 | requestBuilder = httpClient.preparePut(config.getUrl());
285 | } else if (METHOD_HEAD.equals(config.getMethod())) {
286 | requestBuilder = httpClient.prepareHead(config.getUrl());
287 | } else {
288 | requestBuilder = httpClient.prepareGet(config.getUrl());
289 | }
290 |
291 | if (StringUtils.isNotEmpty(config.getRequestBody())) {
292 | requestBuilder.setBody(config.getRequestBody());
293 | }
294 |
295 | if (config.getRequestHeadersToSend() != null) {
296 | for (String header : config.getRequestHeadersToSend()) {
297 | String tokens[] = header.split(":");
298 | requestBuilder.setHeader(tokens[0], tokens[1]);
299 | }
300 | }
301 |
302 | if (StringUtils.isNotEmpty(config.getUsername()) &&
303 | StringUtils.isNotEmpty(config.getPassword())) {
304 | Realm realm = new Realm.RealmBuilder()
305 | .setPrincipal(config.getUsername())
306 | .setPassword(config.getPassword())
307 | .setScheme(Realm.AuthScheme.BASIC).build();
308 | requestBuilder.setRealm(realm);
309 | }
310 |
311 | int timeoutInMs = (int) TimeUnit.MILLISECONDS.convert(config.getTimeout(), config.getTimeoutUnit());
312 | requestBuilder.setRequestTimeout(timeoutInMs);
313 |
314 | if (config.getHttpProxyUri() != null) {
315 | ProxyServer proxyServer = new ProxyServer(config.getHttpProxyUri().getHost(), config.getHttpProxyUri().getPort());
316 | requestBuilder.setProxyServer(proxyServer);
317 | }
318 | }
319 | }
320 |
321 | @FactoryClass
322 | public interface Factory extends Transport.Factory {
323 |
324 | @Override
325 | HttpMonitorTransport create(Configuration configuration);
326 |
327 | @Override
328 | Config getConfig();
329 |
330 | }
331 |
332 | @ConfigClass
333 | public static class Config implements Transport.Config {
334 | @Override
335 | public ConfigurationRequest getRequestedConfiguration() {
336 | final ConfigurationRequest cr = new ConfigurationRequest();
337 | cr.addField(new TextField(CK_CONFIG_URL,
338 | "URL to monitor",
339 | "",
340 | ""));
341 | cr.addField(new TextField(CK_CONFIG_LABEL,
342 | "Label",
343 | "",
344 | "Label to identify this HTTP monitor"));
345 |
346 | Map httpMethods = new HashMap<>();
347 | httpMethods.put(METHOD_GET, METHOD_GET);
348 | httpMethods.put(METHOD_POST, METHOD_POST);
349 | httpMethods.put(METHOD_PUT, METHOD_PUT);
350 | cr.addField(new DropdownField(CK_CONFIG_METHOD,
351 | "HTTP Method",
352 | "GET",
353 | httpMethods,
354 | "Label to identify this HTTP monitor",
355 | ConfigurationField.Optional.NOT_OPTIONAL));
356 |
357 | cr.addField(new TextField(CK_CONFIG_REQUEST_BODY,
358 | "Request Body",
359 | "",
360 | "Request Body to send",
361 | ConfigurationField.Optional.OPTIONAL,
362 | TextField.Attribute.TEXTAREA));
363 |
364 | cr.addField(new TextField(CK_CONFIG_HEADERS_TO_SEND,
365 | "Additional HTTP headers",
366 | "",
367 | "Add a comma separated list of additional HTTP headers to send. For example: Accept: application/json, X-Requester: Graylog2",
368 | ConfigurationField.Optional.OPTIONAL));
369 |
370 | cr.addField(new TextField(CK_CONFIG_USER_NAME,
371 | "HTTP Basic Auth Username",
372 | "",
373 | "Username for HTTP Basic Authentication",
374 | ConfigurationField.Optional.OPTIONAL));
375 | cr.addField(new TextField(CK_CONFIG_PASSWORD,
376 | "HTTP Basic Auth Password",
377 | "",
378 | "Password for HTTP Basic Authentication",
379 | ConfigurationField.Optional.OPTIONAL,
380 | TextField.Attribute.IS_PASSWORD));
381 |
382 | cr.addField(new NumberField(CK_CONFIG_INTERVAL,
383 | "Interval",
384 | 1,
385 | "Time between between requests",
386 | ConfigurationField.Optional.NOT_OPTIONAL));
387 |
388 | Map timeUnits = DropdownField.ValueTemplates.timeUnits();
389 | //Do not add nano seconds and micro seconds
390 | timeUnits.remove(TimeUnit.NANOSECONDS.toString());
391 | timeUnits.remove(TimeUnit.MICROSECONDS.toString());
392 |
393 | cr.addField(new DropdownField(
394 | CK_CONFIG_INTERVAL_UNIT,
395 | "Interval time unit",
396 | TimeUnit.MINUTES.toString(),
397 | timeUnits,
398 | ConfigurationField.Optional.NOT_OPTIONAL
399 | ));
400 |
401 |
402 | cr.addField(new NumberField(CK_CONFIG_TIMEOUT,
403 | "Timeout",
404 | 20,
405 | "Timeout for requests",
406 | ConfigurationField.Optional.NOT_OPTIONAL));
407 |
408 | cr.addField(new DropdownField(
409 | CK_CONFIG_TIMEOUT_UNIT,
410 | "Timeout time unit",
411 | TimeUnit.SECONDS.toString(),
412 | timeUnits,
413 | ConfigurationField.Optional.NOT_OPTIONAL
414 | ));
415 |
416 |
417 | cr.addField(new TextField(CK_CONFIG_HTTP_PROXY,
418 | "HTTP Proxy URI",
419 | "",
420 | "URI of HTTP Proxy to be used if required e.g. http://myproxy:8888",
421 | ConfigurationField.Optional.OPTIONAL));
422 |
423 |
424 | cr.addField(new TextField(CK_CONFIG_HEADERS_TO_RECORD,
425 | "Response headers to log",
426 | "",
427 | "Comma separated response headers to log. For example: Accept,Server,Expires",
428 | ConfigurationField.Optional.OPTIONAL));
429 |
430 | cr.addField(new BooleanField(CK_CONFIG_LOG_RESPONSE_BODY,
431 | "Log full response body",
432 | false,
433 | "Select if the complete response body needs to be logged as part of message"));
434 |
435 | return cr;
436 | }
437 | }
438 |
439 | public static void main(String args[]) {
440 | URLMonitorConfig config = new URLMonitorConfig();
441 | config.setUrl("https://www.skipper18.com");
442 | config.setMethod("GET");
443 | MonitorTask monitorTask = new MonitorTask(config,null);
444 | monitorTask.run();
445 | }
446 | }
447 |
--------------------------------------------------------------------------------
/src/main/java/org/graylog2/plugin/httpmonitor/URLMonitorConfig.java:
--------------------------------------------------------------------------------
1 | package org.graylog2.plugin.httpmonitor;
2 |
3 | import java.net.URI;
4 | import java.util.List;
5 | import java.util.concurrent.TimeUnit;
6 |
7 | /**
8 | * Created on 17/6/15.
9 | */
10 | public class URLMonitorConfig {
11 | private String url,label,type,method,requestBody;
12 | private String[] requestHeadersToSend;
13 | //Basic Auth
14 | private String username,password;
15 | private int timeout, executionInterval;
16 | private String[] responseHeadersToRecord;
17 | private boolean logResponseBody;
18 | private TimeUnit intervalUnit,timeoutUnit;
19 |
20 | public URI getHttpProxyUri() {
21 | return httpProxyUri;
22 | }
23 |
24 | public void setHttpProxyUri(URI httpProxyUri) {
25 | this.httpProxyUri = httpProxyUri;
26 | }
27 |
28 | private URI httpProxyUri;
29 |
30 | public String getUrl() {
31 | return url;
32 | }
33 |
34 | public void setUrl(String url) {
35 | this.url = url;
36 | }
37 |
38 | public String getLabel() {
39 | return label;
40 | }
41 |
42 | public void setLabel(String label) {
43 | this.label = label;
44 | }
45 |
46 | public String getType() {
47 | return type;
48 | }
49 |
50 | public void setType(String type) {
51 | this.type = type;
52 | }
53 |
54 | public String getMethod() {
55 | return method;
56 | }
57 |
58 | public void setMethod(String method) {
59 | this.method = method;
60 | }
61 |
62 | public String getRequestBody() {
63 | return requestBody;
64 | }
65 |
66 | public void setRequestBody(String requestBody) {
67 | this.requestBody = requestBody;
68 | }
69 |
70 | public String[] getRequestHeadersToSend() {
71 | return requestHeadersToSend;
72 | }
73 |
74 | public void setRequestHeadersToSend(String[] requestHeadersToSend) {
75 | this.requestHeadersToSend = requestHeadersToSend;
76 | }
77 |
78 | public String getUsername() {
79 | return username;
80 | }
81 |
82 | public void setUsername(String username) {
83 | this.username = username;
84 | }
85 |
86 | public String getPassword() {
87 | return password;
88 | }
89 |
90 | public void setPassword(String password) {
91 | this.password = password;
92 | }
93 |
94 | public int getTimeout() {
95 | return timeout;
96 | }
97 |
98 | public void setTimeout(int timeout) {
99 | this.timeout = timeout;
100 | }
101 |
102 | public int getExecutionInterval() {
103 | return executionInterval;
104 | }
105 |
106 | public void setExecutionInterval(int executionInterval) {
107 | this.executionInterval = executionInterval;
108 | }
109 |
110 | public String[] getResponseHeadersToRecord() {
111 | return responseHeadersToRecord;
112 | }
113 |
114 | public void setResponseHeadersToRecord(String[] responseHeadersToRecord) {
115 | this.responseHeadersToRecord = responseHeadersToRecord;
116 | }
117 |
118 | public boolean isLogResponseBody() {
119 | return logResponseBody;
120 | }
121 |
122 | public void setLogResponseBody(boolean logResponseBody) {
123 | this.logResponseBody = logResponseBody;
124 | }
125 |
126 | public TimeUnit getIntervalUnit() {
127 | return intervalUnit;
128 | }
129 |
130 | public void setIntervalUnit(TimeUnit intervalUnit) {
131 | this.intervalUnit = intervalUnit;
132 | }
133 |
134 | public TimeUnit getTimeoutUnit() {
135 | return timeoutUnit;
136 | }
137 |
138 | public void setTimeoutUnit(TimeUnit timeoutUnit) {
139 | this.timeoutUnit = timeoutUnit;
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/services/org.graylog2.plugin.Plugin:
--------------------------------------------------------------------------------
1 | org.graylog2.plugin.httpmonitor.HttpMonitorInputPlugin
--------------------------------------------------------------------------------