
io.opencensus.exporter.trace.datadog.DatadogExporterHandler Maven / Gradle / Ivy
The newest version!
/*
* 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.datadog;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.opencensus.common.Duration;
import io.opencensus.common.Functions;
import io.opencensus.common.Timestamp;
import io.opencensus.exporter.trace.util.TimeLimitedHandler;
import io.opencensus.trace.AttributeValue;
import io.opencensus.trace.SpanContext;
import io.opencensus.trace.SpanId;
import io.opencensus.trace.Status;
import io.opencensus.trace.Tracing;
import io.opencensus.trace.export.SpanData;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
@SuppressWarnings({
// This library is not supposed to be Android or Java 7 compatible.
"AndroidJdkLibsChecker",
"Java7ApiChecker"
})
final class DatadogExporterHandler extends TimeLimitedHandler {
private static final String EXPORT_SPAN_NAME = "ExportDatadogTraces";
private static final Gson gson =
new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.create();
private final URL agentEndpoint;
private final String service;
private final String type;
DatadogExporterHandler(String agentEndpoint, String service, String type, Duration deadline)
throws MalformedURLException {
super(deadline, EXPORT_SPAN_NAME);
this.agentEndpoint = new URL(agentEndpoint);
this.service = service;
this.type = type;
}
private static String attributeValueToString(AttributeValue attributeValue) {
return attributeValue.match(
Functions.returnToString(),
Functions.returnToString(),
Functions.returnToString(),
Functions.returnToString(),
Functions.throwIllegalArgumentException());
}
private static Map attributesToMeta(
final Map attributes) {
final HashMap result = new HashMap<>();
attributes.entrySet().stream()
.filter(entry -> entry.getValue() != null)
.forEach(entry -> result.put(entry.getKey(), attributeValueToString(entry.getValue())));
return result;
}
private static long convertSpanId(final SpanId spanId) {
final byte[] bytes = spanId.getBytes();
long result = 0;
for (int i = 0; i < Long.SIZE / Byte.SIZE; i++) {
result <<= Byte.SIZE;
result |= (bytes[i] & 0xff);
}
if (result < 0) {
return -result;
}
return result;
}
private static long timestampToNanos(final Timestamp timestamp) {
return TimeUnit.SECONDS.toNanos(timestamp.getSeconds()) + timestamp.getNanos();
}
private static Integer errorCode(@Nullable final Status status) {
if (status == null || status.equals(Status.OK) || status.equals(Status.ALREADY_EXISTS)) {
return 0;
}
return 1;
}
String convertToJson(Collection spanDataList) {
final ArrayList datadogSpans = new ArrayList<>();
for (SpanData sd : spanDataList) {
SpanContext sc = sd.getContext();
final long startTime = timestampToNanos(sd.getStartTimestamp());
final Timestamp endTimestamp =
Optional.ofNullable(sd.getEndTimestamp()).orElseGet(() -> Tracing.getClock().now());
final long endTime = timestampToNanos(endTimestamp);
final long duration = endTime - startTime;
final Long parentId =
Optional.ofNullable(sd.getParentSpanId())
.map(DatadogExporterHandler::convertSpanId)
.orElse(null);
final Map attributes = sd.getAttributes().getAttributeMap();
final Map meta =
attributes.isEmpty() ? new HashMap<>() : attributesToMeta(attributes);
final String resource = meta.getOrDefault("resource", "UNKNOWN");
final DatadogSpan span =
new DatadogSpan(
sc.getTraceId().getLowerLong(),
convertSpanId(sc.getSpanId()),
sd.getName(),
resource,
this.service,
this.type,
startTime,
duration,
parentId,
errorCode(sd.getStatus()),
meta);
datadogSpans.add(span);
}
final Collection> traces =
datadogSpans.stream()
.collect(Collectors.groupingBy(DatadogSpan::getTraceId, Collectors.toList()))
.values();
return gson.toJson(traces);
}
@Override
public void timeLimitedExport(Collection spanDataList) throws Exception {
final String data = convertToJson(spanDataList);
final HttpURLConnection connection = (HttpURLConnection) agentEndpoint.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(data.getBytes(Charset.defaultCharset()));
outputStream.flush();
outputStream.close();
if (connection.getResponseCode() != 200) {
throw new Exception("Response " + connection.getResponseCode());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy