Skip to main content
Glama

Prisma MCP Server

Official
by prisma
Apache 2.0
4
44,192
  • Linux
  • Apple
span.ts5.95 kB
import { Attributes, AttributeValue, Exception, HrTime, Link, Span, SpanContext, SpanKind, SpanStatus, TimeInput, } from '@opentelemetry/api' import { Temporal } from 'temporal-polyfill' import { instantToHrTime } from '../formats/hr-time' import { ExportableSpanId, parseSpanId, parseTraceId } from './id' import { ExtendedSpanOptions } from './options' /** * A span in the format expected by the Prisma Client. */ export type ExportableSpan = { id: ExportableSpanId parentId: ExportableSpanId | null name: string startTime: HrTime endTime: HrTime kind: ExportableSpanKind attributes?: Attributes links?: ExportableSpanId[] } /** * OpenTelemetry span kind in the format expected by the Prisma Client. */ export type ExportableSpanKind = 'internal' | 'server' | 'client' | 'producer' | 'consumer' /** * Serialize an OpenTelemetry span kind to the format expected by the Prisma Client. */ export function serializeSpanKind(kind: SpanKind): ExportableSpanKind { switch (kind) { case SpanKind.INTERNAL: return 'internal' case SpanKind.SERVER: return 'server' case SpanKind.CLIENT: return 'client' case SpanKind.PRODUCER: return 'producer' case SpanKind.CONSUMER: return 'consumer' default: throw new Error(`Unknown span kind: ${kind satisfies never}`) } } type SpanProxyConstructorOptions = { span: Span parentSpan: Span | undefined spanOptions: ExtendedSpanOptions trueStartTime: Temporal.Instant } /** * Wraps an original OpenTelemetry {@link Span} and records all information we * need to export it to the Prisma Client. * * Normally, a finished span exposing this information for reading is only * available in the `onEnd` hook in a span processor. We, however, need to * retrieve it immediately after finishing the span in our code. */ export class SpanProxy implements Span { readonly #span: Span readonly #parentSpan: Span | undefined readonly #startTime: HrTime #name: string readonly #kind: SpanKind readonly #attributes: Attributes readonly #links: Link[] constructor(options: SpanProxyConstructorOptions) { this.#span = options.span this.#parentSpan = options.parentSpan this.#name = options.spanOptions.name this.#kind = options.spanOptions.kind ?? SpanKind.INTERNAL this.#attributes = options.spanOptions.attributes ?? {} this.#links = options.spanOptions.links ?? [] if (options.spanOptions.startTime) { this.#startTime = timeInputToHrTime(options.spanOptions.startTime) } else { this.#startTime = instantToHrTime(options.trueStartTime) } } /** * Calls {@link Span#end} and exports the span in the format expected by the * Prisma Client. * * This operation is combined in a single method to statically guarantee the * consistency of the end time in both invocations. */ endAndExport(endTime: Temporal.Instant): ExportableSpan { const endTimeAsHrTime = instantToHrTime(endTime) this.#span.end(endTimeAsHrTime) const spanContext = this.#span.spanContext() const parentSpanContext = this.#parentSpan?.spanContext() const traceId = parseTraceId(spanContext.traceId) const spanId = parseSpanId(spanContext.spanId) const id: ExportableSpanId = `${traceId}-${spanId}` let parentId: ExportableSpanId | null = null if (parentSpanContext !== undefined) { const parentTraceId = parseTraceId(parentSpanContext.traceId) const parentSpanId = parseSpanId(parentSpanContext.spanId) parentId = `${parentTraceId}-${parentSpanId}` } let attributes: Attributes | undefined if (Object.keys(this.#attributes).length > 0) { attributes = this.#attributes } let links: ExportableSpanId[] | undefined if (this.#links.length > 0) { links = this.#links.map((link): ExportableSpanId => { const linkTraceId = parseTraceId(link.context.traceId) const linkSpanId = parseSpanId(link.context.spanId) return `${linkTraceId}-${linkSpanId}` }) } return { id, parentId, attributes, links, name: `prisma:engine:${this.#name}`, kind: serializeSpanKind(this.#kind), startTime: this.#startTime, endTime: instantToHrTime(endTime), } } /* * Span interface implementation below */ spanContext(): SpanContext { return this.#span.spanContext() } setAttribute(key: string, value: AttributeValue): this { this.#attributes[key] = value this.#span.setAttribute(key, value) return this } setAttributes(attributes: Attributes): this { for (const [key, value] of Object.entries(attributes)) { this.#attributes[key] = value } this.#span.setAttributes(attributes) return this } addEvent(name: string, attributesOrStartTime?: Attributes | TimeInput, startTime?: TimeInput): this { this.#span.addEvent(name, attributesOrStartTime, startTime) return this } addLink(link: Link): this { this.#links.push(link) this.#span.addLink(link) return this } addLinks(links: Link[]): this { this.#links.push(...links) this.#span.addLinks(links) return this } setStatus(status: SpanStatus): this { this.#span.setStatus(status) return this } updateName(name: string): this { this.#name = name this.#span.updateName(name) return this } end(endTime?: TimeInput): void { this.#span.end(endTime) } isRecording(): boolean { return this.#span.isRecording() } recordException(exception: Exception, time?: TimeInput): void { this.#span.recordException(exception, time) } } function timeInputToHrTime(timeInput: TimeInput): HrTime { if (Array.isArray(timeInput)) { return timeInput } const milliseconds = Number(timeInput) const instant = Temporal.Instant.fromEpochMilliseconds(milliseconds) return instantToHrTime(instant) }

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/prisma/prisma'

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