Skip to content

Instantly share code, notes, and snippets.

@martinamps
Created May 19, 2025 20:45
Show Gist options
  • Save martinamps/ab57c79acb6eb6eebe45b21f84a83e13 to your computer and use it in GitHub Desktop.
Save martinamps/ab57c79acb6eb6eebe45b21f84a83e13 to your computer and use it in GitHub Desktop.
mini proxy to debug requests from Claude Code to Datadog's agentless OTLP intake endpoint
// OTLP Debug Proxy
// tweak datadog site url as necessary
const DATADOG_OTLP_METRICS_ENDPOINT = `https://api.us5.datadoghq.com/api/intake/otlp/v1/metrics`;
console.log(`Starting OTLP Debug Proxy on port 8080...`);
console.log(`Forwarding OTLP/HTTP metrics to: ${DATADOG_OTLP_METRICS_ENDPOINT}`);
Bun.serve({
port: 8080,
async fetch(claudeRequest) {
const claudeRequestUrl = new URL(claudeRequest.url);
console.log(`\n--- [${new Date().toISOString()}] Received Request from Claude ---`);
console.log(`Claude Method: ${claudeRequest.method}`);
console.log(`Claude Path: ${claudeRequestUrl.pathname}${claudeRequestUrl.search}`);
console.log("Claude Request Headers:");
const originalClaudeHeaders = new Headers(claudeRequest.headers);
for (const [key, value] of originalClaudeHeaders) {
console.log(` ${key}: ${value}`);
}
let claudeRequestBodyBuffer: ArrayBuffer | null = null;
if (claudeRequest.method === "POST" && claudeRequest.body) {
try {
claudeRequestBodyBuffer = await claudeRequest.arrayBuffer();
console.log(`Claude Request Body received, ${claudeRequestBodyBuffer.byteLength} bytes.`);
const firstBytes = new Uint8Array(claudeRequestBodyBuffer.slice(0, 64));
const hexDump = Array.from(firstBytes).map(b => b.toString(16).padStart(2, '0')).join('');
console.log(` Claude Body HEX (first 64 bytes): ${hexDump}${claudeRequestBodyBuffer.byteLength > 64 ? '...' : ''}`);
} catch (e: any) {
console.error(" Error reading Claude request body:", e.message);
return new Response("Error reading client request body\n", { status: 500 });
}
} else {
console.log("No body in Claude request or method not POST. Not forwarding.");
return new Response("Request not forwarded (no body or not POST)\n", { status: 400 });
}
console.log(`\n--- [${new Date().toISOString()}] Forwarding Request to Datadog ---`);
const headersToForward = new Headers();
// Forward essential headers
if (originalClaudeHeaders.has("content-type")) {
headersToForward.set("content-type", originalClaudeHeaders.get("content-type")!);
}
if (originalClaudeHeaders.has("dd-api-key")) {
headersToForward.set("dd-api-key", originalClaudeHeaders.get("dd-api-key")!);
}
if (originalClaudeHeaders.has("user-agent")) {
headersToForward.set("user-agent", originalClaudeHeaders.get("user-agent")!);
}
if (originalClaudeHeaders.has("content-encoding")) {
headersToForward.set("content-encoding", originalClaudeHeaders.get("content-encoding")!);
}
console.log("Forwarding these headers to Datadog:");
for (const [key, value] of headersToForward) {
console.log(` ${key}: ${value}`);
}
try {
const datadogResponse = await fetch(DATADOG_OTLP_METRICS_ENDPOINT, {
method: claudeRequest.method,
headers: headersToForward,
body: claudeRequestBodyBuffer,
});
console.log(`\n--- [${new Date().toISOString()}] Received Response from Datadog ---`);
console.log(`Datadog Status: ${datadogResponse.status} ${datadogResponse.statusText}`);
const ddResponseHeaders = new Headers(datadogResponse.headers);
console.log("Datadog Response Headers:");
for (const [key, value] of ddResponseHeaders) {
console.log(` ${key}: ${value}`);
}
const datadogResponseBodyText = await datadogResponse.text();
console.log("Datadog Response Body:");
console.log(datadogResponseBodyText || "[No body content]");
console.log("--- End of Datadog Interaction ---");
return new Response(datadogResponseBodyText || null, {
status: datadogResponse.status,
statusText: datadogResponse.statusText,
headers: ddResponseHeaders,
});
} catch (fetchError: any) {
console.error(`\n--- [${new Date().toISOString()}] Error Fetching from Datadog ---`);
console.error(fetchError.message);
if (fetchError.cause) console.error("Cause:", fetchError.cause);
console.log("--- End of Datadog Interaction (Fetch Error) ---");
return new Response(`Error forwarding request to Datadog: ${fetchError.message}\n`, {
status: 502,
headers: { "Content-Type": "text/plain" },
});
}
},
error(bunServeError: Error) {
console.error(`\n--- [${new Date().toISOString()}] Bun Serve Error (Proxy Level) ---`);
console.error(bunServeError);
return new Response("Internal Server Error in Proxy\n", {
status: 500,
headers: { "Content-Type": "text/plain" },
});
},
});
console.log("OTLP Debug Proxy is listening on http://localhost:8080");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment