diff --git a/braintrust-java-agent/smoke-test/dd-agent/src/main/java/dev/braintrust/smoketest/ddagent/MockBraintrustBackend.java b/braintrust-java-agent/smoke-test/dd-agent/src/main/java/dev/braintrust/smoketest/ddagent/MockBraintrustBackend.java index 6ca3eced..954ab6d4 100644 --- a/braintrust-java-agent/smoke-test/dd-agent/src/main/java/dev/braintrust/smoketest/ddagent/MockBraintrustBackend.java +++ b/braintrust-java-agent/smoke-test/dd-agent/src/main/java/dev/braintrust/smoketest/ddagent/MockBraintrustBackend.java @@ -8,6 +8,7 @@ import io.opentelemetry.proto.trace.v1.ResourceSpans; import io.opentelemetry.proto.trace.v1.ScopeSpans; import io.opentelemetry.proto.trace.v1.Span; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -18,6 +19,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; /** * A mock Braintrust OTLP backend that captures trace export requests sent to {@code POST @@ -219,6 +221,7 @@ private void handleTraces(HttpExchange exchange) throws IOException { return; } byte[] body = exchange.getRequestBody().readAllBytes(); + body = maybeDecompress(exchange, body); List spans = new ArrayList<>(); try { ExportTraceServiceRequest request = ExportTraceServiceRequest.parseFrom(body); @@ -269,4 +272,13 @@ private void handleDefault(HttpExchange exchange) throws IOException { exchange.sendResponseHeaders(404, -1); exchange.close(); } + + /** Decompress the body if the request has {@code Content-Encoding: gzip}. */ + private static byte[] maybeDecompress(HttpExchange exchange, byte[] body) throws IOException { + var encoding = exchange.getRequestHeaders().getFirst("Content-Encoding"); + if ("gzip".equalsIgnoreCase(encoding)) { + return new GZIPInputStream(new ByteArrayInputStream(body)).readAllBytes(); + } + return body; + } } diff --git a/braintrust-java-agent/smoke-test/otel-agent/src/main/java/dev/braintrust/smoketest/otelagent/MockOtlpCollector.java b/braintrust-java-agent/smoke-test/otel-agent/src/main/java/dev/braintrust/smoketest/otelagent/MockOtlpCollector.java index ca932e3a..559f35bf 100644 --- a/braintrust-java-agent/smoke-test/otel-agent/src/main/java/dev/braintrust/smoketest/otelagent/MockOtlpCollector.java +++ b/braintrust-java-agent/smoke-test/otel-agent/src/main/java/dev/braintrust/smoketest/otelagent/MockOtlpCollector.java @@ -8,6 +8,7 @@ import io.opentelemetry.proto.trace.v1.ResourceSpans; import io.opentelemetry.proto.trace.v1.ScopeSpans; import io.opentelemetry.proto.trace.v1.Span; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -17,6 +18,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; /** * A minimal mock OTLP/HTTP collector that captures {@code POST /v1/traces} requests. @@ -150,6 +152,7 @@ private void handleTraces(HttpExchange exchange) throws IOException { return; } byte[] body = exchange.getRequestBody().readAllBytes(); + body = maybeDecompress(exchange, body); List spans = new ArrayList<>(); try { ExportTraceServiceRequest req = ExportTraceServiceRequest.parseFrom(body); @@ -187,4 +190,13 @@ private void handleDefault(HttpExchange exchange) throws IOException { exchange.sendResponseHeaders(404, -1); exchange.close(); } + + /** Decompress the body if the request has {@code Content-Encoding: gzip}. */ + private static byte[] maybeDecompress(HttpExchange exchange, byte[] body) throws IOException { + var encoding = exchange.getRequestHeaders().getFirst("Content-Encoding"); + if ("gzip".equalsIgnoreCase(encoding)) { + return new GZIPInputStream(new ByteArrayInputStream(body)).readAllBytes(); + } + return body; + } } diff --git a/braintrust-sdk/src/main/java/dev/braintrust/config/BraintrustConfig.java b/braintrust-sdk/src/main/java/dev/braintrust/config/BraintrustConfig.java index 30d2888e..e084b628 100644 --- a/braintrust-sdk/src/main/java/dev/braintrust/config/BraintrustConfig.java +++ b/braintrust-sdk/src/main/java/dev/braintrust/config/BraintrustConfig.java @@ -40,6 +40,9 @@ public final class BraintrustConfig extends BaseConfig { Duration.ofSeconds(getConfig("BRAINTRUST_REQUEST_TIMEOUT", 30)); private final Boolean filterAISpans = getConfig("BRAINTRUST_FILTER_AI_SPANS", false); + /** compress otel data before exporting to braintrust */ + private final Boolean compressOtelPayload = getConfig("BRAINTRUST_COMPRESS_OTEL_PAYLOAD", true); + /** Custom SSL context for OTLP exporter. Builder-only field, not backed by envars. */ private final SSLContext sslContext; @@ -190,6 +193,11 @@ public Builder filterAISpans(boolean value) { return this; } + public Builder compressOtelPayload(boolean value) { + envOverrides.put("BRAINTRUST_COMPRESS_OTEL_PAYLOAD", String.valueOf(value)); + return this; + } + public Builder sslContext(SSLContext value) { this.sslContext = value; return this; diff --git a/braintrust-sdk/src/main/java/dev/braintrust/trace/BraintrustLogExporter.java b/braintrust-sdk/src/main/java/dev/braintrust/trace/BraintrustLogExporter.java index 559ecd73..6367e481 100644 --- a/braintrust-sdk/src/main/java/dev/braintrust/trace/BraintrustLogExporter.java +++ b/braintrust-sdk/src/main/java/dev/braintrust/trace/BraintrustLogExporter.java @@ -74,7 +74,8 @@ private CompletableResultCode exportWithParent(String parent, List spa "Authorization", "Bearer " + config.apiKey()) .setTimeout(config.requestTimeout()); - + if (config.compressOtelPayload()) { + exporterBuilder.setCompression("gzip"); + } // Add x-bt-parent header if we have a parent if (!p.isEmpty()) { exporterBuilder.addHeader("x-bt-parent", p);