Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Adding retry logic to Loggly appenders #55

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ target
out
build
local.properties
/.nb-gradle/
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
* @author <a href="mailto:cleclerc@xebia.fr">Cyrille Le Clerc</a>
*/
public abstract class AbstractLogglyAppender<E> extends UnsynchronizedAppenderBase<E> {

public static final String DEFAULT_ENDPOINT_PREFIX = "https://logs-01.loggly.com/";
public static final String DEFAULT_LAYOUT_PATTERN = "%d{\"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\",UTC} %-5level [%thread] %logger: %m%n";
protected static final Charset UTF_8 = Charset.forName("UTF-8");
Expand All @@ -48,6 +49,7 @@ public abstract class AbstractLogglyAppender<E> extends UnsynchronizedAppenderBa
private String proxyHost;
protected Proxy proxy;
private int httpReadTimeoutInMillis = 1000;
private int httpMaxNumberOfRetries = 3;

@Override
public void start() {
Expand Down Expand Up @@ -90,7 +92,7 @@ protected byte[] toBytes(final InputStream is) throws IOException {
int count;
byte[] buf = new byte[512];

while((count = is.read(buf, 0, buf.length)) != -1) {
while ((count = is.read(buf, 0, buf.length)) != -1) {
baos.write(buf, 0, count);
}
baos.flush();
Expand Down Expand Up @@ -135,14 +137,13 @@ protected String buildEndpointUrl(String inputKey) {
return new StringBuilder(DEFAULT_ENDPOINT_PREFIX).append(getEndpointPrefix())
.append(inputKey).toString();
}

/**
* Returns the URL path prefix for the Loggly endpoint to which the
* implementing class will send log events. This path prefix varies
* for the different Loggly services. The final endpoint URL is built
* by concatenating the {@link #DEFAULT_ENDPOINT_PREFIX} with the
* endpoint prefix from {@link #getEndpointPrefix()} and the
* {@link #inputKey}.
* Returns the URL path prefix for the Loggly endpoint to which the
* implementing class will send log events. This path prefix varies for the
* different Loggly services. The final endpoint URL is built by
* concatenating the {@link #DEFAULT_ENDPOINT_PREFIX} with the endpoint
* prefix from {@link #getEndpointPrefix()} and the {@link #inputKey}.
*
* @return the URL path prefix for the Loggly endpoint
*/
Expand Down Expand Up @@ -194,8 +195,9 @@ public int getProxyPort() {
public void setProxyPort(int proxyPort) {
this.proxyPort = proxyPort;
}

public void setProxyPort(String proxyPort) {
if(proxyPort == null || proxyPort.trim().isEmpty()) {
if (proxyPort == null || proxyPort.trim().isEmpty()) {
// handle logback configuration default value like "<proxyPort>${logback.loggly.proxy.port:-}</proxyPort>"
proxyPort = "0";
}
Expand All @@ -207,7 +209,7 @@ public String getProxyHost() {
}

public void setProxyHost(String proxyHost) {
if(proxyHost == null || proxyHost.trim().isEmpty()) {
if (proxyHost == null || proxyHost.trim().isEmpty()) {
// handle logback configuration default value like "<proxyHost>${logback.loggly.proxy.host:-}</proxyHost>"
proxyHost = null;
}
Expand All @@ -221,4 +223,20 @@ public int getHttpReadTimeoutInMillis() {
public void setHttpReadTimeoutInMillis(int httpReadTimeoutInMillis) {
this.httpReadTimeoutInMillis = httpReadTimeoutInMillis;
}

public int getHttpMaxNumberOfRetries() {
return httpMaxNumberOfRetries;
}

public void setHttpMaxNumberOfRetries(int httpMaxNumberOfRetries) {
if (httpMaxNumberOfRetries <= 0) {
this.httpMaxNumberOfRetries = 0;
} else {
this.httpMaxNumberOfRetries = httpMaxNumberOfRetries;
}
}

protected boolean canRetry(int currentRetryCount) {
return currentRetryCount <= getHttpMaxNumberOfRetries();
}
}
57 changes: 33 additions & 24 deletions loggly/src/main/java/ch/qos/logback/ext/loggly/LogglyAppender.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import java.net.URL;

/**
* An Appender that posts logging messages to <a href="http://www.loggly.com">Loggly</a>, a cloud logging service.
* An Appender that posts logging messages to
* <a href="http://www.loggly.com">Loggly</a>, a cloud logging service.
*
* @author Mårten Gustafson
* @author Les Hazlewood
Expand All @@ -30,7 +31,7 @@
public class LogglyAppender<E> extends AbstractLogglyAppender<E> {

public static final String ENDPOINT_URL_PATH = "inputs/";

public LogglyAppender() {
}

Expand All @@ -41,28 +42,37 @@ protected void append(E eventObject) {
}

private void postToLoggly(final String event) {
try {
assert endpointUrl != null;
URL endpoint = new URL(endpointUrl);
final HttpURLConnection connection;
if (proxy == null) {
connection = (HttpURLConnection) endpoint.openConnection();
} else {
connection = (HttpURLConnection) endpoint.openConnection(proxy);
int currentRetryCount = 0;
boolean success = false;
while (!success && canRetry(currentRetryCount)) {
try {
assert endpointUrl != null;
URL endpoint = new URL(endpointUrl);
final HttpURLConnection connection;
if (proxy == null) {
connection = (HttpURLConnection) endpoint.openConnection();
} else {
connection = (HttpURLConnection) endpoint.openConnection(proxy);
}
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.addRequestProperty("Content-Type", this.layout.getContentType());
connection.connect();
sendAndClose(event, connection.getOutputStream());
connection.disconnect();
final int responseCode = connection.getResponseCode();
if (responseCode == 200) {
success = true;
} else if (!canRetry(currentRetryCount)) {
final String message = readResponseBody(connection.getInputStream());
addError("Loggly post failed (HTTP " + responseCode + "). Response body:\n" + message);
}
} catch (final IOException e) {
if (!canRetry(currentRetryCount)) {
addError("IOException while attempting to communicate with Loggly", e);
}
}
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.addRequestProperty("Content-Type", this.layout.getContentType());
connection.connect();
sendAndClose(event, connection.getOutputStream());
connection.disconnect();
final int responseCode = connection.getResponseCode();
if (responseCode != 200) {
final String message = readResponseBody(connection.getInputStream());
addError("Loggly post failed (HTTP " + responseCode + "). Response body:\n" + message);
}
} catch (final IOException e) {
addError("IOException while attempting to communicate with Loggly", e);
currentRetryCount++;
}
}

Expand All @@ -79,4 +89,3 @@ protected String getEndpointPrefix() {
return ENDPOINT_URL_PATH;
}
}

Loading