aggregate_spans
Aggregate Datadog trace spans by attributes like service or status to analyze performance patterns and identify issues through time-series or total summaries.
Instructions
Tool for aggregating Datadog trace spans
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| filterQuery | No | Query string to search for (optional, default is '*') | * |
| filterFrom | No | Search start time (UNIX timestamp in seconds, optional, default is 15 minutes ago) | |
| filterTo | No | Search end time (UNIX timestamp in seconds, optional, default is current time) | |
| groupBy | No | Attributes to group by (example: ['service', 'resource_name']) | |
| interval | No | Time interval to group results by (optional, only used when type is timeseries) | |
| type | No | Result type - timeseries or total (optional, default is 'timeseries') | timeseries |
Implementation Reference
- src/tools/spans/aggregate.ts:125-158 (handler)Handler function for the aggregate_spans tool. Validates input using Zod schema, calls the core aggregateSpans function, formats the response with summary and Datadog link.export const aggregateSpansHandler = async ( parameters: z.infer<typeof aggregateSpansZodSchema> ): Promise<ToolResponse> => { const validation = aggregateSpansZodSchema.safeParse(parameters); if (!validation.success) { return createErrorResponse( `Parameter validation error: ${validation.error.message}` ); } try { // Convert to Date objects after validation const validatedParams = { ...validation.data, filterFrom: new Date(validation.data.filterFrom * 1000), filterTo: new Date(validation.data.filterTo * 1000), }; const result = await aggregateSpans(validatedParams); const formattedResult = generateSummaryText(validation.data, result); const urlText = `[View in Datadog](https://app.datadoghq.com/apm/traces?query=${encodeURIComponent( validation.data.filterQuery )}&start=${validation.data.filterFrom}&end=${ validation.data.filterTo }&viz=${ validation.data.type === "total" ? "toplist" : validation.data.type }&agg_q=${validation.data.groupBy?.join(",") || ""})`; return createSuccessResponse([formattedResult, urlText]); } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); return createErrorResponse(`Span aggregation error: ${errorMessage}`); } };
- src/tools/spans/aggregate.ts:6-60 (schema)Zod schema defining input parameters for the aggregate_spans tool, including query filters, time range, grouping, interval, and aggregation type.export const aggregateSpansZodSchema = z.object({ filterQuery: z .string() .optional() .default("*") .describe("Query string to search for (optional, default is '*')"), filterFrom: z .number() .optional() .default(Date.now() / 1000 - 15 * 60) .describe( "Search start time (UNIX timestamp in seconds, optional, default is 15 minutes ago)" ), filterTo: z .number() .optional() .default(Date.now() / 1000) .describe( "Search end time (UNIX timestamp in seconds, optional, default is current time)" ), groupBy: z .array( z.enum([ "service", "resource_name", "env", "status", "operation_name", "type", "@version", "@http.status_code", "@http.client_ip", "@http.url", "@http.method", "@http.host", "@http.user_agent", "@http.path_group", "@http.route", ]) ) .optional() .describe("Attributes to group by (example: ['service', 'resource_name'])"), interval: z .string() .optional() .describe( "Time interval to group results by (optional, only used when type is timeseries)" ), type: z .enum(["timeseries", "total"]) .default("timeseries") .describe( "Result type - timeseries or total (optional, default is 'timeseries')" ), });
- src/index.ts:32-37 (registration)Registers the 'aggregate_spans' tool on the MCP server using the schema and handler.server.tool( "aggregate_spans", "Tool for aggregating Datadog trace spans", aggregateSpansZodSchema.shape, aggregateSpansHandler );
- src/datadog/spans/aggregate.ts:9-75 (helper)Core helper function that makes the Datadog API call to aggregate spans, constructs the request body, processes the response into structured buckets.export const aggregateSpans = async ( params: SpanAggregationParams ): Promise<SpanAggregationResult> => { try { const configuration = createConfiguration(); const spansApi = new v2.SpansApi(configuration); const { filterFrom, filterTo, filterQuery, interval, type } = params; const requestBody: v2.SpansApiAggregateSpansRequest = { body: { data: { attributes: { compute: [ { aggregation: "count", interval: interval, type: type, }, ], filter: { from: filterFrom.toISOString(), to: filterTo.toISOString(), query: filterQuery, }, groupBy: params.groupBy?.length ? params.groupBy.map((field) => ({ facet: field, limit: 10, })) : undefined, }, type: "aggregate_request", }, }, }; const response = await spansApi.aggregateSpans(requestBody); if (!response.data || response.data.length === 0) { return { buckets: [] }; } const buckets: SpanBucket[] = response.data.map((bucket) => ({ id: bucket.id || "", by: bucket.attributes?.by || {}, compute: bucket.attributes?.compute || {}, computes: bucket.attributes?.computes || {}, })); return { buckets, elapsed: response.meta?.elapsed, requestId: response.meta?.requestId, status: response.meta?.status?.toString(), warnings: response.meta?.warnings?.map((warning) => ({ code: warning.code, detail: warning.detail, title: warning.title, })), }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error); console.error(`Error aggregating spans: ${errorMessage}`); throw new Error(`Datadog API error: ${errorMessage}`); } };