aboutsummaryrefslogtreecommitdiffstats
path: root/packages/trpc/lib/tracing.ts
blob: 7b4fb39f34fb72cbb04d62d1328da10d526359d2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import { SpanKind } from "@opentelemetry/api";

import {
  getTracer,
  setSpanAttributes,
  withSpan,
} from "@karakeep/shared-server";
import serverConfig from "@karakeep/shared/config";

import type { Context } from "../index";

const tracer = getTracer("@karakeep/trpc");

/**
 * tRPC middleware that creates a span for each procedure call.
 * This integrates OpenTelemetry tracing into the tRPC layer.
 */
export function createTracingMiddleware() {
  return async function tracingMiddleware<T>(opts: {
    ctx: Context;
    type: "query" | "mutation" | "subscription";
    path: string;
    input: unknown;
    next: () => Promise<T>;
  }): Promise<T> {
    // Skip if tracing is disabled
    if (!serverConfig.tracing.enabled) {
      return opts.next();
    }

    const spanName = `trpc.${opts.type}.${opts.path}`;

    return withSpan(
      tracer,
      spanName,
      {
        kind: SpanKind.SERVER,
        attributes: {
          "rpc.system": "trpc",
          "rpc.method": opts.path,
          "rpc.type": opts.type,
          "user.id": opts.ctx.user?.id ?? "anonymous",
          "user.role": opts.ctx.user?.role ?? "none",
        },
      },
      async () => {
        return await opts.next();
      },
    );
  };
}

/**
 * Helper to add tracing attributes within a tRPC procedure.
 * Use this to add custom attributes to the current span.
 */
export function addTracingAttributes(
  attributes: Record<string, string | number | boolean>,
): void {
  if (serverConfig.tracing.enabled) {
    setSpanAttributes(attributes);
  }
}