@pingops/sdk 0.1.3 → 0.2.1

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/README.md CHANGED
@@ -1,6 +1,36 @@
1
1
  # @pingops/sdk
2
2
 
3
- PingOps SDK for Node.js. Provides a simple API for bootstrapping OpenTelemetry and capturing outgoing API and LLM calls.
3
+ **PingOps SDK for Node.js** Bootstrap OpenTelemetry and capture outgoing HTTP and fetch API calls with minimal code. Built for observability of external API usage, AI/LLM calls, and third-party integrations.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Overview](#overview)
10
+ - [Installation](#installation)
11
+ - [Quick Start](#quick-start)
12
+ - [Configuration](#configuration)
13
+ - [API Reference](#api-reference)
14
+ - [Tracing](#tracing)
15
+ - [Filtering & Privacy](#filtering--privacy)
16
+ - [Integration with Existing OpenTelemetry](#integration-with-existing-opentelemetry)
17
+ - [What Gets Captured](#what-gets-captured)
18
+ - [Requirements](#requirements)
19
+
20
+ ---
21
+
22
+ ## Overview
23
+
24
+ The PingOps SDK gives you:
25
+
26
+ - **Automatic instrumentation** — Outgoing HTTP (Node.js `http` module) and `fetch` (via Undici) are instrumented without wrapping your code.
27
+ - **Structured traces** — Start traces with `userId`, `sessionId`, tags, and metadata so every span is tied to your business context.
28
+ - **Control over what is captured** — Domain allow/deny lists, header filtering, and optional request/response body capture with size limits.
29
+ - **Flexible setup** — Use environment variables, a config file (JSON or YAML), or pass config programmatically. Auto-initialize via `--require` or import `@pingops/sdk/register` first.
30
+
31
+ You initialize once (at process startup or before any HTTP clients load); after that, outgoing requests are captured and sent to your PingOps backend in batches or immediately.
32
+
33
+ ---
4
34
 
5
35
  ## Installation
6
36
 
@@ -8,17 +38,29 @@ PingOps SDK for Node.js. Provides a simple API for bootstrapping OpenTelemetry a
8
38
  pnpm add @pingops/sdk
9
39
  ```
10
40
 
41
+ Or with npm:
42
+
43
+ ```bash
44
+ npm install @pingops/sdk
45
+ ```
46
+
47
+ **Requirement:** Node.js **20 or later** (for native `fetch` and modern APIs).
48
+
49
+ ---
50
+
11
51
  ## Quick Start
12
52
 
13
- ### Option 1: Auto-initialization (Recommended)
53
+ ### Option 1: Auto-initialization (recommended)
54
+
55
+ **Best for:** Getting started quickly and for production when config comes from environment or a config file.
14
56
 
15
- **Most automatic approach** - Use Node.js `--require` flag (runs before any imports):
57
+ **A. Using Node.js `--require`** (runs before any application code):
16
58
 
17
59
  ```bash
18
60
  node --require @pingops/sdk/register your-app.js
19
61
  ```
20
62
 
21
- Set environment variables:
63
+ Set required environment variables:
22
64
 
23
65
  ```bash
24
66
  export PINGOPS_API_KEY="your-api-key"
@@ -26,168 +68,409 @@ export PINGOPS_BASE_URL="https://api.pingops.com"
26
68
  export PINGOPS_SERVICE_NAME="my-service"
27
69
  ```
28
70
 
29
- **Or** import the register file FIRST in your code:
71
+ **B. Importing the register entry first** (must be before any HTTP client imports):
30
72
 
31
73
  ```typescript
32
- // Import this FIRST, before any HTTP clients
74
+ // Must be first before axios, node-fetch, or any code that makes HTTP requests
33
75
  import "@pingops/sdk/register";
34
76
 
35
77
  import axios from "axios";
36
- // ... rest of your code
78
+ // ... rest of your application
37
79
  ```
38
80
 
81
+ With a config file, set `PINGOPS_CONFIG_FILE` to the path to your JSON or YAML file; environment variables override values from the file.
82
+
39
83
  ### Option 2: Manual initialization
40
84
 
85
+ **Best for:** Config from code, feature flags, or when you need to ensure initialization order explicitly.
86
+
41
87
  ```typescript
42
88
  import { initializePingops } from "@pingops/sdk";
43
89
 
44
- // Option A: pass a config object directly
90
+ // Before importing or using any HTTP clients
45
91
  initializePingops({
46
- apiKey: "your-api-key", // or set PINGOPS_API_KEY env var
92
+ apiKey: process.env.PINGOPS_API_KEY,
47
93
  baseUrl: "https://api.pingops.com",
48
94
  serviceName: "my-service",
49
95
  });
50
96
 
51
- // Option B: pass a JSON/YAML config file path (env vars override file values)
97
+ import axios from "axios";
98
+ // ... rest of your application
99
+ ```
100
+
101
+ You can also initialize from a config file path (environment variables still override file values):
102
+
103
+ ```typescript
52
104
  initializePingops("./pingops.config.yaml");
53
- // or:
105
+ // or
54
106
  initializePingops({ configFile: "./pingops.config.json" });
55
107
  ```
56
108
 
57
- **Important**: If using manual initialization, call `initializePingops()` before importing any HTTP clients (axios, fetch, etc.) to ensure proper instrumentation.
109
+ **Important:** Call `initializePingops` before any HTTP client is loaded or used so instrumentation is applied correctly.
110
+
111
+ ---
112
+
113
+ ## Configuration
114
+
115
+ Configuration can be provided via:
116
+
117
+ 1. **Programmatic config** — Object passed to `initializePingops(...)`
118
+ 2. **Config file** — Path as first argument or `{ configFile: "path" }`; supports JSON and YAML
119
+ 3. **Environment variables** — Always override file and can supply all required fields for auto-init
120
+
121
+ ### Required fields
122
+
123
+ | Field | Env var | Description |
124
+ | ------------- | ---------------------- | ------------------------- |
125
+ | `baseUrl` | `PINGOPS_BASE_URL` | PingOps backend base URL |
126
+ | `serviceName` | `PINGOPS_SERVICE_NAME` | Service name for resource |
127
+
128
+ `apiKey` is optional at config level; if your backend requires it, set `apiKey` or `PINGOPS_API_KEY`.
129
+
130
+ ### Full configuration reference
131
+
132
+ | Option | Type | Default | Description |
133
+ | --------------------- | ---------------------------- | ------------ | ---------------------------------------------- |
134
+ | `apiKey` | `string` | — | API key (or `PINGOPS_API_KEY`) |
135
+ | `baseUrl` | `string` | **required** | Backend base URL |
136
+ | `serviceName` | `string` | **required** | Service name |
137
+ | `debug` | `boolean` | `false` | Enable debug logs (`PINGOPS_DEBUG=true`) |
138
+ | `headersAllowList` | `string[]` | — | Headers to include (case-insensitive) |
139
+ | `headersDenyList` | `string[]` | — | Headers to exclude (overrides allow) |
140
+ | `captureRequestBody` | `boolean` | `false` | Capture request bodies (global) |
141
+ | `captureResponseBody` | `boolean` | `false` | Capture response bodies (global) |
142
+ | `maxRequestBodySize` | `number` | `4096` | Max request body size in bytes |
143
+ | `maxResponseBodySize` | `number` | `4096` | Max response body size in bytes |
144
+ | `domainAllowList` | `DomainRule[]` | — | Domains (and optional rules) to allow |
145
+ | `domainDenyList` | `DomainRule[]` | — | Domains to exclude |
146
+ | `headerRedaction` | `HeaderRedactionConfig` | — | Custom header redaction |
147
+ | `batchSize` | `number` | `50` | Spans per batch (`PINGOPS_BATCH_SIZE`) |
148
+ | `batchTimeout` | `number` | `5000` | Flush interval in ms (`PINGOPS_BATCH_TIMEOUT`) |
149
+ | `exportMode` | `"batched"` \| `"immediate"` | `"batched"` | `PINGOPS_EXPORT_MODE` |
150
+
151
+ **Config file path:** Set `PINGOPS_CONFIG_FILE` to the path of your JSON or YAML file when using the register entry.
152
+
153
+ **Export mode:**
154
+
155
+ - **`batched`** — Best for long-running processes; spans are sent in batches (default).
156
+ - **`immediate`** — Best for serverless/short-lived processes; each span is sent as it finishes to reduce loss on freeze/exit.
157
+
158
+ ### Config file examples
159
+
160
+ **JSON (`pingops.config.json`):**
161
+
162
+ ```json
163
+ {
164
+ "apiKey": "your-api-key",
165
+ "baseUrl": "https://api.pingops.com",
166
+ "serviceName": "my-service",
167
+ "debug": false,
168
+ "exportMode": "batched",
169
+ "batchSize": 50,
170
+ "batchTimeout": 5000,
171
+ "captureRequestBody": false,
172
+ "captureResponseBody": false
173
+ }
174
+ ```
175
+
176
+ **YAML (`pingops.config.yaml`):**
58
177
 
59
- ## Features
178
+ ```yaml
179
+ apiKey: your-api-key
180
+ baseUrl: https://api.pingops.com
181
+ serviceName: my-service
182
+ debug: false
183
+ exportMode: batched
184
+ batchSize: 50
185
+ batchTimeout: 5000
186
+ ```
60
187
 
61
- - **Automatic Instrumentation**: Captures HTTP and fetch API calls automatically
62
- - **Node.js Support**: Works in Node.js environments (including Node.js 20+ with native fetch)
63
- - **GenAI Support**: Captures LLM calls using OpenTelemetry GenAI semantic conventions
64
- - **Manual Instrumentation**: Create custom spans for specific operations
65
- - **Zero Configuration**: Works out of the box with sensible defaults
188
+ ---
66
189
 
67
- ## API
190
+ ## API Reference
68
191
 
69
192
  ### `initializePingops(config)`
70
193
 
71
- Initializes the PingOps SDK with OpenTelemetry.
194
+ Initializes the PingOps SDK: sets up OpenTelemetry `NodeSDK`, registers the PingOps span processor, and enables HTTP and Undici (fetch) instrumentation.
195
+
196
+ **Overloads:**
197
+
198
+ - `initializePingops(config: PingopsProcessorConfig): void`
199
+ - `initializePingops(configFilePath: string): void`
200
+ - `initializePingops({ configFile: string }): void`
72
201
 
73
- **Configuration:**
202
+ **Example:**
74
203
 
75
204
  ```typescript
76
- interface PingopsInitConfig {
77
- apiKey?: string; // Defaults to PINGOPS_API_KEY env var
78
- baseUrl: string; // Required
79
- serviceName: string; // Required
80
- debug?: boolean;
81
- headersAllowList?: string[];
82
- headersDenyList?: string[];
83
- domainAllowList?: DomainRule[];
84
- domainDenyList?: DomainRule[];
85
- batchSize?: number; // Default: 50
86
- batchTimeout?: number; // Default: 5000ms
87
- }
205
+ import { initializePingops } from "@pingops/sdk";
206
+
207
+ initializePingops({
208
+ baseUrl: "https://api.pingops.com",
209
+ serviceName: "my-service",
210
+ apiKey: process.env.PINGOPS_API_KEY,
211
+ exportMode: "immediate", // e.g. for serverless
212
+ });
88
213
  ```
89
214
 
90
- ### `pingops.startSpan(name, attributes, fn)`
215
+ Calling `initializePingops` again after the first successful call is a no-op (idempotent).
216
+
217
+ ---
91
218
 
92
- Creates a manual span for custom instrumentation.
219
+ ### `shutdownPingops()`
220
+
221
+ Gracefully shuts down the SDK and flushes remaining spans. Returns a `Promise<void>`.
222
+
223
+ **Example:**
93
224
 
94
225
  ```typescript
95
- import { pingops } from "@pingops/sdk";
226
+ import { shutdownPingops } from "@pingops/sdk";
227
+
228
+ process.on("SIGTERM", async () => {
229
+ await shutdownPingops();
230
+ process.exit(0);
231
+ });
232
+ ```
233
+
234
+ ---
235
+
236
+ ### `startTrace(options, fn)`
237
+
238
+ Starts a new trace, sets PingOps attributes (e.g. `userId`, `sessionId`, tags, metadata) in context, runs the given function inside that context, and returns the function’s result. Any spans created inside the function (including automatic HTTP/fetch spans) are part of this trace and carry the same context.
239
+
240
+ **Parameters:**
241
+
242
+ - `options.attributes` — Optional [PingopsTraceAttributes](#pingopstraceattributes) to attach to the trace and propagate to spans.
243
+ - `options.seed` — Optional string; when provided, a deterministic trace ID is derived from it (useful for idempotency or correlation with external systems).
244
+ - `fn` — `() => T | Promise<T>`. Your code; runs inside the new trace and attribute context.
96
245
 
97
- await pingops.startSpan(
98
- "external.api.call",
246
+ **Returns:** `Promise<T>` — The result of `fn`.
247
+
248
+ **Example:**
249
+
250
+ ```typescript
251
+ import { startTrace, initializePingops } from "@pingops/sdk";
252
+
253
+ initializePingops({ baseUrl: "...", serviceName: "my-api" });
254
+
255
+ const data = await startTrace(
99
256
  {
100
- customer_id: "cust_123",
101
- correlation_id: "req_456",
102
- "custom_attributes.request_type": "webhook",
257
+ attributes: {
258
+ userId: "user-123",
259
+ sessionId: "sess-456",
260
+ tags: ["checkout", "v2"],
261
+ metadata: { plan: "pro", region: "us" },
262
+ captureRequestBody: true,
263
+ captureResponseBody: true,
264
+ },
265
+ seed: "order-789", // optional: stable trace ID for this order
103
266
  },
104
- async (span) => {
105
- // Your code here
106
- const result = await fetch("https://api.example.com/data");
107
- return result.json();
267
+ async () => {
268
+ const res = await fetch("https://api.stripe.com/v1/charges", { ... });
269
+ return res.json();
108
270
  }
109
271
  );
110
272
  ```
111
273
 
112
- The span is automatically ended when the function completes or throws an error.
274
+ ---
113
275
 
114
- ### `shutdownPingops()`
276
+ ### `getActiveTraceId()`
277
+
278
+ Returns the trace ID of the currently active span, or `undefined` if there is none.
115
279
 
116
- Gracefully shuts down the SDK and flushes remaining spans.
280
+ **Example:**
117
281
 
118
282
  ```typescript
119
- import { shutdownPingops } from "@pingops/sdk";
283
+ import { getActiveTraceId } from "@pingops/sdk";
120
284
 
121
- await shutdownPingops();
285
+ const traceId = getActiveTraceId();
286
+ console.log("Current trace:", traceId);
122
287
  ```
123
288
 
124
- ## Domain Filtering
289
+ ---
290
+
291
+ ### `getActiveSpanId()`
125
292
 
126
- Control which domains and paths are captured:
293
+ Returns the span ID of the currently active span, or `undefined` if there is none.
294
+
295
+ **Example:**
127
296
 
128
297
  ```typescript
129
- initializePingops({
130
- // ... other config
131
- domainAllowList: [
132
- {
133
- domain: "api.github.com",
134
- paths: ["/repos"],
135
- headersAllowList: ["authorization", "user-agent"],
136
- },
298
+ import { getActiveSpanId } from "@pingops/sdk";
299
+
300
+ const spanId = getActiveSpanId();
301
+ ```
302
+
303
+ ---
304
+
305
+ ### `PingopsTraceAttributes`
306
+
307
+ Type for attributes you can pass into `startTrace({ attributes })`:
308
+
309
+ | Field | Type | Description |
310
+ | --------------------- | ------------------------ | --------------------------------------------------------------------- |
311
+ | `traceId` | `string` | Override trace ID (otherwise one is generated or derived from `seed`) |
312
+ | `userId` | `string` | User identifier |
313
+ | `sessionId` | `string` | Session identifier |
314
+ | `tags` | `string[]` | Tags for the trace |
315
+ | `metadata` | `Record<string, string>` | Key-value metadata |
316
+ | `captureRequestBody` | `boolean` | Override request body capture for spans in this trace |
317
+ | `captureResponseBody` | `boolean` | Override response body capture for spans in this trace |
318
+
319
+ ---
320
+
321
+ ## Tracing
322
+
323
+ ### Why use `startTrace`?
324
+
325
+ - **Correlation** — Tie all outgoing calls in a request (or job) to one trace and to a user/session.
326
+ - **Stable IDs** — Use `seed` (e.g. request ID or order ID) to get a deterministic trace ID for logging or external systems.
327
+ - **Scoped body capture** — Enable `captureRequestBody` / `captureResponseBody` only for specific traces (e.g. a single webhook or LLM call) instead of globally.
328
+
329
+ ### Auto-initialization when using `startTrace`
330
+
331
+ If you call `startTrace` before calling `initializePingops`, the SDK will try to auto-initialize from environment variables (`PINGOPS_API_KEY`, `PINGOPS_BASE_URL`, `PINGOPS_SERVICE_NAME`). If any of these are missing, `startTrace` throws. For predictable behavior, prefer initializing explicitly at startup.
332
+
333
+ ### Example: request-scoped trace
334
+
335
+ ```typescript
336
+ import { startTrace, getActiveTraceId, initializePingops } from "@pingops/sdk";
337
+
338
+ initializePingops({ baseUrl: "...", serviceName: "my-api" });
339
+
340
+ app.post("/webhook", async (req, res) => {
341
+ const result = await startTrace(
137
342
  {
138
- domain: ".openai.com", // Suffix match
343
+ attributes: {
344
+ userId: req.user?.id,
345
+ sessionId: req.sessionId,
346
+ tags: ["webhook"],
347
+ metadata: { provider: req.body.provider },
348
+ },
349
+ seed: req.headers["x-request-id"] ?? undefined,
139
350
  },
140
- ],
141
- domainDenyList: [
351
+ async () => {
352
+ await callExternalApi(req.body);
353
+ return { ok: true };
354
+ }
355
+ );
356
+
357
+ const traceId = getActiveTraceId();
358
+ res.setHeader("X-Trace-Id", traceId ?? "");
359
+ res.json(result);
360
+ });
361
+ ```
362
+
363
+ ---
364
+
365
+ ## Filtering & Privacy
366
+
367
+ ### Domain allow/deny lists
368
+
369
+ Restrict which domains (and optionally paths) are captured:
370
+
371
+ ```typescript
372
+ initializePingops({
373
+ baseUrl: "https://api.pingops.com",
374
+ serviceName: "my-service",
375
+ domainAllowList: [
376
+ { domain: "api.github.com", paths: ["/repos"] },
377
+ { domain: ".openai.com" }, // suffix match
142
378
  {
143
- domain: "internal.service.local",
379
+ domain: "generativelanguage.googleapis.com",
380
+ captureRequestBody: true,
381
+ captureResponseBody: true,
144
382
  },
145
383
  ],
384
+ domainDenyList: [{ domain: "internal.corp.local" }],
146
385
  });
147
386
  ```
148
387
 
149
- ## Header Filtering
388
+ Each rule in `domainAllowList` / `domainDenyList` can include:
389
+
390
+ - `domain` — Exact or suffix (e.g. `.openai.com`) match.
391
+ - `paths` — Optional path prefixes to allow/deny.
392
+ - `headersAllowList` / `headersDenyList` — Header rules for that domain.
393
+ - `captureRequestBody` / `captureResponseBody` — Override body capture for that domain.
150
394
 
151
- Control which headers are captured:
395
+ ### Header allow/deny lists
396
+
397
+ Control which headers are included on captured spans (global default; domain rules can refine):
152
398
 
153
399
  ```typescript
154
400
  initializePingops({
155
- // ... other config
156
- headersAllowList: ["user-agent", "x-request-id"],
157
- headersDenyList: ["authorization", "cookie"],
401
+ baseUrl: "https://api.pingops.com",
402
+ serviceName: "my-service",
403
+ headersAllowList: ["user-agent", "x-request-id", "content-type"],
404
+ headersDenyList: ["authorization", "cookie", "x-api-key"],
158
405
  });
159
406
  ```
160
407
 
408
+ Deny list takes precedence over allow list. Sensitive headers are redacted by default; use `headerRedaction` in config for custom behavior.
409
+
410
+ ### Request/response body capture
411
+
412
+ - **Global:** `captureRequestBody` and `captureResponseBody` in config.
413
+ - **Per-domain:** Same flags on a [DomainRule](#domain-allowdeny-lists).
414
+ - **Per-trace:** `captureRequestBody` / `captureResponseBody` in [PingopsTraceAttributes](#pingopstraceattributes) in `startTrace`.
415
+
416
+ Body size is capped by `maxRequestBodySize` and `maxResponseBodySize` (default 4096 bytes each). Larger bodies are truncated.
417
+
418
+ ---
419
+
161
420
  ## Integration with Existing OpenTelemetry
162
421
 
163
- If you already have OpenTelemetry set up, you can use just the `PingopsSpanProcessor`:
422
+ If you already use OpenTelemetry and only want the PingOps exporter and filtering, use `PingopsSpanProcessor` from `@pingops/otel` and add it to your existing `TracerProvider`:
164
423
 
165
424
  ```typescript
425
+ import { NodeSDK } from "@opentelemetry/sdk-node";
166
426
  import { PingopsSpanProcessor } from "@pingops/otel";
167
- import { getTracerProvider } from "@opentelemetry/api";
168
427
 
169
- const processor = new PingopsSpanProcessor({
170
- apiKey: "your-api-key",
171
- baseUrl: "https://api.pingops.com",
172
- serviceName: "my-service",
428
+ const sdk = new NodeSDK({
429
+ spanProcessors: [
430
+ new PingopsSpanProcessor({
431
+ apiKey: "your-api-key",
432
+ baseUrl: "https://api.pingops.com",
433
+ serviceName: "my-service",
434
+ exportMode: "batched",
435
+ domainAllowList: [{ domain: "api.example.com" }],
436
+ }),
437
+ ],
438
+ // your existing instrumentations, resource, etc.
173
439
  });
174
440
 
175
- const tracerProvider = getTracerProvider();
176
- // Add processor to your existing tracer provider
441
+ sdk.start();
177
442
  ```
178
443
 
444
+ You can still use `@pingops/sdk` for `startTrace`, `getActiveTraceId`, and `getActiveSpanId`; ensure your tracer provider is the one that uses `PingopsSpanProcessor` (or is bridged to it) so those spans are exported to PingOps.
445
+
446
+ ---
447
+
179
448
  ## What Gets Captured
180
449
 
181
- - **HTTP Requests**: All outgoing HTTP requests (via `http` module in Node.js)
182
- - **Fetch API**: All `fetch()` calls (universal JS)
183
- - **GenAI Calls**: LLM API calls that follow OpenTelemetry GenAI semantic conventions
450
+ - **Outgoing HTTP** Requests made with Node’s `http` / `https` (e.g. many HTTP clients under the hood).
451
+ - **Outgoing fetch** Requests made with the global `fetch` (in Node.js 18+ this is implemented by Undici; both are instrumented).
184
452
 
185
- ## What Doesn't Get Captured
453
+ Only **CLIENT** spans with HTTP (or supported semantic) attributes are exported to PingOps; server-side and internal spans are filtered out.
186
454
 
187
- - Incoming requests (server-side)
188
- - Internal spans (non-CLIENT spans)
189
- - Spans without HTTP or GenAI attributes
455
+ ---
190
456
 
191
457
  ## Requirements
192
458
 
193
- - **Node.js**: Requires Node.js 20+ (for native fetch support) or Node.js 18+ with fetch polyfill
459
+ - **Node.js** **20**
460
+ - **ESM** — The package is published as ES modules; use `import` and, if needed, `"type": "module"` or `.mjs`.
461
+
462
+ ---
463
+
464
+ ## Summary
465
+
466
+ | Goal | What to do |
467
+ | ------------------ | ----------------------------------------------------------------------------------------------- |
468
+ | Install | `pnpm add @pingops/sdk` |
469
+ | Auto-init from env | `node --require @pingops/sdk/register your-app.js` or `import "@pingops/sdk/register"` first |
470
+ | Manual init | `initializePingops({ baseUrl, serviceName, ... })` before any HTTP usage |
471
+ | Config from file | `PINGOPS_CONFIG_FILE=./pingops.config.yaml` or `initializePingops("./pingops.config.json")` |
472
+ | Trace with context | `startTrace({ attributes: { userId, sessionId, tags, metadata }, seed? }, async () => { ... })` |
473
+ | Get current IDs | `getActiveTraceId()`, `getActiveSpanId()` |
474
+ | Graceful shutdown | `await shutdownPingops()` |
475
+
476
+ For more detail on types and options, see the [Configuration](#configuration) and [API Reference](#api-reference) sections above.
package/dist/index.cjs CHANGED
@@ -1,5 +1,7 @@
1
- const require_pingops = require('./pingops-Cb6UV5D8.cjs');
1
+ const require_pingops = require('./pingops-BBXegVtL.cjs');
2
2
 
3
+ exports.getActiveSpanId = require_pingops.getActiveSpanId;
4
+ exports.getActiveTraceId = require_pingops.getActiveTraceId;
3
5
  exports.initializePingops = require_pingops.initializePingops;
4
6
  exports.shutdownPingops = require_pingops.shutdownPingops;
5
- exports.wrapHttp = require_pingops.wrapHttp;
7
+ exports.startTrace = require_pingops.startTrace;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { PingopsProcessorConfig } from "@pingops/otel";
2
- import { WrapHttpAttributes, WrapHttpAttributes as WrapHttpAttributes$1 } from "@pingops/core";
2
+ import { PingopsTraceAttributes, PingopsTraceAttributes as PingopsTraceAttributes$1 } from "@pingops/core";
3
3
 
4
4
  //#region src/pingops.d.ts
5
5
 
@@ -15,7 +15,7 @@ import { WrapHttpAttributes, WrapHttpAttributes as WrapHttpAttributes$1 } from "
15
15
  *
16
16
  * @param config - Configuration object, config file path, or config file wrapper
17
17
  * @param explicit - Whether this is an explicit call (default: true).
18
- * Set to false when called internally by wrapHttp auto-initialization.
18
+ * Set to false when called internally by startTrace auto-initialization.
19
19
  */
20
20
  declare function initializePingops(config: PingopsProcessorConfig, explicit?: boolean): void;
21
21
  declare function initializePingops(configFilePath: string, explicit?: boolean): void;
@@ -27,61 +27,46 @@ declare function initializePingops(config: {
27
27
  */
28
28
  declare function shutdownPingops(): Promise<void>;
29
29
  /**
30
- * Wraps a function to set attributes on HTTP spans created within the wrapped block.
31
- *
32
- * This function sets attributes (userId, sessionId, tags, metadata) in the OpenTelemetry
33
- * context, which are automatically propagated to all spans created within the wrapped function.
34
- *
35
- * Instrumentation behavior:
36
- * - If `initializePingops` was called: All HTTP requests are instrumented by default.
37
- * `wrapHttp` only adds attributes to spans created within the wrapped block.
38
- * - If `initializePingops` was NOT called: Only HTTP requests within `wrapHttp` blocks
39
- * are instrumented. Requests outside `wrapHttp` are not instrumented.
30
+ * Returns the trace ID of the currently active span, if any.
31
+ */
32
+ declare function getActiveTraceId(): string | undefined;
33
+ /**
34
+ * Returns the span ID of the currently active span, if any.
35
+ */
36
+ declare function getActiveSpanId(): string | undefined;
37
+ /**
38
+ * Starts a new trace using the PingOps tracer provider and runs the callback within that trace.
39
+ * Sets attributes (traceId, userId, sessionId, tags, metadata, etc.) in context so they are
40
+ * propagated to spans created within the callback.
40
41
  *
41
- * @param options - Options including attributes to propagate to spans
42
- * @param fn - Function to execute within the attribute context
43
- * @returns The result of the function
42
+ * @param options - Options including optional attributes and optional seed for deterministic traceId
43
+ * @param fn - Function to execute within the trace and attribute context
44
+ * @returns Promise resolving to the result of the function
44
45
  *
45
46
  * @example
46
47
  * ```typescript
47
- * import { wrapHttp } from '@pingops/sdk';
48
+ * import { startTrace, initializePingops } from '@pingops/sdk';
48
49
  *
49
- * // Scenario 1: initializePingops was called
50
50
  * initializePingops({ ... });
51
51
  *
52
- * // All HTTP requests are instrumented, but this block adds attributes
53
- * const result = await wrapHttp({
52
+ * const result = await startTrace({
54
53
  * attributes: {
55
54
  * userId: 'user-123',
56
55
  * sessionId: 'session-456',
57
56
  * tags: ['production', 'api'],
58
57
  * metadata: { environment: 'prod', version: '1.0.0' }
59
- * }
58
+ * },
59
+ * seed: 'request-123' // optional: deterministic traceId from this seed
60
60
  * }, async () => {
61
- * // This HTTP request will be instrumented AND have the attributes set above
62
61
  * const response = await fetch('https://api.example.com/users/123');
63
62
  * return response.json();
64
63
  * });
65
- *
66
- * // HTTP requests outside wrapHttp are still instrumented, just without the attributes
67
- * const otherResponse = await fetch('https://api.example.com/other');
68
- *
69
- * // Scenario 2: initializePingops was NOT called
70
- * // Only requests within wrapHttp are instrumented
71
- * await wrapHttp({
72
- * attributes: { userId: 'user-123' }
73
- * }, async () => {
74
- * // This request IS instrumented
75
- * return fetch('https://api.example.com/data');
76
- * });
77
- *
78
- * // This request is NOT instrumented (outside wrapHttp)
79
- * await fetch('https://api.example.com/other');
80
64
  * ```
81
65
  */
82
- declare function wrapHttp<T>(options: {
83
- attributes?: WrapHttpAttributes$1;
84
- }, fn: () => T | Promise<T>): T | Promise<T>;
66
+ declare function startTrace<T>(options: {
67
+ attributes?: PingopsTraceAttributes$1;
68
+ seed?: string;
69
+ }, fn: () => T | Promise<T>): Promise<T>;
85
70
  //#endregion
86
- export { type WrapHttpAttributes, initializePingops, shutdownPingops, wrapHttp };
71
+ export { type PingopsTraceAttributes, getActiveSpanId, getActiveTraceId, initializePingops, shutdownPingops, startTrace };
87
72
  //# sourceMappingURL=index.d.cts.map