Skip to main content
Glama
cameronsjo

MCP Server Template

by cameronsjo
tracing.ts3.87 kB
/** * OpenTelemetry tracing utilities * * Provides helpers for creating spans and adding attributes. * Follows OpenTelemetry semantic conventions. */ import { trace, Span, SpanKind, SpanStatusCode } from '@opentelemetry/api'; import { getConfig } from '../config/index.js'; const config = getConfig(); const tracer = trace.getTracer(config.serverName, config.serverVersion); /** * Span options for creating custom spans */ interface SpanOptions { kind?: SpanKind; attributes?: Record<string, string | number | boolean>; } /** * Execute a function within a traced span */ export async function withSpan<T>( name: string, fn: (span: Span) => Promise<T>, options?: SpanOptions ): Promise<T> { return tracer.startActiveSpan( name, { kind: options?.kind ?? SpanKind.INTERNAL, attributes: options?.attributes, }, async (span) => { try { const result = await fn(span); span.setStatus({ code: SpanStatusCode.OK }); return result; } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error), }); span.recordException(error instanceof Error ? error : new Error(String(error))); throw error; } finally { span.end(); } } ); } /** * Execute a sync function within a traced span */ export function withSpanSync<T>( name: string, fn: (span: Span) => T, options?: SpanOptions ): T { const span = tracer.startSpan(name, { kind: options?.kind ?? SpanKind.INTERNAL, attributes: options?.attributes, }); try { const result = fn(span); span.setStatus({ code: SpanStatusCode.OK }); return result; } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error instanceof Error ? error.message : String(error), }); span.recordException(error instanceof Error ? error : new Error(String(error))); throw error; } finally { span.end(); } } /** * Get the current active span */ export function getCurrentSpan(): Span | undefined { return trace.getActiveSpan(); } /** * Get trace and span IDs from current context */ export function getTraceContext(): { traceId?: string; spanId?: string } { const span = getCurrentSpan(); if (!span) { return {}; } const spanContext = span.spanContext(); return { traceId: spanContext.traceId, spanId: spanContext.spanId, }; } /** * Add attributes to the current span */ export function addSpanAttributes(attributes: Record<string, string | number | boolean>): void { const span = getCurrentSpan(); if (span) { span.setAttributes(attributes); } } /** * Record an error on the current span */ export function recordSpanError(error: Error): void { const span = getCurrentSpan(); if (span) { span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); span.recordException(error); } } /** * Create a span for tool execution */ export function createToolSpan(toolName: string): Span { return tracer.startSpan(`tool.${toolName}`, { kind: SpanKind.SERVER, attributes: { 'mcp.tool.name': toolName, }, }); } /** * Create a span for external API calls */ export function createApiSpan(service: string, operation: string): Span { return tracer.startSpan(`${service}.${operation}`, { kind: SpanKind.CLIENT, attributes: { 'peer.service': service, 'rpc.method': operation, }, }); } /** * Create a span for database operations */ export function createDbSpan(operation: string, table?: string): Span { return tracer.startSpan(`db.${operation}`, { kind: SpanKind.CLIENT, attributes: { 'db.system': 'sqlite', 'db.operation': operation, ...(table && { 'db.sql.table': table }), }, }); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cameronsjo/mcp-server-template'

If you have feedback or need assistance with the MCP directory API, please join our Discord server