Skip to content
This repository has been archived by the owner on Jun 29, 2023. It is now read-only.

Commit

Permalink
Polishing #68
Browse files Browse the repository at this point in the history
Add author tags. Reformat code. Remove default port fallback in HTTP sender as default ports are specified by the protocol (HTTP/HTTPS). Add documentation for HTTP transport. Extend tests.
  • Loading branch information
mp911de committed Mar 20, 2016
1 parent 3cc5219 commit b8cdac2
Show file tree
Hide file tree
Showing 14 changed files with 334 additions and 195 deletions.
64 changes: 1 addition & 63 deletions src/main/java/biz/paluch/logging/gelf/GelfUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class GelfUtil {
public static final String MDC_REQUEST_DURATION = "profiling.requestDuration";

public static final String MDC_REQUEST_DURATION_MILLIS = "profiling.requestDuration.millis";

private GelfUtil() {

}
Expand Down Expand Up @@ -96,66 +96,4 @@ public static Set<String> getMatchingMdcNames(DynamicMdcMessageField field, Set<
return matchingMdcNames;
}

public static String addDefaultPortIfMissing(String urlString, String defaultPort) {
URL url;
try {
url = new URL(urlString);
} catch (MalformedURLException e) {
return urlString;
}
if (url.getPort() != -1) {
return urlString;
}
String regex = "http://([^/]+)";
String found = getFirstFound(urlString, regex);
String replacer = "http://" + found + ":" + defaultPort;

if (!isEmpty(found)) {
urlString = urlString.replaceFirst(regex, replacer);
}
return urlString;
}

public static String getFirstFound(String contents, String regex) {
List<String> founds = getFound(contents, regex);
if (isEmpty(founds)) {
return null;
}
return founds.get(0);
}

public static List<String> getFound(String contents, String regex) {
if (isEmpty(regex) || isEmpty(contents)) {
return null;
}
List<String> results = new ArrayList<String>();
Pattern pattern = Pattern.compile(regex, Pattern.UNICODE_CASE);
Matcher matcher = pattern.matcher(contents);

while (matcher.find()) {
if (matcher.groupCount() > 0) {
results.add(matcher.group(1));
} else {
results.add(matcher.group());
}
}
return results;
}

public static boolean isEmpty(List<String> list) {
if (list == null || list.size() == 0) {
return true;
}
if (list.size() == 1 && isEmpty(list.get(0))) {
return true;
}
return false;
}

public static boolean isEmpty(String str) {
if (str != null && str.trim().length() > 0) {
return false;
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
import biz.paluch.logging.gelf.intern.sender.RedisGelfSenderProvider;

/**
* Factory to create a {@link GelfSender} based on the host and protocol details. This factory uses Java's {@link ServiceLoader}
* mechanism to discover classes implementing {@link GelfSenderProvider}.
*
* @author <a href="mailto:[email protected]">Mark Paluch</a>
* @author Aleksandar Stojadinovic
* @since 26.09.13 15:12
*/
public final class GelfSenderFactory {
Expand Down Expand Up @@ -58,12 +62,13 @@ public Map<String, Object> getSpecificConfigurations() {
* @return a new {@link GelfSender} instance
*/
public static GelfSender createSender(GelfSenderConfiguration senderConfiguration) {

ErrorReporter errorReporter = senderConfiguration.getErrorReporter();
if (senderConfiguration.getHost() == null) {
senderConfiguration.getErrorReporter().reportError("GELF server hostname is empty!", null);
} else {
try {

try {
for (GelfSenderProvider provider : SenderProviderHolder.getSenderProvider()) {
if (provider.supports(senderConfiguration.getHost())) {
return provider.create(senderConfiguration);
Expand Down Expand Up @@ -98,6 +103,7 @@ public static void removeAllAddedSenderProviders() {

// For thread safe lazy intialization of provider list
private static class SenderProviderHolder {

private static ServiceLoader<GelfSenderProvider> gelfSenderProvider = ServiceLoader.load(GelfSenderProvider.class);
private static List<GelfSenderProvider> providerList = new ArrayList<GelfSenderProvider>();
private static List<GelfSenderProvider> addedProviders = new ArrayList<GelfSenderProvider>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,37 @@
package biz.paluch.logging.gelf.intern.sender;

import biz.paluch.logging.gelf.intern.GelfSender;
import biz.paluch.logging.gelf.intern.GelfSenderConfiguration;
import biz.paluch.logging.gelf.intern.GelfSenderProvider;

import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static biz.paluch.logging.gelf.GelfUtil.addDefaultPortIfMissing;
import biz.paluch.logging.gelf.intern.GelfSender;
import biz.paluch.logging.gelf.intern.GelfSenderConfiguration;
import biz.paluch.logging.gelf.intern.GelfSenderProvider;

/**
*
* Default provider for {@link GelfSender} that creates UDP, TCP and HTTP senders.
*
* @author https://github.com/Batigoal/logstash-gelf.git
* @author <a href="mailto:[email protected]">Mark Paluch</a>
* @author Aleksandar Stojadinovic
*/
public class DefaultGelfSenderProvider implements GelfSenderProvider {

public static final int DEFAULT_PORT = 12201;
private static final Map<String, GelfSenderProducer> factories;

@Override public boolean supports(String host) {
return host != null;
}

@Override public GelfSender create(GelfSenderConfiguration configuration) throws IOException {
String graylogHost = configuration.getHost();

int port = configuration.getPort();
if (port == 0) {
port = DEFAULT_PORT;
}
private static final GelfSenderProducer tcpSenderFactory = new GelfSenderProducer() {

if (graylogHost.startsWith("tcp:")) {
@Override
public GelfSender create(GelfSenderConfiguration configuration, String host, int port) throws IOException {

int defaultTimeoutMs = (int) TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS);

URI uri = URI.create(graylogHost);
URI uri = URI.create(host);

Map<String, String> params = UriParser.parse(uri);
int connectionTimeMs = (int) UriParser.getTimeAsMs(params, GelfTCPSender.CONNECTION_TIMEOUT, defaultTimeoutMs);
Expand All @@ -48,19 +42,87 @@ public class DefaultGelfSenderProvider implements GelfSenderProvider {
String tcpGraylogHost = UriParser.getHost(uri);
return new GelfTCPSender(tcpGraylogHost, port, connectionTimeMs, readTimeMs, deliveryAttempts, keepAlive,
configuration.getErrorReporter());
} else if (graylogHost.startsWith("udp:")) {
URI uri = URI.create(graylogHost);
}
};

private static final GelfSenderProducer udpSenderFactory = new GelfSenderProducer() {

@Override
public GelfSender create(GelfSenderConfiguration configuration, String host, int port) throws IOException {

URI uri = URI.create(host);
String udpGraylogHost = UriParser.getHost(uri);
return new GelfUDPSender(udpGraylogHost, port, configuration.getErrorReporter());
} else if (graylogHost.startsWith("http")) {
String graylogHostWithDefaultPort = addDefaultPortIfMissing(graylogHost, String.valueOf(port));
URL url = new URL(graylogHostWithDefaultPort);
return new GelfHTTPSender(url, configuration.getErrorReporter());
}
};

private static final GelfSenderProducer defaultSenderFactory = new GelfSenderProducer() {

@Override
public GelfSender create(GelfSenderConfiguration configuration, String host, int port) throws IOException {
return new GelfUDPSender(host, port, configuration.getErrorReporter());
}
};

} else {
return new GelfUDPSender(graylogHost, port, configuration.getErrorReporter());
private static final GelfSenderProducer httpSenderFactory = new GelfSenderProducer() {

@Override
public GelfSender create(GelfSenderConfiguration configuration, String host, int port) throws IOException {

int defaultTimeoutMs = (int) TimeUnit.MILLISECONDS.convert(2, TimeUnit.SECONDS);
URL url = new URL(host);

return new GelfHTTPSender(url, defaultTimeoutMs, defaultTimeoutMs, configuration.getErrorReporter());
}
};

static {
Map<String, GelfSenderProducer> prefixToFactory = new HashMap<String, GelfSenderProducer>();
prefixToFactory.put("tcp:", tcpSenderFactory);
prefixToFactory.put("udp:", udpSenderFactory);
prefixToFactory.put("http", httpSenderFactory);

factories = Collections.unmodifiableMap(prefixToFactory);

}

@Override
public boolean supports(String host) {
return host != null;
}

@Override
public GelfSender create(GelfSenderConfiguration configuration) throws IOException {

String graylogHost = configuration.getHost();

int port = configuration.getPort();
if (port == 0) {
port = DEFAULT_PORT;
}

for (Map.Entry<String, GelfSenderProducer> entry : factories.entrySet()) {
if (graylogHost.startsWith(entry.getKey())) {
return entry.getValue().create(configuration, graylogHost, port);
}
}

return defaultSenderFactory.create(configuration, graylogHost, port);

}

private interface GelfSenderProducer {

/**
* Produce a {@link GelfSender} using {@code configuration}, {@code host} and {@code port},
*
* @param configuration
* @param host
* @param port
* @return
* @throws IOException
*/
GelfSender create(GelfSenderConfiguration configuration, String host, int port) throws IOException;
}

}
Original file line number Diff line number Diff line change
@@ -1,51 +1,70 @@
package biz.paluch.logging.gelf.intern.sender;

import biz.paluch.logging.gelf.intern.ErrorReporter;
import biz.paluch.logging.gelf.intern.GelfMessage;
import biz.paluch.logging.gelf.intern.GelfSender;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

import biz.paluch.logging.gelf.intern.ErrorReporter;
import biz.paluch.logging.gelf.intern.GelfMessage;
import biz.paluch.logging.gelf.intern.GelfSender;

/**
* Created by https://github.com/salex89
* @author Aleksandar Stojadinovic
*/
public class GelfHTTPSender implements GelfSender {

final private ErrorReporter errorReporter;
final private URL url;
private HttpURLConnection connection = null;
private final int connectTimeoutMs;
private final int readTimeoutMs;
private final ErrorReporter errorReporter;
private final URL url;

private int HTTP_ACCEPTED_STATUS = 202;

public GelfHTTPSender(URL url, ErrorReporter errorReporter) {
public GelfHTTPSender(URL url, int connectTimeoutMs, int readTimeoutMs, ErrorReporter errorReporter) {

this.connectTimeoutMs = connectTimeoutMs;
this.readTimeoutMs = readTimeoutMs;
this.errorReporter = errorReporter;
this.url = url;
}

@Override public boolean sendMessage(GelfMessage message) {
@Override
public boolean sendMessage(GelfMessage message) {

HttpURLConnection connection = null;

try {
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(connectTimeoutMs);
connection.setReadTimeout(readTimeoutMs);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.addRequestProperty("Content-type", "application/json");

OutputStream outputStream = connection.getOutputStream();
outputStream.write(message.toJson().getBytes());
outputStream.close();

int responseCode = connection.getResponseCode();
if (responseCode == HTTP_ACCEPTED_STATUS) {
return true;
} else {
errorReporter.reportError("Server responded with unexpected status code: ", null);
errorReporter.reportError("Server responded with unexpected status code: " + responseCode, null);
}
} catch (IOException e) {
errorReporter.reportError("Error when sending log message", e);
errorReporter.reportError("Cannot send data to " + url, e);
} finally {
// disconnecting HttpURLConnection here to avoid underlying premature underlying Socket being closed.
if (connection != null) {
connection.disconnect();
}
}
return false;
}

@Override public void close() {
//disconnecting HttpURLConnection here to avoid underlying premature underlying Socket being closed.
if (connection != null)
connection.disconnect();
@Override
public void close() {

}
}
17 changes: 17 additions & 0 deletions src/site/markdown/http.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# HTTP transport for logstash-gelf


logstash-gelf provides a HTTP/HTTPS transport to send log events to HTTP endpoints. The HTTP sender uses `POST` to
send uncompressed JSON data. It sets the `Content-type` header to `application/json` and expects response status `202 Accepted`.

http://host[:port]/[path] (POST)

Example:

http://localhost/gelf
https://localhost/gelf

* scheme (fixed: http or https, directly used to determine the to be used sender class)
* host (variable: the host)
* port (variable: optional, the port. Defaults to 80 for HTTP and 443 for HTTPS)
* path (variable: optional, path on the server)
1 change: 1 addition & 0 deletions src/site/site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
<item name="Stack Trace Filter" href="stack-trace-filter.html"/>
<item name="TCP Transport" href="tcp.html" />
<item name="Redis Transport" href="redis.html" />
<item name="HTTP Transport" href="http.html" />
<item name="Datenpumpe" href="datenpumpe.html" />
</menu>

Expand Down
Loading

0 comments on commit b8cdac2

Please sign in to comment.