
com.wavefront.sdk.proxy.WavefrontProxyClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of wavefront-sdk-java Show documentation
Show all versions of wavefront-sdk-java Show documentation
Core library for sending telemetry data to Wavefront from Java applications.
The newest version!
package com.wavefront.sdk.proxy;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.wavefront.sdk.common.Constants;
import com.wavefront.sdk.common.NamedThreadFactory;
import com.wavefront.sdk.common.Pair;
import com.wavefront.sdk.common.Utils;
import com.wavefront.sdk.common.WavefrontSender;
import com.wavefront.sdk.common.annotation.Nullable;
import com.wavefront.sdk.common.clients.WavefrontClientFactory;
import com.wavefront.sdk.common.metrics.WavefrontSdkDeltaCounter;
import com.wavefront.sdk.common.metrics.WavefrontSdkMetricsRegistry;
import com.wavefront.sdk.entities.histograms.HistogramGranularity;
import com.wavefront.sdk.entities.tracing.SpanLog;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.SocketFactory;
import static com.wavefront.sdk.common.Utils.histogramToLineData;
import static com.wavefront.sdk.common.Utils.metricToLineData;
import static com.wavefront.sdk.common.Utils.spanLogsToLineData;
import static com.wavefront.sdk.common.Utils.tracingSpanToLineData;
/**
* WavefrontProxyClient that sends data directly via TCP to the Wavefront Proxy Agent.
* User should probably attempt to reconnect when exceptions are thrown from any methods.
*
* @deprecated This class will be removed in future versions in favor of
* {@link com.wavefront.sdk.common.clients.WavefrontClientFactory} to construct Proxy and DirectDataIngestion senders.
* @author Sushant Dewan ([email protected]).
* @version $Id: $Id
*/
@Deprecated
public class WavefrontProxyClient implements WavefrontSender, Runnable {
private static final Logger logger = Logger.getLogger(
WavefrontProxyClient.class.getCanonicalName());
@Nullable
private final ProxyConnectionHandler metricsProxyConnectionHandler;
@Nullable
private final ProxyConnectionHandler histogramProxyConnectionHandler;
@Nullable
private final ProxyConnectionHandler tracingProxyConnectionHandler;
/**
* Source to use if entity source is null
*/
private final String defaultSource;
private final String clientId;
private final ScheduledExecutorService scheduler;
private final WavefrontSdkMetricsRegistry sdkMetricsRegistry;
// Internal point metrics
private final WavefrontSdkDeltaCounter pointsDiscarded;
private final WavefrontSdkDeltaCounter pointsValid;
private final WavefrontSdkDeltaCounter pointsInvalid;
private final WavefrontSdkDeltaCounter pointsDropped;
// Internal histogram metrics
private final WavefrontSdkDeltaCounter histogramsDiscarded;
private final WavefrontSdkDeltaCounter histogramsValid;
private final WavefrontSdkDeltaCounter histogramsInvalid;
private final WavefrontSdkDeltaCounter histogramsDropped;
// Internal tracing span metrics
private final WavefrontSdkDeltaCounter spansDiscarded;
private final WavefrontSdkDeltaCounter spansValid;
private final WavefrontSdkDeltaCounter spansInvalid;
private final WavefrontSdkDeltaCounter spansDropped;
// Internal span log metrics
private final WavefrontSdkDeltaCounter spanLogsDiscarded;
private final WavefrontSdkDeltaCounter spanLogsValid;
private final WavefrontSdkDeltaCounter spanLogsInvalid;
private final WavefrontSdkDeltaCounter spanLogsDropped;
// Flag to prevent sending after close() has been called
private final AtomicBoolean closed = new AtomicBoolean(false);
public static class Builder {
// Required parameters
private final String proxyHostName;
// Optional parameters
private Integer metricsPort;
private Integer distributionPort;
private Integer tracingPort;
private SocketFactory socketFactory = SocketFactory.getDefault();
private int flushIntervalSeconds = 5;
/**
* WavefrontProxyClient.Builder
*
* @param proxyHostName Hostname of the Wavefront proxy
*/
public Builder(String proxyHostName) {
this.proxyHostName = proxyHostName;
}
/**
* Invoke this method to enable sending metrics to Wavefront cluster via proxy
*
* @param metricsPort Metrics Port on which the Wavefront proxy is listening on
* @return {@code this}
*/
public Builder metricsPort(int metricsPort) {
this.metricsPort = metricsPort;
return this;
}
/**
* Invoke this method to enable sending distribution to Wavefront cluster via proxy
*
* @param distributionPort Distribution Port on which the Wavefront proxy is listening on
* @return {@code this}
*/
public Builder distributionPort(int distributionPort) {
this.distributionPort = distributionPort;
return this;
}
/**
* Invoke this method to enable sending tracing spans to Wavefront cluster via proxy
*
* @param tracingPort Tracing Port on which the Wavefront proxy is listening on
* @return {@code this}
*/
public Builder tracingPort(int tracingPort) {
this.tracingPort = tracingPort;
return this;
}
/**
* Set an explicit SocketFactory
*
* @param socketFactory SocketFactory
* @return {@code this}
*/
public Builder socketFactory(SocketFactory socketFactory) {
this.socketFactory = socketFactory;
return this;
}
/**
* Set interval at which you want to flush points to Wavefront proxy
*
* @param flushIntervalSeconds Interval at which you want to flush points to Wavefront proxy
* @return {@code this}
*/
public Builder flushIntervalSeconds(int flushIntervalSeconds) {
this.flushIntervalSeconds = flushIntervalSeconds;
return this;
}
/**
* Builds WavefrontProxyClient instance
*
* @return {@link WavefrontProxyClient}
*/
public WavefrontProxyClient build() {
return new WavefrontProxyClient(this);
}
}
private WavefrontProxyClient(Builder builder) {
String tempSource = "unknown";
try {
tempSource = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException ex) {
logger.log(Level.WARNING,
"Unable to resolve local host name. Source will default to 'unknown'", ex);
}
defaultSource = tempSource;
String processId = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
sdkMetricsRegistry = new WavefrontSdkMetricsRegistry.Builder(this).
prefix(Constants.SDK_METRIC_PREFIX + ".core.sender.proxy").
tag(Constants.PROCESS_TAG_KEY, processId).
build();
String uniqueId = builder.proxyHostName + ":";
if (builder.metricsPort == null) {
metricsProxyConnectionHandler = null;
} else {
metricsProxyConnectionHandler = new ProxyConnectionHandler(
new InetSocketAddress(builder.proxyHostName, builder.metricsPort),
builder.socketFactory, sdkMetricsRegistry, "metricHandler");
uniqueId += builder.metricsPort + ":";
}
if (builder.distributionPort == null) {
histogramProxyConnectionHandler = null;
} else {
histogramProxyConnectionHandler = new ProxyConnectionHandler(
new InetSocketAddress(builder.proxyHostName, builder.distributionPort),
builder.socketFactory, sdkMetricsRegistry, "histogramHandler");
uniqueId += builder.distributionPort + ":";
}
if (builder.tracingPort == null) {
tracingProxyConnectionHandler = null;
} else {
tracingProxyConnectionHandler = new ProxyConnectionHandler(
new InetSocketAddress(builder.proxyHostName, builder.tracingPort),
builder.socketFactory, sdkMetricsRegistry, "tracingHandler");
uniqueId += builder.tracingPort;
}
this.clientId = uniqueId;
scheduler = Executors.newScheduledThreadPool(1,
new NamedThreadFactory("wavefrontProxySender").setDaemon(true));
// flush every 5 seconds
scheduler.scheduleAtFixedRate(this, 1, builder.flushIntervalSeconds, TimeUnit.SECONDS);
pointsDiscarded = sdkMetricsRegistry.newDeltaCounter("points.discarded");
pointsValid = sdkMetricsRegistry.newDeltaCounter("points.valid");
pointsInvalid = sdkMetricsRegistry.newDeltaCounter("points.invalid");
pointsDropped = sdkMetricsRegistry.newDeltaCounter("points.dropped");
histogramsDiscarded = sdkMetricsRegistry.newDeltaCounter("histograms.discarded");
histogramsValid = sdkMetricsRegistry.newDeltaCounter("histograms.valid");
histogramsInvalid = sdkMetricsRegistry.newDeltaCounter("histograms.invalid");
histogramsDropped = sdkMetricsRegistry.newDeltaCounter("histograms.dropped");
spansDiscarded = sdkMetricsRegistry.newDeltaCounter("spans.discarded");
spansValid = sdkMetricsRegistry.newDeltaCounter("spans.valid");
spansInvalid = sdkMetricsRegistry.newDeltaCounter("spans.invalid");
spansDropped = sdkMetricsRegistry.newDeltaCounter("spans.dropped");
spanLogsDiscarded = sdkMetricsRegistry.newDeltaCounter("span_logs.discarded");
spanLogsValid = sdkMetricsRegistry.newDeltaCounter("span_logs.valid");
spanLogsInvalid = sdkMetricsRegistry.newDeltaCounter("span_logs.invalid");
spanLogsDropped = sdkMetricsRegistry.newDeltaCounter("span_logs.dropped");
}
/** {@inheritDoc} */
@Override
public String getClientId() {
return clientId;
}
/** {@inheritDoc} */
@Override
public void sendMetric(String name, double value, @Nullable Long timestamp,
@Nullable String source, @Nullable Map tags)
throws IOException {
if (closed.get()) {
throw new IOException("attempt to send using closed sender");
}
if (metricsProxyConnectionHandler == null) {
pointsDiscarded.inc();
logger.warning("Can't send data to Wavefront. " +
"Please configure metrics port for Wavefront proxy");
return;
}
String lineData;
try {
lineData = metricToLineData(name, value, timestamp, source, tags, defaultSource);
pointsValid.inc();
} catch (IllegalArgumentException e) {
pointsInvalid.inc();
throw e;
}
try {
metricsProxyConnectionHandler.sendData(lineData);
} catch (Exception e) {
pointsDropped.inc();
metricsProxyConnectionHandler.incrementFailureCount();
throw new IOException(e);
}
}
/** {@inheritDoc} */
@Override
public void sendLog(String name, double value, Long timestamp, String source, Map tags) {
throw new IllegalArgumentException("Sending logs using this method is not allowed");
}
/** {@inheritDoc} */
@Override
public void sendFormattedMetric(String point) throws IOException {
if (closed.get()) {
throw new IOException("attempt to send using closed sender");
}
if (metricsProxyConnectionHandler == null) {
pointsDiscarded.inc();
logger.warning("Can't send data to Wavefront. " +
"Please configure metrics port for Wavefront proxy");
return;
}
if (point == null || "".equals(point.trim())) {
pointsInvalid.inc();
throw new IllegalArgumentException("point must be non-null and in WF data format");
}
pointsValid.inc();
String finalPoint = point.endsWith("\n") ? point : point + "\n";
try {
metricsProxyConnectionHandler.sendData(finalPoint);
} catch (Exception e) {
pointsDropped.inc();
metricsProxyConnectionHandler.incrementFailureCount();
throw new IOException(e);
}
}
/** {@inheritDoc} */
@Override
public void sendDistribution(String name, List> centroids,
Set histogramGranularities,
@Nullable Long timestamp, @Nullable String source,
@Nullable Map tags)
throws IOException {
if (closed.get()) {
throw new IOException("attempt to send using closed sender");
}
if (histogramProxyConnectionHandler == null) {
histogramsDiscarded.inc();
logger.warning("Can't send data to Wavefront. " +
"Please configure histogram distribution port for Wavefront proxy");
return;
}
String lineData;
try {
lineData = histogramToLineData(name, centroids, histogramGranularities, timestamp,
source, tags, defaultSource);
histogramsValid.inc();
} catch (IllegalArgumentException e) {
histogramsInvalid.inc();
throw e;
}
try {
histogramProxyConnectionHandler.sendData(lineData);
} catch (Exception e) {
histogramsDropped.inc();
histogramProxyConnectionHandler.incrementFailureCount();
throw new IOException(e);
}
}
/** {@inheritDoc} */
@Override
public void sendSpan(String name, long startMillis, long durationMillis,
@Nullable String source, UUID traceId, UUID spanId,
@Nullable List parents, @Nullable List followsFrom,
@Nullable List> tags, @Nullable List spanLogs)
throws IOException {
if (closed.get()) {
throw new IOException("attempt to send using closed sender");
}
if (tracingProxyConnectionHandler == null) {
spansDiscarded.inc();
if (spanLogs != null && !spanLogs.isEmpty()) {
spanLogsDiscarded.inc();
}
logger.warning("Can't send data to Wavefront. " +
"Please configure tracing port for Wavefront proxy");
return;
}
String lineData;
try {
lineData = tracingSpanToLineData(name, startMillis, durationMillis, source, traceId,
spanId, parents, followsFrom, tags, spanLogs, defaultSource);
spansValid.inc();
} catch (IllegalArgumentException e) {
spansInvalid.inc();
throw e;
}
try {
tracingProxyConnectionHandler.sendData(lineData);
} catch (Exception e) {
spansDropped.inc();
if (spanLogs != null && !spanLogs.isEmpty()) {
spanLogsDropped.inc();
}
tracingProxyConnectionHandler.incrementFailureCount();
throw new IOException(e);
}
if (spanLogs != null && !spanLogs.isEmpty()) {
sendSpanLogsData(traceId, spanId, spanLogs, lineData);
}
}
private void sendSpanLogsData(UUID traceId, UUID spanId, List spanLogs, String span) {
try {
String lineData = spanLogsToLineData(traceId, spanId, spanLogs, span);
spanLogsValid.inc();
tracingProxyConnectionHandler.sendData(lineData);
} catch (JsonProcessingException e) {
spanLogsInvalid.inc();
logger.log(Level.WARNING, "unable to serialize span logs to json: traceId:" + traceId +
" spanId:" + spanId + " spanLogs:" + spanLogs);
} catch (Exception e) {
spanLogsDropped.inc();
logger.log(Level.WARNING, "unable to send span logs for traceId:" + traceId +
" spanId:" + spanId + " due to exception: " + e);
}
}
/** {@inheritDoc} */
@Override
public void sendEvent(String name, long startMillis, long endMillis, @Nullable String source,
@Nullable Map tags,
@Nullable Map annotations)
throws UnsupportedOperationException {
throw new UnsupportedOperationException("Sending event is not supported for " +
"deprecated WavefrontProxyClient. Please use WavefrontClient to send events.");
}
/** {@inheritDoc} */
@Override
public void run() {
try {
this.flush();
} catch (Throwable ex) {
logger.log(Level.WARNING, "Unable to report to Wavefront cluster", ex);
}
}
private void flushNoCheck() throws IOException {
if (metricsProxyConnectionHandler != null) {
metricsProxyConnectionHandler.flush();
}
if (histogramProxyConnectionHandler != null) {
histogramProxyConnectionHandler.flush();
}
if (tracingProxyConnectionHandler != null) {
tracingProxyConnectionHandler.flush();
}
}
/** {@inheritDoc} */
@Override
public void flush() throws IOException {
if (closed.get()) {
throw new IOException("attempt to flush closed sender");
}
this.flushNoCheck();
}
/** {@inheritDoc} */
@Override
public int getFailureCount() {
int failureCount = 0;
if (metricsProxyConnectionHandler != null) {
failureCount += metricsProxyConnectionHandler.getFailureCount();
}
if (histogramProxyConnectionHandler != null) {
failureCount += histogramProxyConnectionHandler.getFailureCount();
}
if (tracingProxyConnectionHandler != null) {
failureCount += tracingProxyConnectionHandler.getFailureCount();
}
return failureCount;
}
/** {@inheritDoc} */
@Override
public void close() {
if (!closed.compareAndSet(false, true)) {
logger.log(Level.FINE,"attempt to close already closed sender");
}
sdkMetricsRegistry.close();
// Flush before closing
try {
flushNoCheck();
} catch (IOException e) {
logger.log(Level.WARNING, "error flushing buffer", e);
}
try {
Utils.shutdownExecutorAndWait(scheduler);
} catch (SecurityException ex) {
logger.log(Level.FINE, "shutdown error", ex);
}
if (metricsProxyConnectionHandler != null) {
try {
metricsProxyConnectionHandler.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error closing metricsProxyConnectionHandler", e);
}
}
if (histogramProxyConnectionHandler != null) {
try {
histogramProxyConnectionHandler.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error closing histogramProxyConnectionHandler", e);
}
}
if (tracingProxyConnectionHandler != null) {
try {
tracingProxyConnectionHandler.close();
} catch (IOException e) {
logger.log(Level.WARNING, "error closing tracingProxyConnectionHandler", e);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy