Skip to content

Feat: Opentelemetry for TS SDK#2828

Merged
mnafees merged 19 commits intohatchet-dev:nafees/ts-sdk-otelfrom
jishnundth:jndth/ts-otel
Mar 9, 2026
Merged

Feat: Opentelemetry for TS SDK#2828
mnafees merged 19 commits intohatchet-dev:nafees/ts-sdk-otelfrom
jishnundth:jndth/ts-otel

Conversation

@jishnundth
Copy link
Contributor

@jishnundth jishnundth commented Jan 20, 2026

Description

  1. OTel Instrumentor for Typescript SDK (Through monkey patching)
  2. OTel example for TS SDK instrumentor
  3. OTel environment variables for TS SDK

Type of change

  • New feature (non-breaking change which adds functionality)

@vercel
Copy link

vercel bot commented Jan 20, 2026

@jishnundth is attempting to deploy a commit to the Hatchet Team on Vercel.

A member of the Team first needs to authorize it.

@jishnundth jishnundth force-pushed the jndth/ts-otel branch 4 times, most recently from 5f7efa9 to bf2bb93 Compare January 22, 2026 16:30
@jishnundth jishnundth marked this pull request as ready for review January 23, 2026 14:21
@jishnundth
Copy link
Contributor Author

jishnundth commented Jan 23, 2026

Hey @mrkaye97,

Please take a look at this, when you have time.

The current approach follows monkey patching files for instrumentation during load time, which is the standard pattern used in OTel TypeScript examples as well.

(References)

  1. https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/packages/instrumentation-amqplib/src/amqplib.ts
  2. https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/packages/instrumentation-graphql/src/instrumentation.ts

However, the issue with this approach is that register instrumentation must occur first, before loading any other libraries. This is because Node.js caches loaded libraries. If a library that needs to be instrumented is imported before the instrumentation is registered, the patching will not occur. The rest of the program will then use the cached version of the library, which does not contain the patched OTel code. As a result, the spans internally added in the patched module will not appear in HyperDX.

You might already know this, just want to give a heads up on how opentelemetry works for JS.

NOTE: Also, for testing with the examples, the code has to built, packed and installed in another node_modules directory. Because patching follows the path of the file inside a node_module directory.

I also had to edit handleStartStepRun to throw the errors upstream, to capture the stacktrace in OTel.

@jishnundth
Copy link
Contributor Author

image

It's working pretty good, same as python OTel

@mrkaye97
Copy link
Contributor

Great, thanks! Will take a look soon :)

Copy link
Contributor

@mrkaye97 mrkaye97 left a comment

Choose a reason for hiding this comment

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

left a couple small comments but basically looks good to me 🥳

will let @grutt take a look through since he has some more context here :) great work!

@mrkaye97
Copy link
Contributor

btw just confirming - you've tested propagating the span context 1) from trigger -> run (so the trigger workflow run and the run workflow are part of the same trace, with the run nested as a span under the trigger) and 2) from parent -> child (when a task spawns a child the child should be nested under the parent)?

@jishnundth
Copy link
Contributor Author

btw just confirming - you've tested propagating the span context 1) from trigger -> run (so the trigger workflow run and the run workflow are part of the same trace, with the run nested as a span under the trigger) and 2) from parent -> child (when a task spawns a child the child should be nested under the parent)?

Thanks for the message.

Case 1 is properly tested. -> run is propagating correctly and showing proper nesting in the trace.
I missed out on Case 2. Will test and confirm shortly

@jishnundth
Copy link
Contributor Author

@mrkaye97 Both cases work seemlessly. Please check the screenshots below

Run Workflow

This is the example in the PR. Where the workflow contains 4 tasks. 2 autoinstrumented ones (no separate spans), and 2 tasks having their own spans in the task.

workflow run

Parent Child Workflow

A parent task spawing 3 child tasks. parent-orchestartion and spawn-child-int are spans inside the parent task.
child-compute is a span inside the child task.

child_parent

Let me know, if there's issues.

Also when you're testing please remember the note I shared above: #2828 (comment)

@mrkaye97
Copy link
Contributor

@mrkaye97 Both cases work seemlessly. Please check the screenshots below

Run Workflow

This is the example in the PR. Where the workflow contains 4 tasks. 2 autoinstrumented ones (no separate spans), and 2 tasks having their own spans in the task.

workflow run ## Parent Child Workflow A parent task spawing 3 child tasks. _parent-orchestartion_ and _spawn-child-int_ are spans inside the parent task. _child-compute_ is a span inside the child task. child_parent Let me know, if there's issues.

Also when you're testing please remember the note I shared above: #2828 (comment)

Amazing!

@mnafees
Copy link
Member

mnafees commented Mar 5, 2026

Hey @jishnundth, sorry this is taking so long. We just merged some major changes in main so could you please rebase with the latest changes and I will make sure this gets shipped this week itself. Thanks so much.

@jishnundth
Copy link
Contributor Author

Hey @jishnundth, sorry this is taking so long. We just merged some major changes in main so could you please rebase with the latest changes and I will make sure this gets shipped this week itself. Thanks so much.

No worries. I'm working on fixing things with the latest changes. Will keep you posted

@jishnundth
Copy link
Contributor Author

@mnafees please check now

Copy link
Contributor

@grutt grutt left a comment

Choose a reason for hiding this comment

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

super close! a few questions and then we'll need to resolve conficts/lint

@grutt grutt changed the base branch from main to nafees/ts-sdk-otel March 9, 2026 13:29
@jishnundth
Copy link
Contributor Author

PTAL, the requested changes are added

Copy link
Contributor

@grutt grutt left a comment

Choose a reason for hiding this comment

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

one last comment to add comments on core sdk functions to prevent future breakage

@jishnundth
Copy link
Contributor Author

one last comment to add comments on core sdk functions to prevent future breakage

Done!

@mnafees mnafees merged commit df36679 into hatchet-dev:nafees/ts-sdk-otel Mar 9, 2026
8 of 9 checks passed
@promptless-for-oss
Copy link

📝 Documentation updates detected!

Updated existing suggestion: Document OpenTelemetry support for Python, TypeScript, and Go SDKs


Tip: Configure how Promptless handles changelogs in Agent Settings 📋

mnafees added a commit that referenced this pull request Mar 9, 2026
* add: otel as optional dep on ts packages

* feat: opentelemetry instrumentor for TS sdk, with example

* fix: lint

* revert: debug print

* remove: trailing space

* fix: ts otel patch file path, throw handlesteprun error upstream, ts otel examples

* fix: lint

* feat: add schedule_workflow instrumentor, add otel conig loader tests

* add: more robust wrap unwrap for patched modules

* fix: lint, update version

* refactor: ts otel config type assertion

* revert: rebase issues

* fix: lint

* fix: update worker patch for ts otel with InternalWorker

* fix: lint

* refactor: parsejson on otel

* fix: pnpm-lock

* fix: lint

* docs: add otel instrumented method warnings

Co-authored-by: Jishnu <jishnun789@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants