{"_id":"@asenajs/asena-otel","_rev":"6-fb430978e80ea11cec9f2538d8ebd57f","name":"@asenajs/asena-otel","dist-tags":{"latest":"3.0.0"},"versions":{"1.0.0":{"name":"@asenajs/asena-otel","version":"1.0.0","author":{"name":"LibirSoft"},"license":"MIT","_id":"@asenajs/asena-otel@1.0.0","maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"homepage":"https://github.com/AsenaJs/asena-otel#readme","bugs":{"url":"https://github.com/AsenaJs/asena-otel/issues"},"dist":{"shasum":"97f05ba5cf249ae43bf50a43c01558a4b32e708b","tarball":"https://registry.npmjs.org/@asenajs/asena-otel/-/asena-otel-1.0.0.tgz","fileCount":36,"integrity":"sha512-zRIhwbyNQ/Hy5Daku4HnC28yystKUMnfPo2Rm52HGbkhdqquy3renTrAawuroTK/YAPYTjPC422B8AafGd+PpA==","signatures":[{"sig":"MEQCIBrIEorpDMJnDgwSMjqMphgt2rrcoqtwtXwO479WcQFEAiAoCsEa8zvEyfqnd24TnrfH24rvsggGwsH1iaUEVEYBEQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":48816},"main":"dist/index.js","types":"dist/index.d.ts","module":"index.ts","gitHead":"e508e9ee65f50e4cede32c4b8108be491485bf93","scripts":{"test":"bun test","build":"bun run clean && tsc","clean":"rm -rf dist","release":"bun run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"bun test --watch","test:coverage":"bun test --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"libir","email":"libirsoft@gmail.com"},"repository":{"url":"git+https://github.com/AsenaJs/asena-otel.git","type":"git"},"_npmVersion":"11.12.1","description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","directories":{},"_nodeVersion":"25.9.0","dependencies":{"@opentelemetry/context-async-hooks":"^2.6.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^8.57.1","prettier":"^3.8.2","@types/bun":"latest","@asenajs/asena":"^0.7.1","@changesets/cli":"^2.30.0","eslint-plugin-n":"^16.6.2","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.1","eslint-config-alloy":"^5.1.2","eslint-plugin-alloy":"^1.2.1","eslint-plugin-import":"^2.32.0","eslint-plugin-promise":"^6.6.0","eslint-config-prettier":"^9.1.2","eslint-plugin-prettier":"^5.5.5","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-metrics":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@typescript-eslint/eslint-plugin":"^6.21.0","@opentelemetry/semantic-conventions":"^1.40.0"},"peerDependencies":{"typescript":"^5.9.3","@asenajs/asena":"^0.7.0","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.6.0","@opentelemetry/sdk-metrics":"^2.6.0","@opentelemetry/sdk-trace-base":"^2.6.0","@opentelemetry/context-async-hooks":"^2.6.0","@opentelemetry/semantic-conventions":"^1.40.0"},"_npmOperationalInternal":{"tmp":"tmp/asena-otel_1.0.0_1775941891526_0.39102345948030925","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@asenajs/asena-otel","version":"1.0.1","author":"LibirSoft","license":"MIT","_id":"@asenajs/asena-otel@1.0.1","maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"dist":{"shasum":"ec1dc65c3bbd10b1f69b6b3912e9e36efe0d476c","tarball":"https://registry.npmjs.org/@asenajs/asena-otel/-/asena-otel-1.0.1.tgz","fileCount":36,"integrity":"sha512-KNwmslhp2WLuIAMvEVG4ZIXb4JuLOQeXkSmpBrYknf2NnZk7Zr4nH5cJZJJhF7kFYY229wegCUbyaaApneHWlg==","signatures":[{"sig":"MEQCIHR1jjy/gVKS1n6RKjFCB7NJNHSa8v0rTH74ddNS44awAiATygkhi8HqOuPxqBQdfy8aTtdKKStEoDJy4o5TL15Byw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":50642},"main":"dist/index.js","types":"dist/index.d.ts","module":"index.ts","shasum":"ec1dc65c3bbd10b1f69b6b3912e9e36efe0d476c","scripts":{"test":"bun test","build":"bun run clean && tsc","clean":"rm -rf dist","release":"bun run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"bun test --watch","test:coverage":"bun test --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"libir","email":"libirsoft@gmail.com"},"_integrity":"sha512-KNwmslhp2WLuIAMvEVG4ZIXb4JuLOQeXkSmpBrYknf2NnZk7Zr4nH5cJZJJhF7kFYY229wegCUbyaaApneHWlg==","repository":{"url":"https://github.com/AsenaJs/asena-otel.git","type":"git"},"_npmVersion":"10.8.3","description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","directories":{},"_nodeVersion":"24.3.0","dependencies":{"@opentelemetry/context-async-hooks":"^2.6.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^8.57.1","prettier":"^3.8.2","@types/bun":"latest","@asenajs/asena":"^0.7.1","@changesets/cli":"^2.30.0","eslint-plugin-n":"^16.6.2","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.1","eslint-config-alloy":"^5.1.2","eslint-plugin-alloy":"^1.2.1","eslint-plugin-import":"^2.32.0","eslint-plugin-promise":"^6.6.0","eslint-config-prettier":"^9.1.2","eslint-plugin-prettier":"^5.5.5","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-metrics":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@typescript-eslint/eslint-plugin":"^6.21.0","@opentelemetry/semantic-conventions":"^1.40.0"},"peerDependencies":{"typescript":"^5.9.3","@asenajs/asena":"^0.7.0","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.6.0","@opentelemetry/sdk-metrics":"^2.6.0","@opentelemetry/sdk-trace-base":"^2.6.0","@opentelemetry/context-async-hooks":"^2.6.0","@opentelemetry/semantic-conventions":"^1.40.0"},"_npmOperationalInternal":{"tmp":"tmp/asena-otel_1.0.1_1783891642152_0.5765609154040292","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@asenajs/asena-otel","version":"1.1.0","author":{"name":"LibirSoft"},"license":"MIT","_id":"@asenajs/asena-otel@1.1.0","maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"homepage":"https://github.com/AsenaJs/asena-otel#readme","bugs":{"url":"https://github.com/AsenaJs/asena-otel/issues"},"dist":{"shasum":"1b0bf0eee8faca783d4bb28f7c814ecb1dc62a7a","tarball":"https://registry.npmjs.org/@asenajs/asena-otel/-/asena-otel-1.1.0.tgz","fileCount":39,"integrity":"sha512-ghIOe3cfnTONkLqj5dsM1BZdrINPInsrrkve9gTXL5BSoXJcA0I9vd97ByClNwce/VNxQJo+Nv71WpYojIcdxw==","signatures":[{"sig":"MEUCIBIjDX/7Z+doUPQ5KagE+XkPJiFOpevFAfqJMgiM7A0wAiEA6+PkozB9pvKUc1h+Gc1IxvEO6ZyYwVHY/ax3rtqcbhc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":58541},"main":"dist/index.js","types":"dist/index.d.ts","module":"index.ts","gitHead":"692bc34c17bf5ae738cbb37887f5ec15daa51f21","scripts":{"test":"bun test","build":"bun run clean && tsc","clean":"rm -rf dist","release":"bun run build && changeset publish","version":"changeset version","changeset":"changeset","test:watch":"bun test --watch","test:coverage":"bun test --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"libir","email":"libirsoft@gmail.com"},"repository":{"url":"git+https://github.com/AsenaJs/asena-otel.git","type":"git"},"_npmVersion":"12.0.1","description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","directories":{},"_nodeVersion":"26.5.0","dependencies":{"@opentelemetry/context-async-hooks":"^2.6.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^8.57.1","prettier":"^3.8.2","@types/bun":"latest","@asenajs/asena":"^0.8.0","@changesets/cli":"^2.30.0","eslint-plugin-n":"^16.6.2","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.1","eslint-config-alloy":"^5.1.2","eslint-plugin-alloy":"^1.2.1","eslint-plugin-import":"^2.32.0","eslint-plugin-promise":"^6.6.0","eslint-config-prettier":"^9.1.2","eslint-plugin-prettier":"^5.5.5","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-metrics":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@typescript-eslint/eslint-plugin":"^6.21.0","@opentelemetry/semantic-conventions":"^1.40.0"},"peerDependencies":{"typescript":"^5.9.3","@asenajs/asena":"^0.8.0","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.6.0","@opentelemetry/sdk-metrics":"^2.6.0","@opentelemetry/sdk-trace-base":"^2.6.0","@opentelemetry/context-async-hooks":"^2.6.0","@opentelemetry/semantic-conventions":"^1.40.0"},"_npmOperationalInternal":{"tmp":"tmp/asena-otel_1.1.0_1785008287743_0.8696713246755492","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@asenajs/asena-otel","version":"1.2.0","author":{"name":"LibirSoft"},"license":"MIT","_id":"@asenajs/asena-otel@1.2.0","maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"homepage":"https://github.com/AsenaJs/asena-otel#readme","bugs":{"url":"https://github.com/AsenaJs/asena-otel/issues"},"dist":{"shasum":"48433929a1b65a902a7d46110de83272c86e32d3","tarball":"https://registry.npmjs.org/@asenajs/asena-otel/-/asena-otel-1.2.0.tgz","fileCount":39,"integrity":"sha512-sQ+N35szJNokiNnMwCNMYLPqixLFzf25nV81u/2YiDO/Bs0bcMF4pLasbH+tDczu0uAgSL93g3j2kllmoxKk1w==","signatures":[{"sig":"MEYCIQCZbJyvAGBgM8XU3j6CNzMutSpnE09bRBLaKsGRKB2wiQIhALX2Vq0JEH5mpptwNxwf09roAYh/vUbEDPccoVDxYPNC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":59826},"main":"dist/index.js","types":"dist/index.d.ts","module":"index.ts","engines":{"bun":">=1.3.12"},"gitHead":"f87a62485599d65ce88c0af55094ad0ff50c6c86","scripts":{"lint":"eslint . --ext .ts","test":"bun test","build":"bun run clean && tsc","check":"bun run lint && bun run format:check","clean":"rm -rf dist","format":"prettier --write .","release":"bun run build && changeset publish","version":"changeset version","lint:fix":"eslint . --ext .ts --fix","changeset":"changeset","check:fix":"bun run lint:fix && bun run format","typecheck":"tsc -p tsconfig.typecheck.json","test:watch":"bun test --watch","format:check":"prettier --check .","test:coverage":"bun test --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"libir","email":"libirsoft@gmail.com"},"repository":{"url":"git+https://github.com/AsenaJs/asena-otel.git","type":"git"},"_npmVersion":"12.0.1","description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","directories":{},"_nodeVersion":"26.5.0","dependencies":{"@opentelemetry/context-async-hooks":"^2.6.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^8.57.1","prettier":"^3.8.2","@types/bun":"latest","@asenajs/asena":"^0.9.0","@changesets/cli":"^2.30.0","eslint-plugin-n":"^16.6.2","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.1","eslint-config-alloy":"^5.1.2","eslint-plugin-alloy":"^1.2.1","eslint-plugin-import":"^2.32.0","eslint-plugin-promise":"^6.6.0","eslint-config-prettier":"^9.1.2","eslint-plugin-prettier":"^5.5.5","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-metrics":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@typescript-eslint/eslint-plugin":"^6.21.0","@opentelemetry/semantic-conventions":"^1.40.0"},"peerDependencies":{"typescript":"^5.9.3","@asenajs/asena":"^0.9.0","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.6.0","@opentelemetry/sdk-metrics":"^2.6.0","@opentelemetry/sdk-trace-base":"^2.6.0","@opentelemetry/context-async-hooks":"^2.6.0","@opentelemetry/semantic-conventions":"^1.40.0"},"_npmOperationalInternal":{"tmp":"tmp/asena-otel_1.2.0_1785197360967_0.7880887289332521","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@asenajs/asena-otel","version":"2.0.0","author":{"name":"LibirSoft"},"license":"MIT","_id":"@asenajs/asena-otel@2.0.0","maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"homepage":"https://github.com/AsenaJs/asena-otel#readme","bugs":{"url":"https://github.com/AsenaJs/asena-otel/issues"},"dist":{"shasum":"43b008e0ec13c211482fd1f9077ce657a0601cc1","tarball":"https://registry.npmjs.org/@asenajs/asena-otel/-/asena-otel-2.0.0.tgz","fileCount":39,"integrity":"sha512-Gr1M43dryDkdGkdNwSNS0d2MVREaf0vq3GqJHPv7YyNh27fFi1d7iaASqPnTk9yEskUHotxsnQX51l3u8MWRdA==","signatures":[{"sig":"MEQCIAQylne5kDUoA6yiyrqjff9oo/GaNVxsdZCoYQobAU3GAiAobHX1NZbmu//JBS9nWypLVb4zmPXCoNRRWbidW/2Ytg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":65686},"main":"dist/index.js","types":"dist/index.d.ts","module":"index.ts","engines":{"bun":">=1.3.12"},"gitHead":"7bd9aed1ad8cf891a1d67d2d20de7541b91f7b2b","scripts":{"lint":"eslint . --ext .ts","test":"bun test","build":"bun run clean && tsc","check":"bun run lint && bun run format:check","clean":"rm -rf dist","format":"prettier --write .","release":"bun run build && changeset publish","version":"changeset version","lint:fix":"eslint . --ext .ts --fix","changeset":"changeset","check:fix":"bun run lint:fix && bun run format","typecheck":"tsc -p tsconfig.typecheck.json","test:watch":"bun test --watch","format:check":"prettier --check .","test:coverage":"bun test --coverage","prepublishOnly":"bun run build"},"_npmUser":{"name":"libir","email":"libirsoft@gmail.com"},"repository":{"url":"git+https://github.com/AsenaJs/asena-otel.git","type":"git"},"_npmVersion":"12.0.1","description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","directories":{},"_nodeVersion":"26.5.0","dependencies":{"@opentelemetry/context-async-hooks":"^2.6.1"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^8.57.1","prettier":"^3.8.2","@types/bun":"latest","@asenajs/asena":"^0.10.0","@changesets/cli":"^2.30.0","eslint-plugin-n":"^16.6.2","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.1","eslint-config-alloy":"^5.1.2","eslint-plugin-alloy":"^1.2.1","eslint-plugin-import":"^2.32.0","eslint-plugin-promise":"^6.6.0","eslint-config-prettier":"^9.1.2","eslint-plugin-prettier":"^5.5.5","@opentelemetry/resources":"^2.6.1","@opentelemetry/sdk-metrics":"^2.6.1","@opentelemetry/sdk-trace-base":"^2.6.1","@typescript-eslint/eslint-plugin":"^6.21.0","@opentelemetry/semantic-conventions":"^1.40.0"},"peerDependencies":{"typescript":"^5.9.3","@asenajs/asena":"^0.10.0","reflect-metadata":"^0.2.2","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.6.0","@opentelemetry/sdk-metrics":"^2.6.0","@opentelemetry/sdk-trace-base":"^2.6.0","@opentelemetry/context-async-hooks":"^2.6.0","@opentelemetry/semantic-conventions":"^1.40.0"},"_npmOperationalInternal":{"tmp":"tmp/asena-otel_2.0.0_1785360855812_0.5064067141228268","host":"s3://npm-registry-packages-npm-production"}},"3.0.0":{"name":"@asenajs/asena-otel","version":"3.0.0","author":{"name":"LibirSoft"},"description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","main":"dist/index.js","module":"index.ts","types":"dist/index.d.ts","license":"MIT","engines":{"bun":">=1.4.0"},"repository":{"type":"git","url":"git+https://github.com/AsenaJs/asena-otel.git"},"scripts":{"test":"bun test","test:watch":"bun test --watch","test:coverage":"bun test --coverage","build":"bun run clean && tsc","typecheck":"tsc -p tsconfig.typecheck.json","clean":"rm -rf dist","prepublishOnly":"bun run build","changeset":"changeset","version":"changeset version","release":"bun run build && changeset publish","lint":"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix","format":"prettier --write .","format:check":"prettier --check .","check":"bun run lint && bun run format:check","check:fix":"bun run lint:fix && bun run format"},"devDependencies":{"@asenajs/asena":"^0.11.0","@changesets/cli":"^2.31.1","@opentelemetry/api":"^1.9.1","@opentelemetry/resources":"^2.10.0","@opentelemetry/sdk-metrics":"^2.10.0","@opentelemetry/sdk-trace-base":"^2.10.0","@opentelemetry/semantic-conventions":"^1.43.0","@types/bun":"latest","@typescript-eslint/eslint-plugin":"^6.21.0","eslint":"^8.57.1","eslint-config-alloy":"^5.1.2","eslint-config-prettier":"^9.1.2","eslint-plugin-alloy":"^1.2.1","eslint-plugin-import":"^2.32.0","eslint-plugin-n":"^16.6.2","eslint-plugin-prettier":"^5.5.6","eslint-plugin-promise":"^6.6.0","prettier":"^3.9.6","reflect-metadata":"^0.2.2"},"peerDependencies":{"@asenajs/asena":"^0.11.0","@opentelemetry/api":"^1.9.0","@opentelemetry/resources":"^2.6.0","@opentelemetry/sdk-metrics":"^2.6.0","@opentelemetry/sdk-trace-base":"^2.6.0","@opentelemetry/semantic-conventions":"^1.40.0","@opentelemetry/context-async-hooks":"^2.6.0","reflect-metadata":"^0.2.2","typescript":"^5.9.3"},"dependencies":{"@opentelemetry/context-async-hooks":"^2.10.0"},"gitHead":"8941a8d73fbd4ba86842b0b2ccea2bd1a3134fec","_id":"@asenajs/asena-otel@3.0.0","bugs":{"url":"https://github.com/AsenaJs/asena-otel/issues"},"homepage":"https://github.com/AsenaJs/asena-otel#readme","_nodeVersion":"26.7.0","_npmVersion":"12.0.2","dist":{"integrity":"sha512-6AyQgRXJk7z0Sm5VttDwPmiY+DmX5n/fwVxQOEJpiwG3tFxcVHsNABxh166vptMaypp2iJcXYRBDkFMRRQxfUg==","shasum":"e17f33b78a5d4b2da417929b7fbe8f23c7c93ce2","tarball":"https://registry.npmjs.org/@asenajs/asena-otel/-/asena-otel-3.0.0.tgz","fileCount":39,"unpackedSize":67730,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBP4v3rdHnOD8Ox7XXZjgBvFGIFvMe3pxJJTy2Fl07VLAiEAo/6ObV0ux4pEE5BEj0b9TTb5LnIMEemO8uDT19UWXv8="}]},"_npmUser":{"name":"libir","email":"libirsoft@gmail.com"},"directories":{},"maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/asena-otel_3.0.0_1787695453271_0.7458361931327147"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-11T21:11:31.363Z","modified":"2026-08-25T22:04:13.587Z","1.0.0":"2026-04-11T21:11:31.693Z","1.0.1":"2026-07-12T21:27:22.308Z","1.1.0":"2026-07-25T19:38:07.876Z","1.2.0":"2026-07-28T00:09:21.092Z","2.0.0":"2026-07-29T21:34:15.958Z","3.0.0":"2026-08-25T22:04:13.409Z"},"bugs":{"url":"https://github.com/AsenaJs/asena-otel/issues"},"author":{"name":"LibirSoft"},"license":"MIT","homepage":"https://github.com/AsenaJs/asena-otel#readme","repository":{"type":"git","url":"git+https://github.com/AsenaJs/asena-otel.git"},"description":"OpenTelemetry integration for AsenaJS - auto-tracing, HTTP metrics, distributed tracing","maintainers":[{"name":"libir","email":"libirsoft@gmail.com"}],"readme":"# @asenajs/asena-otel\n\n[![Version](https://img.shields.io/badge/version-3.0.0-blue.svg)](https://github.com/AsenaJs/asena-otel)\n[![Bun Version](https://img.shields.io/badge/Bun-1.4%2B-blueviolet)](https://bun.sh)\n\nOpenTelemetry integration for AsenaJS — automatic HTTP tracing, method-level auto-tracing, metrics, and distributed tracing support.\n\nA single request automatically produces a full waterfall trace:\n\n```\nGET /api/users (SERVER)\n  └─ UserController.list (INTERNAL)\n       └─ UserService.getAll (INTERNAL)\n```\n\n## Requirements\n\n- [Bun](https://bun.sh) v1.4 or higher\n- [@asenajs/asena](https://github.com/AsenaJs/Asena) v0.11.0 or higher\n\n## Installation\n\n```bash\nbun add @asenajs/asena-otel @opentelemetry/api @opentelemetry/resources @opentelemetry/sdk-trace-base @opentelemetry/sdk-metrics @opentelemetry/semantic-conventions @opentelemetry/context-async-hooks\n```\n\n## Quick Start\n\n### Step 1: Create an @Otel class\n\nCreate a class that extends `OtelTracingPostProcessor` and apply the `@Otel` decorator with your configuration. Asena automatically discovers and initializes it during bootstrap.\n\n```typescript\n// src/otel/AppOtel.ts\nimport { Otel, OtelTracingPostProcessor } from '@asenajs/asena-otel';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';\n\n@Otel({\n  serviceName: 'my-app',\n  serviceVersion: '1.0.0',\n  traceExporter: new OTLPTraceExporter({\n    url: 'http://localhost:4318/v1/traces',\n  }),\n  metricReader: new PeriodicExportingMetricReader({\n    exporter: new OTLPMetricExporter({\n      url: 'http://localhost:4318/v1/metrics',\n    }),\n  }),\n  autoTrace: {\n    services: true,     // auto-trace @Service methods\n    controllers: true,  // auto-trace @Controller methods\n  },\n})\nexport class AppOtel extends OtelTracingPostProcessor {}\n```\n\n### Step 2: Create a Local Middleware Class\n\nCreate a class in your `src` folder that extends `OtelTracingMiddleware` and apply the `@Middleware()` decorator. This registers the middleware in Asena's IoC container.\n\n```typescript\n// src/middlewares/AppOtelMiddleware.ts\nimport { Middleware } from '@asenajs/asena/decorators';\nimport { OtelTracingMiddleware } from '@asenajs/asena-otel';\n\n@Middleware()\nexport class AppOtelMiddleware extends OtelTracingMiddleware {}\n```\n\n> **Important:** Asena's IoC container only scans the `src` folder defined in your `asena.config.ts`. Since `OtelTracingMiddleware` lives in `node_modules`, the container cannot discover it automatically. You **must** create a local class extending it with `@Middleware()` so that Asena can register and use it.\n\n### Step 3: Register the Middleware in your Config\n\nAdd `AppOtelMiddleware` to your config's `globalMiddlewares()`. This is required so that all HTTP requests are traced automatically.\n\n```typescript\nimport { Config } from '@asenajs/asena/decorators';\nimport { ConfigService, type Context, HttpException } from '@asenajs/ergenecore';\nimport { AppOtelMiddleware } from '../middlewares/AppOtelMiddleware';\nimport { AppCorsMiddleware } from '../middlewares/AppCorsMiddleware';\n\n@Config()\nexport class AppConfig extends ConfigService {\n\n  public globalMiddlewares() {\n    return [\n      AppOtelMiddleware,  // traces all HTTP requests automatically\n      AppCorsMiddleware,\n    ];\n  }\n\n  public onError(error: Error, context: Context) {\n    if (error instanceof HttpException) {\n      return context.send(error.body, error.status);\n    }\n    return context.send({ error: 'Internal Server Error' }, 500);\n  }\n\n}\n```\n\nThat's it. The scan picks up `AppOtel` and `AppOtelMiddleware`. `OtelService` ships inside the package, where the scan never looks — if you inject it, hand it in with `imports: [OtelService]` on `AsenaServerFactory.create` (see [asena.sh/docs/packages/opentelemetry](https://asena.sh/docs/packages/opentelemetry)). All HTTP requests are traced, service methods are auto-traced, and metrics are collected — without changing any business logic.\n\n## Components\n\n### @Otel Decorator\n\nConfigures an `OtelTracingPostProcessor` subclass with OpenTelemetry options. Apply it to a class extending `OtelTracingPostProcessor`:\n\n```typescript\nimport { Otel, OtelTracingPostProcessor } from '@asenajs/asena-otel';\n\n@Otel({\n  serviceName: 'my-app',\n  traceExporter: exporter,\n  autoTrace: { services: true, controllers: true },\n})\nexport class AppOtel extends OtelTracingPostProcessor {}\n```\n\nThe decorator stores the options as metadata and applies `@PostProcessor()` automatically. During bootstrap, `@OnStart()` in `OtelTracingPostProcessor` reads the metadata and initializes the OpenTelemetry SDK — tracer provider, meter provider and context manager. The matching `@OnStop()` hook runs from `server.stop()`: it flushes the buffered spans and metrics, stops the exporter timers and unhooks the context manager. A step that fails is logged and the remaining ones still run, so an unreachable collector cannot fail your shutdown.\n\n### OtelService\n\nInjectable `@Service` that provides access to OpenTelemetry tracer and meter. Use it for custom spans and distributed tracing. It lives in `node_modules`, so register it through `imports` before injecting it.\n\n```typescript\nimport { Inject } from '@asenajs/asena/decorators/ioc';\nimport type { OtelService } from '@asenajs/asena-otel';\n\n@Service()\nexport class OrderService {\n\n  @Inject('OtelService')\n  private otelService: OtelService;\n\n  async processOrder(orderId: string) {\n    return this.otelService.withSpan('process-order', async (span) => {\n      span.setAttribute('order.id', orderId);\n      // ... business logic\n      return { success: true };\n    });\n    // span automatically ends, errors are recorded\n  }\n\n}\n```\n\n**API:**\n- `tracer` — OpenTelemetry `Tracer` instance\n- `meter` — OpenTelemetry `Meter` instance\n- `withSpan(name, fn)` — creates a span, sets OK/ERROR status, records exceptions, ends span automatically\n- `getActiveSpan()` — returns current active span (or undefined)\n- `injectTraceContext(headers?)` — injects W3C `traceparent` header into a headers object for distributed tracing (see [Outgoing Request Context Propagation](#outgoing-request-context-propagation))\n\n**Expression injection** (for direct tracer/meter access):\n```typescript\n@Inject('OtelService', (s) => s.tracer)\nprivate tracer: Tracer;\n\n@Inject('OtelService', (s) => s.meter)\nprivate meter: Meter;\n```\n\n### OtelTracingMiddleware\n\n`@Middleware` that automatically traces all HTTP requests. Register in your Config's `globalMiddlewares()` to enable request tracing.\n\n**Creates for each request:**\n- A `SERVER` span named `\"{METHOD} {PATH}\"` (e.g., `GET /api/users`)\n- **Span attributes** (high-cardinality safe): `http.request.method`, `url.path`, `http.route` (after route matching), `http.response.status_code`\n- **Metric attributes** (low-cardinality only): `http.request.method`, `http.route` (or `'unmatched'` for unmatched routes), `http.response.status_code`\n- Metrics: `http.server.request.count` (Counter), `http.server.request.duration` (Histogram)\n- Extracts W3C `traceparent` header from incoming requests for distributed tracing\n\n> **Note on cardinality:** `url.path` is intentionally excluded from metric attributes — raw paths from scanner/bot traffic would otherwise create unbounded metric series. A `View` with `createAllowListAttributesProcessor` is also configured on `http.server.*` instruments as defense-in-depth.\n\n### OtelTracingPostProcessor\n\n`@PostProcessor` that wraps Service and Controller methods with tracing spans via JavaScript Proxy.\n\n- Creates `INTERNAL` spans named `\"{ClassName}.{methodName}\"` (e.g., `UserService.getAll`)\n- Spans are automatically children of the HTTP span (proper waterfall hierarchy)\n- Controlled via `autoTrace` config in the `@Otel` decorator options\n- Skips private methods (`_` prefix), constructors, and Symbol properties\n\n## Configuration\n\n### AsenaOtelOptions\n\n```typescript\ninterface AsenaOtelOptions {\n  serviceName: string;           // Required: identifies your service\n  serviceVersion?: string;       // Optional: defaults to '0.0.0'\n  traceExporter: SpanExporter;   // Required: where to send spans\n  metricReader?: MetricReader;   // Optional: enables metrics collection\n  autoTrace?: AutoTraceConfig;   // Optional: auto-trace settings\n  sampler?: Sampler;             // Optional: custom sampling strategy\n  ignoreRoutes?: string[];       // Optional: routes to exclude from tracing\n}\n\ninterface AutoTraceConfig {\n  services?: boolean;     // auto-trace @Service methods (default: false)\n  controllers?: boolean;  // auto-trace @Controller methods (default: false)\n}\n```\n\n## Sampling\n\nUse `ratioBasedSampler()` for production environments to control trace volume:\n\n```typescript\nimport { Otel, OtelTracingPostProcessor, ratioBasedSampler } from '@asenajs/asena-otel';\n\n@Otel({\n  serviceName: 'my-app',\n  traceExporter: exporter,\n  sampler: ratioBasedSampler(0.1),  // sample 10% of traces\n  autoTrace: { services: true, controllers: true },\n})\nexport class AppOtel extends OtelTracingPostProcessor {}\n```\n\n`ratioBasedSampler(ratio)` creates a `ParentBasedSampler` wrapping `TraceIdRatioBasedSampler`. Root spans are sampled at the given ratio (0.0–1.0); child spans respect the parent's decision.\n\n## Route Exclusion\n\nUse `ignoreRoutes` to skip tracing on specific paths (e.g., health checks, metrics endpoints):\n\n```typescript\n@Otel({\n  serviceName: 'my-app',\n  traceExporter: exporter,\n  ignoreRoutes: ['/health', '/metrics', '/admin/*'],\n})\nexport class AppOtel extends OtelTracingPostProcessor {}\n```\n\n- **Exact match:** `/health` matches only `/health`\n- **Wildcard suffix:** `/admin/*` matches `/admin/` and all sub-paths\n\nIgnored routes produce no spans and no metrics.\n\n## Outgoing Request Context Propagation\n\n`@asenajs/asena-otel` automatically traces **incoming** HTTP requests via `OtelTracingMiddleware` (extracts W3C `traceparent` header). However, **outgoing** HTTP calls (e.g., `fetch` to another service) are **not** automatically instrumented.\n\nUse `OtelService.injectTraceContext()` to manually propagate trace context to downstream services:\n\n```typescript\n@Service()\nexport class PaymentClient {\n\n  @Inject('OtelService')\n  private otelService: OtelService;\n\n  async charge(payload: ChargeRequest) {\n    // injectTraceContext() adds the W3C traceparent header\n    const headers = this.otelService.injectTraceContext({\n      'Content-Type': 'application/json',\n    });\n\n    const res = await fetch('http://payment-service/api/charge', {\n      method: 'POST',\n      headers,\n      body: JSON.stringify(payload),\n    });\n\n    return res.json();\n  }\n\n}\n```\n\nFor full visibility, combine with `withSpan()` to create a dedicated span for the outgoing call:\n\n```typescript\nasync charge(payload: ChargeRequest) {\n  return this.otelService.withSpan('call-payment-service', async (span) => {\n    span.setAttribute('service.target', 'payment-service');\n\n    const headers = this.otelService.injectTraceContext();\n    const res = await fetch('http://payment-service/api/charge', {\n      method: 'POST',\n      headers: { ...headers, 'Content-Type': 'application/json' },\n      body: JSON.stringify(payload),\n    });\n\n    return res.json();\n  });\n}\n```\n\nThis writes a `traceparent` header in the format `00-{traceId}-{spanId}-{traceFlags}`. The downstream service extracts this header to continue the same trace, enabling end-to-end distributed tracing across microservices.\n\n## Testing\n\nUse `InMemorySpanExporter` and `InMemoryMetricExporter` for testing:\n\n```typescript\nimport { Otel, OtelTracingPostProcessor } from '@asenajs/asena-otel';\nimport { InMemorySpanExporter } from '@opentelemetry/sdk-trace-base';\nimport { InMemoryMetricExporter, PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';\n\nconst spanExporter = new InMemorySpanExporter();\nconst metricExporter = new InMemoryMetricExporter();\nconst metricReader = new PeriodicExportingMetricReader({\n  exporter: metricExporter,\n  exportIntervalMillis: 100,\n});\n\n@Otel({\n  serviceName: 'test-service',\n  traceExporter: spanExporter,\n  metricReader,\n  autoTrace: { services: true, controllers: true },\n})\nexport class TestOtel extends OtelTracingPostProcessor {}\n```\n\nAfter making requests, flush spans (`BatchSpanProcessor` is lazy):\n\n```typescript\nimport { trace } from '@opentelemetry/api';\n\nconst provider = trace.getTracerProvider() as any;\nawait provider.forceFlush?.();\nconst spans = spanExporter.getFinishedSpans();\n```\n\nFor metrics, wait for periodic export then read from exporter:\n\n```typescript\nawait metricReader.forceFlush();\nconst metrics = metricExporter.getMetrics();\n```\n\n### Verifying parent-child hierarchy\n\nIn OpenTelemetry SDK v2, use `parentSpanContext` (not `parentSpanId`):\n\n```typescript\nconst httpSpan = spans.find(s => s.kind === SpanKind.SERVER);\nconst serviceSpan = spans.find(s => s.name.includes('UserService'));\n\n// Same trace\nexpect(serviceSpan.spanContext().traceId).toBe(httpSpan.spanContext().traceId);\n\n// Parent-child link (SDK v2)\nexpect(serviceSpan.parentSpanContext?.spanId).toBe(httpSpan.spanContext().spanId);\n```\n\n## License\n\nMIT","readmeFilename":"README.md"}