@mastra/otel-bridge 0.0.0-main-test-2-20251127211532

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # @mastra/otel-bridge
2
+
3
+ ## 0.0.0-main-test-2-20251127211532
4
+
5
+ ### Minor Changes
6
+
7
+ - Adds bidirectional integration with otel tracing via a new @mastra/otel-bridge package. ([#10482](https://github.com/mastra-ai/mastra/pull/10482))
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`2319326`](https://github.com/mastra-ai/mastra/commit/2319326f8c64e503a09bbcf14be2dd65405445e0), [`39c9743`](https://github.com/mastra-ai/mastra/commit/39c97432d084294f8ba85fbf3ef28098ff21459e), [`f743dbb`](https://github.com/mastra-ai/mastra/commit/f743dbb8b40d1627b5c10c0e6fc154f4ebb6e394), [`21a15de`](https://github.com/mastra-ai/mastra/commit/21a15de369fe82aac26bb642ed7be73505475e8b), [`fec5129`](https://github.com/mastra-ai/mastra/commit/fec5129de7fc64423ea03661a56cef31dc747a0d), [`0491e7c`](https://github.com/mastra-ai/mastra/commit/0491e7c9b714cb0ba22187ee062147ec2dd7c712), [`f6f4903`](https://github.com/mastra-ai/mastra/commit/f6f4903397314f73362061dc5a3e8e7c61ea34aa), [`0e8ed46`](https://github.com/mastra-ai/mastra/commit/0e8ed467c54d6901a6a365f270ec15d6faadb36c), [`6c049d9`](https://github.com/mastra-ai/mastra/commit/6c049d94063fdcbd5b81c4912a2bf82a92c9cc0b), [`910db9e`](https://github.com/mastra-ai/mastra/commit/910db9e0312888495eb5617b567f247d03303814), [`2f897df`](https://github.com/mastra-ai/mastra/commit/2f897df208508f46f51b7625e5dd20c37f93e0e3), [`d629361`](https://github.com/mastra-ai/mastra/commit/d629361a60f6565b5bfb11976fdaf7308af858e2), [`feb7ee4`](https://github.com/mastra-ai/mastra/commit/feb7ee4d09a75edb46c6669a3beaceec78811747), [`c237233`](https://github.com/mastra-ai/mastra/commit/c23723399ccedf7f5744b3f40997b79246bfbe64), [`08c31c1`](https://github.com/mastra-ai/mastra/commit/08c31c188ebccd598acaf55e888b6397d01f7eae), [`3443770`](https://github.com/mastra-ai/mastra/commit/3443770662df8eb24c9df3589b2792d78cfcb811), [`b0e2ea5`](https://github.com/mastra-ai/mastra/commit/b0e2ea5b52c40fae438b9e2f7baee6f0f89c5442), [`f0a07e0`](https://github.com/mastra-ai/mastra/commit/f0a07e0111b3307c5fabfa4094c5c2cfb734fbe6), [`aaa40e7`](https://github.com/mastra-ai/mastra/commit/aaa40e788628b319baa8e889407d11ad626547fa), [`1521d71`](https://github.com/mastra-ai/mastra/commit/1521d716e5daedc74690c983fbd961123c56756b), [`9e1911d`](https://github.com/mastra-ai/mastra/commit/9e1911db2b4db85e0e768c3f15e0d61e319869f6), [`c456e01`](https://github.com/mastra-ai/mastra/commit/c456e0149e3c176afcefdbd9bb1d2c5917723725), [`ebac155`](https://github.com/mastra-ai/mastra/commit/ebac15564a590117db7078233f927a7e28a85106), [`dd1c38d`](https://github.com/mastra-ai/mastra/commit/dd1c38d1b75f1b695c27b40d8d9d6ed00d5e0f6f), [`5948e6a`](https://github.com/mastra-ai/mastra/commit/5948e6a5146c83666ba3f294b2be576c82a513fb), [`83b08dc`](https://github.com/mastra-ai/mastra/commit/83b08dcf1bfcc915efab23c09207df90fa247908), [`8940859`](https://github.com/mastra-ai/mastra/commit/89408593658199b4ad67f7b65e888f344e64a442), [`f0f8f12`](https://github.com/mastra-ai/mastra/commit/f0f8f125c308f2d0fd36942ef652fd852df7522f), [`ab035c2`](https://github.com/mastra-ai/mastra/commit/ab035c2ef6d8cc7bb25f06f1a38508bd9e6f126b), [`e629310`](https://github.com/mastra-ai/mastra/commit/e629310f1a73fa236d49ec7a1d1cceb6229dc7cc), [`5ca599d`](https://github.com/mastra-ai/mastra/commit/5ca599d0bb59a1595f19f58473fcd67cc71cef58), [`4c6b492`](https://github.com/mastra-ai/mastra/commit/4c6b492c4dd591c6a592520c1f6855d6e936d71f), [`dff01d8`](https://github.com/mastra-ai/mastra/commit/dff01d81ce1f4e4087cfac20fa868e6db138dd14), [`9d819d5`](https://github.com/mastra-ai/mastra/commit/9d819d54b61481639f4008e4694791bddf187edd), [`a64d16a`](https://github.com/mastra-ai/mastra/commit/a64d16aedafe57ee5707bdcc25f96e07fa1a0233), [`e191844`](https://github.com/mastra-ai/mastra/commit/e1918444ca3f80e82feef1dad506cd4ec6e2875f), [`2500740`](https://github.com/mastra-ai/mastra/commit/2500740ea23da067d6e50ec71c625ab3ce275e64), [`fd3d338`](https://github.com/mastra-ai/mastra/commit/fd3d338a2c362174ed5b383f1f011ad9fb0302aa), [`71c8d6c`](https://github.com/mastra-ai/mastra/commit/71c8d6c161253207b2b9588bdadb7eed604f7253), [`6179a9b`](https://github.com/mastra-ai/mastra/commit/6179a9ba36ffac326de3cc3c43cdc8028d37c251), [`c30400a`](https://github.com/mastra-ai/mastra/commit/c30400a49b994b1b97256fe785eb6c906fc2b232), [`00f4921`](https://github.com/mastra-ai/mastra/commit/00f4921dd2c91a1e5446799599ef7116a8214a1a), [`1a46a56`](https://github.com/mastra-ai/mastra/commit/1a46a566f45a3fcbadc1cf36bf86d351f264bfa3), [`ca8041c`](https://github.com/mastra-ai/mastra/commit/ca8041cce0379fda22ed293a565bcb5b6ddca68a), [`7051bf3`](https://github.com/mastra-ai/mastra/commit/7051bf38b3b122a069008f861f7bfc004a6d9f6e), [`a8f1494`](https://github.com/mastra-ai/mastra/commit/a8f1494f4bbdc2770bcf327d4c7d869e332183f1), [`69e0a87`](https://github.com/mastra-ai/mastra/commit/69e0a878896a2da9494945d86e056a5f8f05b851), [`cd29ad2`](https://github.com/mastra-ai/mastra/commit/cd29ad23a255534e8191f249593849ed29160886), [`bdf4d8c`](https://github.com/mastra-ai/mastra/commit/bdf4d8cdc656d8a2c21d81834bfa3bfa70f56c16), [`3cf540b`](https://github.com/mastra-ai/mastra/commit/3cf540b9fbfea8f4fc8d3a2319a4e6c0b0cbfd52), [`352a5d6`](https://github.com/mastra-ai/mastra/commit/352a5d625cfe09849b21e8f52a24c9f0366759d5), [`1c6ce51`](https://github.com/mastra-ai/mastra/commit/1c6ce51f875915ab57fd36873623013699a2a65d), [`898a972`](https://github.com/mastra-ai/mastra/commit/898a9727d286c2510d6b702dfd367e6aaf5c6b0f), [`0793497`](https://github.com/mastra-ai/mastra/commit/079349753620c40246ffd673e3f9d7d9820beff3), [`a97003a`](https://github.com/mastra-ai/mastra/commit/a97003aa1cf2f4022a41912324a1e77263b326b8), [`ccc141e`](https://github.com/mastra-ai/mastra/commit/ccc141ed27da0abc3a3fc28e9e5128152e8e37f4), [`01f8878`](https://github.com/mastra-ai/mastra/commit/01f88783de25e4de048c1c8aace43e26373c6ea5), [`5df9cce`](https://github.com/mastra-ai/mastra/commit/5df9cce1a753438413f64c11eeef8f845745c2a8), [`4c77209`](https://github.com/mastra-ai/mastra/commit/4c77209e6c11678808b365d545845918c40045c8), [`a854ede`](https://github.com/mastra-ai/mastra/commit/a854ede62bf5ac0945a624ac48913dd69c73aabf), [`fe3b897`](https://github.com/mastra-ai/mastra/commit/fe3b897c2ccbcd2b10e81b099438c7337feddf89), [`c576fc0`](https://github.com/mastra-ai/mastra/commit/c576fc0b100b2085afded91a37c97a0ea0ec09c7), [`3defc80`](https://github.com/mastra-ai/mastra/commit/3defc80cf2b88a1b7fc1cc4ddcb91e982a614609), [`f111eac`](https://github.com/mastra-ai/mastra/commit/f111eac5de509b2e5fccfc1882e7f74cda264c74), [`00123ba`](https://github.com/mastra-ai/mastra/commit/00123ba96dc9e5cd0b110420ebdba56d8f237b25), [`16153fe`](https://github.com/mastra-ai/mastra/commit/16153fe7eb13c99401f48e6ca32707c965ee28b9), [`9f4a683`](https://github.com/mastra-ai/mastra/commit/9f4a6833e88b52574665c028fd5508ad5c2f6004), [`bc94344`](https://github.com/mastra-ai/mastra/commit/bc943444a1342d8a662151b7bce1df7dae32f59c), [`29c4309`](https://github.com/mastra-ai/mastra/commit/29c4309f818b24304c041bcb4a8f19b5f13f6b62), [`16785ce`](https://github.com/mastra-ai/mastra/commit/16785ced928f6f22638f4488cf8a125d99211799), [`57d157f`](https://github.com/mastra-ai/mastra/commit/57d157f0b163a95c3e6c9eae31bdb11d1bfc64f9), [`903f67d`](https://github.com/mastra-ai/mastra/commit/903f67d184504a273893818c02b961f5423a79ad), [`d827d08`](https://github.com/mastra-ai/mastra/commit/d827d0808ffe1f3553a84e975806cc989b9735dd), [`2a90c55`](https://github.com/mastra-ai/mastra/commit/2a90c55a86a9210697d5adaab5ee94584b079adc), [`db70a48`](https://github.com/mastra-ai/mastra/commit/db70a48aeeeeb8e5f92007e8ede52c364ce15287), [`eb09742`](https://github.com/mastra-ai/mastra/commit/eb09742197f66c4c38154c3beec78313e69760b2), [`de8239b`](https://github.com/mastra-ai/mastra/commit/de8239bdcb1d8c0cfa06da21f1569912a66bbc8a), [`23c10a1`](https://github.com/mastra-ai/mastra/commit/23c10a1efdd9a693c405511ab2dc8a1236603162), [`b5e6cd7`](https://github.com/mastra-ai/mastra/commit/b5e6cd77fc8c8e64e0494c1d06cee3d84e795d1e), [`96d35f6`](https://github.com/mastra-ai/mastra/commit/96d35f61376bc2b1bf148648a2c1985bd51bef55), [`5cbe88a`](https://github.com/mastra-ai/mastra/commit/5cbe88aefbd9f933bca669fd371ea36bf939ac6d), [`a1bd7b8`](https://github.com/mastra-ai/mastra/commit/a1bd7b8571db16b94eb01588f451a74758c96d65), [`d78b38d`](https://github.com/mastra-ai/mastra/commit/d78b38d898fce285260d3bbb4befade54331617f), [`a0a5b4b`](https://github.com/mastra-ai/mastra/commit/a0a5b4bbebe6c701ebbadf744873aa0d5ca01371), [`5d171ad`](https://github.com/mastra-ai/mastra/commit/5d171ad9ef340387276b77c2bb3e83e83332d729), [`0633100`](https://github.com/mastra-ai/mastra/commit/0633100a911ad22f5256471bdf753da21c104742), [`3759cb0`](https://github.com/mastra-ai/mastra/commit/3759cb064935b5f74c65ac2f52a1145f7352899d), [`c710c16`](https://github.com/mastra-ai/mastra/commit/c710c1652dccfdc4111c8412bca7a6bb1d48b441), [`354ad0b`](https://github.com/mastra-ai/mastra/commit/354ad0b7b1b8183ac567f236a884fc7ede6d7138), [`cfae733`](https://github.com/mastra-ai/mastra/commit/cfae73394f4920635e6c919c8e95ff9a0788e2e5), [`e3dfda7`](https://github.com/mastra-ai/mastra/commit/e3dfda7b11bf3b8c4bb55637028befb5f387fc74), [`69ea758`](https://github.com/mastra-ai/mastra/commit/69ea758358edd7117f191c2e69c8bb5fc79e7a1a), [`651e772`](https://github.com/mastra-ai/mastra/commit/651e772eb1475fb13e126d3fcc01751297a88214), [`f03ae60`](https://github.com/mastra-ai/mastra/commit/f03ae60500fe350c9d828621006cdafe1975fdd8), [`993ad98`](https://github.com/mastra-ai/mastra/commit/993ad98d7ad3bebda9ecef5fec5c94349a0d04bc), [`676ccc7`](https://github.com/mastra-ai/mastra/commit/676ccc7fe92468d2d45d39c31a87825c89fd1ea0), [`3ff2c17`](https://github.com/mastra-ai/mastra/commit/3ff2c17a58e312fad5ea37377262c12d92ca0908), [`844ea5d`](https://github.com/mastra-ai/mastra/commit/844ea5dc0c248961e7bf73629ae7dcff503e853c), [`398fde3`](https://github.com/mastra-ai/mastra/commit/398fde3f39e707cda79372cdae8f9870e3b57c8d), [`c10398d`](https://github.com/mastra-ai/mastra/commit/c10398d5b88f1d4af556f4267ff06f1d11e89179), [`f0f8f12`](https://github.com/mastra-ai/mastra/commit/f0f8f125c308f2d0fd36942ef652fd852df7522f), [`b61b93f`](https://github.com/mastra-ai/mastra/commit/b61b93f9e058b11dd2eec169853175d31dbdd567), [`bae33d9`](https://github.com/mastra-ai/mastra/commit/bae33d91a63fbb64d1e80519e1fc1acaed1e9013), [`0d7618b`](https://github.com/mastra-ai/mastra/commit/0d7618bc650bf2800934b243eca5648f4aeed9c2), [`7b763e5`](https://github.com/mastra-ai/mastra/commit/7b763e52fc3eaf699c2a99f2adf418dd46e4e9a5), [`d36cfbb`](https://github.com/mastra-ai/mastra/commit/d36cfbbb6565ba5f827883cc9bb648eb14befdc1), [`c0b731f`](https://github.com/mastra-ai/mastra/commit/c0b731fb27d712dc8582e846df5c0332a6a0c5ba), [`3697853`](https://github.com/mastra-ai/mastra/commit/3697853deeb72017d90e0f38a93c1e29221aeca0), [`b2e45ec`](https://github.com/mastra-ai/mastra/commit/b2e45eca727a8db01a81ba93f1a5219c7183c839), [`43ca8f2`](https://github.com/mastra-ai/mastra/commit/43ca8f2c7334851cc7b4d3d2f037d8784bfbdd5f), [`d6d49f7`](https://github.com/mastra-ai/mastra/commit/d6d49f7b8714fa19a52ff9c7cf7fb7e73751901e), [`00c2387`](https://github.com/mastra-ai/mastra/commit/00c2387f5f04a365316f851e58666ac43f8c4edf), [`a534e95`](https://github.com/mastra-ai/mastra/commit/a534e9591f83b3cc1ebff99c67edf4cda7bf81d3), [`9d0e7fe`](https://github.com/mastra-ai/mastra/commit/9d0e7feca8ed98de959f53476ee1456073673348), [`53d927c`](https://github.com/mastra-ai/mastra/commit/53d927cc6f03bff33655b7e2b788da445a08731d), [`ad6250d`](https://github.com/mastra-ai/mastra/commit/ad6250dbdaad927e29f74a27b83f6c468b50a705), [`3f2faf2`](https://github.com/mastra-ai/mastra/commit/3f2faf2e2d685d6c053cc5af1bf9fedf267b2ce5), [`22f64bc`](https://github.com/mastra-ai/mastra/commit/22f64bc1d37149480b58bf2fefe35b79a1e3e7d5), [`3a73998`](https://github.com/mastra-ai/mastra/commit/3a73998fa4ebeb7f3dc9301afe78095fc63e7999), [`83d5942`](https://github.com/mastra-ai/mastra/commit/83d5942669ce7bba4a6ca4fd4da697a10eb5ebdc), [`b7959e6`](https://github.com/mastra-ai/mastra/commit/b7959e6e25a46b480f9ea2217c4c6c588c423791), [`bda6370`](https://github.com/mastra-ai/mastra/commit/bda637009360649aaf579919e7873e33553c273e), [`d7acd8e`](https://github.com/mastra-ai/mastra/commit/d7acd8e987b5d7eff4fd98b0906c17c06a2e83d5), [`c7f1f7d`](https://github.com/mastra-ai/mastra/commit/c7f1f7d24f61f247f018cc2d1f33bf63212959a7), [`0bddc6d`](https://github.com/mastra-ai/mastra/commit/0bddc6d8dbd6f6008c0cba2e4960a2da75a55af1), [`735d8c1`](https://github.com/mastra-ai/mastra/commit/735d8c1c0d19fbc09e6f8b66cf41bc7655993838), [`acf322e`](https://github.com/mastra-ai/mastra/commit/acf322e0f1fd0189684cf529d91c694bea918a45), [`2ca67cc`](https://github.com/mastra-ai/mastra/commit/2ca67cc3bb1f6a617353fdcab197d9efebe60d6f), [`e16d553`](https://github.com/mastra-ai/mastra/commit/e16d55338403c7553531cc568125c63d53653dff), [`c942802`](https://github.com/mastra-ai/mastra/commit/c942802a477a925b01859a7b8688d4355715caaa), [`a0c8c1b`](https://github.com/mastra-ai/mastra/commit/a0c8c1b87d4fee252aebda73e8637fbe01d761c9), [`cc34739`](https://github.com/mastra-ai/mastra/commit/cc34739c34b6266a91bea561119240a7acf47887), [`c218bd3`](https://github.com/mastra-ai/mastra/commit/c218bd3759e32423735b04843a09404572631014), [`9e67002`](https://github.com/mastra-ai/mastra/commit/9e67002b52c9be19936c420a489dbee9c5fd6a78), [`2c4438b`](https://github.com/mastra-ai/mastra/commit/2c4438b87817ab7eed818c7990fef010475af1a3), [`35edc49`](https://github.com/mastra-ai/mastra/commit/35edc49ac0556db609189641d6341e76771b81fc), [`4d59f58`](https://github.com/mastra-ai/mastra/commit/4d59f58de2d90d6e2810a19d4518e38ddddb9038), [`2b8893c`](https://github.com/mastra-ai/mastra/commit/2b8893cb108ef9acb72ee7835cd625610d2c1a4a), [`8e5c75b`](https://github.com/mastra-ai/mastra/commit/8e5c75bdb1d08a42d45309a4c72def4b6890230f), [`e1bb9c9`](https://github.com/mastra-ai/mastra/commit/e1bb9c94b4eb68b019ae275981be3feb769b5365), [`351a11f`](https://github.com/mastra-ai/mastra/commit/351a11fcaf2ed1008977fa9b9a489fc422e51cd4), [`e59e0d3`](https://github.com/mastra-ai/mastra/commit/e59e0d32afb5fcf2c9f3c00c8f81f6c21d3a63fa), [`465ac05`](https://github.com/mastra-ai/mastra/commit/465ac0526a91d175542091c675181f1a96c98c46), [`fa8409b`](https://github.com/mastra-ai/mastra/commit/fa8409bc39cfd8ba6643b9db5269b90b22e2a2f7), [`e7266a2`](https://github.com/mastra-ai/mastra/commit/e7266a278db02035c97a5e9cd9d1669a6b7a535d), [`173c535`](https://github.com/mastra-ai/mastra/commit/173c535c0645b0da404fe09f003778f0b0d4e019)]:
12
+ - @mastra/core@0.0.0-main-test-2-20251127211532
13
+ - @mastra/otel-exporter@0.0.0-main-test-2-20251127211532
14
+ - @mastra/observability@0.0.0-main-test-2-20251127211532
package/LICENSE.md ADDED
@@ -0,0 +1,15 @@
1
+ # Apache License 2.0
2
+
3
+ Copyright (c) 2025 Kepler Software, Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # @mastra/otel-bridge
2
+
3
+ OpenTelemetry Bridge for Mastra Observability.
4
+
5
+ Enables bidirectional integration between Mastra and OpenTelemetry infrastructure, creating real OTEL spans for Mastra operations and maintaining proper trace hierarchy.
6
+
7
+ ## Overview
8
+
9
+ `@mastra/otel-bridge` connects Mastra's observability system with standard OpenTelemetry instrumentation through bidirectional integration:
10
+
11
+ **From OTEL to Mastra:**
12
+
13
+ - Reads from OTEL ambient context (AsyncLocalStorage) automatically
14
+ - Inherits trace ID and parent span ID from active OTEL spans
15
+ - Works with standard OTEL auto-instrumentation (no middleware needed)
16
+
17
+ **From Mastra to OTEL:**
18
+
19
+ - Creates real OTEL spans for Mastra operations (agents, LLM calls, tools, workflows)
20
+ - Maintains proper parent-child relationships in distributed traces
21
+ - Allows OTEL-instrumented code (DB calls, HTTP clients) within Mastra operations to nest correctly
22
+ - Exports spans with OTEL semantic conventions for GenAI operations
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install @mastra/otel-bridge
28
+ # or
29
+ pnpm add @mastra/otel-bridge
30
+ ```
31
+
32
+ For the standard OTEL setup (recommended), also install:
33
+
34
+ ```bash
35
+ npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
36
+ # or
37
+ pnpm add @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node
38
+ ```
39
+
40
+ ## Quick Start
41
+
42
+ ### 1. Set up OpenTelemetry (Standard Pattern)
43
+
44
+ Create an `instrumentation.js` file and import it **before** any other code:
45
+
46
+ ```javascript
47
+ // instrumentation.js
48
+ import { NodeSDK } from '@opentelemetry/sdk-node';
49
+ import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
50
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
51
+
52
+ const sdk = new NodeSDK({
53
+ serviceName: 'my-service',
54
+ traceExporter: new OTLPTraceExporter({
55
+ url: 'http://localhost:4318/v1/traces',
56
+ }),
57
+ instrumentations: [
58
+ getNodeAutoInstrumentations({
59
+ // Automatically instruments Express, Fastify, HTTP, and many others
60
+ '@opentelemetry/instrumentation-fs': {
61
+ enabled: false,
62
+ },
63
+ }),
64
+ ],
65
+ });
66
+
67
+ sdk.start();
68
+
69
+ process.on('SIGTERM', async () => {
70
+ await sdk.shutdown();
71
+ process.exit(0);
72
+ });
73
+ ```
74
+
75
+ Then import this file first in your application:
76
+
77
+ ```typescript
78
+ // IMPORTANT: Import instrumentation FIRST!
79
+ import './instrumentation.js';
80
+
81
+ // Now import your application code
82
+ import express from 'express';
83
+ import { Mastra } from '@mastra/core';
84
+ // ... rest of your imports
85
+ ```
86
+
87
+ ### 2. Configure Mastra with OtelBridge
88
+
89
+ ```typescript
90
+ import { OtelBridge } from '@mastra/otel-bridge';
91
+ import { Mastra } from '@mastra/core';
92
+ import { Observability } from '@mastra/observability';
93
+
94
+ const mastra = new Mastra({
95
+ agents: { myAgent },
96
+ observability: new Observability({
97
+ configs: {
98
+ default: {
99
+ serviceName: 'my-service',
100
+ bridge: new OtelBridge(),
101
+ },
102
+ },
103
+ }),
104
+ });
105
+ ```
106
+
107
+ ### 3. Use Your Agent
108
+
109
+ The OTEL SDK's auto-instrumentation handles context propagation automatically via AsyncLocalStorage. The bridge creates OTEL spans for all Mastra operations.
110
+
111
+ ```typescript
112
+ // Example: Express endpoint using Mastra agent
113
+ app.post('/chat', async (req, res) => {
114
+ // OTEL auto-instrumentation creates HTTP span
115
+ // Bridge inherits trace context and creates child spans for agent operations
116
+ const result = await myAgent.generate(req.body.message);
117
+ res.json(result);
118
+ });
119
+ ```
120
+
121
+ ## How It Works
122
+
123
+ ### Span Creation
124
+
125
+ When Mastra creates a span (agent run, LLM call, tool execution, etc.):
126
+
127
+ 1. **Bridge creates OTEL span** at span creation time with:
128
+ - SpanKind (SERVER for agents/workflows, CLIENT for LLM/MCP tools, INTERNAL for others)
129
+ - Parent context (from active OTEL context or parent Mastra span)
130
+ - Initial span name
131
+
132
+ 2. **Mastra uses OTEL IDs**:
133
+ - `spanId` = OTEL span's 16-char hex ID
134
+ - `traceId` = OTEL span's 32-char hex trace ID
135
+ - `parentSpanId` = parent OTEL span's ID
136
+
137
+ 3. **Internal spans are skipped**:
138
+ - Only external spans (user-facing operations) create OTEL spans
139
+ - Internal spans (workflow internals) don't create OTEL spans to avoid orphaned references
140
+
141
+ ### Span Finalization
142
+
143
+ When a Mastra span ends:
144
+
145
+ 1. **Bridge retrieves OTEL span** from map using span ID
146
+ 2. **Sets all final attributes** using SpanConverter (same formatting as otel-exporter):
147
+ - OTEL semantic conventions for GenAI (`gen_ai.*`)
148
+ - Model parameters, usage, finish reasons
149
+ - Tool names, inputs, outputs
150
+ - Error information
151
+ 3. **Updates span name** to OTEL-compliant format (e.g., `chat gpt-4`, `agent.my-agent`)
152
+ 4. **Ends OTEL span** and removes from map
153
+
154
+ ### Context Execution
155
+
156
+ The bridge provides `executeInContext()` and `executeInContextSync()` to run code within a Mastra span's OTEL context. This allows OTEL-instrumented code (DB clients, HTTP clients) to nest correctly under Mastra spans.
157
+
158
+ ## Requirements
159
+
160
+ - **Dependencies**:
161
+ - `@mastra/core` >= 1.0.0
162
+ - `@opentelemetry/api` >= 1.9.0
163
+
164
+ **For Standard OTEL Setup:**
165
+
166
+ - `@opentelemetry/sdk-node` >= 0.205.0
167
+ - `@opentelemetry/auto-instrumentations-node` >= 0.64.1
168
+
169
+ ## License
170
+
171
+ Apache 2.0
@@ -0,0 +1,106 @@
1
+ /**
2
+ * OpenTelemetry Bridge for Mastra Observability
3
+ *
4
+ * This bridge enables bidirectional integration with OpenTelemetry infrastructure:
5
+ * 1. Reads OTEL trace context from active spans (via AsyncLocalStorage)
6
+ * 2. Creates real OTEL spans when Mastra spans are created
7
+ * 3. Maintains span context for proper parent-child relationships
8
+ * 4. Allows OTEL-instrumented code (DB, HTTP clients) in tools/workflows to have correct parents
9
+ *
10
+ * This creates complete distributed traces where Mastra spans are properly
11
+ * nested within OTEL spans from auto-instrumentation, and any OTEL-instrumented
12
+ * operations within Mastra spans maintain the correct hierarchy.
13
+ */
14
+ import type { ObservabilityBridge, TracingEvent, CreateSpanOptions, SpanType, SpanIds } from '@mastra/core/observability';
15
+ import { BaseExporter } from '@mastra/observability';
16
+ /**
17
+ * Configuration for the OtelBridge
18
+ */
19
+ export type OtelBridgeConfig = {};
20
+ /**
21
+ * OpenTelemetry Bridge implementation
22
+ *
23
+ * Creates real OTEL spans when Mastra spans are created, maintaining proper
24
+ * context propagation for nested instrumentation.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import { OtelBridge } from '@mastra/otel-bridge';
29
+ * import { Mastra } from '@mastra/core';
30
+ *
31
+ * const mastra = new Mastra({
32
+ * agents: { myAgent },
33
+ * observability: {
34
+ * configs: {
35
+ * default: {
36
+ * serviceName: 'my-service',
37
+ * bridge: new OtelBridge(),
38
+ * }
39
+ * }
40
+ * }
41
+ * });
42
+ * ```
43
+ */
44
+ export declare class OtelBridge extends BaseExporter implements ObservabilityBridge {
45
+ name: string;
46
+ private otelTracer;
47
+ private otelSpanMap;
48
+ private spanConverter;
49
+ constructor(config?: OtelBridgeConfig);
50
+ /**
51
+ * Handle Mastra tracing events
52
+ *
53
+ * Ships OTEL spans when Mastra spans end.
54
+ * This maintains proper span hierarchy and allows OTEL-instrumented code within
55
+ * Mastra spans to have correct parent-child relationships.
56
+ * Note: OTEL spans are created when registerSpan is called when the span is first created.
57
+ */
58
+ protected _exportTracingEvent(event: TracingEvent): Promise<void>;
59
+ /**
60
+ * Create a span in the bridge's tracing system.
61
+ * Called during Mastra span construction to get bridge-generated identifiers.
62
+ *
63
+ * @param options - Span creation options from Mastra
64
+ * @returns Span identifiers (spanId, traceId, parentSpanId) from bridge, or undefined if creation fails
65
+ */
66
+ createSpan(options: CreateSpanOptions<SpanType>): SpanIds | undefined;
67
+ /**
68
+ * Handle SPAN_ENDED event
69
+ *
70
+ * Retrieves the OTEL span created at SPAN_STARTED, sets all final attributes,
71
+ * events, and status, then ends the span. Cleans up the span map entry.
72
+ */
73
+ private handleSpanEnded;
74
+ /**
75
+ * Execute a function (sync or async) within the OTEL context of a Mastra span.
76
+ * Retrieves the stored OTEL context for the span and executes the function within it.
77
+ *
78
+ * This is the core implementation used by both executeInContext and executeInContextSync.
79
+ *
80
+ * @param spanId - The ID of the Mastra span to use as context
81
+ * @param fn - The function to execute within the span context
82
+ * @returns The result of the function execution
83
+ */
84
+ private executeWithSpanContext;
85
+ /**
86
+ * Execute an async function within the OTEL context of a Mastra span.
87
+ *
88
+ * @param spanId - The ID of the Mastra span to use as context
89
+ * @param fn - The async function to execute within the span context
90
+ * @returns The result of the function execution
91
+ */
92
+ executeInContext<T>(spanId: string, fn: () => Promise<T>): Promise<T>;
93
+ /**
94
+ * Execute a synchronous function within the OTEL context of a Mastra span.
95
+ *
96
+ * @param spanId - The ID of the Mastra span to use as context
97
+ * @param fn - The synchronous function to execute within the span context
98
+ * @returns The result of the function execution
99
+ */
100
+ executeInContextSync<T>(spanId: string, fn: () => T): T;
101
+ /**
102
+ * Shutdown the bridge and clean up resources
103
+ */
104
+ shutdown(): Promise<void>;
105
+ }
106
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,YAAY,EACZ,iBAAiB,EACjB,QAAQ,EACR,OAAO,EACR,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAK1E;;GAEG;AAEH,MAAM,MAAM,gBAAgB,GAAG,EAE9B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,qBAAa,UAAW,SAAQ,YAAa,YAAW,mBAAmB;IACzE,IAAI,SAAU;IACd,OAAO,CAAC,UAAU,CAAuD;IACzE,OAAO,CAAC,WAAW,CAAuE;IAC1F,OAAO,CAAC,aAAa,CAAuB;gBAEhC,MAAM,GAAE,gBAAqB;IAIzC;;;;;;;OAOG;cACa,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAMvE;;;;;;OAMG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,SAAS;IAoDrE;;;;;OAKG;YACW,eAAe;IAoD7B;;;;;;;;;OASG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;;;;;OAMG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIrE;;;;;;OAMG;IACH,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC;IAIvD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAShC"}
package/dist/index.cjs ADDED
@@ -0,0 +1,166 @@
1
+ 'use strict';
2
+
3
+ var observability$1 = require('@mastra/core/observability');
4
+ var observability = require('@mastra/observability');
5
+ var otelExporter = require('@mastra/otel-exporter');
6
+ var api = require('@opentelemetry/api');
7
+
8
+ // src/bridge.ts
9
+ var OtelBridge = class extends observability.BaseExporter {
10
+ name = "otel";
11
+ otelTracer = api.trace.getTracer("@mastra/otel-bridge", "1.0.0");
12
+ otelSpanMap = /* @__PURE__ */ new Map();
13
+ spanConverter = new otelExporter.SpanConverter();
14
+ constructor(config = {}) {
15
+ super(config);
16
+ }
17
+ /**
18
+ * Handle Mastra tracing events
19
+ *
20
+ * Ships OTEL spans when Mastra spans end.
21
+ * This maintains proper span hierarchy and allows OTEL-instrumented code within
22
+ * Mastra spans to have correct parent-child relationships.
23
+ * Note: OTEL spans are created when registerSpan is called when the span is first created.
24
+ */
25
+ async _exportTracingEvent(event) {
26
+ if (event.type === observability$1.TracingEventType.SPAN_ENDED) {
27
+ await this.handleSpanEnded(event);
28
+ }
29
+ }
30
+ /**
31
+ * Create a span in the bridge's tracing system.
32
+ * Called during Mastra span construction to get bridge-generated identifiers.
33
+ *
34
+ * @param options - Span creation options from Mastra
35
+ * @returns Span identifiers (spanId, traceId, parentSpanId) from bridge, or undefined if creation fails
36
+ */
37
+ createSpan(options) {
38
+ try {
39
+ let parentOtelContext = api.context.active();
40
+ const externalParentId = observability.getExternalParentId(options);
41
+ if (externalParentId) {
42
+ const parentEntry = this.otelSpanMap.get(externalParentId);
43
+ if (parentEntry) {
44
+ parentOtelContext = parentEntry.otelContext;
45
+ }
46
+ }
47
+ const isRootSpan = !options.parent;
48
+ const otelSpan = this.otelTracer.startSpan(
49
+ options.name,
50
+ {
51
+ kind: otelExporter.getSpanKind(options.type, isRootSpan)
52
+ },
53
+ parentOtelContext
54
+ );
55
+ const spanContext = api.trace.setSpan(parentOtelContext, otelSpan);
56
+ const otelSpanContext = otelSpan.spanContext();
57
+ const spanId = otelSpanContext.spanId;
58
+ const traceId = otelSpanContext.traceId;
59
+ this.otelSpanMap.set(spanId, { otelSpan, otelContext: spanContext });
60
+ const parentSpan = api.trace.getSpan(parentOtelContext);
61
+ const parentSpanId = parentSpan?.spanContext().spanId;
62
+ this.logger.debug(
63
+ `[OtelBridge.createSpan] Created span [spanId=${spanId}] [traceId=${traceId}] [parentSpanId=${parentSpanId}] [type=${options.type}] [mapSize=${this.otelSpanMap.size}]`
64
+ );
65
+ return { spanId, traceId, parentSpanId };
66
+ } catch (error) {
67
+ this.logger.error("[OtelBridge] Failed to create span:", error);
68
+ return void 0;
69
+ }
70
+ }
71
+ /**
72
+ * Handle SPAN_ENDED event
73
+ *
74
+ * Retrieves the OTEL span created at SPAN_STARTED, sets all final attributes,
75
+ * events, and status, then ends the span. Cleans up the span map entry.
76
+ */
77
+ async handleSpanEnded(event) {
78
+ try {
79
+ const mastraSpan = event.exportedSpan;
80
+ const entry = this.otelSpanMap.get(mastraSpan.id);
81
+ if (!entry) {
82
+ this.logger.warn(`[OtelBridge] No OTEL span found for Mastra span [id=${mastraSpan.id}].`);
83
+ return;
84
+ }
85
+ this.otelSpanMap.delete(mastraSpan.id);
86
+ const { otelSpan } = entry;
87
+ this.logger.debug(`[OtelBridge] Ending OTEL span [mastraId=${mastraSpan.id}] [name=${mastraSpan.name}]`);
88
+ const readableSpan = this.spanConverter.convertSpan(mastraSpan);
89
+ otelSpan.updateName(readableSpan.name);
90
+ for (const [key, value] of Object.entries(readableSpan.attributes)) {
91
+ if (value !== void 0 && value !== null && typeof value !== "object") {
92
+ otelSpan.setAttribute(key, value);
93
+ }
94
+ }
95
+ otelSpan.setStatus(readableSpan.status);
96
+ for (const event2 of readableSpan.events) {
97
+ if (event2.name === "exception" && event2.attributes) {
98
+ const error = new Error(event2.attributes["exception.message"]);
99
+ otelSpan.recordException(error);
100
+ }
101
+ }
102
+ otelSpan.end(mastraSpan.endTime);
103
+ this.logger.debug(
104
+ `[OtelBridge] Completed OTEL span [mastraId=${mastraSpan.id}] [traceId=${otelSpan.spanContext().traceId}]`
105
+ );
106
+ } catch (error) {
107
+ this.logger.error("[OtelBridge] Failed to handle SPAN_ENDED:", error);
108
+ }
109
+ }
110
+ /**
111
+ * Execute a function (sync or async) within the OTEL context of a Mastra span.
112
+ * Retrieves the stored OTEL context for the span and executes the function within it.
113
+ *
114
+ * This is the core implementation used by both executeInContext and executeInContextSync.
115
+ *
116
+ * @param spanId - The ID of the Mastra span to use as context
117
+ * @param fn - The function to execute within the span context
118
+ * @returns The result of the function execution
119
+ */
120
+ executeWithSpanContext(spanId, fn) {
121
+ const entry = this.otelSpanMap.get(spanId);
122
+ this.logger.debug(
123
+ `[OtelBridge.executeWithSpanContext] spanId=${spanId}, inMap=${!!entry}, storedOtelSpan=${entry?.otelSpan.spanContext().spanId || "none"}`
124
+ );
125
+ const spanContext = entry?.otelContext;
126
+ if (spanContext) {
127
+ return api.context.with(spanContext, fn);
128
+ }
129
+ return fn();
130
+ }
131
+ /**
132
+ * Execute an async function within the OTEL context of a Mastra span.
133
+ *
134
+ * @param spanId - The ID of the Mastra span to use as context
135
+ * @param fn - The async function to execute within the span context
136
+ * @returns The result of the function execution
137
+ */
138
+ executeInContext(spanId, fn) {
139
+ return this.executeWithSpanContext(spanId, fn);
140
+ }
141
+ /**
142
+ * Execute a synchronous function within the OTEL context of a Mastra span.
143
+ *
144
+ * @param spanId - The ID of the Mastra span to use as context
145
+ * @param fn - The synchronous function to execute within the span context
146
+ * @returns The result of the function execution
147
+ */
148
+ executeInContextSync(spanId, fn) {
149
+ return this.executeWithSpanContext(spanId, fn);
150
+ }
151
+ /**
152
+ * Shutdown the bridge and clean up resources
153
+ */
154
+ async shutdown() {
155
+ for (const [spanId, { otelSpan }] of this.otelSpanMap.entries()) {
156
+ this.logger.warn(`[OtelBridge] Force-ending span that was not properly closed [id=${spanId}]`);
157
+ otelSpan.end();
158
+ }
159
+ this.otelSpanMap.clear();
160
+ this.logger.info("[OtelBridge] Shutdown complete");
161
+ }
162
+ };
163
+
164
+ exports.OtelBridge = OtelBridge;
165
+ //# sourceMappingURL=index.cjs.map
166
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridge.ts"],"names":["BaseExporter","otelTrace","SpanConverter","TracingEventType","otelContext","getExternalParentId","getSpanKind","event"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * OpenTelemetry Bridge for Mastra Observability\n *\n * This bridge enables bidirectional integration with OpenTelemetry infrastructure:\n * 1. Reads OTEL trace context from active spans (via AsyncLocalStorage)\n * 2. Creates real OTEL spans when Mastra spans are created\n * 3. Maintains span context for proper parent-child relationships\n * 4. Allows OTEL-instrumented code (DB, HTTP clients) in tools/workflows to have correct parents\n *\n * This creates complete distributed traces where Mastra spans are properly\n * nested within OTEL spans from auto-instrumentation, and any OTEL-instrumented\n * operations within Mastra spans maintain the correct hierarchy.\n */\n\nimport type {\n ObservabilityBridge,\n TracingEvent,\n CreateSpanOptions,\n SpanType,\n SpanIds,\n} from '@mastra/core/observability';\nimport { TracingEventType } from '@mastra/core/observability';\nimport { BaseExporter, getExternalParentId } from '@mastra/observability';\nimport { SpanConverter, getSpanKind } from '@mastra/otel-exporter';\nimport { trace as otelTrace, context as otelContext } from '@opentelemetry/api';\nimport type { Span as OtelSpan, Context as OtelContext } from '@opentelemetry/api';\n\n/**\n * Configuration for the OtelBridge\n */\n\nexport type OtelBridgeConfig = {\n // Currently no configuration options - placeholder for future options\n};\n\n/**\n * OpenTelemetry Bridge implementation\n *\n * Creates real OTEL spans when Mastra spans are created, maintaining proper\n * context propagation for nested instrumentation.\n *\n * @example\n * ```typescript\n * import { OtelBridge } from '@mastra/otel-bridge';\n * import { Mastra } from '@mastra/core';\n *\n * const mastra = new Mastra({\n * agents: { myAgent },\n * observability: {\n * configs: {\n * default: {\n * serviceName: 'my-service',\n * bridge: new OtelBridge(),\n * }\n * }\n * }\n * });\n * ```\n */\nexport class OtelBridge extends BaseExporter implements ObservabilityBridge {\n name = 'otel';\n private otelTracer = otelTrace.getTracer('@mastra/otel-bridge', '1.0.0');\n private otelSpanMap = new Map<string, { otelSpan: OtelSpan; otelContext: OtelContext }>();\n private spanConverter = new SpanConverter();\n\n constructor(config: OtelBridgeConfig = {}) {\n super(config);\n }\n\n /**\n * Handle Mastra tracing events\n *\n * Ships OTEL spans when Mastra spans end.\n * This maintains proper span hierarchy and allows OTEL-instrumented code within\n * Mastra spans to have correct parent-child relationships.\n * Note: OTEL spans are created when registerSpan is called when the span is first created.\n */\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (event.type === TracingEventType.SPAN_ENDED) {\n await this.handleSpanEnded(event);\n }\n }\n\n /**\n * Create a span in the bridge's tracing system.\n * Called during Mastra span construction to get bridge-generated identifiers.\n *\n * @param options - Span creation options from Mastra\n * @returns Span identifiers (spanId, traceId, parentSpanId) from bridge, or undefined if creation fails\n */\n createSpan(options: CreateSpanOptions<SpanType>): SpanIds | undefined {\n try {\n // Determine parent context\n let parentOtelContext = otelContext.active();\n\n // Get external parent ID (walks up chain to find non-internal parent)\n const externalParentId = getExternalParentId(options);\n if (externalParentId) {\n // Look up external parent's OTEL span from map\n const parentEntry = this.otelSpanMap.get(externalParentId);\n if (parentEntry) {\n parentOtelContext = parentEntry.otelContext;\n }\n }\n\n // Create OTEL span with SpanKind (must be set at creation, immutable)\n const isRootSpan = !options.parent;\n const otelSpan = this.otelTracer.startSpan(\n options.name,\n {\n kind: getSpanKind(options.type, isRootSpan),\n },\n parentOtelContext,\n );\n\n // Create context with this span active\n const spanContext = otelTrace.setSpan(parentOtelContext, otelSpan);\n\n // Get OTEL span identifiers\n const otelSpanContext = otelSpan.spanContext();\n const spanId = otelSpanContext.spanId;\n const traceId = otelSpanContext.traceId;\n\n // Store for later retrieval (for executeWithSpanContext and event handling)\n this.otelSpanMap.set(spanId, { otelSpan, otelContext: spanContext });\n\n // Get parentSpanId from parent context if available\n const parentSpan = otelTrace.getSpan(parentOtelContext);\n const parentSpanId = parentSpan?.spanContext().spanId;\n\n this.logger.debug(\n `[OtelBridge.createSpan] Created span [spanId=${spanId}] [traceId=${traceId}] ` +\n `[parentSpanId=${parentSpanId}] [type=${options.type}] [mapSize=${this.otelSpanMap.size}]`,\n );\n\n return { spanId, traceId, parentSpanId };\n } catch (error) {\n this.logger.error('[OtelBridge] Failed to create span:', error);\n return undefined;\n }\n }\n\n /**\n * Handle SPAN_ENDED event\n *\n * Retrieves the OTEL span created at SPAN_STARTED, sets all final attributes,\n * events, and status, then ends the span. Cleans up the span map entry.\n */\n private async handleSpanEnded(event: TracingEvent): Promise<void> {\n try {\n const mastraSpan = event.exportedSpan;\n const entry = this.otelSpanMap.get(mastraSpan.id);\n\n if (!entry) {\n this.logger.warn(`[OtelBridge] No OTEL span found for Mastra span [id=${mastraSpan.id}].`);\n return;\n }\n\n // Remove from map immediately to prevent memory leak\n this.otelSpanMap.delete(mastraSpan.id);\n\n const { otelSpan } = entry;\n\n this.logger.debug(`[OtelBridge] Ending OTEL span [mastraId=${mastraSpan.id}] [name=${mastraSpan.name}]`);\n\n // Use SpanConverter to get consistent span formatting with otel-exporter\n const readableSpan = this.spanConverter.convertSpan(mastraSpan);\n\n // Update span name to match the converter's formatting\n otelSpan.updateName(readableSpan.name);\n\n // Set all attributes from the converter (includes OTEL semantic conventions)\n for (const [key, value] of Object.entries(readableSpan.attributes)) {\n if (value !== undefined && value !== null && typeof value !== 'object') {\n otelSpan.setAttribute(key, value);\n }\n }\n\n // Set status from the converter\n otelSpan.setStatus(readableSpan.status);\n\n // Add exception events if present\n for (const event of readableSpan.events) {\n if (event.name === 'exception' && event.attributes) {\n const error = new Error(event.attributes['exception.message'] as string);\n otelSpan.recordException(error);\n }\n }\n\n // End the span with the actual end time\n otelSpan.end(mastraSpan.endTime);\n\n this.logger.debug(\n `[OtelBridge] Completed OTEL span [mastraId=${mastraSpan.id}] [traceId=${otelSpan.spanContext().traceId}]`,\n );\n } catch (error) {\n this.logger.error('[OtelBridge] Failed to handle SPAN_ENDED:', error);\n }\n }\n\n /**\n * Execute a function (sync or async) within the OTEL context of a Mastra span.\n * Retrieves the stored OTEL context for the span and executes the function within it.\n *\n * This is the core implementation used by both executeInContext and executeInContextSync.\n *\n * @param spanId - The ID of the Mastra span to use as context\n * @param fn - The function to execute within the span context\n * @returns The result of the function execution\n */\n private executeWithSpanContext<T>(spanId: string, fn: () => T): T {\n const entry = this.otelSpanMap.get(spanId);\n\n this.logger.debug(\n `[OtelBridge.executeWithSpanContext] spanId=${spanId}, ` +\n `inMap=${!!entry}, ` +\n `storedOtelSpan=${entry?.otelSpan.spanContext().spanId || 'none'}`,\n );\n\n const spanContext = entry?.otelContext;\n if (spanContext) {\n return otelContext.with(spanContext, fn);\n }\n return fn();\n }\n\n /**\n * Execute an async function within the OTEL context of a Mastra span.\n *\n * @param spanId - The ID of the Mastra span to use as context\n * @param fn - The async function to execute within the span context\n * @returns The result of the function execution\n */\n executeInContext<T>(spanId: string, fn: () => Promise<T>): Promise<T> {\n return this.executeWithSpanContext(spanId, fn);\n }\n\n /**\n * Execute a synchronous function within the OTEL context of a Mastra span.\n *\n * @param spanId - The ID of the Mastra span to use as context\n * @param fn - The synchronous function to execute within the span context\n * @returns The result of the function execution\n */\n executeInContextSync<T>(spanId: string, fn: () => T): T {\n return this.executeWithSpanContext(spanId, fn);\n }\n\n /**\n * Shutdown the bridge and clean up resources\n */\n async shutdown(): Promise<void> {\n // End any remaining spans\n for (const [spanId, { otelSpan }] of this.otelSpanMap.entries()) {\n this.logger.warn(`[OtelBridge] Force-ending span that was not properly closed [id=${spanId}]`);\n otelSpan.end();\n }\n this.otelSpanMap.clear();\n this.logger.info('[OtelBridge] Shutdown complete');\n }\n}\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @mastra/otel-bridge
3
+ *
4
+ * OpenTelemetry Bridge for Mastra Observability
5
+ *
6
+ * Enables bidirectional integration with OpenTelemetry infrastructure:
7
+ *
8
+ * **From OTEL to Mastra:**
9
+ * - Reads from OTEL ambient context (AsyncLocalStorage) automatically
10
+ * - Inherits trace ID and parent span ID from active OTEL spans
11
+ * - Extracts W3C trace context from headers when needed
12
+ *
13
+ * **From Mastra to OTEL:**
14
+ * - Creates real OTEL spans for Mastra spans
15
+ * - Maintains proper parent-child relationships in distributed traces
16
+ * - Allows OTEL-instrumented code (HTTP clients, DB calls) to nest under Mastra spans
17
+ */
18
+ export * from './bridge.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,164 @@
1
+ import { TracingEventType } from '@mastra/core/observability';
2
+ import { BaseExporter, getExternalParentId } from '@mastra/observability';
3
+ import { SpanConverter, getSpanKind } from '@mastra/otel-exporter';
4
+ import { trace, context } from '@opentelemetry/api';
5
+
6
+ // src/bridge.ts
7
+ var OtelBridge = class extends BaseExporter {
8
+ name = "otel";
9
+ otelTracer = trace.getTracer("@mastra/otel-bridge", "1.0.0");
10
+ otelSpanMap = /* @__PURE__ */ new Map();
11
+ spanConverter = new SpanConverter();
12
+ constructor(config = {}) {
13
+ super(config);
14
+ }
15
+ /**
16
+ * Handle Mastra tracing events
17
+ *
18
+ * Ships OTEL spans when Mastra spans end.
19
+ * This maintains proper span hierarchy and allows OTEL-instrumented code within
20
+ * Mastra spans to have correct parent-child relationships.
21
+ * Note: OTEL spans are created when registerSpan is called when the span is first created.
22
+ */
23
+ async _exportTracingEvent(event) {
24
+ if (event.type === TracingEventType.SPAN_ENDED) {
25
+ await this.handleSpanEnded(event);
26
+ }
27
+ }
28
+ /**
29
+ * Create a span in the bridge's tracing system.
30
+ * Called during Mastra span construction to get bridge-generated identifiers.
31
+ *
32
+ * @param options - Span creation options from Mastra
33
+ * @returns Span identifiers (spanId, traceId, parentSpanId) from bridge, or undefined if creation fails
34
+ */
35
+ createSpan(options) {
36
+ try {
37
+ let parentOtelContext = context.active();
38
+ const externalParentId = getExternalParentId(options);
39
+ if (externalParentId) {
40
+ const parentEntry = this.otelSpanMap.get(externalParentId);
41
+ if (parentEntry) {
42
+ parentOtelContext = parentEntry.otelContext;
43
+ }
44
+ }
45
+ const isRootSpan = !options.parent;
46
+ const otelSpan = this.otelTracer.startSpan(
47
+ options.name,
48
+ {
49
+ kind: getSpanKind(options.type, isRootSpan)
50
+ },
51
+ parentOtelContext
52
+ );
53
+ const spanContext = trace.setSpan(parentOtelContext, otelSpan);
54
+ const otelSpanContext = otelSpan.spanContext();
55
+ const spanId = otelSpanContext.spanId;
56
+ const traceId = otelSpanContext.traceId;
57
+ this.otelSpanMap.set(spanId, { otelSpan, otelContext: spanContext });
58
+ const parentSpan = trace.getSpan(parentOtelContext);
59
+ const parentSpanId = parentSpan?.spanContext().spanId;
60
+ this.logger.debug(
61
+ `[OtelBridge.createSpan] Created span [spanId=${spanId}] [traceId=${traceId}] [parentSpanId=${parentSpanId}] [type=${options.type}] [mapSize=${this.otelSpanMap.size}]`
62
+ );
63
+ return { spanId, traceId, parentSpanId };
64
+ } catch (error) {
65
+ this.logger.error("[OtelBridge] Failed to create span:", error);
66
+ return void 0;
67
+ }
68
+ }
69
+ /**
70
+ * Handle SPAN_ENDED event
71
+ *
72
+ * Retrieves the OTEL span created at SPAN_STARTED, sets all final attributes,
73
+ * events, and status, then ends the span. Cleans up the span map entry.
74
+ */
75
+ async handleSpanEnded(event) {
76
+ try {
77
+ const mastraSpan = event.exportedSpan;
78
+ const entry = this.otelSpanMap.get(mastraSpan.id);
79
+ if (!entry) {
80
+ this.logger.warn(`[OtelBridge] No OTEL span found for Mastra span [id=${mastraSpan.id}].`);
81
+ return;
82
+ }
83
+ this.otelSpanMap.delete(mastraSpan.id);
84
+ const { otelSpan } = entry;
85
+ this.logger.debug(`[OtelBridge] Ending OTEL span [mastraId=${mastraSpan.id}] [name=${mastraSpan.name}]`);
86
+ const readableSpan = this.spanConverter.convertSpan(mastraSpan);
87
+ otelSpan.updateName(readableSpan.name);
88
+ for (const [key, value] of Object.entries(readableSpan.attributes)) {
89
+ if (value !== void 0 && value !== null && typeof value !== "object") {
90
+ otelSpan.setAttribute(key, value);
91
+ }
92
+ }
93
+ otelSpan.setStatus(readableSpan.status);
94
+ for (const event2 of readableSpan.events) {
95
+ if (event2.name === "exception" && event2.attributes) {
96
+ const error = new Error(event2.attributes["exception.message"]);
97
+ otelSpan.recordException(error);
98
+ }
99
+ }
100
+ otelSpan.end(mastraSpan.endTime);
101
+ this.logger.debug(
102
+ `[OtelBridge] Completed OTEL span [mastraId=${mastraSpan.id}] [traceId=${otelSpan.spanContext().traceId}]`
103
+ );
104
+ } catch (error) {
105
+ this.logger.error("[OtelBridge] Failed to handle SPAN_ENDED:", error);
106
+ }
107
+ }
108
+ /**
109
+ * Execute a function (sync or async) within the OTEL context of a Mastra span.
110
+ * Retrieves the stored OTEL context for the span and executes the function within it.
111
+ *
112
+ * This is the core implementation used by both executeInContext and executeInContextSync.
113
+ *
114
+ * @param spanId - The ID of the Mastra span to use as context
115
+ * @param fn - The function to execute within the span context
116
+ * @returns The result of the function execution
117
+ */
118
+ executeWithSpanContext(spanId, fn) {
119
+ const entry = this.otelSpanMap.get(spanId);
120
+ this.logger.debug(
121
+ `[OtelBridge.executeWithSpanContext] spanId=${spanId}, inMap=${!!entry}, storedOtelSpan=${entry?.otelSpan.spanContext().spanId || "none"}`
122
+ );
123
+ const spanContext = entry?.otelContext;
124
+ if (spanContext) {
125
+ return context.with(spanContext, fn);
126
+ }
127
+ return fn();
128
+ }
129
+ /**
130
+ * Execute an async function within the OTEL context of a Mastra span.
131
+ *
132
+ * @param spanId - The ID of the Mastra span to use as context
133
+ * @param fn - The async function to execute within the span context
134
+ * @returns The result of the function execution
135
+ */
136
+ executeInContext(spanId, fn) {
137
+ return this.executeWithSpanContext(spanId, fn);
138
+ }
139
+ /**
140
+ * Execute a synchronous function within the OTEL context of a Mastra span.
141
+ *
142
+ * @param spanId - The ID of the Mastra span to use as context
143
+ * @param fn - The synchronous function to execute within the span context
144
+ * @returns The result of the function execution
145
+ */
146
+ executeInContextSync(spanId, fn) {
147
+ return this.executeWithSpanContext(spanId, fn);
148
+ }
149
+ /**
150
+ * Shutdown the bridge and clean up resources
151
+ */
152
+ async shutdown() {
153
+ for (const [spanId, { otelSpan }] of this.otelSpanMap.entries()) {
154
+ this.logger.warn(`[OtelBridge] Force-ending span that was not properly closed [id=${spanId}]`);
155
+ otelSpan.end();
156
+ }
157
+ this.otelSpanMap.clear();
158
+ this.logger.info("[OtelBridge] Shutdown complete");
159
+ }
160
+ };
161
+
162
+ export { OtelBridge };
163
+ //# sourceMappingURL=index.js.map
164
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridge.ts"],"names":["otelTrace","otelContext","event"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * OpenTelemetry Bridge for Mastra Observability\n *\n * This bridge enables bidirectional integration with OpenTelemetry infrastructure:\n * 1. Reads OTEL trace context from active spans (via AsyncLocalStorage)\n * 2. Creates real OTEL spans when Mastra spans are created\n * 3. Maintains span context for proper parent-child relationships\n * 4. Allows OTEL-instrumented code (DB, HTTP clients) in tools/workflows to have correct parents\n *\n * This creates complete distributed traces where Mastra spans are properly\n * nested within OTEL spans from auto-instrumentation, and any OTEL-instrumented\n * operations within Mastra spans maintain the correct hierarchy.\n */\n\nimport type {\n ObservabilityBridge,\n TracingEvent,\n CreateSpanOptions,\n SpanType,\n SpanIds,\n} from '@mastra/core/observability';\nimport { TracingEventType } from '@mastra/core/observability';\nimport { BaseExporter, getExternalParentId } from '@mastra/observability';\nimport { SpanConverter, getSpanKind } from '@mastra/otel-exporter';\nimport { trace as otelTrace, context as otelContext } from '@opentelemetry/api';\nimport type { Span as OtelSpan, Context as OtelContext } from '@opentelemetry/api';\n\n/**\n * Configuration for the OtelBridge\n */\n\nexport type OtelBridgeConfig = {\n // Currently no configuration options - placeholder for future options\n};\n\n/**\n * OpenTelemetry Bridge implementation\n *\n * Creates real OTEL spans when Mastra spans are created, maintaining proper\n * context propagation for nested instrumentation.\n *\n * @example\n * ```typescript\n * import { OtelBridge } from '@mastra/otel-bridge';\n * import { Mastra } from '@mastra/core';\n *\n * const mastra = new Mastra({\n * agents: { myAgent },\n * observability: {\n * configs: {\n * default: {\n * serviceName: 'my-service',\n * bridge: new OtelBridge(),\n * }\n * }\n * }\n * });\n * ```\n */\nexport class OtelBridge extends BaseExporter implements ObservabilityBridge {\n name = 'otel';\n private otelTracer = otelTrace.getTracer('@mastra/otel-bridge', '1.0.0');\n private otelSpanMap = new Map<string, { otelSpan: OtelSpan; otelContext: OtelContext }>();\n private spanConverter = new SpanConverter();\n\n constructor(config: OtelBridgeConfig = {}) {\n super(config);\n }\n\n /**\n * Handle Mastra tracing events\n *\n * Ships OTEL spans when Mastra spans end.\n * This maintains proper span hierarchy and allows OTEL-instrumented code within\n * Mastra spans to have correct parent-child relationships.\n * Note: OTEL spans are created when registerSpan is called when the span is first created.\n */\n protected async _exportTracingEvent(event: TracingEvent): Promise<void> {\n if (event.type === TracingEventType.SPAN_ENDED) {\n await this.handleSpanEnded(event);\n }\n }\n\n /**\n * Create a span in the bridge's tracing system.\n * Called during Mastra span construction to get bridge-generated identifiers.\n *\n * @param options - Span creation options from Mastra\n * @returns Span identifiers (spanId, traceId, parentSpanId) from bridge, or undefined if creation fails\n */\n createSpan(options: CreateSpanOptions<SpanType>): SpanIds | undefined {\n try {\n // Determine parent context\n let parentOtelContext = otelContext.active();\n\n // Get external parent ID (walks up chain to find non-internal parent)\n const externalParentId = getExternalParentId(options);\n if (externalParentId) {\n // Look up external parent's OTEL span from map\n const parentEntry = this.otelSpanMap.get(externalParentId);\n if (parentEntry) {\n parentOtelContext = parentEntry.otelContext;\n }\n }\n\n // Create OTEL span with SpanKind (must be set at creation, immutable)\n const isRootSpan = !options.parent;\n const otelSpan = this.otelTracer.startSpan(\n options.name,\n {\n kind: getSpanKind(options.type, isRootSpan),\n },\n parentOtelContext,\n );\n\n // Create context with this span active\n const spanContext = otelTrace.setSpan(parentOtelContext, otelSpan);\n\n // Get OTEL span identifiers\n const otelSpanContext = otelSpan.spanContext();\n const spanId = otelSpanContext.spanId;\n const traceId = otelSpanContext.traceId;\n\n // Store for later retrieval (for executeWithSpanContext and event handling)\n this.otelSpanMap.set(spanId, { otelSpan, otelContext: spanContext });\n\n // Get parentSpanId from parent context if available\n const parentSpan = otelTrace.getSpan(parentOtelContext);\n const parentSpanId = parentSpan?.spanContext().spanId;\n\n this.logger.debug(\n `[OtelBridge.createSpan] Created span [spanId=${spanId}] [traceId=${traceId}] ` +\n `[parentSpanId=${parentSpanId}] [type=${options.type}] [mapSize=${this.otelSpanMap.size}]`,\n );\n\n return { spanId, traceId, parentSpanId };\n } catch (error) {\n this.logger.error('[OtelBridge] Failed to create span:', error);\n return undefined;\n }\n }\n\n /**\n * Handle SPAN_ENDED event\n *\n * Retrieves the OTEL span created at SPAN_STARTED, sets all final attributes,\n * events, and status, then ends the span. Cleans up the span map entry.\n */\n private async handleSpanEnded(event: TracingEvent): Promise<void> {\n try {\n const mastraSpan = event.exportedSpan;\n const entry = this.otelSpanMap.get(mastraSpan.id);\n\n if (!entry) {\n this.logger.warn(`[OtelBridge] No OTEL span found for Mastra span [id=${mastraSpan.id}].`);\n return;\n }\n\n // Remove from map immediately to prevent memory leak\n this.otelSpanMap.delete(mastraSpan.id);\n\n const { otelSpan } = entry;\n\n this.logger.debug(`[OtelBridge] Ending OTEL span [mastraId=${mastraSpan.id}] [name=${mastraSpan.name}]`);\n\n // Use SpanConverter to get consistent span formatting with otel-exporter\n const readableSpan = this.spanConverter.convertSpan(mastraSpan);\n\n // Update span name to match the converter's formatting\n otelSpan.updateName(readableSpan.name);\n\n // Set all attributes from the converter (includes OTEL semantic conventions)\n for (const [key, value] of Object.entries(readableSpan.attributes)) {\n if (value !== undefined && value !== null && typeof value !== 'object') {\n otelSpan.setAttribute(key, value);\n }\n }\n\n // Set status from the converter\n otelSpan.setStatus(readableSpan.status);\n\n // Add exception events if present\n for (const event of readableSpan.events) {\n if (event.name === 'exception' && event.attributes) {\n const error = new Error(event.attributes['exception.message'] as string);\n otelSpan.recordException(error);\n }\n }\n\n // End the span with the actual end time\n otelSpan.end(mastraSpan.endTime);\n\n this.logger.debug(\n `[OtelBridge] Completed OTEL span [mastraId=${mastraSpan.id}] [traceId=${otelSpan.spanContext().traceId}]`,\n );\n } catch (error) {\n this.logger.error('[OtelBridge] Failed to handle SPAN_ENDED:', error);\n }\n }\n\n /**\n * Execute a function (sync or async) within the OTEL context of a Mastra span.\n * Retrieves the stored OTEL context for the span and executes the function within it.\n *\n * This is the core implementation used by both executeInContext and executeInContextSync.\n *\n * @param spanId - The ID of the Mastra span to use as context\n * @param fn - The function to execute within the span context\n * @returns The result of the function execution\n */\n private executeWithSpanContext<T>(spanId: string, fn: () => T): T {\n const entry = this.otelSpanMap.get(spanId);\n\n this.logger.debug(\n `[OtelBridge.executeWithSpanContext] spanId=${spanId}, ` +\n `inMap=${!!entry}, ` +\n `storedOtelSpan=${entry?.otelSpan.spanContext().spanId || 'none'}`,\n );\n\n const spanContext = entry?.otelContext;\n if (spanContext) {\n return otelContext.with(spanContext, fn);\n }\n return fn();\n }\n\n /**\n * Execute an async function within the OTEL context of a Mastra span.\n *\n * @param spanId - The ID of the Mastra span to use as context\n * @param fn - The async function to execute within the span context\n * @returns The result of the function execution\n */\n executeInContext<T>(spanId: string, fn: () => Promise<T>): Promise<T> {\n return this.executeWithSpanContext(spanId, fn);\n }\n\n /**\n * Execute a synchronous function within the OTEL context of a Mastra span.\n *\n * @param spanId - The ID of the Mastra span to use as context\n * @param fn - The synchronous function to execute within the span context\n * @returns The result of the function execution\n */\n executeInContextSync<T>(spanId: string, fn: () => T): T {\n return this.executeWithSpanContext(spanId, fn);\n }\n\n /**\n * Shutdown the bridge and clean up resources\n */\n async shutdown(): Promise<void> {\n // End any remaining spans\n for (const [spanId, { otelSpan }] of this.otelSpanMap.entries()) {\n this.logger.warn(`[OtelBridge] Force-ending span that was not properly closed [id=${spanId}]`);\n otelSpan.end();\n }\n this.otelSpanMap.clear();\n this.logger.info('[OtelBridge] Shutdown complete');\n }\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@mastra/otel-bridge",
3
+ "version": "0.0.0-main-test-2-20251127211532",
4
+ "description": "OpenTelemetry observability bridge for Mastra",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "CHANGELOG.md"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "import": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "require": {
19
+ "types": "./dist/index.d.ts",
20
+ "default": "./dist/index.cjs"
21
+ }
22
+ },
23
+ "./package.json": "./package.json"
24
+ },
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "@opentelemetry/api": "^1.9.0",
28
+ "@mastra/observability": "0.0.0-main-test-2-20251127211532",
29
+ "@mastra/otel-exporter": "0.0.0-main-test-2-20251127211532"
30
+ },
31
+ "devDependencies": {
32
+ "@microsoft/api-extractor": "^7.52.8",
33
+ "@types/node": "^20.19.0",
34
+ "eslint": "^9.37.0",
35
+ "tsup": "^8.5.0",
36
+ "typescript": "^5.8.3",
37
+ "vitest": "^3.2.4",
38
+ "@internal/types-builder": "0.0.0-main-test-2-20251127211532",
39
+ "@internal/lint": "0.0.0-main-test-2-20251127211532",
40
+ "@mastra/core": "0.0.0-main-test-2-20251127211532"
41
+ },
42
+ "peerDependencies": {
43
+ "@opentelemetry/sdk-node": ">=0.50.0",
44
+ "@opentelemetry/auto-instrumentations-node": ">=0.50.0",
45
+ "@mastra/core": "0.0.0-main-test-2-20251127211532"
46
+ },
47
+ "peerDependenciesMeta": {
48
+ "@opentelemetry/sdk-node": {
49
+ "optional": true
50
+ },
51
+ "@opentelemetry/auto-instrumentations-node": {
52
+ "optional": true
53
+ }
54
+ },
55
+ "homepage": "https://mastra.ai",
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "git+https://github.com/mastra-ai/mastra.git",
59
+ "directory": "observability/otel-bridge"
60
+ },
61
+ "bugs": {
62
+ "url": "https://github.com/mastra-ai/mastra/issues"
63
+ },
64
+ "engines": {
65
+ "node": ">=22.13.0"
66
+ },
67
+ "scripts": {
68
+ "build": "tsup --silent --config tsup.config.ts",
69
+ "build:watch": "pnpm build --watch",
70
+ "test": "vitest run",
71
+ "test:watch": "vitest watch",
72
+ "lint": "eslint ."
73
+ }
74
+ }