com.coalmine.connector.SimpleConnector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coalmine-connector Show documentation
Show all versions of coalmine-connector Show documentation
Coalmine connector for Java. Coalmine (https://www.getcoalmine.com) is a cloud-based exception and error tracking service for your web apps.
The newest version!
package com.coalmine.connector;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.coalmine.connector.notification.Notification;
/**
* The simplest implementation of a Coalmine Connector. This is the class
* responsible for sending messages to the Coalmine API.
*
* This connector honors rate throttling on the client side so that when a
* throttle event occurs, the client (this connector) will not send another
* message for the throttle period (value of Retry-After response header).
*/
public class SimpleConnector extends Connector {
/** The system time that we were last throttled. */
private Long lastThrottled;
/**
* The number of seconds to wait (from lastThrottled) before sending another
* message to Coalmine.
*/
private int throttleTimeout;
/** Content type of the HTTP request. */
private static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
/** Class level logger. */
private static final Logger LOG = LoggerFactory.getLogger(SimpleConnector.class);
/**
* The default number of seconds we will wait, if throttled, before
* sending another. It is expected that a throttle response will include
* a Retry-After header with the number of seconds to wait before sending
* another message. If this is not set, or cannot be parsed, this value will
* be used.
*/
private static final int DEFAULT_THROTTLE_TIMEOUT = 60;
public SimpleConnector(String signature) {
super(signature);
}
@Override
public boolean send(Notification notification) {
if (!isSendable(notification)) {
LOG.warn(
String.format("Coalmine notifications are disabled for the current environment (%s). Enable this environment via connector.addEnabledEnvironment(\"%s\");",
applicationEnvironment, applicationEnvironment));
return false;
}
try {
return _send(notification);
} catch (RuntimeException e) {
LOG.error("Unable to send notification to Coalmine.", e);
return false;
}
}
protected boolean isThrottled() {
if (lastThrottled == null) {
return false;
}
long diff = System.currentTimeMillis() - lastThrottled;
if (diff > throttleTimeout * 1000) {
lastThrottled = null;
return false;
}
return true;
}
private boolean _send(Notification notification) {
if (isThrottled()) {
logThrottled();
return false;
}
notification.setApplicationEnvironment(applicationEnvironment);
notification.setVersion(version);
if (getUserProvider() != null) {
notification.setUserId(getUserProvider().getUser());
}
URL url = null;
HttpURLConnection conn = null;
try {
url = new URL(getUrl());
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", CONTENT_TYPE);
conn.setUseCaches(false);
conn.setDoOutput(true); // Implicitly sets conn to POST
conn.setConnectTimeout(timeout);
Map params = notification.getQueryParams();
params.put("signature", signature);
StringBuilder queryBuilder = new StringBuilder();
for (String key : params.keySet()) {
queryBuilder.append(URLEncoder.encode(key, "UTF-8"));
queryBuilder.append("=");
if (params.get(key) != null) {
queryBuilder.append(URLEncoder.encode(params.get(key).toString(), "UTF-8"));
}
queryBuilder.append("&");
}
String query = queryBuilder.toString();
query = query.substring(0, query.length() - 1);
LOG.debug(String.format("Sending %s to %s", query, getUrl()));
DataOutputStream writer = new DataOutputStream(conn.getOutputStream());
writer.writeBytes(query);
writer.flush ();
writer.close ();
if (conn.getResponseCode() == 200) {
LOG.info("Successfully posted notification to Coalmine");
return true;
} else if (conn.getResponseCode() == 429) {
logThrottled();
setTemporaryTimeout(conn.getHeaderField("Retry-After"));
return false;
}
LOG.warn("Unable to communicate with the Coalmine server.");
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append("\n");
}
br.close();
LOG.warn("Response from Coalmine was: " + sb.toString());
} catch (IOException e) {
LOG.error("Unable to send notification to Coalmine", e);
} finally {
if (conn != null) {
conn.disconnect();
}
}
return false;
}
/**
* Set the temporary timeout, but take a string as a param. Convenience for
* accepting values directly from response headers.
*
* @param strTimeoutSeconds
*/
protected void setTemporaryTimeout(String strTimeoutSeconds) {
if (strTimeoutSeconds == null || strTimeoutSeconds.isEmpty()) {
setTemporaryTimeout(DEFAULT_THROTTLE_TIMEOUT);
return;
}
try {
setTemporaryTimeout(Integer.parseInt(strTimeoutSeconds));
} catch (NumberFormatException e) {
LOG.warn("Unable to parse retry-after header value ({}) from throttled Coalmine response", strTimeoutSeconds);
setTemporaryTimeout(DEFAULT_THROTTLE_TIMEOUT);
}
}
/**
* Set the number of seconds to wait before sending another message to
* Coalmine.
*
* @param strTimeoutSeconds The number of seconds to wait
*/
protected void setTemporaryTimeout(int timeout) {
lastThrottled = System.currentTimeMillis();
throttleTimeout = timeout;
}
private void logThrottled() {
LOG.warn("Application is being throttled by Coalmine. Notification will not be sent.");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy