@juspay/neurolink
Version:
Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applicatio
197 lines (196 loc) • 7.09 kB
JavaScript
/**
* Datadog Exporter
* Exports spans to Datadog APM platform
*/
import { logger } from "../../utils/logger.js";
import { SpanStatus } from "../../types/index.js";
import { BaseExporter } from "./baseExporter.js";
/**
* Datadog exporter for enterprise APM integration
* Supports trace correlation and AI-specific custom metrics
*/
export class DatadogExporter extends BaseExporter {
apiKey;
appKey;
site;
service;
source;
logsEndpoint;
constructor(config) {
super("datadog", config);
this.apiKey = config.apiKey;
this.appKey = config.appKey;
this.site = config.site ?? "us1";
this.service = config.service ?? "neurolink";
this.source = config.source ?? "neurolink-ai";
const baseDomain = this.site === "us1" ? "datadoghq.com" : `${this.site}.datadoghq.com`;
this.logsEndpoint = `https://http-intake.logs.${baseDomain}/api/v2/logs`;
}
async initialize() {
if (this.initialized) {
return;
}
// Validate API key
try {
const validateUrl = this.site === "us1"
? "https://api.datadoghq.com/api/v1/validate"
: `https://api.${this.site}.datadoghq.com/api/v1/validate`;
const response = await fetch(validateUrl, {
headers: {
"DD-API-KEY": this.apiKey,
...(this.appKey && { "DD-APPLICATION-KEY": this.appKey }),
},
});
if (!response.ok) {
throw new Error(`Datadog API key validation failed: ${response.statusText}`);
}
}
catch (error) {
// Allow initialization to proceed even if API is unreachable
logger.warn("[Datadog] Could not verify API connection:", error instanceof Error ? error.message : error);
}
this.initialized = true;
this.startFlushInterval(this.config.flushIntervalMs ?? 10000);
}
async exportSpan(span) {
const startTime = Date.now();
try {
const log = this.convertToDatadogLog(span);
const response = await fetch(this.logsEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"DD-API-KEY": this.apiKey,
},
body: JSON.stringify([log]),
});
if (!response.ok) {
throw new Error(`Export failed: ${response.statusText}`);
}
return this.createSuccessResult(1, Date.now() - startTime);
}
catch (error) {
return this.createFailureResult([span.spanId], error instanceof Error ? error.message : String(error), Date.now() - startTime);
}
}
async exportBatch(spans) {
const startTime = Date.now();
try {
const logs = spans.map((s) => this.convertToDatadogLog(s));
const response = await fetch(this.logsEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"DD-API-KEY": this.apiKey,
},
body: JSON.stringify(logs),
});
if (!response.ok) {
throw new Error(`Batch export failed: ${response.statusText}`);
}
return this.createSuccessResult(spans.length, Date.now() - startTime);
}
catch (error) {
return this.createFailureResult(spans.map((s) => s.spanId), error instanceof Error ? error.message : String(error), Date.now() - startTime);
}
}
async flush() {
if (this.buffer.length > 0) {
const spans = [...this.buffer];
this.buffer = [];
await this.exportBatch(spans);
}
}
async shutdown() {
await this.flush();
this.stopFlushInterval();
this.initialized = false;
}
async healthCheck() {
try {
await this.withRetry(() => this.ping(), "health check");
return this.createHealthStatus(true);
}
catch {
return this.createHealthStatus(false, ["Health check failed"]);
}
}
/**
* Verify connectivity to Datadog API
*/
async ping() {
const validateUrl = this.site === "us1"
? "https://api.datadoghq.com/api/v1/validate"
: `https://api.${this.site}.datadoghq.com/api/v1/validate`;
const response = await fetch(validateUrl, {
headers: { "DD-API-KEY": this.apiKey },
});
if (!response.ok) {
throw new Error(`Datadog API validation failed: ${response.status}`);
}
}
/**
* Convert span to Datadog log format with trace correlation
*/
convertToDatadogLog(span) {
return {
ddsource: this.source,
ddtags: this.buildTags(span),
hostname: process.env.HOSTNAME || "unknown",
message: `${span.type}: ${span.name}`,
service: this.service,
status: span.status === SpanStatus.ERROR ? "error" : "info",
timestamp: new Date(span.startTime).getTime(),
// Trace correlation
dd: {
trace_id: span.traceId,
span_id: span.spanId,
},
// AI-specific attributes
ai: {
provider: span.attributes["ai.provider"],
model: span.attributes["ai.model"],
tokens: {
input: span.attributes["ai.tokens.input"],
output: span.attributes["ai.tokens.output"],
total: span.attributes["ai.tokens.total"],
},
cost: span.attributes["ai.cost.total"],
duration_ms: span.durationMs,
},
// User context
usr: {
id: span.attributes["user.id"],
session_id: span.attributes["session.id"],
},
// Error details
...(span.status === SpanStatus.ERROR && {
error: {
message: span.statusMessage,
type: span.attributes["error.type"],
stack: span.attributes["error.stack"],
},
}),
};
}
/**
* Build Datadog tags from span attributes
*/
buildTags(span) {
const tags = [
`env:${this.config.environment ?? "production"}`,
`version:${this.config.version ?? "unknown"}`,
`span_type:${span.type}`,
];
if (span.attributes["ai.provider"]) {
tags.push(`ai_provider:${span.attributes["ai.provider"]}`);
}
if (span.attributes["ai.model"]) {
tags.push(`ai_model:${span.attributes["ai.model"]}`);
}
if (span.attributes["tool.name"]) {
tags.push(`tool:${span.attributes["tool.name"]}`);
}
return tags.join(",");
}
}