Skip to content

startSpan experience weird behavior with events #13848

Closed
@zhiyan114

Description

@zhiyan114

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/node

SDK Version

8.32.0

Framework Version

No response

Link to Sentry event

No response

Reproduction Example/SDK Setup

Assume two different file and index.js will always be the first to load AND
require("./main.js"); will be inserted somewhere in index.js for the main to run.

index.js:

// index.ts

//require("./main.js"); // sentry will capture span correctly, but it breaks OpenTelemetry Hook for redisIntegration
import { init as SentryInit, prismaIntegration, extraErrorDataIntegration, rewriteFramesIntegration,  redisIntegration } from "@sentry/node";
SentryInit({
  dsn: "DSN",
  debug: true,
  integrations: [
      extraErrorDataIntegration({
        depth: 3
      }),
      rewriteFramesIntegration({
        iteratee(frame) {
          const absPath = frame.filename;
          if(!absPath) return frame;
          frame.filename = `/${path.relative(__dirname, absPath).replace(/\\/g, "/")}`
          return frame;
        }
      }),
      prismaIntegration(),
      redisIntegration({cachePrefixes: ["tester:"]}),
    ],
    tracesSampleRate: 1.0,
        
    ignoreErrors: [
      "ETIMEDOUT",
      "EADDRINUSE",
      "ENOTFOUND",
      "TimeoutError",
      "AbortError",
      "NetworkError",
      "ECONNREFUSED",
      "ECONNRESET",
    ]
});

//require("./main.js"); // startSpan requires `setParent: null` to avoid timing out, but will properly run the hooked version of ioredis

main.js:

import { Client, GatewayIntentBits, Partials } from "discord.js";
import {  startSpan, withScope } from "@sentry/node";
const cli = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMembers,
        GatewayIntentBits.MessageContent,
        GatewayIntentBits.GuildMessages,
      ],
      partials: [
        Partials.Channel,
        Partials.GuildMember,
        Partials.User,
      ]
})

cli.on("messageCreate", async (message)=>{
    if(message.author.bot) return;
    await withScope(async (scope)=>{
      scope.setTag("user", message.author.id);
      await startSpan({
        name: "ChatHandler",
        op: "processMessage",
      }, async () => {
        
        const content = message.content;
        if(content === "!ping")
          return await message.reply("Pong!");
        await message.reply("Fail!")
      });
    });
});

cli.login("BOT TOKEN").then(()=>console.log("SERVER OPERATED!"));

Steps to Reproduce

Make sentry init run first (as intended) before other code (aka require("./main.js"); will be set at the bottom of the index.js)

Expected Result

All the tracing should process through properly when sentry is initialized first.

Actual Result

  1. Span will eventually hit the 5 minutes timeout and be dropped unless spanParent: null is set inside startSpan (only required if the span is the parent of the rootSpan or "trace span").

  2. startSpan will also reuse trace ID for the duration of the software's lifetime, requiring me to use the following workaround to ensure each event callback is assigned a unique rootSpan ID:

scope.setPropagationContext({
    traceId: randomBytes(16).toString("hex"),
    spanId: randomBytes(16).toString("hex"),
});

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    Package: nodeIssues related to the Sentry Node SDK

    Type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions