@ogcio/o11y-sdk-node 0.1.0-beta.1 → 0.1.0-beta.11

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.
Files changed (86) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +222 -0
  3. package/dist/index.d.ts +3 -2
  4. package/dist/index.js +2 -0
  5. package/dist/lib/exporter/console.d.ts +3 -0
  6. package/dist/lib/exporter/console.js +20 -0
  7. package/dist/lib/exporter/grpc.d.ts +3 -0
  8. package/dist/lib/exporter/grpc.js +41 -0
  9. package/dist/lib/exporter/http.d.ts +3 -0
  10. package/dist/lib/{http.js → exporter/http.js} +15 -9
  11. package/dist/lib/exporter/index.d.ts +8 -0
  12. package/dist/lib/index.d.ts +36 -6
  13. package/dist/lib/instrumentation.node.d.ts +1 -1
  14. package/dist/lib/instrumentation.node.js +47 -23
  15. package/dist/lib/metrics.d.ts +18 -0
  16. package/dist/lib/metrics.js +24 -0
  17. package/dist/lib/processor/enrich-logger-processor.d.ts +10 -0
  18. package/dist/lib/processor/enrich-logger-processor.js +19 -0
  19. package/dist/lib/processor/enrich-span-processor.d.ts +11 -0
  20. package/dist/lib/processor/enrich-span-processor.js +22 -0
  21. package/dist/lib/resource.d.ts +7 -0
  22. package/dist/lib/resource.js +18 -0
  23. package/dist/lib/traces.d.ts +1 -0
  24. package/dist/lib/traces.js +4 -0
  25. package/dist/lib/url-sampler.d.ts +10 -0
  26. package/dist/lib/url-sampler.js +25 -0
  27. package/dist/lib/utils.d.ts +4 -2
  28. package/dist/lib/utils.js +8 -3
  29. package/dist/package.json +58 -0
  30. package/dist/vitest.config.js +15 -1
  31. package/index.ts +4 -2
  32. package/lib/exporter/console.ts +31 -0
  33. package/lib/exporter/grpc.ts +52 -0
  34. package/lib/{http.ts → exporter/http.ts} +19 -11
  35. package/lib/exporter/index.ts +9 -0
  36. package/lib/index.ts +46 -5
  37. package/lib/instrumentation.node.ts +61 -28
  38. package/lib/metrics.ts +75 -0
  39. package/lib/processor/enrich-logger-processor.ts +34 -0
  40. package/lib/processor/enrich-span-processor.ts +39 -0
  41. package/lib/resource.ts +30 -0
  42. package/lib/traces.ts +5 -0
  43. package/lib/url-sampler.ts +52 -0
  44. package/lib/utils.ts +16 -4
  45. package/package.json +33 -25
  46. package/test/index.test.ts +22 -12
  47. package/test/integration/README.md +26 -0
  48. package/test/integration/integration.test.ts +58 -0
  49. package/test/integration/run.sh +88 -0
  50. package/test/metrics.test.ts +142 -0
  51. package/test/node-config.test.ts +76 -44
  52. package/test/processor/enrich-logger-processor.test.ts +58 -0
  53. package/test/processor/enrich-span-processor.test.ts +104 -0
  54. package/test/resource.test.ts +33 -0
  55. package/test/url-sampler.test.ts +215 -0
  56. package/test/utils/alloy-log-parser.ts +46 -0
  57. package/test/validation.test.ts +48 -11
  58. package/tsconfig.json +2 -1
  59. package/vitest.config.ts +15 -1
  60. package/coverage/cobertura-coverage.xml +0 -199
  61. package/coverage/lcov-report/base.css +0 -224
  62. package/coverage/lcov-report/block-navigation.js +0 -87
  63. package/coverage/lcov-report/favicon.png +0 -0
  64. package/coverage/lcov-report/index.html +0 -131
  65. package/coverage/lcov-report/prettify.css +0 -1
  66. package/coverage/lcov-report/prettify.js +0 -2
  67. package/coverage/lcov-report/sdk-node/index.html +0 -116
  68. package/coverage/lcov-report/sdk-node/index.ts.html +0 -106
  69. package/coverage/lcov-report/sdk-node/lib/grpc.ts.html +0 -178
  70. package/coverage/lcov-report/sdk-node/lib/http.ts.html +0 -190
  71. package/coverage/lcov-report/sdk-node/lib/index.html +0 -191
  72. package/coverage/lcov-report/sdk-node/lib/index.ts.html +0 -265
  73. package/coverage/lcov-report/sdk-node/lib/instrumentation.node.ts.html +0 -310
  74. package/coverage/lcov-report/sdk-node/lib/options.ts.html +0 -109
  75. package/coverage/lcov-report/sdk-node/lib/utils.ts.html +0 -115
  76. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  77. package/coverage/lcov-report/sorter.js +0 -196
  78. package/coverage/lcov.info +0 -206
  79. package/dist/lib/grpc.d.ts +0 -3
  80. package/dist/lib/grpc.js +0 -26
  81. package/dist/lib/http.d.ts +0 -3
  82. package/dist/lib/options.d.ts +0 -7
  83. package/lib/grpc.ts +0 -31
  84. package/lib/options.ts +0 -8
  85. package/test-report.xml +0 -39
  86. /package/dist/lib/{options.js → exporter/index.js} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,86 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.0-beta.11](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.10...@ogcio/o11y-sdk-node@v0.1.0-beta.11) (2025-05-21)
