Browse Source

run error reporting API in a background thread

tags/2.0.1
Jonathan Cobb 4 years ago
parent
commit
95260bc7e8
2 changed files with 64 additions and 8 deletions
  1. +8
    -3
      wizard-server/src/main/java/org/cobbzilla/wizard/server/config/ErrorApiConfiguration.java
  2. +56
    -5
      wizard-server/src/main/java/org/cobbzilla/wizard/server/listener/ErrbitConfigListener.java

+ 8
- 3
wizard-server/src/main/java/org/cobbzilla/wizard/server/config/ErrorApiConfiguration.java View File

@@ -5,9 +5,10 @@ import airbrake.AirbrakeNotifier;
import lombok.*; import lombok.*;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.buffer.CircularFifoBuffer; import org.apache.commons.collections.buffer.CircularFifoBuffer;
import org.cobbzilla.util.system.CommandShell;


import static java.util.concurrent.TimeUnit.SECONDS;
import static org.cobbzilla.util.daemon.ZillaRuntime.empty; import static org.cobbzilla.util.daemon.ZillaRuntime.empty;
import static org.cobbzilla.util.system.CommandShell.hostname;


@NoArgsConstructor @AllArgsConstructor @Slf4j @ToString @NoArgsConstructor @AllArgsConstructor @Slf4j @ToString
public class ErrorApiConfiguration { public class ErrorApiConfiguration {
@@ -15,15 +16,19 @@ public class ErrorApiConfiguration {
@Getter @Setter private String url; @Getter @Setter private String url;
@Getter @Setter private String key; @Getter @Setter private String key;
@Setter private String env; @Setter private String env;
@Getter @Setter private int dupCacheSize = 100;
@Getter @Setter private int bufferSize = 200;
@Getter @Setter private long sendInterval = SECONDS.toMillis(5);


@Getter(lazy=true) private final AirbrakeNotifier notifier = initNotifier(); @Getter(lazy=true) private final AirbrakeNotifier notifier = initNotifier();

private AirbrakeNotifier initNotifier() { return new AirbrakeNotifier(getUrl()); } private AirbrakeNotifier initNotifier() { return new AirbrakeNotifier(getUrl()); }


public String getEnv() { return !empty(env) ? env : CommandShell.hostname(); }
public String getEnv() { return !empty(env) ? env : hostname(); }


public boolean isValid() { return !empty(getUrl()) && !empty(getKey()) && !empty(getEnv()); } public boolean isValid() { return !empty(getUrl()) && !empty(getKey()) && !empty(getEnv()); }


private final CircularFifoBuffer cache = new CircularFifoBuffer(20);
private final CircularFifoBuffer cache = new CircularFifoBuffer(dupCacheSize);


public void report(Exception e) { public void report(Exception e) {
if (inCache(e)) return; if (inCache(e)) return;


+ 56
- 5
wizard-server/src/main/java/org/cobbzilla/wizard/server/listener/ErrbitConfigListener.java View File

@@ -2,7 +2,7 @@ package org.cobbzilla.wizard.server.listener;


import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.collections.buffer.CircularFifoBuffer;
import org.cobbzilla.util.daemon.ErrorApi; import org.cobbzilla.util.daemon.ErrorApi;
import org.cobbzilla.util.daemon.ZillaRuntime; import org.cobbzilla.util.daemon.ZillaRuntime;
import org.cobbzilla.wizard.server.RestServer; import org.cobbzilla.wizard.server.RestServer;
@@ -10,6 +10,13 @@ import org.cobbzilla.wizard.server.RestServerBase;
import org.cobbzilla.wizard.server.RestServerLifecycleListenerBase; import org.cobbzilla.wizard.server.RestServerLifecycleListenerBase;
import org.cobbzilla.wizard.server.config.RestServerConfiguration; import org.cobbzilla.wizard.server.config.RestServerConfiguration;


import java.util.ArrayList;
import java.util.List;

import static org.apache.commons.lang3.exception.ExceptionUtils.getStackTrace;
import static org.cobbzilla.util.daemon.ZillaRuntime.shortError;
import static org.cobbzilla.util.system.Sleep.sleep;

@Slf4j @Slf4j
public class ErrbitConfigListener extends RestServerLifecycleListenerBase { public class ErrbitConfigListener extends RestServerLifecycleListenerBase {


@@ -17,18 +24,22 @@ public class ErrbitConfigListener extends RestServerLifecycleListenerBase {
final ErrbitApi errorApi = new ErrbitApi(server.getConfiguration()); final ErrbitApi errorApi = new ErrbitApi(server.getConfiguration());
RestServerBase.setErrorApi(errorApi); RestServerBase.setErrorApi(errorApi);
ZillaRuntime.setErrorApi(errorApi); ZillaRuntime.setErrorApi(errorApi);
errorApi.start();
log.info("onStart: "+server.getConfiguration().getErrorApi()); log.info("onStart: "+server.getConfiguration().getErrorApi());
} }


@AllArgsConstructor @Slf4j @AllArgsConstructor @Slf4j
static class ErrbitApi implements ErrorApi {
static class ErrbitApi implements ErrorApi, Runnable {

private static final String SLEEP_MESSAGE = ErrbitApi.class.getName()+"waiting for more errors";


private final RestServerConfiguration config; private final RestServerConfiguration config;
private final CircularFifoBuffer fifo = new CircularFifoBuffer(config.getErrorApi().getBufferSize());


@Override public void report(Exception e) { @Override public void report(Exception e) {
if (config.hasErrorApi()) { if (config.hasErrorApi()) {
log.error(e.toString()); log.error(e.toString());
config.getErrorApi().report(e);
synchronized (fifo) { fifo.add(e); }
} else { } else {
log.warn("report: could not send exception to error reporting API: "+e, e); log.warn("report: could not send exception to error reporting API: "+e, e);
} }
@@ -37,14 +48,54 @@ public class ErrbitConfigListener extends RestServerLifecycleListenerBase {
@Override public void report(String s) { @Override public void report(String s) {
if (config.hasErrorApi()) { if (config.hasErrorApi()) {
log.error(s); log.error(s);
config.getErrorApi().report(s);
synchronized (fifo) { fifo.add(s); }
} else { } else {
log.warn("report: could not send exception to error reporting API: "+s); log.warn("report: could not send exception to error reporting API: "+s);
} }
} }


@Override public void report(String s, Exception e) { @Override public void report(String s, Exception e) {
report(s+"\nException: "+e+"\n"+ExceptionUtils.getStackTrace(e));
report(s+"\nException: "+e+"\n"+getStackTrace(e));
}

public void start() {
final Thread t = new Thread(this);
t.setDaemon(true);
t.setName(getClass().getName());
t.start();
}

@Override public void run() {
while (true) {
try {
final List reports;
synchronized (fifo) {
if (fifo.isEmpty()) {
reports = new ArrayList(fifo);
fifo.clear();
} else {
reports = null;
}
}
if (reports == null) {
sleep(config.getErrorApi().getSendInterval(), SLEEP_MESSAGE);
continue;
}
for (Object o : reports) {
if (o instanceof Exception) {
config.getErrorApi().report((Exception) o);
} else if (o instanceof String) {
config.getErrorApi().report((String) o);
} else {
final String val = o.toString();
log.warn("ErrbitApi.run: reporting object that is neither Exception nor String (" + o.getClass().getName() + ") as String: " + val);
config.getErrorApi().report(val);
}
}
} catch (Exception e) {
log.error("ErrbitApi.run: unexpected exception: "+shortError(e));
}
}
} }
} }




Loading…
Cancel
Save