Bring tracing service more in line with upstream APIs
Signed-off-by: Eric Peterson <ericpeterson@spotify.com>
This commit is contained in:
@@ -68,7 +68,11 @@ export const createSseRouter = ({
|
||||
|
||||
const transport = transportsToSessionId.get(sessionId);
|
||||
if (transport) {
|
||||
await tracing.withPropagatedContext(req.headers, () =>
|
||||
const ctx = tracing.propagation.extract(
|
||||
tracing.context.active(),
|
||||
req.headers,
|
||||
);
|
||||
await tracing.context.with(ctx, () =>
|
||||
transport.handlePostMessage(req, res, req.body),
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -77,7 +77,11 @@ export const createStreamableRouter = ({
|
||||
});
|
||||
|
||||
await server.connect(transport);
|
||||
await tracing.withPropagatedContext(req.headers, () =>
|
||||
const ctx = tracing.propagation.extract(
|
||||
tracing.context.active(),
|
||||
req.headers,
|
||||
);
|
||||
await tracing.context.with(ctx, () =>
|
||||
transport.handleRequest(req, res, req.body),
|
||||
);
|
||||
|
||||
|
||||
@@ -981,7 +981,7 @@ describe('McpService', () => {
|
||||
await invokeMockAction({ tracing, credentials });
|
||||
|
||||
expect(tracing.startActiveSpan).toHaveBeenCalledTimes(1);
|
||||
const [name, , options] = tracing.startActiveSpan.mock.calls[0];
|
||||
const [name, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
expect(name).toBe('tools/call test.mock-action');
|
||||
expect(options?.kind).toBe('server');
|
||||
expect(options?.attributes).toEqual(
|
||||
@@ -1012,7 +1012,7 @@ describe('McpService', () => {
|
||||
|
||||
it('includes gen_ai baggage entries as span attributes when present', async () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
tracing.getActiveBaggage.mockReturnValue({
|
||||
tracing.propagation.getActiveBaggage.mockReturnValue({
|
||||
getEntry: (key: string) => {
|
||||
const entries: Record<string, { value: string }> = {
|
||||
'gen_ai.conversation.id': { value: 'conv-123' },
|
||||
@@ -1028,14 +1028,14 @@ describe('McpService', () => {
|
||||
|
||||
await invokeMockAction({ tracing });
|
||||
|
||||
const [, , options] = tracing.startActiveSpan.mock.calls[0];
|
||||
const [, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
expect(options?.attributes?.['gen_ai.conversation.id']).toBe('conv-123');
|
||||
expect(options?.attributes?.['gen_ai.agent.id']).toBe('agent-456');
|
||||
});
|
||||
|
||||
it('only forwards allowlisted baggage keys onto the span', async () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
tracing.getActiveBaggage.mockReturnValue({
|
||||
tracing.propagation.getActiveBaggage.mockReturnValue({
|
||||
getEntry: (key: string) => {
|
||||
const entries: Record<string, { value: string }> = {
|
||||
'gen_ai.conversation.id': { value: 'conv-123' },
|
||||
@@ -1055,7 +1055,7 @@ describe('McpService', () => {
|
||||
|
||||
await invokeMockAction({ tracing });
|
||||
|
||||
const [, , options] = tracing.startActiveSpan.mock.calls[0];
|
||||
const [, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
expect(options?.attributes?.['gen_ai.conversation.id']).toBe('conv-123');
|
||||
expect(options?.attributes).not.toHaveProperty('gen_ai.tool.call.result');
|
||||
expect(options?.attributes).not.toHaveProperty('gen_ai.prompt');
|
||||
@@ -1066,7 +1066,7 @@ describe('McpService', () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
await invokeMockAction({ tracing });
|
||||
|
||||
const [, , options] = tracing.startActiveSpan.mock.calls[0];
|
||||
const [, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
expect(options?.attributes).not.toHaveProperty('gen_ai.conversation.id');
|
||||
expect(options?.attributes).not.toHaveProperty('gen_ai.agent.id');
|
||||
});
|
||||
@@ -1075,7 +1075,7 @@ describe('McpService', () => {
|
||||
const tracing = tracingServiceMock.mock();
|
||||
await invokeMockAction({ tracing, captureToolPayloads: true });
|
||||
|
||||
const [, , options] = tracing.startActiveSpan.mock.calls[0];
|
||||
const [, options] = tracing.startActiveSpan.mock.calls[0];
|
||||
expect(options?.attributes?.['gen_ai.tool.call.arguments']).toBe(
|
||||
JSON.stringify({ input: 'val' }),
|
||||
);
|
||||
|
||||
@@ -57,7 +57,7 @@ const PROPAGATED_BAGGAGE_ATTRIBUTES: readonly string[] = [
|
||||
function baggageAttributes(
|
||||
tracingService: TracingService,
|
||||
): Record<string, string> {
|
||||
const baggage = tracingService.getActiveBaggage();
|
||||
const baggage = tracingService.propagation.getActiveBaggage();
|
||||
if (!baggage) return {};
|
||||
const attrs: Record<string, string> = {};
|
||||
for (const key of PROPAGATED_BAGGAGE_ATTRIBUTES) {
|
||||
@@ -189,6 +189,19 @@ export class McpService {
|
||||
try {
|
||||
return await this.tracingService.startActiveSpan(
|
||||
`tools/call ${params.name}`,
|
||||
{
|
||||
kind: 'server',
|
||||
credentials,
|
||||
attributes: {
|
||||
...baggageAttributes(this.tracingService),
|
||||
'mcp.method.name': 'tools/call',
|
||||
'gen_ai.tool.name': params.name,
|
||||
'gen_ai.operation.name': 'execute_tool',
|
||||
...(this.captureToolPayloads && {
|
||||
'gen_ai.tool.call.arguments': safeStringify(params.arguments),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async span => {
|
||||
const result = await handleErrors(async () => {
|
||||
const { actions: allActions } = await this.actions.list({
|
||||
@@ -249,19 +262,6 @@ export class McpService {
|
||||
}
|
||||
return result;
|
||||
},
|
||||
{
|
||||
kind: 'server',
|
||||
credentials,
|
||||
attributes: {
|
||||
...baggageAttributes(this.tracingService),
|
||||
'mcp.method.name': 'tools/call',
|
||||
'gen_ai.tool.name': params.name,
|
||||
'gen_ai.operation.name': 'execute_tool',
|
||||
...(this.captureToolPayloads && {
|
||||
'gen_ai.tool.call.arguments': safeStringify(params.arguments),
|
||||
}),
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
errorType = err instanceof Error ? err.name : 'Error';
|
||||
|
||||
Reference in New Issue
Block a user