4
+
5
+
6
+ ### Features
7
+
8
+ * may deps update ([#136](https://github.com/ogcio/o11y/issues/136)) ([3edd8b1](https://github.com/ogcio/o11y/commit/3edd8b1d823740d555fc4d93be427e9dc1438a95))
9
+
10
+ ## [0.1.0-beta.10](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.9...@ogcio/o11y-sdk-node@v0.1.0-beta.10) (2025-04-09)
11
+
12
+
13
+ ### Features
14
+
15
+ * april depedency upgrade AB[#27200](https://github.com/ogcio/o11y/issues/27200) ([#116](https://github.com/ogcio/o11y/issues/116)) ([d792fe5](https://github.com/ogcio/o11y/commit/d792fe5a783b0b495912b5bef2babfe11ef5e01d))
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * default attributes in resource ([#112](https://github.com/ogcio/o11y/issues/112)) ([f0f0b9d](https://github.com/ogcio/o11y/commit/f0f0b9d555ef321d31f7171e25dc4b8a5b044522))
21
+
22
+ ## [0.1.0-beta.9](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.8...@ogcio/o11y-sdk-node@v0.1.0-beta.9) (2025-03-24)
23
+
24
+
25
+ ### Features
26
+
27
+ * add custom log processor for span enrich ([#102](https://github.com/ogcio/o11y/issues/102)) ([bbf8334](https://github.com/ogcio/o11y/commit/bbf83340940ed651dff63bbe7aaa52881d1e8c8c))
28
+ * upgrade to opentelemetry 2 AB[#25863](https://github.com/ogcio/o11y/issues/25863) ([#106](https://github.com/ogcio/o11y/issues/106)) ([3ff0314](https://github.com/ogcio/o11y/commit/3ff0314fef9f4d7b5db76da3b94e9035801384c7))
29
+
30
+ ## [0.1.0-beta.8](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.7...@ogcio/o11y-sdk-node@v0.1.0-beta.8) (2025-03-07)
31
+
32
+
33
+ ### Features
34
+
35
+ * o11y showcase AB[#25895](https://github.com/ogcio/o11y/issues/25895) ([#84](https://github.com/ogcio/o11y/issues/84)) ([f8f10af](https://github.com/ogcio/o11y/commit/f8f10af97d9f5c188e3e65f7d62d5c673edce25a))
36
+
37
+
38
+ ### Bug Fixes
39
+
40
+ * improve getMetric attributes types ([#76](https://github.com/ogcio/o11y/issues/76)) ([243649c](https://github.com/ogcio/o11y/commit/243649c4bfe750687a729fbd836772cce16e0cb1))
41
+
42
+ ## [0.1.0-beta.7](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.6...@ogcio/o11y-sdk-node@v0.1.0-beta.7) (2025-02-18)
43
+
44
+
45
+ ### Features
46
+
47
+ * **sdk-node:** add span customization AB[#25358](https://github.com/ogcio/o11y/issues/25358) ([46ba97b](https://github.com/ogcio/o11y/commit/46ba97bac4004ff326a954592f45213ce0e4d683))
48
+
49
+ ## [0.1.0-beta.6](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.5...@ogcio/o11y-sdk-node@v0.1.0-beta.6) (2025-02-06)
50
+
51
+
52
+ ### Features
53
+
54
+ * remove pnpm test on prepublishOnly script ([#68](https://github.com/ogcio/o11y/issues/68)) ([41f6f57](https://github.com/ogcio/o11y/commit/41f6f57fa415c4f7adc29f49f983539274ef7320))
55
+
56
+ ## [0.1.0-beta.5](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.4...@ogcio/o11y-sdk-node@v0.1.0-beta.5) (2025-02-06)
57
+
58
+
59
+ ### Features
60
+
61
+ * add opentelemetry sampler ([#65](https://github.com/ogcio/o11y/issues/65)) ([66793fd](https://github.com/ogcio/o11y/commit/66793fd36bf071e592e3b455f2e33ad9d5b2db37))
62
+
63
+ ## [0.1.0-beta.4](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.1.0-beta.3...@ogcio/o11y-sdk-node@v0.1.0-beta.4) (2025-01-29)
64
+
65
+
66
+ ### Bug Fixes
67
+
68
+ * prepublishOnly hook ([#60](https://github.com/ogcio/o11y/issues/60)) ([9fbd3ad](https://github.com/ogcio/o11y/commit/9fbd3ad0b45a1604cf2eccc26b2f8855640417a1))
69
+
70
+ ## [0.1.0-beta.3](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@0.1.0-beta.2...@ogcio/o11y-sdk-node@v0.1.0-beta.3) (2025-01-28)
71
+
72
+
73
+ ### Features
74
+
75
+ * **sdk-node:** custom metrics ([#53](https://github.com/ogcio/o11y/issues/53)) ([3cb40b1](https://github.com/ogcio/o11y/commit/3cb40b1add3d80615c8d123d233724094559c7ff))
76
+
77
+ ## [0.1.0-beta.2](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@0.1.0-beta.1...@ogcio/o11y-sdk-node@0.1.0-beta.2) (2024-11-28)
78
+
79
+
80
+ ### Bug Fixes
81
+
82
+ * Add readme file inside submodule ([#27](https://github.com/ogcio/o11y/issues/27)) ([dc518d5](https://github.com/ogcio/o11y/commit/dc518d5dde573368443bc0f8619e80e331880c78))
83
+
3
84
  ## [0.1.0-beta.1](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@0.0.1-beta.1...@ogcio/o11y-sdk-node@0.1.0-beta.1) (2024-11-27)
4
85
 
5
86
 
package/README.md ADDED
@@ -0,0 +1,222 @@
1
+ # Observability NodeJS SDK
2
+
3
+ The NodeJS observability sdk is a npm package used to setup and implement opentelemetry instrumentation.
4
+
5
+ ## Installation
6
+
7
+ pnpm
8
+
9
+ ```bash
10
+ pnpm i --save @ogcio/o11y-sdk-node
11
+ ```
12
+
13
+ npm
14
+
15
+ ```bash
16
+ npm i @ogcio/o11y-sdk-node
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ Setup using constructor function
22
+
23
+ ```javascript
24
+ // instrumentation.ts
25
+
26
+ import("@ogcio/o11y-sdk-node/lib/index").then((sdk) =>
27
+ sdk.instrumentNode({
28
+ serviceName: "node-microservice",
29
+ collectorUrl: "http://localhost:4317",
30
+ resourceAttributes: {
31
+ "team.infra.cluster": "dev-01",
32
+ "team.infra.pod": "01",
33
+ "team.service.type": "fastify",
34
+ },
35
+ spanAttributes: {
36
+ "signal.namespace": "documentation",
37
+ },
38
+ ignoreUrls: [{ type: "equals", url: "/api/health" }],
39
+ }),
40
+ );
41
+ ```
42
+
43
+ Run your node script with instrumentation
44
+
45
+ `node --import instrumentation.js server.js`
46
+
47
+ Or setup inside your package.json
48
+
49
+ ```json
50
+ {
51
+ "main": "dist/index.js",
52
+ "type": "module",
53
+ "scripts": {
54
+ "start": "node --env-file=.env --import ./dist/instrumentation.js dist/index.js"
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## Span Customization
60
+
61
+ It is possible to customize spans such as traces and logs globally or in a single code statement using predefined functions.
62
+
63
+ ### Global Configuration
64
+
65
+ In the SDK configuration, you can set the following properties:
66
+
67
+ - `spanAttributes` Object containing static properties or functions used to evaluate custom attributes for every logs and traces.
68
+ - `resourceAttributes` Object containing static properties used as resources attributes for any signal.
69
+ - `traceRatio` Faction value from 0 to 1, used by TraceIdRatioBasedSampler which it deterministically samples a percentage of traces that you pass in as a parameter.
70
+
71
+ ```typescript
72
+ function generateRandomString(): string {
73
+ return Math.random() + "_" + Date.now();
74
+ }
75
+
76
+ instrumentNode({
77
+ resourceAttributes: {
78
+ "property.name.one": "value_one",
79
+ "property.name.two": "value_two",
80
+ },
81
+ spanAttributes: {
82
+ "custom.span.value": "example",
83
+ "custom.span.value_with_function": generateRandomString,
84
+ },
85
+ });
86
+ ```
87
+
88
+ ### Edit Active Span
89
+
90
+ Using `getActiveSpan` function, you can access to current transaction span and customize it.
91
+
92
+ You can use the function everywhere in your code, and set some custom attributes that are enabled for that single span
93
+
94
+ ```typescript
95
+ import { getActiveSpan } from "@ogcio/o11y-sdk-node";
96
+
97
+ async function routes(app: FastifyInstance) {
98
+ app.get("/", async (req, reply) => {
99
+ // validation and business logic
100
+
101
+ // set span attribute
102
+ getActiveSpan()?.setAttribute("business.info", "dummy");
103
+
104
+ reply.status(200).send(response);
105
+ });
106
+ }
107
+ ```
108
+
109
+ ## Sending Custom Metrics
110
+
111
+ This package gives the possibility to send custom metrics and define them as desired in the code, you can choose between sync metrics and observable async metrics.
112
+
113
+ To use this functionality, you only need to import `getMetric` and enable the application instrumentation.
114
+
115
+ ```typescript
116
+ import { getMetric } from "@ogcio/o11y-sdk-node";
117
+ ```
118
+
119
+ ### Sync
120
+
121
+ Sync metrics are signals sent when the function has been called.
122
+
123
+ Creating a counter, there are 2 types of counter:
124
+
125
+ - **counter** a simple counter that can only add positive numbers
126
+ - **updowncounter** counter that support also negative numbers
127
+
128
+ ```typescript
129
+ const counter = getMetric("counter", {
130
+ attributeName: "counter",
131
+ metricName: "fastify-counter",
132
+ });
133
+
134
+ counter.add(1, {
135
+ my: "my",
136
+ custom: "custom",
137
+ attributes: "attributes",
138
+ });
139
+ ```
140
+
141
+ Creating a Histogram
142
+
143
+ ```typescript
144
+ const histogram = getMetric("histogram", {
145
+ metricName: "response_duration",
146
+ attributeName: "http_response",
147
+ options: {
148
+ advice: {
149
+ explicitBucketBoundaries: [0, 100, 200, 500, 1000],
150
+ },
151
+ description: "Response durations",
152
+ },
153
+ });
154
+
155
+ histogram.record(120, { path: "/home" });
156
+ ```
157
+
158
+ ### Async
159
+
160
+ Async metrics are called by the scraper collector to read current data using the `Observable` pattern.
161
+ Creating an async metric means that the application will subscribe to the observability URL and record data on call (default 60s).
162
+
163
+ _keep in mind, you can't send signals on-demand with this component_
164
+
165
+ Creating an async Gauge
166
+
167
+ ```typescript
168
+ const asyncGauge = getMetric("async-gauge", {
169
+ metricName: "cpu_usage",
170
+ attributeName: "server_load",
171
+ options: { unit: "percentage" },
172
+ }).addCallback((observer) => {
173
+ observer.observe(50, { host: "server1" });
174
+ });
175
+ ```
176
+
177
+ Creating an async Counter
178
+
179
+ ```typescript
180
+ getMetric("async-counter", {
181
+ attributeName: "scraped-memory",
182
+ metricName: "fastify-counter",
183
+ }).addCallback((observer) => {
184
+ observer.observe(freemem(), {
185
+ "application.os.memory": "free-memory",
186
+ });
187
+ });
188
+ ```
189
+
190
+ ## API Reference
191
+
192
+ #### Protocol
193
+
194
+ protocol is a string parameter used to define how to send signals to observability infrastructure
195
+
196
+ - **grpc** Use gRPC protocol, usually default port use 4317. Is the most performant option for server side applications.
197
+ - **http** Use HTTP standard protocol, usually default port use 4318. Mainly used on web or UI client applications.
198
+ - **console** Used for debugging sending signals to observability cluster, every information will be printed to your runtime console.
199
+
200
+ #### Shared Types
201
+
202
+ ```ts
203
+ export type SDKLogLevel =
204
+ | "NONE"
205
+ | "ERROR"
206
+ | "WARN"
207
+ | "INFO"
208
+ | "DEBUG"
209
+ | "VERBOSE"
210
+ | "ALL";
211
+ ```
212
+
213
+ ### Config
214
+
215
+ | Parameter | Type | Description |
216
+ | :-------------- | :---------------- | :------------------------------------------------------------------------------------------------------- |
217
+ | `collectorUrl` | `string` | **Required**. The opentelemetry collector entrypoint url, if null, instrumentation will not be activated |
218
+ | `serviceName` | `string` | Name of your application used for the collector to group logs |
219
+ | `diagLogLevel` | `SDKLogLevel` | Diagnostic log level for the internal runtime instrumentation |
220
+ | `collectorMode` | `single \| batch` | Signals sending mode, default is batch for performance |
221
+ | `enableFS` | `boolean` | Flag to enable or disable the tracing for node:fs module |
222
+ | `protocol` | `string` | Type of the protocol used to send signals |
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { NodeSDK } from "@opentelemetry/sdk-node";
2
- import type { NodeSDKConfig } from "./lib/index.js";
3
2
  import buildNodeInstrumentation from "./lib/instrumentation.node.js";
4
3
  export type * from "./lib/index.js";
5
- export type { NodeSDKConfig, NodeSDK };
4
+ export type { NodeSDK };
6
5
  export { buildNodeInstrumentation as instrumentNode };
6
+ export * from "./lib/metrics.js";
7
+ export * from "./lib/traces.js";
package/dist/index.js CHANGED
@@ -1,2 +1,4 @@
1
1
  import buildNodeInstrumentation from "./lib/instrumentation.node.js";
2
2
  export { buildNodeInstrumentation as instrumentNode };
3
+ export * from "./lib/metrics.js";
4
+ export * from "./lib/traces.js";
@@ -0,0 +1,3 @@
1
+ import { NodeSDKConfig } from "../index.js";
2
+ import { Exporters } from "./index.js";
3
+ export default function buildConsoleExporters(config: NodeSDKConfig): Exporters;
@@ -0,0 +1,20 @@
1
+ import { ConsoleLogRecordExporter, SimpleLogRecordProcessor, } from "@opentelemetry/sdk-logs";
2
+ import { metrics } from "@opentelemetry/sdk-node";
3
+ import { ConsoleSpanExporter, SimpleSpanProcessor, } from "@opentelemetry/sdk-trace-base";
4
+ import { EnrichSpanProcessor } from "../processor/enrich-span-processor.js";
5
+ import { EnrichLogProcessor } from "../processor/enrich-logger-processor.js";
6
+ export default function buildConsoleExporters(config) {
7
+ return {
8
+ spans: [
9
+ new SimpleSpanProcessor(new ConsoleSpanExporter()),
10
+ new EnrichSpanProcessor(config.spanAttributes),
11
+ ],
12
+ metrics: new metrics.PeriodicExportingMetricReader({
13
+ exporter: new metrics.ConsoleMetricExporter(),
14
+ }),
15
+ logs: [
16
+ new EnrichLogProcessor(config.spanAttributes),
17
+ new SimpleLogRecordProcessor(new ConsoleLogRecordExporter()),
18
+ ],
19
+ };
20
+ }
@@ -0,0 +1,3 @@
1
+ import { NodeSDKConfig } from "../index.js";
2
+ import { Exporters } from "./index.js";
3
+ export default function buildGrpcExporters(config: NodeSDKConfig): Promise<Exporters>;
@@ -0,0 +1,41 @@
1
+ import { metrics } from "@opentelemetry/sdk-node";
2
+ import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
3
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
4
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-grpc";
5
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-grpc";
6
+ import { LogRecordProcessorMap, SpanProcessorMap } from "../utils.js";
7
+ import { EnrichSpanProcessor } from "../processor/enrich-span-processor.js";
8
+ import { EnrichLogProcessor } from "../processor/enrich-logger-processor.js";
9
+ async function defaultMetadata() {
10
+ const { Metadata } = await import("@grpc/grpc-js");
11
+ return new Metadata({
12
+ waitForReady: true,
13
+ });
14
+ }
15
+ export default async function buildGrpcExporters(config) {
16
+ return {
17
+ spans: [
18
+ new SpanProcessorMap[config.collectorMode ?? "batch"](new OTLPTraceExporter({
19
+ url: `${config.collectorUrl}`,
20
+ compression: CompressionAlgorithm.GZIP,
21
+ metadata: config.grpcMetadata ?? (await defaultMetadata()),
22
+ })),
23
+ new EnrichSpanProcessor(config.spanAttributes),
24
+ ],
25
+ metrics: new metrics.PeriodicExportingMetricReader({
26
+ exporter: new OTLPMetricExporter({
27
+ url: `${config.collectorUrl}`,
28
+ compression: CompressionAlgorithm.GZIP,
29
+ metadata: config.grpcMetadata ?? (await defaultMetadata()),
30
+ }),
31
+ }),
32
+ logs: [
33
+ new EnrichLogProcessor(config.spanAttributes),
34
+ new LogRecordProcessorMap[config.collectorMode ?? "batch"](new OTLPLogExporter({
35
+ url: `${config.collectorUrl}`,
36
+ compression: CompressionAlgorithm.GZIP,
37
+ metadata: config.grpcMetadata ?? (await defaultMetadata()),
38
+ })),
39
+ ],
40
+ };
41
+ }
@@ -0,0 +1,3 @@
1
+ import { Exporters } from "./index.js";
2
+ import { NodeSDKConfig } from "../index.js";
3
+ export default function buildHttpExporters(config: NodeSDKConfig): Exporters;
@@ -1,25 +1,31 @@
1
- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
2
- import { LogRecordProcessorMap } from "./utils.js";
1
+ import { metrics } from "@opentelemetry/sdk-node";
3
2
  import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
4
- import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
5
- import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
3
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
6
4
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
5
+ import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
6
+ import { LogRecordProcessorMap, SpanProcessorMap } from "../utils.js";
7
+ import { EnrichSpanProcessor } from "../processor/enrich-span-processor.js";
8
+ import { EnrichLogProcessor } from "../processor/enrich-logger-processor.js";
7
9
  export default function buildHttpExporters(config) {
8
10
  if (config.collectorUrl.endsWith("/")) {
9
11
  config.collectorUrl = config.collectorUrl.slice(0, -1);
10
12
  }
11
13
  return {
12
- traces: new OTLPTraceExporter({
13
- url: `${config.collectorUrl}/v1/traces`,
14
- compression: CompressionAlgorithm.GZIP,
15
- }),
16
- metrics: new PeriodicExportingMetricReader({
14
+ spans: [
15
+ new SpanProcessorMap[config.collectorMode ?? "batch"](new OTLPTraceExporter({
16
+ url: `${config.collectorUrl}/v1/traces`,
17
+ compression: CompressionAlgorithm.GZIP,
18
+ })),
19
+ new EnrichSpanProcessor(config.spanAttributes),
20
+ ],
21
+ metrics: new metrics.PeriodicExportingMetricReader({
17
22
  exporter: new OTLPMetricExporter({
18
23
  url: `${config.collectorUrl}/v1/metrics`,
19
24
  compression: CompressionAlgorithm.GZIP,
20
25
  }),
21
26
  }),
22
27
  logs: [
28
+ new EnrichLogProcessor(config.spanAttributes),
23
29
  new LogRecordProcessorMap[config.collectorMode ?? "batch"](new OTLPLogExporter({
24
30
  url: `${config.collectorUrl}/v1/logs`,
25
31
  compression: CompressionAlgorithm.GZIP,
@@ -0,0 +1,8 @@
1
+ import { LogRecordProcessor } from "@opentelemetry/sdk-logs";
2
+ import type { metrics } from "@opentelemetry/sdk-node";
3
+ import { SpanProcessor } from "@opentelemetry/sdk-trace-base";
4
+ export type Exporters = {
5
+ spans: SpanProcessor[];
6
+ metrics: metrics.MetricReader;
7
+ logs: LogRecordProcessor[];
8
+ };
@@ -1,4 +1,5 @@
1
- interface SDKConfig {
1
+ import type { Metadata } from "@grpc/grpc-js";
2
+ export interface NodeSDKConfig {
2
3
  /**
3
4
  * The opentelemetry collector entrypoint GRPC url.
4
5
  * If the collectoUrl is null or undefined, the instrumentation will not be activated.
@@ -25,8 +26,27 @@ interface SDKConfig {
25
26
  * @default batch
26
27
  */
27
28
  collectorMode?: SDKCollectorMode;
28
- }
29
- export interface NodeSDKConfig extends SDKConfig {
29
+ /**
30
+ * Array of not traced urls.
31
+ *
32
+ * @type {SamplerCondition}
33
+ * @default []
34
+ */
35
+ ignoreUrls?: SamplerCondition[];
36
+ /**
37
+ * Object containing static properties or functions used to evaluate custom attributes for every logs and traces.
38
+ */
39
+ spanAttributes?: Record<string, SignalAttributeValue | (() => SignalAttributeValue)>;
40
+ /**
41
+ * Object containing static properties used as resources attributes for the Node SDK initialization.
42
+ */
43
+ resourceAttributes?: Record<string, SignalAttributeValue>;
44
+ /**
45
+ * Faction value from 0 to 1, used by TraceIdRatioBasedSampler which it deterministically samples a percentage of traces that you pass in as a parameter.
46
+ *
47
+ * @default 1
48
+ */
49
+ traceRatio?: number;
30
50
  /**
31
51
  * Flag to enable or disable the tracing for node:fs module
32
52
  *
@@ -34,13 +54,23 @@ export interface NodeSDKConfig extends SDKConfig {
34
54
  */
35
55
  enableFS?: boolean;
36
56
  /**
37
- * http based connection protocol used to send signals.
57
+ * Protocol used to send signals.
38
58
  *
39
59
  * @default grpc
40
60
  */
41
61
  protocol?: SDKProtocol;
62
+ /**
63
+ * Grpc Metadata for the grpc-js client.
64
+ *
65
+ * @default { waitForReady: true }
66
+ */
67
+ grpcMetadata?: Metadata;
68
+ }
69
+ export interface SamplerCondition {
70
+ type: "endsWith" | "includes" | "equals";
71
+ url: string;
42
72
  }
73
+ export type SignalAttributeValue = string | number | boolean;
43
74
  export type SDKCollectorMode = "single" | "batch";
44
- export type SDKProtocol = "grpc" | "http";
75
+ export type SDKProtocol = "grpc" | "http" | "console";
45
76
  export type SDKLogLevel = "NONE" | "ERROR" | "WARN" | "INFO" | "DEBUG" | "VERBOSE" | "ALL";
46
- export {};
@@ -1,3 +1,3 @@
1
1
  import { NodeSDK } from "@opentelemetry/sdk-node";
2
2
  import type { NodeSDKConfig } from "./index.js";
3
- export default function buildNodeInstrumentation(config?: NodeSDKConfig): NodeSDK | undefined;
3
+ export default function buildNodeInstrumentation(config?: NodeSDKConfig): Promise<NodeSDK | undefined>;
@@ -1,11 +1,14 @@
1
- import { NodeSDK } from "@opentelemetry/sdk-node";
2
- import isUrl from "is-url";
3
- import buildHttpExporters from "./http.js";
4
- import buildGrpcExporters from "./grpc.js";
5
1
  import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
6
2
  import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
7
3
  import { W3CTraceContextPropagator } from "@opentelemetry/core";
8
- export default function buildNodeInstrumentation(config) {
4
+ import { NodeSDK } from "@opentelemetry/sdk-node";
5
+ import { AlwaysOffSampler, ParentBasedSampler, TraceIdRatioBasedSampler, } from "@opentelemetry/sdk-trace-base";
6
+ import buildConsoleExporters from "./exporter/console.js";
7
+ import buildGrpcExporters from "./exporter/grpc.js";
8
+ import buildHttpExporters from "./exporter/http.js";
9
+ import { ObservabilityResourceDetector } from "./resource.js";
10
+ import { UrlSampler } from "./url-sampler.js";
11
+ export default async function buildNodeInstrumentation(config) {
9
12
  if (!config) {
10
13
  console.warn("observability config not set. Skipping NodeJS OpenTelemetry instrumentation.");
11
14
  return;
@@ -18,30 +21,42 @@ export default function buildNodeInstrumentation(config) {
18
21
  console.error("collectorUrl does not use a valid format. Skipping NodeJS OpenTelemetry instrumentation.");
19
22
  return;
20
23
  }
21
- let exporter;
22
- if (config.protocol === "http") {
23
- exporter = buildHttpExporters(config);
24
- }
25
- else {
26
- exporter = buildGrpcExporters(config);
27
- }
24
+ const urlSampler = new UrlSampler(config.ignoreUrls, new TraceIdRatioBasedSampler(config.traceRatio ?? 1));
25
+ const mainSampler = new ParentBasedSampler({
26
+ root: urlSampler,
27
+ remoteParentSampled: urlSampler,
28
+ remoteParentNotSampled: new AlwaysOffSampler(),
29
+ localParentSampled: urlSampler,
30
+ localParentNotSampled: new AlwaysOffSampler(),
31
+ });
32
+ diag.setLogger(new DiagConsoleLogger(), config.diagLogLevel ? DiagLogLevel[config.diagLogLevel] : DiagLogLevel.INFO);
28
33
  try {
29
- diag.setLogger(new DiagConsoleLogger(), config.diagLogLevel
30
- ? DiagLogLevel[config.diagLogLevel]
31
- : DiagLogLevel.INFO);
34
+ const nodeSdkInstrumentation = getNodeAutoInstrumentations({
35
+ "@opentelemetry/instrumentation-fs": {
36
+ enabled: config.enableFS ?? false,
37
+ },
38
+ });
39
+ let exporter;
40
+ if (config.protocol === "http") {
41
+ exporter = buildHttpExporters(config);
42
+ }
43
+ else if (config.protocol === "console") {
44
+ exporter = buildConsoleExporters(config);
45
+ }
46
+ else {
47
+ exporter = await buildGrpcExporters(config);
48
+ }
32
49
  const sdk = new NodeSDK({
50
+ resourceDetectors: [
51
+ new ObservabilityResourceDetector(config.resourceAttributes),
52
+ ],
53
+ spanProcessors: exporter.spans,
33
54
  serviceName: config.serviceName,
34
- traceExporter: exporter.traces,
35
55
  metricReader: exporter.metrics,
36
56
  logRecordProcessors: exporter.logs,
57
+ sampler: mainSampler,
37
58
  textMapPropagator: new W3CTraceContextPropagator(),
38
- instrumentations: [
39
- getNodeAutoInstrumentations({
40
- "@opentelemetry/instrumentation-fs": {
41
- enabled: config.enableFS ?? false,
42
- },
43
- }),
44
- ],
59
+ instrumentations: [nodeSdkInstrumentation],
45
60
  });
46
61
  sdk.start();
47
62
  console.log("NodeJS OpenTelemetry instrumentation started successfully.");
@@ -51,3 +66,12 @@ export default function buildNodeInstrumentation(config) {
51
66
  console.error("Error starting NodeJS OpenTelemetry instrumentation:", error);
52
67
  }
53
68
  }
69
+ function isUrl(url) {
70
+ try {
71
+ new URL(url);
72
+ return true;
73
+ }
74
+ catch (_) {
75
+ return false;
76
+ }
77
+ }
@@ -0,0 +1,18 @@
1
+ import { Counter, Gauge, Histogram, MetricOptions, ObservableCounter, ObservableGauge, ObservableUpDownCounter, UpDownCounter, Attributes } from "@opentelemetry/api";
2
+ type MetricTypeMap<TAttributes extends Attributes> = {
3
+ counter: Counter<TAttributes>;
4
+ histogram: Histogram<TAttributes>;
5
+ gauge: Gauge<TAttributes>;
6
+ updowncounter: UpDownCounter<TAttributes>;
7
+ "async-counter": ObservableCounter<TAttributes>;
8
+ "async-updowncounter": ObservableUpDownCounter<TAttributes>;
9
+ "async-gauge": ObservableGauge<TAttributes>;
10
+ };
11
+ export type MetricType = keyof MetricTypeMap<Attributes>;
12
+ export interface MetricsParams {
13
+ meterName: string;
14
+ metricName: string;
15
+ options?: MetricOptions;
16
+ }
17
+ export declare function getMetric<T extends MetricType, TAttributes extends Attributes = Attributes>(type: T, p: MetricsParams): MetricTypeMap<TAttributes>[T];
18
+ export {};
@@ -0,0 +1,24 @@
1
+ import { createNoopMeter, metrics, } from "@opentelemetry/api";
2
+ const MetricsFactoryMap = {
3
+ gauge: (meter) => meter.createGauge,
4
+ histogram: (meter) => meter.createHistogram,
5
+ counter: (meter) => meter.createCounter,
6
+ updowncounter: (meter) => meter.createUpDownCounter,
7
+ "async-counter": (meter) => meter.createObservableCounter,
8
+ "async-updowncounter": (meter) => meter.createObservableUpDownCounter,
9
+ "async-gauge": (meter) => meter.createObservableGauge,
10
+ };
11
+ function getMeter({ meterName }) {
12
+ if (!meterName) {
13
+ console.error("Invalid metric name!");
14
+ return createNoopMeter();
15
+ }
16
+ return metrics.getMeter(`custom_metric.${meterName}`);
17
+ }
18
+ export function getMetric(type, p) {
19
+ const meter = getMeter(p);
20
+ if (!MetricsFactoryMap[type]) {
21
+ throw new Error(`Unsupported metric type: ${type}`);
22
+ }
23
+ return MetricsFactoryMap[type](meter).bind(meter)(p.metricName, p.options);
24
+ }