@owlpane/node 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Owlpane
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # @owlpane/node
2
+
3
+ One-line OpenTelemetry setup for Node.js that sends traces and metrics to Owlpane, plus job tracing and
4
+ per-user tagging. Optional NestJS helpers live at `@owlpane/node/nest`.
5
+
6
+ ```ts
7
+ // Run before anything else is imported (for example the first line of main.ts).
8
+ import { owlpane } from "@owlpane/node";
9
+
10
+ owlpane.start({
11
+ service: "checkout-api",
12
+ endpoint: "https://ingest.example.com", // your Owlpane ingest gateway
13
+ ingestKey: process.env.OWLPANE_INGEST_KEY, // owl_ing_..., one per project
14
+ release: process.env.GIT_SHA, // shows on the Releases page
15
+ });
16
+ ```
17
+
18
+ Everything can also come from environment variables: `OTEL_EXPORTER_OTLP_ENDPOINT`, `OWLPANE_INGEST_KEY`,
19
+ `OTEL_SERVICE_NAME`, `OWLPANE_RELEASE`, `OWLPANE_ENVIRONMENT`. Set `OTEL_SDK_DISABLED=true` to switch it off.
20
+
21
+ - **Never blocks your app.** Export is batched and fails quietly; the SDK does nothing when no endpoint is set.
22
+ - **Your key is a write-only credential.** It can send data for one project and cannot read anything.
23
+ - **Privacy.** Query strings, cookies and authorization headers are removed at the gateway as well as here.
24
+
25
+ Track a background job: `await owlpane.job("nightly-report", "cron", async () => { ... })`.
26
+ Tag the signed-in user (opaque id only): `owlpane.setUser(user.id)`. Email and name are **not** recorded unless you opt in with `traceUserProfile: true` or `OWLPANE_TRACE_USER_PROFILE=1` (discouraged for production).
27
+
28
+ **LLM usage in Owlpane:** when your app calls the official [`openai`](https://www.npmjs.com/package/openai) client (including Groq via `baseURL: "https://api.groq.com/openai/v1"`), `@opentelemetry/instrumentation-openai` is registered automatically and emits `gen_ai.*` span attributes for the LLM usage page. Disable with `disableInstrumentations: ["@opentelemetry/instrumentation-openai"]`. Raw `fetch` to an LLM API is not instrumented.
29
+
30
+ Full documentation: the `docs/05-onboarding-applications.md` guide in the Owlpane repository.
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @owlpane/node — one-line OpenTelemetry setup for any Node.js service.
3
+ *
4
+ * import { owlpane } from "@owlpane/node";
5
+ * owlpane.start({ service: "my-api" }); // call before any other app code is imported
6
+ *
7
+ * Activation: set OWLPANE_INGEST_URL (or the standard OTEL_EXPORTER_OTLP_ENDPOINT) to turn on.
8
+ * Without it, start() is a no-op — zero overhead when there is nowhere to send data.
9
+ *
10
+ * What you get: HTTP/Express/pg/ioredis/… auto-instrumentation, a `job()` wrapper for background
11
+ * work (cron, queue, one-off), `setUser()` to tag the current trace with a signed-in user, and
12
+ * process CPU/memory metrics. Framework-specific helpers (NestJS job discovery, a request
13
+ * interceptor) are at "@owlpane/node/nest" so this entry point has no framework dependency.
14
+ */
15
+ import { api } from "@opentelemetry/sdk-node";
16
+ export type InitOptions = {
17
+ /** Shows up as `service.name`. Falls back to OTEL_SERVICE_NAME, then "node-app". */
18
+ service?: string;
19
+ /** OTLP/HTTP endpoint (an Owlpane ingest gateway, or any OTel collector). Falls back to OTEL_EXPORTER_OTLP_ENDPOINT. */
20
+ endpoint?: string;
21
+ /** Sent as `Authorization: Bearer <key>` to the ingest gateway. */
22
+ ingestKey?: string;
23
+ /** `deployment.environment.name`. Falls back to OTEL_RESOURCE_ATTRIBUTES / NODE_ENV. */
24
+ environment?: string;
25
+ /** `service.version` — the release/deploy identifier shown on the Releases page. */
26
+ release?: string;
27
+ /** Trace sample ratio 0–1. */
28
+ sampleRatio?: number;
29
+ /** Extra resource attributes merged in alongside service/version/environment. */
30
+ resourceAttributes?: Record<string, string>;
31
+ /** Auto-instrumentation names to turn off, e.g. ["@opentelemetry/instrumentation-fs"]. */
32
+ disableInstrumentations?: string[];
33
+ /** When true, setUser may record enduser.email / enduser.name (off by default). */
34
+ traceUserProfile?: boolean;
35
+ };
36
+ /** Whether setUser may attach email/name (requires start({ traceUserProfile: true }) or OWLPANE_TRACE_USER_PROFILE=1). */
37
+ export declare function traceUserProfileEnabled(): boolean;
38
+ /** True once `start()` has turned tracing on (an endpoint was configured and it isn't disabled). */
39
+ export declare function isEnabled(): boolean;
40
+ /**
41
+ * Starts the telemetry pipeline. Call once, as the very first thing the process does — before any
42
+ * other import — so every module picks up the instrumented http/pg/etc. Safe to call when
43
+ * unconfigured: it just does nothing.
44
+ */
45
+ export declare function start(options?: InitOptions): void;
46
+ /** Flushes and stops the pipeline. Call on shutdown so the last batch of spans isn't dropped. */
47
+ export declare function shutdown(): Promise<void>;
48
+ export type JobKind = "cron" | "interval" | "timeout" | "queue" | "task";
49
+ /**
50
+ * Runs `fn` as a traced, measured unit of background work: a root span named `name` (so the
51
+ * work's own database/HTTP calls nest under it instead of being dropped as parentless), plus a
52
+ * `job.duration` histogram recording (job.name, job.kind, job.outcome) that stays exact even when
53
+ * traces are sampled. Errors are recorded on the span and re-thrown unchanged.
54
+ */
55
+ export declare function job<T>(name: string, kind: JobKind, attributes: api.Attributes, fn: () => Promise<T>): Promise<T>;
56
+ /**
57
+ * Tags the current trace with the signed-in user (`enduser.id`), so per-user activity and errors
58
+ * show up in the console. Call from request middleware/an interceptor once the user is known.
59
+ * Only the opaque id is recorded — never email or name.
60
+ */
61
+ export declare function setUser(id: string, profile?: {
62
+ email?: string;
63
+ name?: string;
64
+ }): void;
65
+ export declare const owlpane: {
66
+ start: typeof start;
67
+ shutdown: typeof shutdown;
68
+ job: typeof job;
69
+ setUser: typeof setUser;
70
+ isEnabled: typeof isEnabled;
71
+ };
package/dist/index.js ADDED
@@ -0,0 +1,248 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.owlpane = void 0;
4
+ exports.traceUserProfileEnabled = traceUserProfileEnabled;
5
+ exports.isEnabled = isEnabled;
6
+ exports.start = start;
7
+ exports.shutdown = shutdown;
8
+ exports.job = job;
9
+ exports.setUser = setUser;
10
+ /**
11
+ * @owlpane/node — one-line OpenTelemetry setup for any Node.js service.
12
+ *
13
+ * import { owlpane } from "@owlpane/node";
14
+ * owlpane.start({ service: "my-api" }); // call before any other app code is imported
15
+ *
16
+ * Activation: set OWLPANE_INGEST_URL (or the standard OTEL_EXPORTER_OTLP_ENDPOINT) to turn on.
17
+ * Without it, start() is a no-op — zero overhead when there is nowhere to send data.
18
+ *
19
+ * What you get: HTTP/Express/pg/ioredis/… auto-instrumentation, a `job()` wrapper for background
20
+ * work (cron, queue, one-off), `setUser()` to tag the current trace with a signed-in user, and
21
+ * process CPU/memory metrics. Framework-specific helpers (NestJS job discovery, a request
22
+ * interceptor) are at "@owlpane/node/nest" so this entry point has no framework dependency.
23
+ */
24
+ const sdk_node_1 = require("@opentelemetry/sdk-node");
25
+ const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
26
+ const exporter_logs_otlp_http_1 = require("@opentelemetry/exporter-logs-otlp-http");
27
+ const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
28
+ const instrumentation_openai_1 = require("@opentelemetry/instrumentation-openai");
29
+ const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
30
+ const api_logs_1 = require("@opentelemetry/api-logs");
31
+ const sdk_logs_1 = require("@opentelemetry/sdk-logs");
32
+ const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
33
+ const { BatchSpanProcessor, ParentBasedSampler, TraceIdRatioBasedSampler } = sdk_node_1.tracing;
34
+ const { resourceFromAttributes } = sdk_node_1.resources;
35
+ let sdk;
36
+ let logProvider;
37
+ let traceUserProfile = false;
38
+ /** Whether setUser may attach email/name (requires start({ traceUserProfile: true }) or OWLPANE_TRACE_USER_PROFILE=1). */
39
+ function traceUserProfileEnabled() {
40
+ return traceUserProfile;
41
+ }
42
+ function endpointOf(o) {
43
+ return (o.endpoint?.trim() || process.env.OTEL_EXPORTER_OTLP_ENDPOINT?.trim() || undefined);
44
+ }
45
+ /** True once `start()` has turned tracing on (an endpoint was configured and it isn't disabled). */
46
+ function isEnabled() {
47
+ return sdk !== undefined;
48
+ }
49
+ function sampleRatio(o) {
50
+ if (o.sampleRatio !== undefined)
51
+ return o.sampleRatio;
52
+ const raw = process.env.OTEL_TRACES_SAMPLER_ARG;
53
+ if (!raw)
54
+ return process.env.NODE_ENV === "production" ? 0.1 : 1;
55
+ const n = Number.parseFloat(raw);
56
+ return Number.isFinite(n) && n >= 0 && n <= 1 ? n : 0.1;
57
+ }
58
+ /**
59
+ * Starts the telemetry pipeline. Call once, as the very first thing the process does — before any
60
+ * other import — so every module picks up the instrumented http/pg/etc. Safe to call when
61
+ * unconfigured: it just does nothing.
62
+ */
63
+ function start(options = {}) {
64
+ if (process.env.OTEL_SDK_DISABLED === "true")
65
+ return;
66
+ traceUserProfile =
67
+ options.traceUserProfile === true ||
68
+ ["1", "true", "yes"].includes((process.env.OWLPANE_TRACE_USER_PROFILE ?? "").trim().toLowerCase());
69
+ const endpoint = endpointOf(options);
70
+ if (!endpoint)
71
+ return;
72
+ if (sdk)
73
+ return; // already started
74
+ const serviceName = options.service?.trim() ||
75
+ process.env.OTEL_SERVICE_NAME?.trim() ||
76
+ "node-app";
77
+ const version = options.release?.trim() ||
78
+ process.env.OWLPANE_RELEASE?.trim() ||
79
+ "0.0.0";
80
+ const environment = options.environment?.trim() ||
81
+ process.env.OWLPANE_ENVIRONMENT?.trim() ||
82
+ process.env.NODE_ENV?.trim() ||
83
+ "development";
84
+ const ingestKey = options.ingestKey?.trim() || process.env.OWLPANE_INGEST_KEY?.trim();
85
+ const headers = ingestKey ? { Authorization: `Bearer ${ingestKey}` } : undefined;
86
+ const baseUrl = endpoint.replace(/\/+$/, "");
87
+ const exportProcessor = new BatchSpanProcessor(new exporter_trace_otlp_http_1.OTLPTraceExporter({ url: `${baseUrl}/v1/traces`, headers }));
88
+ const ratio = sampleRatio(options);
89
+ const disabled = new Set(options.disableInstrumentations ?? []);
90
+ const off = (name) => ({ enabled: !disabled.has(name) });
91
+ const resource = resourceFromAttributes({
92
+ [semantic_conventions_1.ATTR_SERVICE_NAME]: serviceName,
93
+ [semantic_conventions_1.ATTR_SERVICE_VERSION]: version,
94
+ "deployment.environment.name": environment,
95
+ ...options.resourceAttributes,
96
+ });
97
+ logProvider = new sdk_logs_1.LoggerProvider({
98
+ resource,
99
+ processors: [
100
+ new sdk_logs_1.BatchLogRecordProcessor({
101
+ exporter: new exporter_logs_otlp_http_1.OTLPLogExporter({ url: `${baseUrl}/v1/logs`, headers }),
102
+ }),
103
+ ],
104
+ });
105
+ api_logs_1.logs.setGlobalLoggerProvider(logProvider);
106
+ sdk = new sdk_node_1.NodeSDK({
107
+ resource,
108
+ spanProcessors: [exportProcessor],
109
+ // Metrics go to the same gateway with the same key; left to environment defaults they would be
110
+ // sent without the credential and refused.
111
+ metricReaders: [
112
+ new sdk_node_1.metrics.PeriodicExportingMetricReader({
113
+ exporter: new exporter_metrics_otlp_http_1.OTLPMetricExporter({ url: `${baseUrl}/v1/metrics`, headers }),
114
+ exportIntervalMillis: Math.max(5_000, Number(process.env.OWLPANE_METRICS_EXPORT_INTERVAL_MS?.trim()) || 30_000),
115
+ }),
116
+ ],
117
+ sampler: new ParentBasedSampler({
118
+ root: new TraceIdRatioBasedSampler(ratio),
119
+ }),
120
+ instrumentations: [
121
+ (0, auto_instrumentations_node_1.getNodeAutoInstrumentations)({
122
+ "@opentelemetry/instrumentation-fs": off("@opentelemetry/instrumentation-fs"),
123
+ "@opentelemetry/instrumentation-dns": off("@opentelemetry/instrumentation-dns"),
124
+ // A tcp.connect span per socket and a span per router layer are low-value noise.
125
+ "@opentelemetry/instrumentation-net": off("@opentelemetry/instrumentation-net"),
126
+ "@opentelemetry/instrumentation-router": off("@opentelemetry/instrumentation-router"),
127
+ // Each sync Express layer registers res.once("finish"). Nest + pino-http + HTTP instr. exceed
128
+ // Node's default MaxListeners (10). Use HTTP + Nest instrumentations for request spans instead.
129
+ "@opentelemetry/instrumentation-express": off("@opentelemetry/instrumentation-express"),
130
+ // Only trace queries inside a request or job span, so idle background loops don't emit
131
+ // hundreds of parentless query spans per minute; wrap loop iterations with job() instead.
132
+ "@opentelemetry/instrumentation-pg": { requireParentSpan: true, ...off("@opentelemetry/instrumentation-pg") },
133
+ // nestjs-pino → OTLP logs (Owlpane Logs page) with trace correlation when a span is active.
134
+ "@opentelemetry/instrumentation-pino": off("@opentelemetry/instrumentation-pino"),
135
+ }),
136
+ ...(disabled.has("@opentelemetry/instrumentation-openai")
137
+ ? []
138
+ : [new instrumentation_openai_1.OpenAIInstrumentation()]),
139
+ ],
140
+ });
141
+ sdk.start();
142
+ registerProcessMetrics(serviceName);
143
+ }
144
+ /** Flushes and stops the pipeline. Call on shutdown so the last batch of spans isn't dropped. */
145
+ function shutdown() {
146
+ return Promise.all([sdk?.shutdown(), logProvider?.shutdown()]).then(() => undefined);
147
+ }
148
+ let jobHistogram;
149
+ function histogram() {
150
+ jobHistogram ??= sdk_node_1.api.metrics
151
+ .getMeter("owlpane-jobs")
152
+ .createHistogram("job.duration", {
153
+ unit: "s",
154
+ description: "Background job run time, by job and outcome",
155
+ advice: {
156
+ explicitBucketBoundaries: [0.01, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10, 30, 60, 300],
157
+ },
158
+ });
159
+ return jobHistogram;
160
+ }
161
+ /**
162
+ * Runs `fn` as a traced, measured unit of background work: a root span named `name` (so the
163
+ * work's own database/HTTP calls nest under it instead of being dropped as parentless), plus a
164
+ * `job.duration` histogram recording (job.name, job.kind, job.outcome) that stays exact even when
165
+ * traces are sampled. Errors are recorded on the span and re-thrown unchanged.
166
+ */
167
+ async function job(name, kind, attributes, fn) {
168
+ const started = performance.now();
169
+ const tracer = sdk_node_1.api.trace.getTracer("owlpane-jobs");
170
+ return tracer.startActiveSpan(name, {
171
+ root: true,
172
+ kind: kind === "queue" ? sdk_node_1.api.SpanKind.CONSUMER : sdk_node_1.api.SpanKind.INTERNAL,
173
+ attributes: { "job.name": name, "job.kind": kind, ...attributes },
174
+ }, async (span) => {
175
+ let outcome = "success";
176
+ try {
177
+ return await fn();
178
+ }
179
+ catch (err) {
180
+ outcome = "failure";
181
+ const e = err instanceof Error ? err : new Error(String(err));
182
+ span.recordException(e);
183
+ span.setStatus({ code: sdk_node_1.api.SpanStatusCode.ERROR, message: e.message });
184
+ throw err;
185
+ }
186
+ finally {
187
+ span.setAttribute("job.outcome", outcome);
188
+ span.end();
189
+ histogram().record((performance.now() - started) / 1000, {
190
+ "job.name": name,
191
+ "job.kind": kind,
192
+ "job.outcome": outcome,
193
+ });
194
+ }
195
+ });
196
+ }
197
+ // ---------- Users ----------
198
+ /**
199
+ * Tags the current trace with the signed-in user (`enduser.id`), so per-user activity and errors
200
+ * show up in the console. Call from request middleware/an interceptor once the user is known.
201
+ * Only the opaque id is recorded — never email or name.
202
+ */
203
+ function setUser(id, profile) {
204
+ if (!id)
205
+ return;
206
+ const span = sdk_node_1.api.trace.getActiveSpan();
207
+ if (!span)
208
+ return;
209
+ span.setAttribute("enduser.id", id);
210
+ if (!traceUserProfile)
211
+ return;
212
+ const email = profile?.email?.trim();
213
+ const name = profile?.name?.trim();
214
+ if (email)
215
+ span.setAttribute("enduser.email", email);
216
+ if (name)
217
+ span.setAttribute("enduser.name", name);
218
+ }
219
+ // ---------- Process metrics ----------
220
+ /** CPU and resident memory, under semantic-convention names any OTel backend understands. */
221
+ function registerProcessMetrics(meterName) {
222
+ const meter = sdk_node_1.api.metrics.getMeter(`owlpane-process-${meterName}`);
223
+ let lastCpu = process.cpuUsage();
224
+ let lastAt = process.hrtime.bigint();
225
+ meter
226
+ .createObservableGauge("process.cpu.utilization", {
227
+ unit: "1",
228
+ description: "Share of one CPU core used by this process since the previous reading",
229
+ })
230
+ .addCallback((result) => {
231
+ const now = process.hrtime.bigint();
232
+ const cpu = process.cpuUsage();
233
+ const elapsedUs = Number(now - lastAt) / 1000;
234
+ const usedUs = cpu.user - lastCpu.user + (cpu.system - lastCpu.system);
235
+ if (elapsedUs > 0)
236
+ result.observe(usedUs / elapsedUs);
237
+ lastCpu = cpu;
238
+ lastAt = now;
239
+ });
240
+ meter
241
+ .createObservableGauge("process.memory.usage", {
242
+ unit: "By",
243
+ description: "Resident set size",
244
+ })
245
+ .addCallback((result) => result.observe(process.memoryUsage().rss));
246
+ }
247
+ exports.owlpane = { start, shutdown, job, setUser, isEnabled };
248
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/nest.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @owlpane/node/nest — optional NestJS helpers, kept out of the main entry point so a plain Node
3
+ * or Express service pulls in no NestJS code.
4
+ *
5
+ * import { installNestJobTracing, OwlpaneUserInterceptor } from "@owlpane/node/nest";
6
+ * installNestJobTracing(); // after owlpane.start(), before app.listen()
7
+ */
8
+ import type { CallHandler, ExecutionContext, NestInterceptor } from "@nestjs/common";
9
+ import type { Observable } from "rxjs";
10
+ import "reflect-metadata";
11
+ /**
12
+ * Traces every `@Cron`/`@Interval`/`@Timeout` handler (`@nestjs/schedule`) and every BullMQ
13
+ * processor (`@nestjs/bullmq`) as its own root span, named after the class and method or the
14
+ * queue and job name. Each run also feeds the `job.duration` histogram.
15
+ *
16
+ * Works by patching two library extension points instead of touching job code, so a version bump
17
+ * that renames either seam only disables tracing for that one (logged), never breaks the app.
18
+ */
19
+ export declare function installNestJobTracing(): void;
20
+ /**
21
+ * Register globally (`APP_INTERCEPTOR`) to tag each request's trace with the signed-in user
22
+ * (`req.user.id`) once auth guards have run, for per-user activity and error views in the console.
23
+ */
24
+ export declare class OwlpaneUserInterceptor implements NestInterceptor {
25
+ intercept(context: ExecutionContext, next: CallHandler): Observable<unknown>;
26
+ }
package/dist/nest.js ADDED
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.OwlpaneUserInterceptor = void 0;
10
+ exports.installNestJobTracing = installNestJobTracing;
11
+ const common_1 = require("@nestjs/common");
12
+ const node_module_1 = require("node:module");
13
+ const node_path_1 = require("node:path");
14
+ require("reflect-metadata");
15
+ const index_1 = require("./index");
16
+ const logger = new common_1.Logger("OwlpaneNest");
17
+ /** Load a peer from the host app (BFF), not from @owlpane/node's copy — otherwise monkey-patches miss. */
18
+ function requireFromHost(specifier) {
19
+ const roots = new Set();
20
+ const entry = process.argv[1];
21
+ if (entry)
22
+ roots.add((0, node_path_1.join)((0, node_path_1.dirname)(entry), ".."));
23
+ roots.add(process.cwd());
24
+ for (const root of roots) {
25
+ try {
26
+ return (0, node_module_1.createRequire)((0, node_path_1.join)(root, "package.json"))(specifier);
27
+ }
28
+ catch {
29
+ // try next root
30
+ }
31
+ }
32
+ return require(specifier);
33
+ }
34
+ const SCHEDULER_KIND = {
35
+ 1: "cron",
36
+ 2: "timeout",
37
+ 3: "interval",
38
+ };
39
+ let installed = false;
40
+ /**
41
+ * Traces every `@Cron`/`@Interval`/`@Timeout` handler (`@nestjs/schedule`) and every BullMQ
42
+ * processor (`@nestjs/bullmq`) as its own root span, named after the class and method or the
43
+ * queue and job name. Each run also feeds the `job.duration` histogram.
44
+ *
45
+ * Works by patching two library extension points instead of touching job code, so a version bump
46
+ * that renames either seam only disables tracing for that one (logged), never breaks the app.
47
+ */
48
+ function installNestJobTracing() {
49
+ if (installed)
50
+ return;
51
+ installed = true;
52
+ installScheduleTracing();
53
+ installBullmqTracing();
54
+ }
55
+ function installScheduleTracing() {
56
+ try {
57
+ /* eslint-disable @typescript-eslint/no-require-imports -- optional peer dep, loaded lazily */
58
+ const { ScheduleExplorer } = requireFromHost("@nestjs/schedule/dist/schedule.explorer");
59
+ const { SCHEDULER_TYPE } = requireFromHost("@nestjs/schedule/dist/schedule.constants");
60
+ /* eslint-enable @typescript-eslint/no-require-imports */
61
+ const original = ScheduleExplorer?.prototype?.wrapFunctionInTryCatchBlocks;
62
+ if (typeof original !== "function")
63
+ throw new Error("wrapFunctionInTryCatchBlocks not found");
64
+ ScheduleExplorer.prototype.wrapFunctionInTryCatchBlocks = function (methodRef, instance) {
65
+ const className = instance?.constructor?.name ?? "Job";
66
+ const method = methodRef?.name || "run";
67
+ const kind = SCHEDULER_KIND[Reflect.getMetadata(SCHEDULER_TYPE, methodRef)] ?? "cron";
68
+ const name = `${className}.${method}`;
69
+ const traced = function (...args) {
70
+ return (0, index_1.job)(name, kind, { "code.namespace": className, "code.function": method }, async () => methodRef.apply(this, args));
71
+ };
72
+ return original.call(this, traced, instance);
73
+ };
74
+ }
75
+ catch (err) {
76
+ logger.warn(`Scheduled jobs will not be traced: ${String(err)}`);
77
+ }
78
+ }
79
+ function installBullmqTracing() {
80
+ try {
81
+ /* eslint-disable @typescript-eslint/no-require-imports -- optional peer dep, loaded lazily */
82
+ const { ProcessorDecoratorService } = requireFromHost("@nestjs/bullmq/dist/instrument/processor-decorator.service");
83
+ /* eslint-enable @typescript-eslint/no-require-imports */
84
+ const original = ProcessorDecoratorService?.prototype?.decorate;
85
+ if (typeof original !== "function")
86
+ throw new Error("ProcessorDecoratorService.decorate not found");
87
+ ProcessorDecoratorService.prototype.decorate = function (processor) {
88
+ const decorated = original.call(this, processor);
89
+ return (bullJob, ...rest) => {
90
+ const queue = bullJob?.queueName ?? "queue";
91
+ const name = `${queue}.${bullJob?.name ?? "job"}`;
92
+ return (0, index_1.job)(name, "queue", {
93
+ "messaging.system": "bullmq",
94
+ "messaging.destination.name": queue,
95
+ "messaging.message.id": String(bullJob?.id ?? ""),
96
+ "job.attempt": (bullJob?.attemptsMade ?? 0) + 1,
97
+ }, () => decorated(bullJob, ...rest));
98
+ };
99
+ };
100
+ }
101
+ catch (err) {
102
+ logger.warn(`Queue jobs will not be traced: ${String(err)}`);
103
+ }
104
+ }
105
+ /**
106
+ * Register globally (`APP_INTERCEPTOR`) to tag each request's trace with the signed-in user
107
+ * (`req.user.id`) once auth guards have run, for per-user activity and error views in the console.
108
+ */
109
+ let OwlpaneUserInterceptor = class OwlpaneUserInterceptor {
110
+ intercept(context, next) {
111
+ if (context.getType() === "http") {
112
+ const req = context.switchToHttp().getRequest();
113
+ if (typeof req.user?.id === "string") {
114
+ (0, index_1.setUser)(req.user.id, (0, index_1.traceUserProfileEnabled)()
115
+ ? {
116
+ email: typeof req.user.email === "string" ? req.user.email : undefined,
117
+ name: typeof req.user.name === "string" ? req.user.name : undefined,
118
+ }
119
+ : undefined);
120
+ }
121
+ }
122
+ return next.handle();
123
+ }
124
+ };
125
+ exports.OwlpaneUserInterceptor = OwlpaneUserInterceptor;
126
+ exports.OwlpaneUserInterceptor = OwlpaneUserInterceptor = __decorate([
127
+ (0, common_1.Injectable)()
128
+ ], OwlpaneUserInterceptor);
129
+ //# sourceMappingURL=nest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nest.js","sourceRoot":"","sources":["../src/nest.ts"],"names":[],"mappings":"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"}
package/nest.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./dist/nest";
package/nest.js ADDED
@@ -0,0 +1,4 @@
1
+ // Compatibility shim for TS "node10"/classic module resolution, which does not read package.json
2
+ // "exports" subpaths. Modern resolvers (node16/nodenext/bundler) use the "exports" map instead and
3
+ // never load this file. Keep in sync with the "exports" map in package.json.
4
+ module.exports = require("./dist/nest");
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@owlpane/node",
3
+ "version": "0.1.1",
4
+ "description": "Owlpane telemetry SDK for Node.js: one-line OpenTelemetry setup, job tracing, and user tagging. Optional NestJS helpers at @owlpane/node/nest.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/balaji-singh/owlpane-sdk.git",
9
+ "directory": "packages/node"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./nest": {
22
+ "types": "./dist/nest.d.ts",
23
+ "default": "./dist/nest.js"
24
+ }
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "nest.js",
29
+ "nest.d.ts",
30
+ "LICENSE"
31
+ ],
32
+ "scripts": {
33
+ "build": "tsc -p tsconfig.json",
34
+ "typecheck": "tsc -p tsconfig.json --noEmit",
35
+ "test": "node --test --import tsx test/export.test.ts"
36
+ },
37
+ "dependencies": {
38
+ "@opentelemetry/auto-instrumentations-node": "^0.80.0",
39
+ "@opentelemetry/instrumentation-openai": "^0.20.0",
40
+ "@opentelemetry/api-logs": "^0.222.0",
41
+ "@opentelemetry/exporter-logs-otlp-http": "^0.222.0",
42
+ "@opentelemetry/exporter-metrics-otlp-http": "^0.222.0",
43
+ "@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
44
+ "@opentelemetry/sdk-logs": "^0.222.0",
45
+ "@opentelemetry/resources": "^2.6.1",
46
+ "@opentelemetry/sdk-metrics": "^2.11.0",
47
+ "@opentelemetry/sdk-node": "^0.222.0",
48
+ "@opentelemetry/semantic-conventions": "^1.40.0"
49
+ },
50
+ "peerDependencies": {
51
+ "@nestjs/bullmq": "*",
52
+ "@nestjs/common": "*",
53
+ "@nestjs/schedule": "*"
54
+ },
55
+ "peerDependenciesMeta": {
56
+ "@nestjs/bullmq": {
57
+ "optional": true
58
+ },
59
+ "@nestjs/common": {
60
+ "optional": true
61
+ },
62
+ "@nestjs/schedule": {
63
+ "optional": true
64
+ }
65
+ },
66
+ "devDependencies": {
67
+ "@nestjs/bullmq": "^11.0.4",
68
+ "@nestjs/common": "^11.1.16",
69
+ "@nestjs/schedule": "^6.1.1",
70
+ "@types/node": "^20.19.0",
71
+ "reflect-metadata": "^0.2.2",
72
+ "rxjs": "^7.8.2",
73
+ "tsx": "^4.20.6",
74
+ "typescript": "^5.9.3"
75
+ }
76
+ }