package org.stagemonitor.tracing.reporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.stagemonitor.configuration.ConfigurationRegistry;
import org.stagemonitor.core.CorePlugin;
import org.stagemonitor.core.util.CompletedFuture;
import org.stagemonitor.core.util.ExecutorUtils;
import org.stagemonitor.tracing.SpanContextInformation;
import org.stagemonitor.tracing.TracingPlugin;
import org.stagemonitor.tracing.wrapper.SpanWrapper;
import org.stagemonitor.tracing.wrapper.StatelessSpanEventListener;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
public class ReportingSpanEventListener extends StatelessSpanEventListener {
private static final Logger logger = LoggerFactory.getLogger(ReportingSpanEventListener.class);
private final TracingPlugin tracingPlugin;
private final ExecutorService asyncSpanReporterPool;
private final List<SpanReporter> spanReporters = new CopyOnWriteArrayList<SpanReporter>();
private final ConfigurationRegistry configuration;
public ReportingSpanEventListener(ConfigurationRegistry configuration) {
this.configuration = configuration;
this.tracingPlugin = configuration.getConfig(TracingPlugin.class);
final int threadPoolQueueCapacityLimit = configuration.getConfig(CorePlugin.class).getThreadPoolQueueCapacityLimit();
this.asyncSpanReporterPool = ExecutorUtils
.createSingleThreadDeamonPool("async-request-reporter", threadPoolQueueCapacityLimit);
}
@Override
public void onFinish(SpanWrapper spanWrapper, String operationName, long durationNanos) {
final SpanContextInformation info = SpanContextInformation.forSpan(spanWrapper);
if (info.isSampled() && info.getReadbackSpan() != null) {
try {
report(info);
} catch (Exception e) {
logger.warn(e.getMessage() + " (this exception is ignored) " + info.toString(), e);
}
}
}
private Future<?> report(final SpanContextInformation spanContext) {
try {
if (tracingPlugin.isReportAsync()) {
return asyncSpanReporterPool.submit(new Runnable() {
@Override
public void run() {
doReport(spanContext);
}
});
} else {
doReport(spanContext);
return new CompletedFuture<Object>(null);
}
} catch (RejectedExecutionException e) {
ExecutorUtils.logRejectionWarning(e);
return new CompletedFuture<Object>(null);
}
}
private void doReport(SpanContextInformation spanContext) {
for (SpanReporter spanReporter : spanReporters) {
if (spanReporter.isActive(spanContext)) {
try {
spanReporter.report(spanContext);
} catch (Exception e) {
logger.warn(e.getMessage() + " (this exception is ignored)", e);
}
}
}
}
/**
* Shuts down the internal thread pool
*/
public void close() {
asyncSpanReporterPool.shutdown();
}
/**
* Adds a {@link SpanReporter}
*
* @param spanReporter the {@link SpanReporter} to add
*/
public void addReporter(SpanReporter spanReporter) {
spanReporters.add(0, spanReporter);
spanReporter.init(configuration);
}
boolean isAnyReporterActive(SpanContextInformation spanContext) {
for (SpanReporter spanReporter : spanReporters) {
if (spanReporter.isActive(spanContext)) {
return true;
}
}
return false;
}
}