├── .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 | ![maintenance-status](https://img.shields.io/badge/maintenance-deprecated-red.svg) 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 | ![Dashboard for Hacker News Monitor](https://raw.githubusercontent.com/sivasamyk/graylog2-plugin-input-httpmonitor/master/HTTP%20Monitor%20Screenshot.png) 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 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 --------------------------------------------------------------------------------