Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.
Merged
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
6 changes: 2 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ break behaviors for applications that rely on this to be always enabled.
- Provide a `Deadline` option to Stackdriver Stats exporter. Default value is 10 seconds.
Also provide a `MetricServiceStub` option so that advanced users can use a custom Stackdriver
Monitoring client to make RPCs.
- Use `JaegerExporterConfiguration` for creating `JaegerTraceExporter`. Provide a `Deadline` option
with default value 10 seconds.
- Use `ZipkinExporterConfiguration` for creating `ZipkinTraceExporter`. Provide a `Deadline` option
with default value 10 seconds.
- Use `Configuration` builder pattern for creating `JaegerTraceExporter`, `ZipkinTraceExporter` and
`InstanaTraceExporter`. Provide a `Deadline` option with default value 10 seconds.
- Provide a `Deadline` option to Datadog and Elasticsearch exporter. Default value is 10 seconds.
- Extract the common timeout logic of Trace exporters to `opencensus-exporter-trace-util`.

Expand Down
2 changes: 2 additions & 0 deletions exporters/trace/instana/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description = 'OpenCensus Trace Instana Exporter'
}

dependencies {
compileOnly libraries.auto_value

compile project(':opencensus-api'),
project(':opencensus-exporter-trace-util'),
libraries.guava
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright 2019, OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.opencensus.exporter.trace.instana;

import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import io.opencensus.common.Duration;
import javax.annotation.concurrent.Immutable;

/**
* Configuration for {@link InstanaTraceExporter}.
*
* @since 0.22
*/
@AutoValue
@Immutable
public abstract class InstanaExporterConfiguration {

@VisibleForTesting static final Duration DEFAULT_DEADLINE = Duration.create(10, 0);
@VisibleForTesting static final Duration ZERO = Duration.fromMillis(0);

InstanaExporterConfiguration() {}

/**
* Returns the endpoint of the Instana agent.
*
* @return the endpoint of the Instana agent.
* @since 0.22
*/
public abstract String getAgentEndpoint();

/**
* Returns the deadline for exporting to Instana.
*
* <p>Default value is 10 seconds.
*
* @return the export deadline.
* @since 0.22
*/
public abstract Duration getDeadline();

/**
* Return a new {@link Builder}.
*
* @return a {@code Builder}
* @since 0.22
*/
public static Builder builder() {
return new AutoValue_InstanaExporterConfiguration.Builder().setDeadline(DEFAULT_DEADLINE);
}

/**
* Builder for {@link InstanaExporterConfiguration}.
*
* @since 0.22
*/
@AutoValue.Builder
public abstract static class Builder {

Builder() {}

/**
* Sets the endpoint of Instana agent to send traces to. E.g
* http://localhost:42699/com.instana.plugin.generic.trace
*
* @param agentEndpoint the endpoint of the agent.
* @return this.
* @since 0.22
*/
public abstract Builder setAgentEndpoint(String agentEndpoint);

/**
* Sets the deadline for exporting to Instana.
*
* @param deadline the export deadline.
* @return this
* @since 0.22
*/
public abstract Builder setDeadline(Duration deadline);

abstract Duration getDeadline();

abstract InstanaExporterConfiguration autoBuild();

/**
* Builds a {@link InstanaExporterConfiguration}.
*
* @return a {@code InstanaExporterConfiguration}.
* @since 0.22
*/
public InstanaExporterConfiguration build() {
Preconditions.checkArgument(getDeadline().compareTo(ZERO) > 0, "Deadline must be positive.");
return autoBuild();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,16 @@
import io.opencensus.common.Duration;
import io.opencensus.common.Function;
import io.opencensus.common.Functions;
import io.opencensus.common.Scope;
import io.opencensus.common.Timestamp;
import io.opencensus.exporter.trace.util.TimeLimitedHandler;
import io.opencensus.trace.AttributeValue;
import io.opencensus.trace.Sampler;
import io.opencensus.trace.Span.Kind;
import io.opencensus.trace.SpanContext;
import io.opencensus.trace.SpanId;
import io.opencensus.trace.Status;
import io.opencensus.trace.TraceId;
import io.opencensus.trace.Tracer;
import io.opencensus.trace.Tracing;
import io.opencensus.trace.export.SpanData;
import io.opencensus.trace.export.SpanExporter;
import io.opencensus.trace.samplers.Samplers;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
Expand All @@ -63,13 +59,13 @@
* Major TODO is the limitation of Instana to only suport 64bit trace ids, which will be resolved.
* Until then it is crossing fingers and treating it as 50% sampler :).
*/
final class InstanaExporterHandler extends SpanExporter.Handler {
final class InstanaExporterHandler extends TimeLimitedHandler {

private static final Tracer tracer = Tracing.getTracer();
private static final Sampler probabilitySpampler = Samplers.probabilitySampler(0.0001);
private static final String EXPORT_SPAN_NAME = "ExportInstanaTraces";
private final URL agentEndpoint;

InstanaExporterHandler(URL agentEndpoint) {
InstanaExporterHandler(URL agentEndpoint, Duration deadline) {
super(deadline, EXPORT_SPAN_NAME);
this.agentEndpoint = agentEndpoint;
}

Expand Down Expand Up @@ -180,56 +176,36 @@ static String convertToJson(Collection<SpanData> spanDataList) {
}

@Override
public void export(Collection<SpanData> spanDataList) {
// Start a new span with explicit 1/10000 sampling probability to avoid the case when user
// sets the default sampler to always sample and we get the gRPC span of the instana
// export call always sampled and go to an infinite loop.
Scope scope =
tracer.spanBuilder("ExportInstanaTraces").setSampler(probabilitySpampler).startScopedSpan();
public void timeLimitedExport(Collection<SpanData> spanDataList) throws Exception {
String json = convertToJson(spanDataList);

OutputStream outputStream = null;
InputStream inputStream = null;
try {
String json = convertToJson(spanDataList);
HttpURLConnection connection = (HttpURLConnection) agentEndpoint.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
outputStream = connection.getOutputStream();
outputStream.write(json.getBytes(Charset.defaultCharset()));
outputStream.flush();
inputStream = connection.getInputStream();
if (connection.getResponseCode() != 200) {
throw new Exception("Response " + connection.getResponseCode());
}
} finally {
closeStream(inputStream);
closeStream(outputStream);
}
}

OutputStream outputStream = null;
InputStream inputStream = null;
// Closes an input or output stream and ignores potential IOException.
private static void closeStream(@javax.annotation.Nullable Closeable stream) {
if (stream != null) {
try {
HttpURLConnection connection = (HttpURLConnection) agentEndpoint.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
outputStream = connection.getOutputStream();
outputStream.write(json.getBytes(Charset.defaultCharset()));
outputStream.flush();
inputStream = connection.getInputStream();
if (connection.getResponseCode() != 200) {
tracer
.getCurrentSpan()
.setStatus(
Status.UNKNOWN.withDescription("Response " + connection.getResponseCode()));
}
stream.close();
} catch (IOException e) {
tracer
.getCurrentSpan()
.setStatus(
Status.UNKNOWN.withDescription(
e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage()));
// dropping span batch
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// ignore
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
// ignore
}
}
// ignore
}
} finally {
scope.close();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
*
* <pre>{@code
* public static void main(String[] args) {
* InstanaTraceExporter.createAndRegister("http://localhost:42699/com.instana.plugin.generic.trace");
* String agentEndpoint = "http://localhost:42699/com.instana.plugin.generic.trace";
* InstanaTraceExporter.createAndRegister(
* InstanaExporterConfiguration.builder().setAgentEndpoint(agentEndpoint).build());
* ... // Do work.
* }
* }</pre>
Expand All @@ -56,20 +58,39 @@ private InstanaTraceExporter() {}
* Creates and registers the Instana Trace exporter to the OpenCensus library. Only one Instana
* exporter can be registered at any point.
*
* @param agentEndpoint Ex http://localhost:42699/com.instana.plugin.generic.trace
* @param configuration Configuration for InstanaTraceExporter.
* @throws MalformedURLException if the agentEndpoint is not a valid http url.
* @throws IllegalStateException if a Instana exporter is already registered.
* @since 0.12
* @since 0.22
*/
public static void createAndRegister(String agentEndpoint) throws MalformedURLException {
public static void createAndRegister(InstanaExporterConfiguration configuration)
throws MalformedURLException {
synchronized (monitor) {
checkState(handler == null, "Instana exporter is already registered.");
Handler newHandler = new InstanaExporterHandler(new URL(agentEndpoint));
Handler newHandler =
new InstanaExporterHandler(
new URL(configuration.getAgentEndpoint()), configuration.getDeadline());
handler = newHandler;
register(Tracing.getExportComponent().getSpanExporter(), newHandler);
}
}

/**
* Creates and registers the Instana Trace exporter to the OpenCensus library. Only one Instana
* exporter can be registered at any point.
*
* @param agentEndpoint Ex http://localhost:42699/com.instana.plugin.generic.trace
* @throws MalformedURLException if the agentEndpoint is not a valid http url.
* @throws IllegalStateException if a Instana exporter is already registered.
* @since 0.12
* @deprecated in favor of {@link #createAndRegister(InstanaExporterConfiguration)}.
*/
@Deprecated
public static void createAndRegister(String agentEndpoint) throws MalformedURLException {
createAndRegister(
InstanaExporterConfiguration.builder().setAgentEndpoint(agentEndpoint).build());
}

/**
* Registers the {@code InstanaTraceExporter}.
*
Expand Down