@observantic/sdk 1.0.0
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/LICENSE +0 -0
- package/README.md +180 -0
- package/dist/index.cjs +375 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +159 -0
- package/dist/index.d.ts +159 -0
- package/dist/index.js +369 -0
- package/dist/index.js.map +1 -0
- package/package.json +69 -0
package/LICENSE
ADDED
|
File without changes
|
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# `@observantic/sdk`
|
|
2
|
+
|
|
3
|
+
> The official Node.js SDK and zero-friction OpenTelemetry auto-instrumentation package for the **Observantic** observability platform.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@observantic/sdk)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ⚡ Quick Start
|
|
11
|
+
|
|
12
|
+
### 1. Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @observantic/sdk
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### 2. Initialize in your application
|
|
19
|
+
|
|
20
|
+
Initialize `@observantic/sdk` at the **very top** of your application entry point before importing `express` or other modules:
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
import { initObservantic } from "@observantic/sdk";
|
|
24
|
+
|
|
25
|
+
initObservantic({
|
|
26
|
+
apiKey: "cw_live_sec_your_api_key_here",
|
|
27
|
+
endpoint: "https://api.observantic.com",
|
|
28
|
+
serviceName: "my-express-app",
|
|
29
|
+
environment: "production",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
import express from "express";
|
|
33
|
+
|
|
34
|
+
const app = express();
|
|
35
|
+
|
|
36
|
+
app.get("/users", (req, res) => {
|
|
37
|
+
res.json({ message: "Hello Observantic!" });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
app.listen(3000, () => console.log("Server running on port 3000"));
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## ⚙️ Configuration
|
|
46
|
+
|
|
47
|
+
### Programmatic Options (`ObservanticOptions`)
|
|
48
|
+
|
|
49
|
+
You can pass options directly into `initObservantic(options)`:
|
|
50
|
+
|
|
51
|
+
| Option | Type | Default | Description |
|
|
52
|
+
| :--- | :--- | :--- | :--- |
|
|
53
|
+
| `apiKey` | `string` | `process.env.OBSERVANTIC_API_KEY` | Ingestion API key for your Observantic workspace. |
|
|
54
|
+
| `endpoint` | `string` | `https://api.observantic.com` | Observantic base ingestion endpoint URL. |
|
|
55
|
+
| `serviceName` | `string` | `process.env.npm_package_name` \| `"node-service"` | Service name displayed in the Observantic dashboard. |
|
|
56
|
+
| `environment` | `string` | `process.env.NODE_ENV` \| `"development"` | Environment (e.g., `production`, `staging`). |
|
|
57
|
+
| `serviceVersion` | `string` | `process.env.npm_package_version` \| `"1.0.0"` | Version of your application. |
|
|
58
|
+
| `traceSampleRate` | `number` | `1.0` | Sampling ratio from `0.0` (0%) to `1.0` (100%). |
|
|
59
|
+
| `autoShutdown` | `boolean` | `true` | Automatically flush telemetry on `SIGTERM` and `SIGINT`. |
|
|
60
|
+
| `debug` | `boolean` | `false` | Enable OpenTelemetry internal diagnostic logging. |
|
|
61
|
+
| `disabled` | `boolean` | `false` | Disable all telemetry collection (e.g. in unit tests). |
|
|
62
|
+
| `headers` | `Record<string, string>` | `{}` | Custom HTTP headers sent to the OTLP exporter. |
|
|
63
|
+
| `resourceAttributes` | `Record<string, any>` | `{}` | Custom resource attributes attached to all spans/metrics/logs. |
|
|
64
|
+
| `batchTimeoutMillis` | `number` | `5000` | Batch delay before flushing spans. |
|
|
65
|
+
| `signals` | `{ traces?, metrics?, logs? }` | All `true` | Selectively enable or disable individual telemetry signals. |
|
|
66
|
+
|
|
67
|
+
### Environment Variables
|
|
68
|
+
|
|
69
|
+
Alternatively, configure the SDK entirely through environment variables without hardcoding secrets:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Required authentication
|
|
73
|
+
export OBSERVANTIC_API_KEY="cw_live_sec_xxxxx"
|
|
74
|
+
|
|
75
|
+
# Optional overrides
|
|
76
|
+
export OBSERVANTIC_ENDPOINT="https://api.observantic.com"
|
|
77
|
+
export OBSERVANTIC_SERVICE_NAME="auth-service"
|
|
78
|
+
export OBSERVANTIC_ENVIRONMENT="production"
|
|
79
|
+
export OBSERVANTIC_SERVICE_VERSION="2.4.0"
|
|
80
|
+
export OBSERVANTIC_TRACE_SAMPLE_RATE="1.0"
|
|
81
|
+
export OBSERVANTIC_DEBUG="false"
|
|
82
|
+
export OBSERVANTIC_DISABLED="false"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Then initialize with zero arguments:
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
import { initObservantic } from "@observantic/sdk";
|
|
89
|
+
|
|
90
|
+
initObservantic();
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 🔍 Features
|
|
96
|
+
|
|
97
|
+
### 🚀 Express & Node.js Auto-Instrumentation
|
|
98
|
+
Automatically instruments HTTP requests, routes, middleware, and database operations without requiring manual span creation:
|
|
99
|
+
- Preserves **Trace ID** & **Span ID** across asynchronous workflows.
|
|
100
|
+
- Captures HTTP method, status codes, route templates, client IP, and query parameters.
|
|
101
|
+
- Records unhandled exceptions and errors automatically.
|
|
102
|
+
|
|
103
|
+
### 📊 Custom Tracing & OpenTelemetry API Re-exports
|
|
104
|
+
`@observantic/sdk` re-exports standard OpenTelemetry APIs (`trace`, `context`, `metrics`, `logs`, `SpanStatusCode`, `SpanKind`) so you don't need additional dependencies for manual instrumentation:
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
import { initObservantic, trace, SpanStatusCode } from "@observantic/sdk";
|
|
108
|
+
|
|
109
|
+
const client = initObservantic({ apiKey: "cw_live_sec_..." });
|
|
110
|
+
const tracer = client.getTracer("order-processor");
|
|
111
|
+
|
|
112
|
+
async function processOrder(orderId) {
|
|
113
|
+
return await tracer.startActiveSpan("order.process", async (span) => {
|
|
114
|
+
try {
|
|
115
|
+
span.setAttribute("order.id", orderId);
|
|
116
|
+
span.setAttribute("order.amount", 99.99);
|
|
117
|
+
|
|
118
|
+
// Business logic
|
|
119
|
+
const result = await saveToDatabase(orderId);
|
|
120
|
+
return result;
|
|
121
|
+
} catch (err) {
|
|
122
|
+
span.recordException(err);
|
|
123
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
|
|
124
|
+
throw err;
|
|
125
|
+
} finally {
|
|
126
|
+
span.end();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 📈 Custom Metrics
|
|
133
|
+
```javascript
|
|
134
|
+
import { metrics } from "@observantic/sdk";
|
|
135
|
+
|
|
136
|
+
const meter = metrics.getMeter("order-service");
|
|
137
|
+
const orderCounter = meter.createCounter("orders_total", {
|
|
138
|
+
description: "Total number of completed orders",
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
orderCounter.add(1, { "order.type": "subscription" });
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 🛑 Graceful Shutdown
|
|
145
|
+
The SDK automatically registers shutdown handlers for `SIGTERM` and `SIGINT` to ensure all in-flight spans and metrics are flushed to Observantic before process exit.
|
|
146
|
+
|
|
147
|
+
You can also trigger shutdown manually:
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
import { shutdownObservantic } from "@observantic/sdk";
|
|
151
|
+
|
|
152
|
+
await shutdownObservantic();
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🏗 Architecture
|
|
158
|
+
|
|
159
|
+
```text
|
|
160
|
+
User Application (Express / Node.js)
|
|
161
|
+
↓
|
|
162
|
+
@observantic/sdk (initObservantic)
|
|
163
|
+
↓
|
|
164
|
+
OpenTelemetry NodeSDK
|
|
165
|
+
↓
|
|
166
|
+
OTLP HTTP Exporters (Traces, Logs, Metrics)
|
|
167
|
+
↓ (HTTP POST + Bearer Auth)
|
|
168
|
+
Observantic Ingestion (/v1/traces, /v1/logs, /v1/metrics)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- Standard OpenTelemetry protocol (OTLP/HTTP).
|
|
172
|
+
- Ingestion token sent via `Authorization: Bearer <apiKey>` and `x-cw-token: <apiKey>` headers.
|
|
173
|
+
- Zero vendor lock-in: compatible with the entire OpenTelemetry ecosystem.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## 📄 License
|
|
178
|
+
|
|
179
|
+
Apache-2.0
|
|
180
|
+
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
SpanKind: () => import_api2.SpanKind,
|
|
24
|
+
SpanStatusCode: () => import_api2.SpanStatusCode,
|
|
25
|
+
context: () => import_api2.context,
|
|
26
|
+
initObservantic: () => initObservantic,
|
|
27
|
+
logs: () => import_api_logs2.logs,
|
|
28
|
+
metrics: () => import_api2.metrics,
|
|
29
|
+
normalizeEndpoints: () => normalizeEndpoints,
|
|
30
|
+
resolveConfig: () => resolveConfig,
|
|
31
|
+
shutdownObservantic: () => shutdownObservantic,
|
|
32
|
+
trace: () => import_api2.trace
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
var import_sdk_node = require("@opentelemetry/sdk-node");
|
|
36
|
+
var import_api2 = require("@opentelemetry/api");
|
|
37
|
+
var import_api_logs = require("@opentelemetry/api-logs");
|
|
38
|
+
|
|
39
|
+
// src/config.ts
|
|
40
|
+
function normalizeEndpoints(baseEndpoint) {
|
|
41
|
+
let cleaned = (baseEndpoint || "https://api.observantic.com").trim();
|
|
42
|
+
cleaned = cleaned.replace(/\/+$/, "");
|
|
43
|
+
if (cleaned.endsWith("/v1/traces")) {
|
|
44
|
+
const root = cleaned.slice(0, -"/v1/traces".length);
|
|
45
|
+
return {
|
|
46
|
+
endpoint: root,
|
|
47
|
+
tracesEndpoint: cleaned,
|
|
48
|
+
metricsEndpoint: `${root}/v1/metrics`,
|
|
49
|
+
logsEndpoint: `${root}/v1/logs`
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (cleaned.endsWith("/v1")) {
|
|
53
|
+
return {
|
|
54
|
+
endpoint: cleaned,
|
|
55
|
+
tracesEndpoint: `${cleaned}/traces`,
|
|
56
|
+
metricsEndpoint: `${cleaned}/metrics`,
|
|
57
|
+
logsEndpoint: `${cleaned}/logs`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
endpoint: cleaned,
|
|
62
|
+
tracesEndpoint: `${cleaned}/v1/traces`,
|
|
63
|
+
metricsEndpoint: `${cleaned}/v1/metrics`,
|
|
64
|
+
logsEndpoint: `${cleaned}/v1/logs`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function parseOtelHeaders(headerStr) {
|
|
68
|
+
if (!headerStr) return {};
|
|
69
|
+
const headers = {};
|
|
70
|
+
const pairs = headerStr.split(",");
|
|
71
|
+
for (const pair of pairs) {
|
|
72
|
+
const idx = pair.indexOf("=");
|
|
73
|
+
if (idx > 0) {
|
|
74
|
+
const key = pair.substring(0, idx).trim();
|
|
75
|
+
const val = pair.substring(idx + 1).trim();
|
|
76
|
+
if (key) headers[key] = val;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return headers;
|
|
80
|
+
}
|
|
81
|
+
function resolveConfig(options = {}) {
|
|
82
|
+
const env = process.env;
|
|
83
|
+
const apiKey = options.apiKey || env.OBSERVANTIC_API_KEY || "";
|
|
84
|
+
const rawEndpoint = options.endpoint || env.OBSERVANTIC_ENDPOINT || env.OTEL_EXPORTER_OTLP_ENDPOINT || "https://api.observantic.com";
|
|
85
|
+
const { endpoint, tracesEndpoint, metricsEndpoint, logsEndpoint } = normalizeEndpoints(rawEndpoint);
|
|
86
|
+
const serviceName = options.serviceName || env.OBSERVANTIC_SERVICE_NAME || env.OTEL_SERVICE_NAME || env.npm_package_name || process.title || "node-service";
|
|
87
|
+
const environment = options.environment || env.OBSERVANTIC_ENVIRONMENT || env.NODE_ENV || "development";
|
|
88
|
+
const serviceVersion = options.serviceVersion || env.OBSERVANTIC_SERVICE_VERSION || env.npm_package_version || "1.0.0";
|
|
89
|
+
const disabled = options.disabled !== void 0 ? options.disabled : env.OBSERVANTIC_DISABLED === "true" || env.OTEL_SDK_DISABLED === "true";
|
|
90
|
+
const debug = options.debug !== void 0 ? options.debug : env.OBSERVANTIC_DEBUG === "true" || env.OTEL_LOG_LEVEL === "debug";
|
|
91
|
+
const autoShutdown = options.autoShutdown !== void 0 ? options.autoShutdown : true;
|
|
92
|
+
const traceSampleRate = options.traceSampleRate !== void 0 ? Math.max(0, Math.min(1, options.traceSampleRate)) : env.OBSERVANTIC_TRACE_SAMPLE_RATE ? parseFloat(env.OBSERVANTIC_TRACE_SAMPLE_RATE) : 1;
|
|
93
|
+
const envHeaders = parseOtelHeaders(env.OTEL_EXPORTER_OTLP_HEADERS);
|
|
94
|
+
const headers = {
|
|
95
|
+
...envHeaders,
|
|
96
|
+
...options.headers || {}
|
|
97
|
+
};
|
|
98
|
+
if (apiKey) {
|
|
99
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
100
|
+
headers["x-cw-token"] = apiKey;
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
apiKey,
|
|
104
|
+
endpoint,
|
|
105
|
+
tracesEndpoint,
|
|
106
|
+
metricsEndpoint,
|
|
107
|
+
logsEndpoint,
|
|
108
|
+
serviceName,
|
|
109
|
+
environment,
|
|
110
|
+
serviceVersion,
|
|
111
|
+
resourceAttributes: options.resourceAttributes || {},
|
|
112
|
+
headers,
|
|
113
|
+
disabled,
|
|
114
|
+
debug,
|
|
115
|
+
autoShutdown,
|
|
116
|
+
traceSampleRate,
|
|
117
|
+
batchTimeoutMillis: options.batchTimeoutMillis || 5e3,
|
|
118
|
+
maxQueueSize: options.maxQueueSize || 2048,
|
|
119
|
+
maxExportBatchSize: options.maxExportBatchSize || 512,
|
|
120
|
+
metricExportIntervalMillis: options.metricExportIntervalMillis || 6e4,
|
|
121
|
+
signals: {
|
|
122
|
+
traces: options.signals?.traces !== false,
|
|
123
|
+
metrics: options.signals?.metrics !== false,
|
|
124
|
+
logs: options.signals?.logs !== false
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/resource.ts
|
|
130
|
+
var import_resources = require("@opentelemetry/resources");
|
|
131
|
+
var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
|
|
132
|
+
function createResource(config) {
|
|
133
|
+
const customAttributes = {
|
|
134
|
+
[import_semantic_conventions.SEMRESATTRS_SERVICE_NAME]: config.serviceName,
|
|
135
|
+
[import_semantic_conventions.SEMRESATTRS_SERVICE_VERSION]: config.serviceVersion,
|
|
136
|
+
[import_semantic_conventions.SEMRESATTRS_DEPLOYMENT_ENVIRONMENT]: config.environment,
|
|
137
|
+
[import_semantic_conventions.SEMRESATTRS_TELEMETRY_SDK_NAME]: "@observantic/sdk",
|
|
138
|
+
[import_semantic_conventions.SEMRESATTRS_TELEMETRY_SDK_LANGUAGE]: "nodejs",
|
|
139
|
+
[import_semantic_conventions.SEMRESATTRS_TELEMETRY_SDK_VERSION]: "1.0.0",
|
|
140
|
+
[import_semantic_conventions.SEMRESATTRS_PROCESS_PID]: process.pid,
|
|
141
|
+
[import_semantic_conventions.SEMRESATTRS_PROCESS_RUNTIME_NAME]: "nodejs",
|
|
142
|
+
[import_semantic_conventions.SEMRESATTRS_PROCESS_RUNTIME_VERSION]: process.version,
|
|
143
|
+
...config.resourceAttributes
|
|
144
|
+
};
|
|
145
|
+
return new import_resources.Resource(customAttributes);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/tracing.ts
|
|
149
|
+
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
|
150
|
+
var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
|
|
151
|
+
function createTraceExporter(config) {
|
|
152
|
+
return new import_exporter_trace_otlp_http.OTLPTraceExporter({
|
|
153
|
+
url: config.tracesEndpoint,
|
|
154
|
+
headers: config.headers,
|
|
155
|
+
timeoutMillis: 1e4
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
function createSampler(sampleRate) {
|
|
159
|
+
if (sampleRate >= 1) {
|
|
160
|
+
return new import_sdk_trace_base.ParentBasedSampler({ root: new import_sdk_trace_base.AlwaysOnSampler() });
|
|
161
|
+
}
|
|
162
|
+
if (sampleRate <= 0) {
|
|
163
|
+
return new import_sdk_trace_base.ParentBasedSampler({ root: new import_sdk_trace_base.AlwaysOffSampler() });
|
|
164
|
+
}
|
|
165
|
+
return new import_sdk_trace_base.ParentBasedSampler({
|
|
166
|
+
root: new import_sdk_trace_base.TraceIdRatioBasedSampler(sampleRate)
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function createSpanProcessor(exporter, config) {
|
|
170
|
+
return new import_sdk_trace_base.BatchSpanProcessor(exporter, {
|
|
171
|
+
maxQueueSize: config.maxQueueSize,
|
|
172
|
+
maxExportBatchSize: config.maxExportBatchSize,
|
|
173
|
+
scheduledDelayMillis: config.batchTimeoutMillis,
|
|
174
|
+
exportTimeoutMillis: 1e4
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/metrics.ts
|
|
179
|
+
var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
|
|
180
|
+
var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
|
|
181
|
+
function createMetricExporter(config) {
|
|
182
|
+
return new import_exporter_metrics_otlp_http.OTLPMetricExporter({
|
|
183
|
+
url: config.metricsEndpoint,
|
|
184
|
+
headers: config.headers,
|
|
185
|
+
timeoutMillis: 1e4,
|
|
186
|
+
temporalityPreference: import_sdk_metrics.AggregationTemporality.DELTA
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
function createMetricReader(exporter, config) {
|
|
190
|
+
return new import_sdk_metrics.PeriodicExportingMetricReader({
|
|
191
|
+
exporter,
|
|
192
|
+
exportIntervalMillis: config.metricExportIntervalMillis,
|
|
193
|
+
exportTimeoutMillis: 1e4
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// src/logging.ts
|
|
198
|
+
var import_exporter_logs_otlp_http = require("@opentelemetry/exporter-logs-otlp-http");
|
|
199
|
+
var import_sdk_logs = require("@opentelemetry/sdk-logs");
|
|
200
|
+
function createLogExporter(config) {
|
|
201
|
+
return new import_exporter_logs_otlp_http.OTLPLogExporter({
|
|
202
|
+
url: config.logsEndpoint,
|
|
203
|
+
headers: config.headers,
|
|
204
|
+
timeoutMillis: 1e4
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function createLogRecordProcessor(exporter, config) {
|
|
208
|
+
return new import_sdk_logs.BatchLogRecordProcessor(exporter, {
|
|
209
|
+
maxQueueSize: config.maxQueueSize,
|
|
210
|
+
maxExportBatchSize: config.maxExportBatchSize,
|
|
211
|
+
scheduledDelayMillis: config.batchTimeoutMillis,
|
|
212
|
+
exportTimeoutMillis: 1e4
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/instrumentation.ts
|
|
217
|
+
var import_auto_instrumentations_node = require("@opentelemetry/auto-instrumentations-node");
|
|
218
|
+
function createInstrumentations(_config) {
|
|
219
|
+
return [
|
|
220
|
+
(0, import_auto_instrumentations_node.getNodeAutoInstrumentations)({
|
|
221
|
+
"@opentelemetry/instrumentation-fs": {
|
|
222
|
+
// Disable noisy fs hooks by default to prevent span flooding
|
|
223
|
+
enabled: false
|
|
224
|
+
},
|
|
225
|
+
"@opentelemetry/instrumentation-http": {
|
|
226
|
+
enabled: true
|
|
227
|
+
},
|
|
228
|
+
"@opentelemetry/instrumentation-express": {
|
|
229
|
+
enabled: true
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/shutdown.ts
|
|
236
|
+
var import_api = require("@opentelemetry/api");
|
|
237
|
+
var activeSdk = null;
|
|
238
|
+
var isShuttingDown = false;
|
|
239
|
+
var isSignalHandlerRegistered = false;
|
|
240
|
+
function registerSdk(sdk) {
|
|
241
|
+
activeSdk = sdk;
|
|
242
|
+
}
|
|
243
|
+
async function shutdownObservantic() {
|
|
244
|
+
if (!activeSdk) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (isShuttingDown) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
isShuttingDown = true;
|
|
251
|
+
import_api.diag.info("Shutting down Observantic OpenTelemetry SDK...");
|
|
252
|
+
try {
|
|
253
|
+
await activeSdk.shutdown();
|
|
254
|
+
import_api.diag.info("Observantic OpenTelemetry SDK terminated successfully.");
|
|
255
|
+
} catch (err) {
|
|
256
|
+
import_api.diag.error("Error shutting down Observantic OpenTelemetry SDK", err);
|
|
257
|
+
throw err;
|
|
258
|
+
} finally {
|
|
259
|
+
activeSdk = null;
|
|
260
|
+
isShuttingDown = false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function installShutdownHooks(sdk) {
|
|
264
|
+
registerSdk(sdk);
|
|
265
|
+
if (isSignalHandlerRegistered) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const handleSignal = async (signal) => {
|
|
269
|
+
import_api.diag.info(`Received ${signal}, gracefully shutting down Observantic telemetry...`);
|
|
270
|
+
try {
|
|
271
|
+
await shutdownObservantic();
|
|
272
|
+
} catch (err) {
|
|
273
|
+
import_api.diag.error(`Failed to flush telemetry on ${signal}:`, err);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
process.once("SIGTERM", () => void handleSignal("SIGTERM"));
|
|
277
|
+
process.once("SIGINT", () => void handleSignal("SIGINT"));
|
|
278
|
+
isSignalHandlerRegistered = true;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/index.ts
|
|
282
|
+
var import_api_logs2 = require("@opentelemetry/api-logs");
|
|
283
|
+
var isInitialized = false;
|
|
284
|
+
function initObservantic(options = {}) {
|
|
285
|
+
const config = resolveConfig(options);
|
|
286
|
+
if (config.debug) {
|
|
287
|
+
import_api2.diag.setLogger(new import_api2.DiagConsoleLogger(), import_api2.DiagLogLevel.DEBUG);
|
|
288
|
+
}
|
|
289
|
+
if (config.disabled) {
|
|
290
|
+
import_api2.diag.info("[@observantic/node] Telemetry is disabled via configuration.");
|
|
291
|
+
return {
|
|
292
|
+
sdk: null,
|
|
293
|
+
config,
|
|
294
|
+
shutdown: async () => {
|
|
295
|
+
},
|
|
296
|
+
getTracer: (name = "observantic", version = "1.0.0") => import_api2.trace.getTracer(name, version),
|
|
297
|
+
getMeter: (name = "observantic", version = "1.0.0") => import_api2.metrics.getMeter(name, version),
|
|
298
|
+
getLogger: (name = "observantic", version = "1.0.0") => import_api_logs.logs.getLogger(name, version)
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
if (!config.apiKey) {
|
|
302
|
+
console.warn(
|
|
303
|
+
"[@observantic/node] Warning: No apiKey provided. Please provide an apiKey in initObservantic({ apiKey }) or set the OBSERVANTIC_API_KEY environment variable."
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
if (isInitialized) {
|
|
307
|
+
import_api2.diag.warn("[@observantic/node] initObservantic was called multiple times. Returning existing client.");
|
|
308
|
+
return {
|
|
309
|
+
sdk: null,
|
|
310
|
+
config,
|
|
311
|
+
shutdown: shutdownObservantic,
|
|
312
|
+
getTracer: (name = "observantic", version = "1.0.0") => import_api2.trace.getTracer(name, version),
|
|
313
|
+
getMeter: (name = "observantic", version = "1.0.0") => import_api2.metrics.getMeter(name, version),
|
|
314
|
+
getLogger: (name = "observantic", version = "1.0.0") => import_api_logs.logs.getLogger(name, version)
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
const resource = createResource(config);
|
|
318
|
+
const sdkConfig = {
|
|
319
|
+
resource,
|
|
320
|
+
instrumentations: createInstrumentations(config)
|
|
321
|
+
};
|
|
322
|
+
if (config.signals.traces) {
|
|
323
|
+
const traceExporter = createTraceExporter(config);
|
|
324
|
+
const spanProcessor = createSpanProcessor(traceExporter, config);
|
|
325
|
+
const sampler = createSampler(config.traceSampleRate);
|
|
326
|
+
sdkConfig.spanProcessor = spanProcessor;
|
|
327
|
+
sdkConfig.sampler = sampler;
|
|
328
|
+
}
|
|
329
|
+
if (config.signals.metrics) {
|
|
330
|
+
const metricExporter = createMetricExporter(config);
|
|
331
|
+
const metricReader = createMetricReader(metricExporter, config);
|
|
332
|
+
sdkConfig.metricReader = metricReader;
|
|
333
|
+
}
|
|
334
|
+
if (config.signals.logs) {
|
|
335
|
+
const logExporter = createLogExporter(config);
|
|
336
|
+
const logRecordProcessor = createLogRecordProcessor(logExporter, config);
|
|
337
|
+
sdkConfig.logRecordProcessor = logRecordProcessor;
|
|
338
|
+
}
|
|
339
|
+
const sdk = new import_sdk_node.NodeSDK(sdkConfig);
|
|
340
|
+
try {
|
|
341
|
+
sdk.start();
|
|
342
|
+
isInitialized = true;
|
|
343
|
+
import_api2.diag.info(`[@observantic/node] Initialized successfully for service: "${config.serviceName}" [${config.environment}]`);
|
|
344
|
+
if (config.autoShutdown) {
|
|
345
|
+
installShutdownHooks(sdk);
|
|
346
|
+
} else {
|
|
347
|
+
registerSdk(sdk);
|
|
348
|
+
}
|
|
349
|
+
} catch (err) {
|
|
350
|
+
import_api2.diag.error("[@observantic/node] Failed to start OpenTelemetry NodeSDK:", err);
|
|
351
|
+
throw err;
|
|
352
|
+
}
|
|
353
|
+
return {
|
|
354
|
+
sdk,
|
|
355
|
+
config,
|
|
356
|
+
shutdown: shutdownObservantic,
|
|
357
|
+
getTracer: (name = config.serviceName, version = config.serviceVersion) => import_api2.trace.getTracer(name, version),
|
|
358
|
+
getMeter: (name = config.serviceName, version = config.serviceVersion) => import_api2.metrics.getMeter(name, version),
|
|
359
|
+
getLogger: (name = config.serviceName, version = config.serviceVersion) => import_api_logs.logs.getLogger(name, version)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
363
|
+
0 && (module.exports = {
|
|
364
|
+
SpanKind,
|
|
365
|
+
SpanStatusCode,
|
|
366
|
+
context,
|
|
367
|
+
initObservantic,
|
|
368
|
+
logs,
|
|
369
|
+
metrics,
|
|
370
|
+
normalizeEndpoints,
|
|
371
|
+
resolveConfig,
|
|
372
|
+
shutdownObservantic,
|
|
373
|
+
trace
|
|
374
|
+
});
|
|
375
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/resource.ts","../src/tracing.ts","../src/metrics.ts","../src/logging.ts","../src/instrumentation.ts","../src/shutdown.ts"],"sourcesContent":["import { NodeSDK } from \"@opentelemetry/sdk-node\";\nimport {\n diag,\n DiagConsoleLogger,\n DiagLogLevel,\n trace,\n context,\n metrics,\n SpanStatusCode,\n SpanKind,\n Tracer,\n Meter,\n} from \"@opentelemetry/api\";\nimport { logs, Logger } from \"@opentelemetry/api-logs\";\n\nimport {\n ObservanticOptions,\n ResolvedObservanticConfig,\n resolveConfig,\n normalizeEndpoints,\n} from \"./config.js\";\nimport { createResource } from \"./resource.js\";\nimport {\n createTraceExporter,\n createSpanProcessor,\n createSampler,\n} from \"./tracing.js\";\nimport { createMetricExporter, createMetricReader } from \"./metrics.js\";\nimport { createLogExporter, createLogRecordProcessor } from \"./logging.js\";\nimport { createInstrumentations } from \"./instrumentation.js\";\nimport {\n shutdownObservantic,\n installShutdownHooks,\n registerSdk,\n} from \"./shutdown.js\";\n\nexport interface ObservanticClient {\n sdk: NodeSDK | null;\n config: ResolvedObservanticConfig;\n shutdown: () => Promise<void>;\n getTracer: (name?: string, version?: string) => Tracer;\n getMeter: (name?: string, version?: string) => Meter;\n getLogger: (name?: string, version?: string) => Logger;\n}\n\nlet isInitialized = false;\n\n/**\n * Initializes Observantic OpenTelemetry instrumentation for Node.js and Express.\n *\n * @example\n * ```ts\n * import { initObservantic } from \"@observantic/node\";\n *\n * initObservantic({\n * apiKey: \"cw_live_sec_xxxxx\",\n * endpoint: \"https://api.observantic.com\",\n * serviceName: \"my-express-app\"\n * });\n * ```\n */\nexport function initObservantic(options: ObservanticOptions = {}): ObservanticClient {\n const config = resolveConfig(options);\n\n if (config.debug) {\n diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);\n }\n\n if (config.disabled) {\n diag.info(\"[@observantic/node] Telemetry is disabled via configuration.\");\n return {\n sdk: null,\n config,\n shutdown: async () => {},\n getTracer: (name = \"observantic\", version = \"1.0.0\") => trace.getTracer(name, version),\n getMeter: (name = \"observantic\", version = \"1.0.0\") => metrics.getMeter(name, version),\n getLogger: (name = \"observantic\", version = \"1.0.0\") => logs.getLogger(name, version),\n };\n }\n\n if (!config.apiKey) {\n console.warn(\n \"[@observantic/node] Warning: No apiKey provided. Please provide an apiKey in initObservantic({ apiKey }) or set the OBSERVANTIC_API_KEY environment variable.\"\n );\n }\n\n if (isInitialized) {\n diag.warn(\"[@observantic/node] initObservantic was called multiple times. Returning existing client.\");\n return {\n sdk: null,\n config,\n shutdown: shutdownObservantic,\n getTracer: (name = \"observantic\", version = \"1.0.0\") => trace.getTracer(name, version),\n getMeter: (name = \"observantic\", version = \"1.0.0\") => metrics.getMeter(name, version),\n getLogger: (name = \"observantic\", version = \"1.0.0\") => logs.getLogger(name, version),\n };\n }\n\n const resource = createResource(config);\n\n const sdkConfig: any = {\n resource,\n instrumentations: createInstrumentations(config),\n };\n\n // Configure Tracing\n if (config.signals.traces) {\n const traceExporter = createTraceExporter(config);\n const spanProcessor = createSpanProcessor(traceExporter, config);\n const sampler = createSampler(config.traceSampleRate);\n\n sdkConfig.spanProcessor = spanProcessor;\n sdkConfig.sampler = sampler;\n }\n\n // Configure Metrics\n if (config.signals.metrics) {\n const metricExporter = createMetricExporter(config);\n const metricReader = createMetricReader(metricExporter, config);\n sdkConfig.metricReader = metricReader;\n }\n\n // Configure Logs\n if (config.signals.logs) {\n const logExporter = createLogExporter(config);\n const logRecordProcessor = createLogRecordProcessor(logExporter, config);\n sdkConfig.logRecordProcessor = logRecordProcessor;\n }\n\n const sdk = new NodeSDK(sdkConfig);\n\n try {\n sdk.start();\n isInitialized = true;\n diag.info(`[@observantic/node] Initialized successfully for service: \"${config.serviceName}\" [${config.environment}]`);\n\n if (config.autoShutdown) {\n installShutdownHooks(sdk);\n } else {\n registerSdk(sdk);\n }\n } catch (err) {\n diag.error(\"[@observantic/node] Failed to start OpenTelemetry NodeSDK:\", err);\n throw err;\n }\n\n return {\n sdk,\n config,\n shutdown: shutdownObservantic,\n getTracer: (name = config.serviceName, version = config.serviceVersion) =>\n trace.getTracer(name, version),\n getMeter: (name = config.serviceName, version = config.serviceVersion) =>\n metrics.getMeter(name, version),\n getLogger: (name = config.serviceName, version = config.serviceVersion) =>\n logs.getLogger(name, version),\n };\n}\n\n// Export lifecycle methods\nexport { shutdownObservantic };\n\n// Export configuration helpers & types\nexport type { ObservanticOptions, ResolvedObservanticConfig };\nexport { resolveConfig, normalizeEndpoints };\n\n// Re-export standard OpenTelemetry APIs for convenience\nexport {\n trace,\n context,\n metrics,\n SpanStatusCode,\n SpanKind,\n};\nexport { logs } from \"@opentelemetry/api-logs\";\n\n","export interface ObservanticOptions {\n /**\n * Ingestion API key for your Observantic workspace.\n * Defaults to process.env.OBSERVANTIC_API_KEY.\n */\n apiKey?: string;\n\n /**\n * Observantic ingestion base endpoint URL.\n * Defaults to process.env.OBSERVANTIC_ENDPOINT or \"https://api.observantic.com\".\n */\n endpoint?: string;\n\n /**\n * Name of your application service.\n * Defaults to process.env.OBSERVANTIC_SERVICE_NAME, process.env.OTEL_SERVICE_NAME,\n * process.env.npm_package_name, or \"node-service\".\n */\n serviceName?: string;\n\n /**\n * Deployment environment (e.g., \"production\", \"staging\", \"development\").\n * Defaults to process.env.OBSERVANTIC_ENVIRONMENT, process.env.NODE_ENV, or \"development\".\n */\n environment?: string;\n\n /**\n * Version of your application.\n * Defaults to process.env.OBSERVANTIC_SERVICE_VERSION, process.env.npm_package_version, or \"1.0.0\".\n */\n serviceVersion?: string;\n\n /**\n * Custom resource attributes to attach to all telemetry (traces, metrics, logs).\n */\n resourceAttributes?: Record<string, string | number | boolean>;\n\n /**\n * Additional HTTP headers to attach to OTLP export requests.\n */\n headers?: Record<string, string>;\n\n /**\n * Disable telemetry collection entirely (useful in test or CI environments).\n * Defaults to process.env.OBSERVANTIC_DISABLED === \"true\".\n */\n disabled?: boolean;\n\n /**\n * Enable verbose OpenTelemetry internal diagnostic logging.\n * Defaults to process.env.OBSERVANTIC_DEBUG === \"true\".\n */\n debug?: boolean;\n\n /**\n * Automatically install graceful shutdown hooks for SIGINT and SIGTERM.\n * Defaults to true.\n */\n autoShutdown?: boolean;\n\n /**\n * Sampling ratio for traces from 0.0 (0%) to 1.0 (100%).\n * Defaults to 1.0.\n */\n traceSampleRate?: number;\n\n /**\n * Batch span export timeout in milliseconds.\n * Defaults to 5000ms.\n */\n batchTimeoutMillis?: number;\n\n /**\n * Maximum queue size for spans and logs waiting to be exported.\n * Defaults to 2048.\n */\n maxQueueSize?: number;\n\n /**\n * Maximum batch size per export request.\n * Defaults to 512.\n */\n maxExportBatchSize?: number;\n\n /**\n * Metrics periodic export interval in milliseconds.\n * Defaults to 60000ms (60s).\n */\n metricExportIntervalMillis?: number;\n\n /**\n * Enable or disable individual telemetry signals.\n */\n signals?: {\n traces?: boolean;\n metrics?: boolean;\n logs?: boolean;\n };\n}\n\nexport interface ResolvedObservanticConfig {\n apiKey: string;\n endpoint: string;\n tracesEndpoint: string;\n metricsEndpoint: string;\n logsEndpoint: string;\n serviceName: string;\n environment: string;\n serviceVersion: string;\n resourceAttributes: Record<string, string | number | boolean>;\n headers: Record<string, string>;\n disabled: boolean;\n debug: boolean;\n autoShutdown: boolean;\n traceSampleRate: number;\n batchTimeoutMillis: number;\n maxQueueSize: number;\n maxExportBatchSize: number;\n metricExportIntervalMillis: number;\n signals: {\n traces: boolean;\n metrics: boolean;\n logs: boolean;\n };\n}\n\n/**\n * Normalizes an endpoint URL and constructs signal-specific paths.\n */\nexport function normalizeEndpoints(baseEndpoint: string) {\n let cleaned = (baseEndpoint || \"https://api.observantic.com\").trim();\n // Strip trailing slashes\n cleaned = cleaned.replace(/\\/+$/, \"\");\n\n // If user passed specific /v1/traces URL directly as endpoint, handle gracefully\n if (cleaned.endsWith(\"/v1/traces\")) {\n const root = cleaned.slice(0, -\"/v1/traces\".length);\n return {\n endpoint: root,\n tracesEndpoint: cleaned,\n metricsEndpoint: `${root}/v1/metrics`,\n logsEndpoint: `${root}/v1/logs`,\n };\n }\n\n // If user passed /v1 at the end\n if (cleaned.endsWith(\"/v1\")) {\n return {\n endpoint: cleaned,\n tracesEndpoint: `${cleaned}/traces`,\n metricsEndpoint: `${cleaned}/metrics`,\n logsEndpoint: `${cleaned}/logs`,\n };\n }\n\n return {\n endpoint: cleaned,\n tracesEndpoint: `${cleaned}/v1/traces`,\n metricsEndpoint: `${cleaned}/v1/metrics`,\n logsEndpoint: `${cleaned}/v1/logs`,\n };\n}\n\n/**\n * Parses comma-delimited key=value headers often used in OTEL_EXPORTER_OTLP_HEADERS.\n */\nexport function parseOtelHeaders(headerStr?: string): Record<string, string> {\n if (!headerStr) return {};\n const headers: Record<string, string> = {};\n const pairs = headerStr.split(\",\");\n for (const pair of pairs) {\n const idx = pair.indexOf(\"=\");\n if (idx > 0) {\n const key = pair.substring(0, idx).trim();\n const val = pair.substring(idx + 1).trim();\n if (key) headers[key] = val;\n }\n }\n return headers;\n}\n\n/**\n * Resolves user options with environment variables and sensible defaults.\n */\nexport function resolveConfig(options: ObservanticOptions = {}): ResolvedObservanticConfig {\n const env = process.env;\n\n const apiKey =\n options.apiKey ||\n env.OBSERVANTIC_API_KEY ||\n \"\";\n\n const rawEndpoint =\n options.endpoint ||\n env.OBSERVANTIC_ENDPOINT ||\n env.OTEL_EXPORTER_OTLP_ENDPOINT ||\n \"https://api.observantic.com\";\n\n const { endpoint, tracesEndpoint, metricsEndpoint, logsEndpoint } = normalizeEndpoints(rawEndpoint);\n\n const serviceName =\n options.serviceName ||\n env.OBSERVANTIC_SERVICE_NAME ||\n env.OTEL_SERVICE_NAME ||\n env.npm_package_name ||\n process.title ||\n \"node-service\";\n\n const environment =\n options.environment ||\n env.OBSERVANTIC_ENVIRONMENT ||\n env.NODE_ENV ||\n \"development\";\n\n const serviceVersion =\n options.serviceVersion ||\n env.OBSERVANTIC_SERVICE_VERSION ||\n env.npm_package_version ||\n \"1.0.0\";\n\n const disabled =\n options.disabled !== undefined\n ? options.disabled\n : env.OBSERVANTIC_DISABLED === \"true\" || env.OTEL_SDK_DISABLED === \"true\";\n\n const debug =\n options.debug !== undefined\n ? options.debug\n : env.OBSERVANTIC_DEBUG === \"true\" || env.OTEL_LOG_LEVEL === \"debug\";\n\n const autoShutdown = options.autoShutdown !== undefined ? options.autoShutdown : true;\n\n const traceSampleRate =\n options.traceSampleRate !== undefined\n ? Math.max(0, Math.min(1, options.traceSampleRate))\n : env.OBSERVANTIC_TRACE_SAMPLE_RATE\n ? parseFloat(env.OBSERVANTIC_TRACE_SAMPLE_RATE)\n : 1.0;\n\n // Build headers with authentication for Observantic\n const envHeaders = parseOtelHeaders(env.OTEL_EXPORTER_OTLP_HEADERS);\n const headers: Record<string, string> = {\n ...envHeaders,\n ...(options.headers || {}),\n };\n\n if (apiKey) {\n headers[\"Authorization\"] = `Bearer ${apiKey}`;\n headers[\"x-cw-token\"] = apiKey;\n }\n\n return {\n apiKey,\n endpoint,\n tracesEndpoint,\n metricsEndpoint,\n logsEndpoint,\n serviceName,\n environment,\n serviceVersion,\n resourceAttributes: options.resourceAttributes || {},\n headers,\n disabled,\n debug,\n autoShutdown,\n traceSampleRate,\n batchTimeoutMillis: options.batchTimeoutMillis || 5000,\n maxQueueSize: options.maxQueueSize || 2048,\n maxExportBatchSize: options.maxExportBatchSize || 512,\n metricExportIntervalMillis: options.metricExportIntervalMillis || 60000,\n signals: {\n traces: options.signals?.traces !== false,\n metrics: options.signals?.metrics !== false,\n logs: options.signals?.logs !== false,\n },\n };\n}\n\n","import { Resource } from \"@opentelemetry/resources\";\nimport {\n SEMRESATTRS_SERVICE_NAME,\n SEMRESATTRS_SERVICE_VERSION,\n SEMRESATTRS_DEPLOYMENT_ENVIRONMENT,\n SEMRESATTRS_TELEMETRY_SDK_NAME,\n SEMRESATTRS_TELEMETRY_SDK_LANGUAGE,\n SEMRESATTRS_TELEMETRY_SDK_VERSION,\n SEMRESATTRS_PROCESS_PID,\n SEMRESATTRS_PROCESS_RUNTIME_NAME,\n SEMRESATTRS_PROCESS_RUNTIME_VERSION,\n} from \"@opentelemetry/semantic-conventions\";\nimport { ResolvedObservanticConfig } from \"./config.js\";\n\n/**\n * Builds OpenTelemetry Resource with standard semantic conventions and custom attributes.\n */\nexport function createResource(config: ResolvedObservanticConfig): Resource {\n const customAttributes: Record<string, string | number | boolean> = {\n [SEMRESATTRS_SERVICE_NAME]: config.serviceName,\n [SEMRESATTRS_SERVICE_VERSION]: config.serviceVersion,\n [SEMRESATTRS_DEPLOYMENT_ENVIRONMENT]: config.environment,\n [SEMRESATTRS_TELEMETRY_SDK_NAME]: \"@observantic/sdk\",\n [SEMRESATTRS_TELEMETRY_SDK_LANGUAGE]: \"nodejs\",\n [SEMRESATTRS_TELEMETRY_SDK_VERSION]: \"1.0.0\",\n [SEMRESATTRS_PROCESS_PID]: process.pid,\n [SEMRESATTRS_PROCESS_RUNTIME_NAME]: \"nodejs\",\n [SEMRESATTRS_PROCESS_RUNTIME_VERSION]: process.version,\n ...config.resourceAttributes,\n };\n\n return new Resource(customAttributes);\n}\n\n","import { OTLPTraceExporter } from \"@opentelemetry/exporter-trace-otlp-http\";\nimport {\n BatchSpanProcessor,\n ParentBasedSampler,\n TraceIdRatioBasedSampler,\n AlwaysOnSampler,\n AlwaysOffSampler,\n Sampler,\n SpanProcessor,\n} from \"@opentelemetry/sdk-trace-base\";\nimport { ResolvedObservanticConfig } from \"./config.js\";\n\nexport function createTraceExporter(config: ResolvedObservanticConfig): OTLPTraceExporter {\n return new OTLPTraceExporter({\n url: config.tracesEndpoint,\n headers: config.headers,\n timeoutMillis: 10000,\n });\n}\n\nexport function createSampler(sampleRate: number): Sampler {\n if (sampleRate >= 1.0) {\n return new ParentBasedSampler({ root: new AlwaysOnSampler() });\n }\n if (sampleRate <= 0.0) {\n return new ParentBasedSampler({ root: new AlwaysOffSampler() });\n }\n return new ParentBasedSampler({\n root: new TraceIdRatioBasedSampler(sampleRate),\n });\n}\n\nexport function createSpanProcessor(\n exporter: OTLPTraceExporter,\n config: ResolvedObservanticConfig\n): SpanProcessor {\n return new BatchSpanProcessor(exporter, {\n maxQueueSize: config.maxQueueSize,\n maxExportBatchSize: config.maxExportBatchSize,\n scheduledDelayMillis: config.batchTimeoutMillis,\n exportTimeoutMillis: 10000,\n });\n}\n\n","import { OTLPMetricExporter } from \"@opentelemetry/exporter-metrics-otlp-http\";\nimport {\n PeriodicExportingMetricReader,\n MetricReader,\n AggregationTemporality,\n} from \"@opentelemetry/sdk-metrics\";\nimport { ResolvedObservanticConfig } from \"./config.js\";\n\nexport function createMetricExporter(config: ResolvedObservanticConfig): OTLPMetricExporter {\n return new OTLPMetricExporter({\n url: config.metricsEndpoint,\n headers: config.headers,\n timeoutMillis: 10000,\n temporalityPreference: AggregationTemporality.DELTA,\n });\n}\n\nexport function createMetricReader(\n exporter: OTLPMetricExporter,\n config: ResolvedObservanticConfig\n): MetricReader {\n return new PeriodicExportingMetricReader({\n exporter,\n exportIntervalMillis: config.metricExportIntervalMillis,\n exportTimeoutMillis: 10000,\n });\n}\n\n","import { OTLPLogExporter } from \"@opentelemetry/exporter-logs-otlp-http\";\nimport { BatchLogRecordProcessor, LogRecordProcessor } from \"@opentelemetry/sdk-logs\";\nimport { ResolvedObservanticConfig } from \"./config.js\";\n\nexport function createLogExporter(config: ResolvedObservanticConfig): OTLPLogExporter {\n return new OTLPLogExporter({\n url: config.logsEndpoint,\n headers: config.headers,\n timeoutMillis: 10000,\n });\n}\n\nexport function createLogRecordProcessor(\n exporter: OTLPLogExporter,\n config: ResolvedObservanticConfig\n): LogRecordProcessor {\n return new BatchLogRecordProcessor(exporter, {\n maxQueueSize: config.maxQueueSize,\n maxExportBatchSize: config.maxExportBatchSize,\n scheduledDelayMillis: config.batchTimeoutMillis,\n exportTimeoutMillis: 10000,\n });\n}\n\n","import { getNodeAutoInstrumentations } from \"@opentelemetry/auto-instrumentations-node\";\nimport { Instrumentation } from \"@opentelemetry/instrumentation\";\nimport { ResolvedObservanticConfig } from \"./config.js\";\n\n/**\n * Configures auto-instrumentations with production defaults for Node.js and Express.\n */\nexport function createInstrumentations(\n _config: ResolvedObservanticConfig\n): (Instrumentation | Instrumentation[])[] {\n return [\n getNodeAutoInstrumentations({\n \"@opentelemetry/instrumentation-fs\": {\n // Disable noisy fs hooks by default to prevent span flooding\n enabled: false,\n },\n \"@opentelemetry/instrumentation-http\": {\n enabled: true,\n },\n \"@opentelemetry/instrumentation-express\": {\n enabled: true,\n },\n }),\n ];\n}\n\n","import { NodeSDK } from \"@opentelemetry/sdk-node\";\nimport { diag } from \"@opentelemetry/api\";\n\nlet activeSdk: NodeSDK | null = null;\nlet isShuttingDown = false;\nlet isSignalHandlerRegistered = false;\n\n/**\n * Registers the active NodeSDK instance for lifecycle management.\n */\nexport function registerSdk(sdk: NodeSDK): void {\n activeSdk = sdk;\n}\n\n/**\n * Gracefully shuts down the Observantic OpenTelemetry SDK and flushes pending telemetry.\n */\nexport async function shutdownObservantic(): Promise<void> {\n if (!activeSdk) {\n return;\n }\n\n if (isShuttingDown) {\n return;\n }\n\n isShuttingDown = true;\n diag.info(\"Shutting down Observantic OpenTelemetry SDK...\");\n\n try {\n await activeSdk.shutdown();\n diag.info(\"Observantic OpenTelemetry SDK terminated successfully.\");\n } catch (err) {\n diag.error(\"Error shutting down Observantic OpenTelemetry SDK\", err);\n throw err;\n } finally {\n activeSdk = null;\n isShuttingDown = false;\n }\n}\n\n/**\n * Installs graceful process shutdown listeners for SIGINT and SIGTERM.\n */\nexport function installShutdownHooks(sdk: NodeSDK): void {\n registerSdk(sdk);\n\n if (isSignalHandlerRegistered) {\n return;\n }\n\n const handleSignal = async (signal: string) => {\n diag.info(`Received ${signal}, gracefully shutting down Observantic telemetry...`);\n try {\n await shutdownObservantic();\n } catch (err) {\n diag.error(`Failed to flush telemetry on ${signal}:`, err);\n }\n };\n\n process.once(\"SIGTERM\", () => void handleSignal(\"SIGTERM\"));\n process.once(\"SIGINT\", () => void handleSignal(\"SIGINT\"));\n\n isSignalHandlerRegistered = true;\n}\n\n"],"mappings":"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","names":["import_api","import_api_logs"]}
|