@bluealba/opentelemetry-tracer 1.0.4-develop-1171
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/.turbo/turbo-build.log +4 -0
- package/.turbo/turbo-test.log +24 -0
- package/CHANGELOG.md +186 -0
- package/LICENSE +134 -0
- package/README.md +55 -0
- package/__tests__/tracing.test.ts +77 -0
- package/__tests__/with-tracing.test.ts +41 -0
- package/bluealba-opentelemetry-tracer-1.0.4-develop-1171.tgz +0 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/tracing.d.ts +65 -0
- package/dist/tracing.js +132 -0
- package/dist/with-tracing.d.ts +19 -0
- package/dist/with-tracing.js +41 -0
- package/jest.config.js +6 -0
- package/package.json +15 -0
- package/src/index.ts +2 -0
- package/src/tracing.ts +122 -0
- package/src/with-tracing.ts +44 -0
- package/tsconfig.json +12 -0
- package/version.json +1 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
> @bluealba/opentelemetry-tracer@1.0.4-develop-1171 test
|
|
3
|
+
> jest --detectOpenHandles --forceExit
|
|
4
|
+
|
|
5
|
+
PASS __tests__/tracing.test.ts
|
|
6
|
+
● Console
|
|
7
|
+
|
|
8
|
+
console.log
|
|
9
|
+
[Tracing] Disabled
|
|
10
|
+
|
|
11
|
+
at Object.log (src/tracing.ts:54:33)
|
|
12
|
+
|
|
13
|
+
console.log
|
|
14
|
+
[Tracing] Enabled: Publishing traces to http://localhost:4318/v1/traces with service test-service
|
|
15
|
+
|
|
16
|
+
at Object.log (src/tracing.ts:54:33)
|
|
17
|
+
|
|
18
|
+
PASS __tests__/with-tracing.test.ts
|
|
19
|
+
|
|
20
|
+
Test Suites: 2 passed, 2 total
|
|
21
|
+
Tests: 4 passed, 4 total
|
|
22
|
+
Snapshots: 0 total
|
|
23
|
+
Time: 4.694 s
|
|
24
|
+
Ran all test suites.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# @bluealba-public/opentelemetry-tracer
|
|
2
|
+
|
|
3
|
+
## 1.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Root dependency changes:
|
|
8
|
+
|
|
9
|
+
## devDependencies
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Added @faker-js/faker@9.2.0
|
|
14
|
+
- Added autocannon@^8.0.0
|
|
15
|
+
|
|
16
|
+
- Root dependency changes:
|
|
17
|
+
|
|
18
|
+
## devDependencies
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Added @faker-js/faker@9.2.0
|
|
23
|
+
- Added autocannon@^8.0.0
|
|
24
|
+
|
|
25
|
+
## 1.0.3
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- Root dependency changes:
|
|
30
|
+
|
|
31
|
+
## dependencies
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- Added pino-nestjs@^0.1.3
|
|
36
|
+
|
|
37
|
+
- fd6d8c7: Root dependency changes:
|
|
38
|
+
|
|
39
|
+
## dependencies
|
|
40
|
+
|
|
41
|
+
### Removed
|
|
42
|
+
|
|
43
|
+
- Removed pino-pretty@^13.0.0
|
|
44
|
+
|
|
45
|
+
## 1.0.2
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
- b3e2c49: Forcing bump to build the packages (previous versions didn't get build/published)
|
|
50
|
+
|
|
51
|
+
## 1.0.1
|
|
52
|
+
|
|
53
|
+
### Patch Changes
|
|
54
|
+
|
|
55
|
+
- 602f1c8: Root dependency changes:
|
|
56
|
+
|
|
57
|
+
## dependencies
|
|
58
|
+
|
|
59
|
+
### Updated
|
|
60
|
+
|
|
61
|
+
- Updated cache-manager from ^6.4.0 to ^5.5.2
|
|
62
|
+
- Updated prettier from ~3.4.2 to ~3.0.3
|
|
63
|
+
- Updated reflect-metadata from ^0.2.2 to ^0.2.0
|
|
64
|
+
|
|
65
|
+
### Removed
|
|
66
|
+
|
|
67
|
+
- Removed @autotelic/fastify-opentelemetry@^0.22.1
|
|
68
|
+
- Removed @aws-sdk/client-secrets-manager@^3.744.0
|
|
69
|
+
- Removed @bluealba/microservices-toolkit@^1.9.5
|
|
70
|
+
- Removed @faker-js/faker@9.5.0
|
|
71
|
+
- Removed @fastify/cookie@^11.0.2
|
|
72
|
+
- Removed @fastify/express@^4.0.2
|
|
73
|
+
- Removed @fastify/reply-from@^12.0.2
|
|
74
|
+
- Removed @fastify/static@^8.1.0
|
|
75
|
+
- Removed @fastify/swagger@^9.4.2
|
|
76
|
+
- Removed @fastify/swagger-ui@^5.2.1
|
|
77
|
+
- Removed @nestjs/axios@^4.0.0
|
|
78
|
+
- Removed @nestjs/cache-manager@^3.0.0
|
|
79
|
+
- Removed @nestjs/common@^11.0.9
|
|
80
|
+
- Removed @nestjs/config@^4.0.0
|
|
81
|
+
- Removed @nestjs/core@^11.0.9
|
|
82
|
+
- Removed @nestjs/devtools-integration@^0.2.0
|
|
83
|
+
- Removed @nestjs/jwt@^11.0.0
|
|
84
|
+
- Removed @nestjs/mapped-types@2.1.0
|
|
85
|
+
- Removed @nestjs/passport@^11.0.5
|
|
86
|
+
- Removed @nestjs/platform-express@^11.0.9
|
|
87
|
+
- Removed @nestjs/platform-fastify@^11.0.12
|
|
88
|
+
- Removed @nestjs/platform-ws@^11.0.9
|
|
89
|
+
- Removed @nestjs/schematics@^11.0.0
|
|
90
|
+
- Removed @nestjs/swagger@^11.0.3
|
|
91
|
+
- Removed @nestjs/testing@^11.0.9
|
|
92
|
+
- Removed @nestjs/websockets@^11.0.9
|
|
93
|
+
- Removed @nestjs/event-emitter@^3.0.0
|
|
94
|
+
- Removed @opentelemetry/api@^1.9.0
|
|
95
|
+
- Removed @opentelemetry/auto-instrumentations-node@^0.56.0
|
|
96
|
+
- Removed @opentelemetry/exporter-trace-otlp-http@^0.57.2
|
|
97
|
+
- Removed @opentelemetry/resources@^1.30.1
|
|
98
|
+
- Removed @opentelemetry/sdk-node@^0.57.2
|
|
99
|
+
- Removed @opentelemetry/semantic-conventions@^1.30.0
|
|
100
|
+
- Removed @radix-ui/react-dialog@^1.1.6
|
|
101
|
+
- Removed @testing-library/jest-dom@^6.6.3
|
|
102
|
+
- Removed @testing-library/react@^16.2.0
|
|
103
|
+
- Removed @types/express-serve-static-core@4.19.6
|
|
104
|
+
- Removed @types/react@18.3.18
|
|
105
|
+
- Removed @types/react-dom@^18.3.5
|
|
106
|
+
- Removed @types/supertest@^6.0.0
|
|
107
|
+
- Removed @types/systemjs@^6.15.0
|
|
108
|
+
- Removed axios@^1.6.8
|
|
109
|
+
- Removed ba-db-postgres@^6.0.0
|
|
110
|
+
- Removed basic-auth@^2.0.1
|
|
111
|
+
- Removed bcryptjs@^3.0.2
|
|
112
|
+
- Removed body-parser@^1.20.2
|
|
113
|
+
- Removed class-validator@^0.14.1
|
|
114
|
+
- Removed clsx@^2.1.1
|
|
115
|
+
- Removed co@~4.6.0
|
|
116
|
+
- Removed compression@~1.7.4
|
|
117
|
+
- Removed cookie-parser@^1.4.6
|
|
118
|
+
- Removed cross-spawn@7.0.3
|
|
119
|
+
- Removed dayjs@^1.11.13
|
|
120
|
+
- Removed dotenv@^8.6.0
|
|
121
|
+
- Removed ejs@^3.1.9
|
|
122
|
+
- Removed esbuild@0.20.2
|
|
123
|
+
- Removed express@^4.18.2
|
|
124
|
+
- Removed fastify@^5.2.1
|
|
125
|
+
- Removed husky@9.1.7
|
|
126
|
+
- Removed identity-obj-proxy@^3.0.0
|
|
127
|
+
- Removed jest@^29.7.0
|
|
128
|
+
- Removed jest-environment-jsdom@^29.7.0
|
|
129
|
+
- Removed jest-html-reporter@^3.10.2
|
|
130
|
+
- Removed jsonwebtoken@9.0.2
|
|
131
|
+
- Removed kafkajs@~1.11.0
|
|
132
|
+
- Removed knex@^3.1.0
|
|
133
|
+
- Removed lodash@^4.17.15
|
|
134
|
+
- Removed moment@^2.30.1
|
|
135
|
+
- Removed morgan@^1.10.0
|
|
136
|
+
- Removed negotiator@^0.6.3
|
|
137
|
+
- Removed nestjs-cls@^5.0.1
|
|
138
|
+
- Removed node-cache@^5.1.2
|
|
139
|
+
- Removed nodemon@^3.1.4
|
|
140
|
+
- Removed path-to-regexp@6.3.0
|
|
141
|
+
- Removed pino@^9.6.0
|
|
142
|
+
- Removed pino-http@^10.4.0
|
|
143
|
+
- Removed ramda@^0.30.1
|
|
144
|
+
- Removed react@^18.3.1
|
|
145
|
+
- Removed react-dom@18.3.1
|
|
146
|
+
- Removed react-hook-form@^7.54.2
|
|
147
|
+
- Removed rxjs@^7.8.1
|
|
148
|
+
- Removed single-spa@^6.0.3
|
|
149
|
+
- Removed swagger-jsdoc@^6.2.8
|
|
150
|
+
- Removed swagger-ui-express@^5.0.1
|
|
151
|
+
- Removed underscore@^1.13.7
|
|
152
|
+
- Removed url-join@^4.0.1
|
|
153
|
+
- Removed winston@^2.4.7
|
|
154
|
+
- Removed @bluealba-public/from-env@\*
|
|
155
|
+
|
|
156
|
+
## devDependencies
|
|
157
|
+
|
|
158
|
+
### Added
|
|
159
|
+
|
|
160
|
+
- Added jest-environment-jsdom@^29.7.0
|
|
161
|
+
- Added jest-html-reporter@^3.10.2
|
|
162
|
+
- Added nodemon@^3.1.4
|
|
163
|
+
- Added ts-jest@^29.2.5
|
|
164
|
+
- Added ts-loader@9.5.1
|
|
165
|
+
- Added ts-node@10.9.2
|
|
166
|
+
- Added tsconfig-paths@^4.2.0
|
|
167
|
+
- Added typescript@5.8.3
|
|
168
|
+
- Added identity-obj-proxy@^3.0.0
|
|
169
|
+
- Added @types/express-serve-static-core@4.19.6
|
|
170
|
+
- Added @types/ramda@^0.30.2
|
|
171
|
+
- Added @types/react@18.3.3
|
|
172
|
+
- Added @types/react-dom@^18.3.0
|
|
173
|
+
- Added @types/supertest@^6.0.0
|
|
174
|
+
- Added @types/systemjs@^6.15.0
|
|
175
|
+
- Added @nestjs/cli@^11.0.6
|
|
176
|
+
- Added @testing-library/jest-dom@^6.5.0
|
|
177
|
+
- Added glob@^11.0.1
|
|
178
|
+
- Added husky@^9.1.7
|
|
179
|
+
- Added lint-staged@^15.5.0
|
|
180
|
+
- Added syncpack@^13.0.3
|
|
181
|
+
|
|
182
|
+
### Updated
|
|
183
|
+
|
|
184
|
+
- Updated @types/jsonwebtoken from ^9.0.8 to ^9.0.9
|
|
185
|
+
|
|
186
|
+
- d1a9ccb: Add NestJS Gateway
|
package/LICENSE
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Required Notice: Copyright Blue Alba LLC 2025 (https://bluealba.com)
|
|
2
|
+
|
|
3
|
+
# PolyForm Noncommercial License 1.0.0
|
|
4
|
+
|
|
5
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
6
|
+
|
|
7
|
+
## Acceptance
|
|
8
|
+
|
|
9
|
+
In order to get any license under these terms, you
|
|
10
|
+
must agree to them as both strict obligations and
|
|
11
|
+
conditions to all your licenses.
|
|
12
|
+
|
|
13
|
+
## Copyright License
|
|
14
|
+
|
|
15
|
+
The licensor grants you a copyright license for the
|
|
16
|
+
software to do everything you might do with the
|
|
17
|
+
software that would otherwise infringe the licensor's
|
|
18
|
+
copyright in it for any permitted purpose. However,
|
|
19
|
+
you may only distribute the software according to
|
|
20
|
+
[Distribution License](#distribution-license) and make
|
|
21
|
+
changes or new works based on the software according to
|
|
22
|
+
[Changes and New Works License](#changes-and-new-works-license).
|
|
23
|
+
|
|
24
|
+
## Distribution License
|
|
25
|
+
|
|
26
|
+
The licensor grants you an additional copyright license
|
|
27
|
+
to distribute copies of the software. Your license
|
|
28
|
+
to distribute covers distributing the software with
|
|
29
|
+
changes and new works permitted by [Changes and New Works
|
|
30
|
+
License](#changes-and-new-works-license).
|
|
31
|
+
|
|
32
|
+
## Notices
|
|
33
|
+
|
|
34
|
+
You must ensure that anyone who gets a copy of any part of
|
|
35
|
+
the software from you also gets a copy of these terms or
|
|
36
|
+
the URL for them above, as well as copies of any plain-text
|
|
37
|
+
lines beginning with `Required Notice:` that the licensor
|
|
38
|
+
provided with the software. For example:
|
|
39
|
+
|
|
40
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
41
|
+
|
|
42
|
+
## Changes and New Works License
|
|
43
|
+
|
|
44
|
+
The licensor grants you an additional copyright license to
|
|
45
|
+
make changes and new works based on the software for any
|
|
46
|
+
permitted purpose.
|
|
47
|
+
|
|
48
|
+
## Patent License
|
|
49
|
+
|
|
50
|
+
The licensor grants you a patent license for the software
|
|
51
|
+
that covers patent claims the licensor can license, as well
|
|
52
|
+
as patent claims that the licensor becomes able to license.
|
|
53
|
+
|
|
54
|
+
## Noncommercial Purposes
|
|
55
|
+
|
|
56
|
+
Any noncommercial purpose is a permitted purpose.
|
|
57
|
+
|
|
58
|
+
## Personal Uses
|
|
59
|
+
|
|
60
|
+
Personal use for research, experiment, and testing for
|
|
61
|
+
the benefit of public knowledge, personal study, private
|
|
62
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
63
|
+
observance, without any anticipated commercial application,
|
|
64
|
+
is use for a permitted purpose.
|
|
65
|
+
|
|
66
|
+
## Noncommercial Organizations
|
|
67
|
+
|
|
68
|
+
Use by any charitable organization, educational institution,
|
|
69
|
+
public research organization, public safety or health
|
|
70
|
+
organization, environmental protection organization, or
|
|
71
|
+
government institution is use for a permitted purpose
|
|
72
|
+
regardless of the source of funding or obligations resulting
|
|
73
|
+
from the funding.
|
|
74
|
+
|
|
75
|
+
## Fair Use
|
|
76
|
+
|
|
77
|
+
You may have "fair use" rights for the software under the
|
|
78
|
+
law. These terms do not limit them.
|
|
79
|
+
|
|
80
|
+
## No Other Rights
|
|
81
|
+
|
|
82
|
+
These terms do not allow you to sublicense or transfer any of
|
|
83
|
+
your licenses to anyone else, or prevent the licensor from
|
|
84
|
+
granting licenses to anyone else. These terms do not imply
|
|
85
|
+
any other licenses.
|
|
86
|
+
|
|
87
|
+
## Patent Defense
|
|
88
|
+
|
|
89
|
+
If you make any written claim that the software infringes or
|
|
90
|
+
contributes to infringement of any patent, your patent license
|
|
91
|
+
for the software granted under these terms ends immediately. If
|
|
92
|
+
your company makes such a claim, your patent license ends
|
|
93
|
+
immediately for work on behalf of your company.
|
|
94
|
+
|
|
95
|
+
## Violations
|
|
96
|
+
|
|
97
|
+
The first time you are notified in writing that you have
|
|
98
|
+
violated any of these terms, or done anything with the software
|
|
99
|
+
not covered by your licenses, your licenses can nonetheless
|
|
100
|
+
continue if you come into full compliance with these terms,
|
|
101
|
+
and take practical steps to correct past violations, within
|
|
102
|
+
32 days of receiving notice. Otherwise, all your licenses
|
|
103
|
+
end immediately.
|
|
104
|
+
|
|
105
|
+
## No Liability
|
|
106
|
+
|
|
107
|
+
***As far as the law allows, the software comes as is, without
|
|
108
|
+
any warranty or condition, and the licensor will not be liable
|
|
109
|
+
to you for any damages arising out of these terms or the use
|
|
110
|
+
or nature of the software, under any kind of legal claim.***
|
|
111
|
+
|
|
112
|
+
## Definitions
|
|
113
|
+
|
|
114
|
+
The **licensor** is the individual or entity offering these
|
|
115
|
+
terms, and the **software** is the software the licensor makes
|
|
116
|
+
available under these terms, including any portion of the
|
|
117
|
+
software.
|
|
118
|
+
|
|
119
|
+
**You** refers to the individual or entity agreeing to these
|
|
120
|
+
terms.
|
|
121
|
+
|
|
122
|
+
**Your company** is any legal entity, sole proprietorship,
|
|
123
|
+
or other kind of organization that you work for, plus all
|
|
124
|
+
organizations that have control over, are under the control of,
|
|
125
|
+
or are under common control with that organization. **Control**
|
|
126
|
+
means ownership of substantially all the assets of an entity,
|
|
127
|
+
or the power to direct its management and policies by vote,
|
|
128
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
129
|
+
|
|
130
|
+
**Your licenses** are all the licenses granted to you for the
|
|
131
|
+
software under these terms.
|
|
132
|
+
|
|
133
|
+
**Use** means anything you do with the software requiring one
|
|
134
|
+
of your licenses.
|
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# OpenTelemetry Tracer
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
OpenTelemetry Tracer provides a robust tracing utility built on OpenTelemetry, enabling seamless instrumentation of asynchronous operations in your application. It supports auto-instrumentation and custom tracer configuration to effectively monitor performance and troubleshoot issues.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
Install the package from npm:
|
|
9
|
+
```bash
|
|
10
|
+
npm install @bluealba/opentelemetry-tracer
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
Initialize tracing in your application by importing and calling the `initTracing` function:
|
|
15
|
+
```typescript
|
|
16
|
+
import { initTracing } from '@bluealba/opentelemetry-tracer';
|
|
17
|
+
|
|
18
|
+
const tracing = initTracing({
|
|
19
|
+
enabled: true,
|
|
20
|
+
url: process.env.TRACE_URL,
|
|
21
|
+
serviceName: 'your-service-name'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Wrap asynchronous operations with tracing
|
|
25
|
+
const tracedOperation = tracing.withTracing('operation-span', async () => {
|
|
26
|
+
// ... your code ...
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
### For Fastify Applications >5.x
|
|
32
|
+
For Fastify applications, use the provided Fastify plugin to automatically trace incoming requests and responses:
|
|
33
|
+
```
|
|
34
|
+
npm install @autotelic/fastify-opentelemetry
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import fastify from 'fastify';
|
|
39
|
+
import fastifyOpenTelemetry from '@autotelic/fastify-opentelemetry';
|
|
40
|
+
|
|
41
|
+
const app = fastify();
|
|
42
|
+
|
|
43
|
+
app.register(fastifyOpenTelemetry);
|
|
44
|
+
|
|
45
|
+
// ... existing code ...
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
Customize the tracer with the following options:
|
|
51
|
+
- **enabled**: Toggle tracing on or off.
|
|
52
|
+
- **url**: Specify the OTLP trace exporter endpoint.
|
|
53
|
+
- **serviceName**: Name your service for trace identification.
|
|
54
|
+
- **logger**: (Optional) Custom logger for additional logging.
|
|
55
|
+
- **instrumentations**: (Optional) List of instrumentations to enable.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { NodeSDK } from '@opentelemetry/sdk-node';
|
|
2
|
+
import { trace, context } from '@opentelemetry/api';
|
|
3
|
+
import { initTracing, Tracing } from '../src/tracing';
|
|
4
|
+
|
|
5
|
+
trace.setSpan = jest.fn().mockImplementation((ctx, span) => ctx);
|
|
6
|
+
|
|
7
|
+
jest.mock('@opentelemetry/sdk-node', () => {
|
|
8
|
+
return {
|
|
9
|
+
NodeSDK: jest.fn().mockImplementation(() => ({
|
|
10
|
+
start: jest.fn(),
|
|
11
|
+
shutdown: jest.fn().mockResolvedValue(undefined),
|
|
12
|
+
})),
|
|
13
|
+
};
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
jest.mock('@opentelemetry/auto-instrumentations-node', () => ({
|
|
17
|
+
getNodeAutoInstrumentations: jest.fn().mockReturnValue([]),
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
jest.mock('@opentelemetry/exporter-trace-otlp-http', () => ({
|
|
21
|
+
OTLPTraceExporter: jest.fn(),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
jest.mock('@opentelemetry/resources', () => ({
|
|
25
|
+
Resource: jest.fn(),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
jest.mock('@opentelemetry/api', () => {
|
|
29
|
+
const originalModule = jest.requireActual('@opentelemetry/api');
|
|
30
|
+
return {
|
|
31
|
+
...originalModule,
|
|
32
|
+
trace: {
|
|
33
|
+
getTracer: jest.fn().mockReturnValue({
|
|
34
|
+
startSpan: jest.fn().mockReturnValue({
|
|
35
|
+
setStatus: jest.fn(),
|
|
36
|
+
recordException: jest.fn(),
|
|
37
|
+
end: jest.fn(),
|
|
38
|
+
}),
|
|
39
|
+
}),
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('initTracing', () => {
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
jest.clearAllMocks();
|
|
47
|
+
delete process.env.TRACE_URL;
|
|
48
|
+
delete process.env.npm_package_name;
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return the disabled implementation when tracing is not enabled', () => {
|
|
52
|
+
const tracing: Tracing = initTracing({ enabled: false });
|
|
53
|
+
const fakeFn = jest.fn().mockResolvedValue('result');
|
|
54
|
+
const wrappedFn = tracing.withTracing('span-test', fakeFn);
|
|
55
|
+
expect(wrappedFn).toBe(fakeFn);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should initialize tracing when it is enabled', async () => {
|
|
59
|
+
process.env.TRACE_URL = 'http://localhost:4318/v1/traces';
|
|
60
|
+
process.env.npm_package_name = 'test-service';
|
|
61
|
+
const tracing: Tracing = initTracing();
|
|
62
|
+
expect(NodeSDK).toHaveBeenCalled();
|
|
63
|
+
expect(trace.getTracer).toHaveBeenCalledWith('test-service');
|
|
64
|
+
|
|
65
|
+
// We verify that withTracing wraps the function correctly
|
|
66
|
+
const fakeFn = jest.fn().mockResolvedValue('result');
|
|
67
|
+
const wrappedFn = tracing.withTracing('span-test', fakeFn);
|
|
68
|
+
const result = await wrappedFn('argument');
|
|
69
|
+
expect(result).toBe('result');
|
|
70
|
+
expect(fakeFn).toHaveBeenCalledWith('argument');
|
|
71
|
+
|
|
72
|
+
// We verify shutdown
|
|
73
|
+
await tracing.shutdown?.();
|
|
74
|
+
const sdkInstance = (NodeSDK as jest.Mock).mock.results[0].value;
|
|
75
|
+
expect(sdkInstance.shutdown).toHaveBeenCalled();
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { SpanStatusCode } from '@opentelemetry/api';
|
|
2
|
+
import { withTracing } from '../src/with-tracing';
|
|
3
|
+
|
|
4
|
+
describe('withTracing', () => {
|
|
5
|
+
let fakeSpan: any;
|
|
6
|
+
let fakeTracer: any;
|
|
7
|
+
let fakeFn: jest.Mock;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
fakeSpan = {
|
|
11
|
+
setStatus: jest.fn(),
|
|
12
|
+
recordException: jest.fn(),
|
|
13
|
+
end: jest.fn(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
fakeTracer = {
|
|
17
|
+
startSpan: jest.fn().mockReturnValue(fakeSpan),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
fakeFn = jest.fn().mockResolvedValue('result');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should execute the function and mark the span as OK on success', async () => {
|
|
24
|
+
const wrappedFn = withTracing(fakeTracer, 'span-test', fakeFn);
|
|
25
|
+
const result = await wrappedFn('arg1');
|
|
26
|
+
expect(result).toBe('result');
|
|
27
|
+
expect(fakeTracer.startSpan).toHaveBeenCalledWith('span-test');
|
|
28
|
+
expect(fakeSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.OK });
|
|
29
|
+
expect(fakeSpan.end).toHaveBeenCalled();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should record the exception and mark the span as ERROR on failure', async () => {
|
|
33
|
+
const error = new Error('failed');
|
|
34
|
+
fakeFn.mockRejectedValue(error);
|
|
35
|
+
const wrappedFn = withTracing(fakeTracer, 'span-test', fakeFn);
|
|
36
|
+
await expect(wrappedFn('arg1')).rejects.toThrow('failed');
|
|
37
|
+
expect(fakeSpan.recordException).toHaveBeenCalledWith(error);
|
|
38
|
+
expect(fakeSpan.setStatus).toHaveBeenCalledWith({ code: SpanStatusCode.ERROR });
|
|
39
|
+
expect(fakeSpan.end).toHaveBeenCalled();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
Binary file
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withTracing = exports.initTracing = void 0;
|
|
4
|
+
var tracing_1 = require("./tracing");
|
|
5
|
+
Object.defineProperty(exports, "initTracing", { enumerable: true, get: function () { return tracing_1.initTracing; } });
|
|
6
|
+
var with_tracing_1 = require("./with-tracing");
|
|
7
|
+
Object.defineProperty(exports, "withTracing", { enumerable: true, get: function () { return with_tracing_1.withTracing; } });
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a tracing utility built on top of OpenTelemetry to instrument and monitor asynchronous operations.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* The tracing module conditionally initializes the OpenTelemetry Node SDK with the OTLP trace exporter.
|
|
6
|
+
* Tracing is enabled if the provided options flag "enabled" is true or if the TRACE_URL environment variable is defined.
|
|
7
|
+
* If not enabled or the trace exporter URL is not provided, the module returns a no-op implementation that simply executes
|
|
8
|
+
* the provided function without instrumentation.
|
|
9
|
+
*
|
|
10
|
+
* The module exposes two primary interfaces:
|
|
11
|
+
*
|
|
12
|
+
* - {@link Tracing}: Defines an API for wrapping asynchronous functions with tracing spans using the {withTracing} method.
|
|
13
|
+
* Optionally, it also provides a {shutdown} method to gracefully terminate the OpenTelemetry SDK.
|
|
14
|
+
*
|
|
15
|
+
* - {@link TracingOptions}: Allows configuration of the tracing behavior. It supports:
|
|
16
|
+
* - `enabled`: A boolean flag to explicitly enable or disable tracing.
|
|
17
|
+
* - `url`: The endpoint URL for the OTLP trace exporter.
|
|
18
|
+
* - `serviceName`: The name of the service, defaulting to the npm package name or 'anonymous-service' if unspecified.
|
|
19
|
+
*
|
|
20
|
+
* The tracing spans are created using a tracer instance from the OpenTelemetry API, which is configured with
|
|
21
|
+
* automatic instrumentation via {@link getNodeAutoInstrumentations}, and the service resource is tagged with
|
|
22
|
+
* the provided service name.
|
|
23
|
+
*
|
|
24
|
+
* @packageDocumentation
|
|
25
|
+
*/
|
|
26
|
+
import * as opentelemetry from '@opentelemetry/sdk-node';
|
|
27
|
+
export interface Tracing {
|
|
28
|
+
withTracing: <T extends (...args: any[]) => Promise<any>>(spanName: string, fn: T) => T;
|
|
29
|
+
shutdown?: () => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export interface Logger {
|
|
32
|
+
log: (msg: string) => void;
|
|
33
|
+
error: (msg: string) => void;
|
|
34
|
+
}
|
|
35
|
+
export interface TracingOptions {
|
|
36
|
+
enabled?: boolean;
|
|
37
|
+
url?: string;
|
|
38
|
+
serviceName?: string;
|
|
39
|
+
logger?: Logger;
|
|
40
|
+
instrumentations?: opentelemetry.NodeSDKConfiguration["instrumentations"];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Initializes tracing for the application using OpenTelemetry.
|
|
44
|
+
*
|
|
45
|
+
* @remarks
|
|
46
|
+
* This function configures and starts the OpenTelemetry NodeSDK with the OTLP trace exporter.
|
|
47
|
+
* It determines whether tracing is enabled based on the provided options or the environment variable `TRACE_URL`.
|
|
48
|
+
* If tracing is disabled or the `url` is not specified, a no-operation version of the tracing interface is returned.
|
|
49
|
+
*
|
|
50
|
+
* @param options - Optional configuration settings for tracing. If not provided, values are inferred from environment variables:
|
|
51
|
+
* - `enabled`: Boolean flag to enable tracing. Defaults to true if `TRACE_URL` is defined.
|
|
52
|
+
* - `url`: The endpoint URL for the trace exporter.
|
|
53
|
+
* - `serviceName`: The service name used for tracing. Defaults to the value of `npm_package_name` or a predefined anonymous service name.
|
|
54
|
+
*
|
|
55
|
+
* @returns An object with:
|
|
56
|
+
* - `withTracing`: A function that wraps a given function execution with a tracing span.
|
|
57
|
+
* - `shutdown`: An async function to gracefully shutdown the tracing SDK.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* const tracing = initTracing({ enabled: true, url: 'http://localhost:4318', serviceName: 'my-service' });
|
|
61
|
+
* tracing.withTracing('my-span', () => {
|
|
62
|
+
* // ... code to be traced ...
|
|
63
|
+
* });
|
|
64
|
+
*/
|
|
65
|
+
export declare function initTracing(options?: TracingOptions): Tracing;
|
package/dist/tracing.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.initTracing = initTracing;
|
|
37
|
+
/**
|
|
38
|
+
* Provides a tracing utility built on top of OpenTelemetry to instrument and monitor asynchronous operations.
|
|
39
|
+
*
|
|
40
|
+
* @remarks
|
|
41
|
+
* The tracing module conditionally initializes the OpenTelemetry Node SDK with the OTLP trace exporter.
|
|
42
|
+
* Tracing is enabled if the provided options flag "enabled" is true or if the TRACE_URL environment variable is defined.
|
|
43
|
+
* If not enabled or the trace exporter URL is not provided, the module returns a no-op implementation that simply executes
|
|
44
|
+
* the provided function without instrumentation.
|
|
45
|
+
*
|
|
46
|
+
* The module exposes two primary interfaces:
|
|
47
|
+
*
|
|
48
|
+
* - {@link Tracing}: Defines an API for wrapping asynchronous functions with tracing spans using the {withTracing} method.
|
|
49
|
+
* Optionally, it also provides a {shutdown} method to gracefully terminate the OpenTelemetry SDK.
|
|
50
|
+
*
|
|
51
|
+
* - {@link TracingOptions}: Allows configuration of the tracing behavior. It supports:
|
|
52
|
+
* - `enabled`: A boolean flag to explicitly enable or disable tracing.
|
|
53
|
+
* - `url`: The endpoint URL for the OTLP trace exporter.
|
|
54
|
+
* - `serviceName`: The name of the service, defaulting to the npm package name or 'anonymous-service' if unspecified.
|
|
55
|
+
*
|
|
56
|
+
* The tracing spans are created using a tracer instance from the OpenTelemetry API, which is configured with
|
|
57
|
+
* automatic instrumentation via {@link getNodeAutoInstrumentations}, and the service resource is tagged with
|
|
58
|
+
* the provided service name.
|
|
59
|
+
*
|
|
60
|
+
* @packageDocumentation
|
|
61
|
+
*/
|
|
62
|
+
const opentelemetry = __importStar(require("@opentelemetry/sdk-node"));
|
|
63
|
+
const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
|
|
64
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
65
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
66
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
67
|
+
const api_1 = require("@opentelemetry/api");
|
|
68
|
+
const with_tracing_1 = require("./with-tracing");
|
|
69
|
+
const ANONYMOUS_SERVICE_NAME = 'anonymous-service';
|
|
70
|
+
const defaultLogger = {
|
|
71
|
+
log: (msg) => console.log(msg),
|
|
72
|
+
error: (msg) => console.error(msg),
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Initializes tracing for the application using OpenTelemetry.
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* This function configures and starts the OpenTelemetry NodeSDK with the OTLP trace exporter.
|
|
79
|
+
* It determines whether tracing is enabled based on the provided options or the environment variable `TRACE_URL`.
|
|
80
|
+
* If tracing is disabled or the `url` is not specified, a no-operation version of the tracing interface is returned.
|
|
81
|
+
*
|
|
82
|
+
* @param options - Optional configuration settings for tracing. If not provided, values are inferred from environment variables:
|
|
83
|
+
* - `enabled`: Boolean flag to enable tracing. Defaults to true if `TRACE_URL` is defined.
|
|
84
|
+
* - `url`: The endpoint URL for the trace exporter.
|
|
85
|
+
* - `serviceName`: The service name used for tracing. Defaults to the value of `npm_package_name` or a predefined anonymous service name.
|
|
86
|
+
*
|
|
87
|
+
* @returns An object with:
|
|
88
|
+
* - `withTracing`: A function that wraps a given function execution with a tracing span.
|
|
89
|
+
* - `shutdown`: An async function to gracefully shutdown the tracing SDK.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* const tracing = initTracing({ enabled: true, url: 'http://localhost:4318', serviceName: 'my-service' });
|
|
93
|
+
* tracing.withTracing('my-span', () => {
|
|
94
|
+
* // ... code to be traced ...
|
|
95
|
+
* });
|
|
96
|
+
*/
|
|
97
|
+
function initTracing(options) {
|
|
98
|
+
var _a, _b, _c, _d, _e;
|
|
99
|
+
const enabled = (_a = options === null || options === void 0 ? void 0 : options.enabled) !== null && _a !== void 0 ? _a : process.env.TRACE_URL !== undefined;
|
|
100
|
+
const url = (_b = options === null || options === void 0 ? void 0 : options.url) !== null && _b !== void 0 ? _b : process.env.TRACE_URL;
|
|
101
|
+
const serviceName = (_d = (_c = options === null || options === void 0 ? void 0 : options.serviceName) !== null && _c !== void 0 ? _c : process.env.npm_package_name) !== null && _d !== void 0 ? _d : ANONYMOUS_SERVICE_NAME;
|
|
102
|
+
const logger = (options === null || options === void 0 ? void 0 : options.logger) || defaultLogger;
|
|
103
|
+
const instrumentations = (_e = options === null || options === void 0 ? void 0 : options.instrumentations) !== null && _e !== void 0 ? _e : [];
|
|
104
|
+
if (!enabled || !url) {
|
|
105
|
+
logger.log('[Tracing] Disabled');
|
|
106
|
+
return { withTracing: (_spanName, fn) => fn };
|
|
107
|
+
}
|
|
108
|
+
const sdk = new opentelemetry.NodeSDK({
|
|
109
|
+
autoDetectResources: true,
|
|
110
|
+
traceExporter: new exporter_trace_otlp_http_1.OTLPTraceExporter({ url }),
|
|
111
|
+
instrumentations: [
|
|
112
|
+
(0, auto_instrumentations_node_1.getNodeAutoInstrumentations)(),
|
|
113
|
+
...instrumentations
|
|
114
|
+
],
|
|
115
|
+
resource: new resources_1.Resource({
|
|
116
|
+
[semantic_conventions_1.SemanticResourceAttributes.SERVICE_NAME]: serviceName
|
|
117
|
+
})
|
|
118
|
+
});
|
|
119
|
+
sdk.start();
|
|
120
|
+
logger.log(`[Tracing] Enabled: Publishing traces to ${url} with service ${serviceName}`);
|
|
121
|
+
process.on('SIGTERM', () => {
|
|
122
|
+
sdk.shutdown()
|
|
123
|
+
.then(() => logger.log('Tracing terminated'))
|
|
124
|
+
.catch((error) => logger.error('Error terminating tracing: ' + error))
|
|
125
|
+
.finally(() => process.exit(0));
|
|
126
|
+
});
|
|
127
|
+
const tracer = api_1.trace.getTracer(serviceName);
|
|
128
|
+
return {
|
|
129
|
+
withTracing: (spanName, fn) => (0, with_tracing_1.withTracing)(tracer, spanName, fn),
|
|
130
|
+
shutdown: async () => { await sdk.shutdown(); }
|
|
131
|
+
};
|
|
132
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps an asynchronous function with tracing instrumentation using OpenTelemetry.
|
|
3
|
+
*
|
|
4
|
+
* This function creates a new trace span and executes the provided function within this span's context.
|
|
5
|
+
* Upon completion, the span status is set based on the execution's outcome:
|
|
6
|
+
* - If the function completes successfully, the span status is set to OK.
|
|
7
|
+
* - If an error is thrown, the error is recorded and the span status is set to ERROR, and the error is rethrown.
|
|
8
|
+
*
|
|
9
|
+
* @template T - A function type extending a function that returns a Promise.
|
|
10
|
+
*
|
|
11
|
+
* @param tracer - An OpenTelemetry Tracer used to start a new trace span.
|
|
12
|
+
* @param spanName - The name to assign to the newly created span.
|
|
13
|
+
* @param fn - The asynchronous function to be wrapped with tracing.
|
|
14
|
+
*
|
|
15
|
+
* @returns A new function that returns the same promise as the original function, but with tracing applied.
|
|
16
|
+
*/
|
|
17
|
+
import { Tracer } from '@opentelemetry/api';
|
|
18
|
+
export type TracingFunction<T> = (...args: any[]) => Promise<T>;
|
|
19
|
+
export declare function withTracing<T extends TracingFunction<T>>(tracer: Tracer, spanName: string, fn: T): T;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withTracing = withTracing;
|
|
4
|
+
/**
|
|
5
|
+
* Wraps an asynchronous function with tracing instrumentation using OpenTelemetry.
|
|
6
|
+
*
|
|
7
|
+
* This function creates a new trace span and executes the provided function within this span's context.
|
|
8
|
+
* Upon completion, the span status is set based on the execution's outcome:
|
|
9
|
+
* - If the function completes successfully, the span status is set to OK.
|
|
10
|
+
* - If an error is thrown, the error is recorded and the span status is set to ERROR, and the error is rethrown.
|
|
11
|
+
*
|
|
12
|
+
* @template T - A function type extending a function that returns a Promise.
|
|
13
|
+
*
|
|
14
|
+
* @param tracer - An OpenTelemetry Tracer used to start a new trace span.
|
|
15
|
+
* @param spanName - The name to assign to the newly created span.
|
|
16
|
+
* @param fn - The asynchronous function to be wrapped with tracing.
|
|
17
|
+
*
|
|
18
|
+
* @returns A new function that returns the same promise as the original function, but with tracing applied.
|
|
19
|
+
*/
|
|
20
|
+
const api_1 = require("@opentelemetry/api");
|
|
21
|
+
function withTracing(tracer, spanName, fn) {
|
|
22
|
+
const wrapped = async (...args) => {
|
|
23
|
+
const span = tracer.startSpan(spanName);
|
|
24
|
+
try {
|
|
25
|
+
return await api_1.context.with(api_1.trace.setSpan(api_1.context.active(), span), async () => {
|
|
26
|
+
const result = await fn(...args);
|
|
27
|
+
span.setStatus({ code: api_1.SpanStatusCode.OK });
|
|
28
|
+
return result;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
span.recordException(error);
|
|
33
|
+
span.setStatus({ code: api_1.SpanStatusCode.ERROR });
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
span.end();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
return wrapped;
|
|
41
|
+
}
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bluealba/opentelemetry-tracer",
|
|
3
|
+
"version": "1.0.4-develop-1171",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"test": "jest"
|
|
9
|
+
},
|
|
10
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"@bluealba:registry": "https://registry.npmjs.org/",
|
|
13
|
+
"access": "public"
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/index.ts
ADDED
package/src/tracing.ts
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provides a tracing utility built on top of OpenTelemetry to instrument and monitor asynchronous operations.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* The tracing module conditionally initializes the OpenTelemetry Node SDK with the OTLP trace exporter.
|
|
6
|
+
* Tracing is enabled if the provided options flag "enabled" is true or if the TRACE_URL environment variable is defined.
|
|
7
|
+
* If not enabled or the trace exporter URL is not provided, the module returns a no-op implementation that simply executes
|
|
8
|
+
* the provided function without instrumentation.
|
|
9
|
+
*
|
|
10
|
+
* The module exposes two primary interfaces:
|
|
11
|
+
*
|
|
12
|
+
* - {@link Tracing}: Defines an API for wrapping asynchronous functions with tracing spans using the {withTracing} method.
|
|
13
|
+
* Optionally, it also provides a {shutdown} method to gracefully terminate the OpenTelemetry SDK.
|
|
14
|
+
*
|
|
15
|
+
* - {@link TracingOptions}: Allows configuration of the tracing behavior. It supports:
|
|
16
|
+
* - `enabled`: A boolean flag to explicitly enable or disable tracing.
|
|
17
|
+
* - `url`: The endpoint URL for the OTLP trace exporter.
|
|
18
|
+
* - `serviceName`: The name of the service, defaulting to the npm package name or 'anonymous-service' if unspecified.
|
|
19
|
+
*
|
|
20
|
+
* The tracing spans are created using a tracer instance from the OpenTelemetry API, which is configured with
|
|
21
|
+
* automatic instrumentation via {@link getNodeAutoInstrumentations}, and the service resource is tagged with
|
|
22
|
+
* the provided service name.
|
|
23
|
+
*
|
|
24
|
+
* @packageDocumentation
|
|
25
|
+
*/
|
|
26
|
+
import * as opentelemetry from '@opentelemetry/sdk-node';
|
|
27
|
+
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
|
|
28
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
29
|
+
import { Resource } from '@opentelemetry/resources';
|
|
30
|
+
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
|
|
31
|
+
import { trace, Tracer } from '@opentelemetry/api';
|
|
32
|
+
import { withTracing as createWithTracing } from './with-tracing';
|
|
33
|
+
|
|
34
|
+
const ANONYMOUS_SERVICE_NAME = 'anonymous-service';
|
|
35
|
+
|
|
36
|
+
export interface Tracing {
|
|
37
|
+
withTracing: <T extends (...args: any[]) => Promise<any>>(spanName: string, fn: T) => T;
|
|
38
|
+
shutdown?: () => Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Logger {
|
|
42
|
+
log: (msg: string) => void;
|
|
43
|
+
error: (msg: string) => void;
|
|
44
|
+
}
|
|
45
|
+
export interface TracingOptions {
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
url?: string;
|
|
48
|
+
serviceName?: string;
|
|
49
|
+
logger?: Logger;
|
|
50
|
+
instrumentations?: opentelemetry.NodeSDKConfiguration["instrumentations"];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const defaultLogger: Logger = {
|
|
54
|
+
log: (msg: string) => console.log(msg),
|
|
55
|
+
error: (msg: string) => console.error(msg),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Initializes tracing for the application using OpenTelemetry.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* This function configures and starts the OpenTelemetry NodeSDK with the OTLP trace exporter.
|
|
63
|
+
* It determines whether tracing is enabled based on the provided options or the environment variable `TRACE_URL`.
|
|
64
|
+
* If tracing is disabled or the `url` is not specified, a no-operation version of the tracing interface is returned.
|
|
65
|
+
*
|
|
66
|
+
* @param options - Optional configuration settings for tracing. If not provided, values are inferred from environment variables:
|
|
67
|
+
* - `enabled`: Boolean flag to enable tracing. Defaults to true if `TRACE_URL` is defined.
|
|
68
|
+
* - `url`: The endpoint URL for the trace exporter.
|
|
69
|
+
* - `serviceName`: The service name used for tracing. Defaults to the value of `npm_package_name` or a predefined anonymous service name.
|
|
70
|
+
*
|
|
71
|
+
* @returns An object with:
|
|
72
|
+
* - `withTracing`: A function that wraps a given function execution with a tracing span.
|
|
73
|
+
* - `shutdown`: An async function to gracefully shutdown the tracing SDK.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* const tracing = initTracing({ enabled: true, url: 'http://localhost:4318', serviceName: 'my-service' });
|
|
77
|
+
* tracing.withTracing('my-span', () => {
|
|
78
|
+
* // ... code to be traced ...
|
|
79
|
+
* });
|
|
80
|
+
*/
|
|
81
|
+
export function initTracing(options?: TracingOptions): Tracing {
|
|
82
|
+
const enabled = options?.enabled ?? process.env.TRACE_URL !== undefined;
|
|
83
|
+
const url = options?.url ?? process.env.TRACE_URL;
|
|
84
|
+
const serviceName = options?.serviceName ?? process.env.npm_package_name ?? ANONYMOUS_SERVICE_NAME;
|
|
85
|
+
const logger = options?.logger || defaultLogger;
|
|
86
|
+
const instrumentations = options?.instrumentations ?? [];
|
|
87
|
+
|
|
88
|
+
if (!enabled || !url) {
|
|
89
|
+
logger.log('[Tracing] Disabled');
|
|
90
|
+
return { withTracing: (_spanName, fn) => fn };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const sdk = new opentelemetry.NodeSDK({
|
|
94
|
+
autoDetectResources: true,
|
|
95
|
+
traceExporter: new OTLPTraceExporter({ url }),
|
|
96
|
+
instrumentations: [
|
|
97
|
+
getNodeAutoInstrumentations(),
|
|
98
|
+
...instrumentations
|
|
99
|
+
],
|
|
100
|
+
resource: new Resource({
|
|
101
|
+
[SemanticResourceAttributes.SERVICE_NAME]: serviceName
|
|
102
|
+
})
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
sdk.start();
|
|
106
|
+
|
|
107
|
+
logger.log(`[Tracing] Enabled: Publishing traces to ${url} with service ${serviceName}`);
|
|
108
|
+
|
|
109
|
+
process.on('SIGTERM', () => {
|
|
110
|
+
sdk.shutdown()
|
|
111
|
+
.then(() => logger.log('Tracing terminated'))
|
|
112
|
+
.catch((error: any) => logger.error('Error terminating tracing: ' + error))
|
|
113
|
+
.finally(() => process.exit(0));
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const tracer: Tracer = trace.getTracer(serviceName);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
withTracing: (spanName, fn) => createWithTracing(tracer, spanName, fn),
|
|
120
|
+
shutdown: async () => { await sdk.shutdown(); }
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps an asynchronous function with tracing instrumentation using OpenTelemetry.
|
|
3
|
+
*
|
|
4
|
+
* This function creates a new trace span and executes the provided function within this span's context.
|
|
5
|
+
* Upon completion, the span status is set based on the execution's outcome:
|
|
6
|
+
* - If the function completes successfully, the span status is set to OK.
|
|
7
|
+
* - If an error is thrown, the error is recorded and the span status is set to ERROR, and the error is rethrown.
|
|
8
|
+
*
|
|
9
|
+
* @template T - A function type extending a function that returns a Promise.
|
|
10
|
+
*
|
|
11
|
+
* @param tracer - An OpenTelemetry Tracer used to start a new trace span.
|
|
12
|
+
* @param spanName - The name to assign to the newly created span.
|
|
13
|
+
* @param fn - The asynchronous function to be wrapped with tracing.
|
|
14
|
+
*
|
|
15
|
+
* @returns A new function that returns the same promise as the original function, but with tracing applied.
|
|
16
|
+
*/
|
|
17
|
+
import { context, trace, Tracer, SpanStatusCode } from '@opentelemetry/api';
|
|
18
|
+
|
|
19
|
+
export type TracingFunction<T> = (...args: any[]) => Promise<T>;
|
|
20
|
+
|
|
21
|
+
export function withTracing<T extends TracingFunction<T>>(
|
|
22
|
+
tracer: Tracer,
|
|
23
|
+
spanName: string,
|
|
24
|
+
fn: T
|
|
25
|
+
): T {
|
|
26
|
+
const wrapped = async (...args: Parameters<T>) => {
|
|
27
|
+
const span = tracer.startSpan(spanName);
|
|
28
|
+
try {
|
|
29
|
+
return await context.with(trace.setSpan(context.active(), span), async () => {
|
|
30
|
+
const result = await fn(...args);
|
|
31
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
32
|
+
return result;
|
|
33
|
+
});
|
|
34
|
+
} catch (error) {
|
|
35
|
+
span.recordException(error as Error);
|
|
36
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
37
|
+
throw error;
|
|
38
|
+
} finally {
|
|
39
|
+
span.end();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return wrapped as T;
|
|
43
|
+
}
|
|
44
|
+
|
package/tsconfig.json
ADDED
package/version.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version": "1.0.4-develop-1171", "name": "bluealba-opentelemetry-tracer", "displayName": "null"}
|