Skip to content

feat(client): tracing#10764

Merged
millsp merged 53 commits intomainfrom
integration/feat/tracing
Jan 26, 2022
Merged

feat(client): tracing#10764
millsp merged 53 commits intomainfrom
integration/feat/tracing

Conversation

@millsp
Copy link
Copy Markdown
Contributor

@millsp millsp commented Dec 19, 2021

This PR brings OpenTelemetry tracing support to the Prisma Client.
The feature is in preview an is guarded by the tracing feature flag.
I've refactored runtime models while looking at propagation issues.
Note: Waiting to integrate until the engines have tracing support.

closes #10310

Example project that uses tracing for Prisma Client queries:

import { trace, context } from "@opentelemetry/api";
import { PrismaClient } from ".prisma/client";
import { otelSetup } from "./otelSetup";

otelSetup();

// set things up for tracing our "app"
const tracer = trace.getTracer("myApp");
const span = tracer.startSpan("mySpan");
const ctx = trace.setSpan(context.active(), span);

context.with(ctx, async () => {
  await main();

  span.end();
});

async function main() {
  const prisma = new PrismaClient();

  // this middleware gets the current span and add info to it
  prisma.$use(function spanModifierMiddleware(params, next) {
    const span = trace.getSpan(context.active())

    span.setAttributes({
      model: params['model'],
      action: params['action']
    });

    return next(params)
  });

  // this middleware self-registers in a span to trace itself
  prisma.$use(function spanCreatingMiddleware(params, next) {
    const span = tracer.startSpan("middleware");
    const ctx = trace.setSpan(context.active(), span)

    const result = context.with(ctx, () => next(params));

    span.end()

    return result
  });

  // here begins the actual prisma client logic to be traced
  const email = Date.now() + "@gmail.com"

  await prisma.user.create({
    data: {
      name: 'John Doe',
      email: email,
      link: {
        create: {
          url: "http://www.google.com",
          shortUrl: "http://www.google.com",
        },
      },
    },
  });

  await prisma.user.findMany({})

  await prisma.$transaction([
    prisma.user.findUnique({
      where: { email }
    }),
    prisma.user.findMany({})
  ])

  await prisma.$disconnect();
}

Setup needed to begin tracing with OTEL, ./otelSetup:

import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import {
  BasicTracerProvider,
  ConsoleSpanExporter,
  SimpleSpanProcessor,
} from "@opentelemetry/sdk-trace-base";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { AsyncHooksContextManager } from "@opentelemetry/context-async-hooks";
import * as api from "@opentelemetry/api";

/** SETUP */

export function otelSetup() {
  // a context manager is required to propagate the context
  const contextManager = new AsyncHooksContextManager().enable();

  // it's for node.js for span nesting and ctx propagation
  api.context.setGlobalContextManager(contextManager);

  // a simple exporter that logs the raw data to the console
  const consoleExporter = new ConsoleSpanExporter();

  // exporter that natively works with jaeger without extras
  const otlpTraceExporter = new OTLPTraceExporter();
  // docker run --rm -d -p 13133:13133 -p 16686:16686 -p 4317:55680 jaegertracing/opentelemetry-all-in-one:latest

  // a standard provider that can run on the web and in node
  const provider = new BasicTracerProvider({
    resource: new Resource({
      // we can define some metadata about the trace resource
      [SemanticResourceAttributes.SERVICE_NAME]: "basic-service",
      [SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0",
    }),
  });

  // a provider combines multiple exporters to send the data
  // provider.addSpanProcessor(new SimpleSpanProcessor(consoleExporter));
  provider.addSpanProcessor(new SimpleSpanProcessor(otlpTraceExporter));

  // makes the provider the global tracer provider for telemetry
  provider.register();
}

What to expect in the visualizer
Screenshot from 2021-12-19 16-54-57

@matthewmueller
Copy link
Copy Markdown
Contributor

matthewmueller commented Jan 11, 2022

Stuck this back in Doing, though currently waiting on #10004

@millsp millsp marked this pull request as ready for review January 14, 2022 22:28
@millsp millsp requested review from Jolg42 and aqrln as code owners January 14, 2022 22:28
@millsp millsp linked an issue Jan 17, 2022 that may be closed by this pull request
Copy link
Copy Markdown
Contributor

@Jolg42 Jolg42 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done!

So the refactors are really neat using Proxies, it's much easier to read and has nice docs 💚

About the tracing, someone reading this PR might assume this is a GA feature, so having some preview feature gating would be great before the release.

(+ see comments)

@millsp millsp merged commit f395aba into main Jan 26, 2022
@millsp millsp deleted the integration/feat/tracing branch January 26, 2022 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect type for DMMF.Field.type field PCO: Pass the trace ID through end-to-end PCO: Pass the trace ID through to an SQL comment

5 participants