@monocle.sh/adonisjs-agent 1.0.2 → 1.1.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/dist/ai.d.mts ADDED
@@ -0,0 +1,2 @@
1
+ import { getConversationId, withConversationId } from "@monocle.sh/instrumentation-vercel-ai";
2
+ export { getConversationId, withConversationId };
package/dist/ai.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { getConversationId, withConversationId } from "@monocle.sh/instrumentation-vercel-ai";
2
+ export { getConversationId, withConversationId };
@@ -1,14 +1,6 @@
1
- import { Attributes } from "@opentelemetry/api";
1
+ import { SpanAllOptions, SpanOptions } from "./src/types/decorators.mjs";
2
2
 
3
3
  //#region src/decorators.d.ts
4
- interface SpanOptions {
5
- name?: string;
6
- attributes?: Attributes;
7
- }
8
- interface SpanAllOptions {
9
- prefix?: string;
10
- attributes?: Attributes;
11
- }
12
4
  /**
13
5
  * Decorator to create a span around a method.
14
6
  *
@@ -80,4 +72,4 @@ declare function span(options?: SpanOptions): (target: any, propertyKey: string,
80
72
  */
81
73
  declare function spanAll(options?: SpanAllOptions): <T extends new (...args: any[]) => any>(constructor: T) => T;
82
74
  //#endregion
83
- export { SpanAllOptions, SpanOptions, span, spanAll };
75
+ export { span, spanAll };
package/dist/index.d.mts CHANGED
@@ -1,8 +1,9 @@
1
- import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./src/types.mjs";
1
+ import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./src/types/config.mjs";
2
2
  import { defineConfig } from "./src/define_config.mjs";
3
+ import { SpanAllOptions, SpanOptions } from "./src/types/decorators.mjs";
3
4
  import { Monocle } from "./src/monocle.mjs";
4
5
  import { configure } from "./configure.mjs";
5
6
  import { extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes } from "./helpers.mjs";
6
- import { SpanAllOptions, SpanOptions, span, spanAll } from "./decorators.mjs";
7
+ import { span, spanAll } from "./decorators.mjs";
7
8
  import { destinations } from "@adonisjs/otel";
8
9
  export { type BatchConfig, type CliTracingConfig, type HostMetricsConfig, Monocle, type MonocleConfig, type SpanAllOptions, type SpanOptions, configure, defineConfig, destinations, extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes, span, spanAll };
package/dist/init.mjs CHANGED
@@ -23,6 +23,22 @@ async function init(dirname) {
23
23
  const config = await loadConfig(join(dirname, "config/monocle.js"));
24
24
  if (!config) return;
25
25
  if (!OtelManager.isEnabled(config)) return;
26
+ /**
27
+ * AI SDK Instrumentation (Vercel AI SDK)
28
+ *
29
+ * Uses import-in-the-middle to hook the `ai` module BEFORE it's loaded.
30
+ * Must be registered before OtelManager.create() so the hook is in place.
31
+ * The SpanProcessor is added via config.spanProcessors.
32
+ */
33
+ if (config.ai !== false) try {
34
+ const { VercelAiInstrumentation, VercelAiSpanProcessor } = await import("@monocle.sh/instrumentation-vercel-ai");
35
+ const aiOpts = typeof config.ai === "object" ? config.ai : {};
36
+ new VercelAiInstrumentation({
37
+ recordInputs: aiOpts.recordInputs,
38
+ recordOutputs: aiOpts.recordOutputs
39
+ }).enable();
40
+ config.spanProcessors = [...config.spanProcessors ?? [], new VercelAiSpanProcessor()];
41
+ } catch {}
26
42
  const manager = OtelManager.create(config);
27
43
  manager?.start();
28
44
  const shutdown = async () => {
@@ -87,6 +103,18 @@ async function init(dirname) {
87
103
  await instrumentQueue(queueConfig ?? { enabled: true }, dirname);
88
104
  }
89
105
  /**
106
+ * BullMQ Instrumentation
107
+ *
108
+ * Automatically instruments bullmq if installed.
109
+ * Creates PRODUCER spans for dispatch and CONSUMER spans for execution,
110
+ * with configurable span link mode and queue time calculation.
111
+ */
112
+ const bullmqConfig = config.bullmq;
113
+ if (bullmqConfig !== false) {
114
+ const { instrumentBullMQ } = await import("./src/instrumentations/bullmq/instrumentation.mjs");
115
+ await instrumentBullMQ(bullmqConfig);
116
+ }
117
+ /**
90
118
  * Cache Instrumentation
91
119
  *
92
120
  * Automatically instruments @adonisjs/cache (bentocache) if installed.
@@ -1,4 +1,4 @@
1
- import { MonocleConfig } from "./types.mjs";
1
+ import { MonocleConfig } from "./types/config.mjs";
2
2
 
3
3
  //#region src/define_config.d.ts
4
4
  /**
@@ -0,0 +1,15 @@
1
+ //#region src/instrumentations/bullmq/instrumentation.ts
2
+ /**
3
+ * Auto-instruments BullMQ with OpenTelemetry spans for job
4
+ * dispatch (PRODUCER) and execution (CONSUMER).
5
+ *
6
+ * Does nothing if `@monocle.sh/instrumentation-bullmq` is not installed.
7
+ */
8
+ async function instrumentBullMQ(config) {
9
+ try {
10
+ const { BullMQInstrumentation } = await import("@monocle.sh/instrumentation-bullmq");
11
+ new BullMQInstrumentation(config).enable();
12
+ } catch {}
13
+ }
14
+ //#endregion
15
+ export { instrumentBullMQ };
@@ -112,23 +112,34 @@ var MailInstrumentation = class extends InstrumentationBase {
112
112
  }
113
113
  /**
114
114
  * Patches Mailer.prototype methods with tracing wrappers.
115
+ *
116
+ * Note: InstrumentationBase constructor calls enable() synchronously
117
+ * without awaiting (it ignores the returned Promise). Then instrumentMail()
118
+ * also calls `await enable()`. Setting `this.patched = true` before any
119
+ * `await` prevents the second call from double-patching the prototype,
120
+ * which would create duplicate spans for every email sent.
115
121
  */
116
122
  async enable() {
117
123
  if (this.patched) return;
124
+ this.patched = true;
118
125
  const appRoot = this.getConfig().appRoot;
119
126
  const require = createRequire(appRoot ? pathToFileURL(`${appRoot}/package.json`).href : import.meta.url);
120
127
  let mailerPath;
121
128
  try {
122
129
  mailerPath = require.resolve("@adonisjs/mail");
123
130
  } catch {
131
+ this.patched = false;
124
132
  return;
125
133
  }
126
- this.mailerClass = (await import(pathToFileURL(mailerPath).href)).Mailer;
127
- this.originalSendCompiled = this.mailerClass.prototype.sendCompiled;
128
- this.originalSendLaterCompiled = this.mailerClass.prototype.sendLaterCompiled;
129
- this.mailerClass.prototype.sendCompiled = this.#createSendCompiledWrapper(this.originalSendCompiled);
130
- this.mailerClass.prototype.sendLaterCompiled = this.#createSendLaterCompiledWrapper(this.originalSendLaterCompiled);
131
- this.patched = true;
134
+ try {
135
+ this.mailerClass = (await import(pathToFileURL(mailerPath).href)).Mailer;
136
+ this.originalSendCompiled = this.mailerClass.prototype.sendCompiled;
137
+ this.originalSendLaterCompiled = this.mailerClass.prototype.sendLaterCompiled;
138
+ this.mailerClass.prototype.sendCompiled = this.#createSendCompiledWrapper(this.originalSendCompiled);
139
+ this.mailerClass.prototype.sendLaterCompiled = this.#createSendLaterCompiledWrapper(this.originalSendLaterCompiled);
140
+ } catch {
141
+ this.patched = false;
142
+ }
132
143
  }
133
144
  /**
134
145
  * Restores original Mailer.prototype methods.
@@ -11,21 +11,31 @@ import { pathToFileURL } from "node:url";
11
11
  async function instrumentQueue(config, appRoot) {
12
12
  if (config.enabled === false) return void 0;
13
13
  const appRequire = createRequire(appRoot ? pathToFileURL(`${appRoot}/package.json`).href : import.meta.url);
14
+ let queueOtelPath;
14
15
  try {
15
- appRequire.resolve("@boringnode/queue");
16
+ queueOtelPath = appRequire.resolve("@boringnode/queue/otel");
16
17
  } catch {
17
- return;
18
+ try {
19
+ queueOtelPath = appRequire.resolve("@adonisjs/queue/otel");
20
+ } catch {
21
+ return;
22
+ }
18
23
  }
19
- const { QueueInstrumentation } = await import("@boringnode/queue/otel");
24
+ const { QueueInstrumentation } = await import(pathToFileURL(queueOtelPath).href);
20
25
  const instrumentation = new QueueInstrumentation({
21
26
  executionSpanLinkMode: config.executionSpanLinkMode,
22
27
  messagingSystem: config.messagingSystem
23
28
  });
24
29
  instrumentation.enable();
25
30
  try {
26
- const queueModule = await import("@boringnode/queue");
31
+ const queueModule = await import(pathToFileURL(appRequire.resolve("@boringnode/queue")).href);
27
32
  instrumentation.manuallyRegister(queueModule);
28
- } catch {}
33
+ } catch {
34
+ try {
35
+ const queueModule = await import(pathToFileURL(appRequire.resolve("@adonisjs/queue")).href);
36
+ instrumentation.manuallyRegister(queueModule);
37
+ } catch {}
38
+ }
29
39
  return instrumentation;
30
40
  }
31
41
  //#endregion
@@ -1,28 +1,6 @@
1
- import { UserContextResult } from "@adonisjs/otel/types";
1
+ import { CaptureExceptionContext, CaptureMessageContext, MessageLevel, MonocleUser } from "./types/monocle.mjs";
2
2
 
3
3
  //#region src/monocle.d.ts
4
- type MessageLevel = 'debug' | 'info' | 'log' | 'warning' | 'error' | 'fatal';
5
- interface CaptureContext {
6
- user?: {
7
- id: string;
8
- email?: string;
9
- name?: string;
10
- };
11
- tags?: Record<string, string>;
12
- extra?: Record<string, unknown>;
13
- }
14
- interface CaptureMessageContext extends CaptureContext {
15
- level?: MessageLevel;
16
- }
17
- type CaptureExceptionContext = CaptureContext;
18
- /**
19
- * User information for tracing. When displayed in the Monocle UI,
20
- * `name` takes priority over `email` as the display label, with
21
- * `email` used as fallback.
22
- */
23
- interface MonocleUser extends UserContextResult {
24
- name?: string;
25
- }
26
4
  /**
27
5
  * Monocle helper class for manual instrumentation.
28
6
  */
@@ -55,4 +33,4 @@ declare class Monocle {
55
33
  static setUser(user: MonocleUser): void;
56
34
  }
57
35
  //#endregion
58
- export { Monocle, MonocleUser };
36
+ export { Monocle };
@@ -1,7 +1,8 @@
1
+ import { BullMQInstrumentationConfig } from "@monocle.sh/instrumentation-bullmq";
1
2
  import { BentoCacheInstrumentationConfig } from "@bentocache/otel/types";
2
3
  import { DestinationMap, OtelConfig } from "@adonisjs/otel/types";
3
4
 
4
- //#region src/types.d.ts
5
+ //#region src/types/config.d.ts
5
6
  /**
6
7
  * Configuration for cache instrumentation
7
8
  */
@@ -86,6 +87,22 @@ interface BatchConfig {
86
87
  */
87
88
  maxQueueSize?: number;
88
89
  }
90
+ /**
91
+ * Configuration for AI SDK instrumentation
92
+ */
93
+ interface AiInstrumentationConfig {
94
+ /**
95
+ * Record prompt/input data in span attributes.
96
+ * @default true
97
+ */
98
+ recordInputs?: boolean;
99
+ /**
100
+ * Record response/output data in span attributes.
101
+ * @default true
102
+ */
103
+ recordOutputs?: boolean;
104
+ }
105
+ type BullMQAgentConfig = BullMQInstrumentationConfig;
89
106
  interface MonocleConfig extends Omit<OtelConfig, 'traceExporter' | 'metricExporter'> {
90
107
  /**
91
108
  * Your Monocle API key. If not provided, telemetry will be disabled.
@@ -158,6 +175,20 @@ interface MonocleConfig extends Omit<OtelConfig, 'traceExporter' | 'metricExport
158
175
  * @default { enabled: true }
159
176
  */
160
177
  queue?: false | QueueInstrumentationConfig;
178
+ /**
179
+ * BullMQ instrumentation configuration.
180
+ * Automatically instruments BullMQ if installed.
181
+ * Set to `false` to disable.
182
+ * @default { enabled: true }
183
+ */
184
+ bullmq?: false | BullMQAgentConfig;
185
+ /**
186
+ * AI SDK instrumentation configuration.
187
+ * Automatically instruments the Vercel AI SDK (`ai` package) if installed.
188
+ * Set to `false` to disable.
189
+ * @default { enabled: true }
190
+ */
191
+ ai?: false | AiInstrumentationConfig;
161
192
  }
162
193
  //#endregion
163
194
  export { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig };
@@ -0,0 +1,13 @@
1
+ import { Attributes } from "@opentelemetry/api";
2
+
3
+ //#region src/types/decorators.d.ts
4
+ interface SpanOptions {
5
+ name?: string;
6
+ attributes?: Attributes;
7
+ }
8
+ interface SpanAllOptions {
9
+ prefix?: string;
10
+ attributes?: Attributes;
11
+ }
12
+ //#endregion
13
+ export { SpanAllOptions, SpanOptions };
@@ -0,0 +1,3 @@
1
+ import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./config.mjs";
2
+ import { SpanAllOptions, SpanOptions } from "./decorators.mjs";
3
+ import { CaptureContext, CaptureExceptionContext, CaptureMessageContext, MessageLevel, MonocleUser } from "./monocle.mjs";
@@ -0,0 +1,27 @@
1
+ import { UserContextResult } from "@adonisjs/otel/types";
2
+
3
+ //#region src/types/monocle.d.ts
4
+ type MessageLevel = 'debug' | 'info' | 'log' | 'warning' | 'error' | 'fatal';
5
+ interface CaptureContext {
6
+ user?: {
7
+ id: string;
8
+ email?: string;
9
+ name?: string;
10
+ };
11
+ tags?: Record<string, string>;
12
+ extra?: Record<string, unknown>;
13
+ }
14
+ interface CaptureMessageContext extends CaptureContext {
15
+ level?: MessageLevel;
16
+ }
17
+ type CaptureExceptionContext = CaptureContext;
18
+ /**
19
+ * User information for tracing. When displayed in the Monocle UI,
20
+ * `name` takes priority over `email` as the display label, with
21
+ * `email` used as fallback.
22
+ */
23
+ interface MonocleUser extends UserContextResult {
24
+ name?: string;
25
+ }
26
+ //#endregion
27
+ export { CaptureContext, CaptureExceptionContext, CaptureMessageContext, MessageLevel, MonocleUser };
package/dist/types.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./src/types.mjs";
2
- import { MonocleUser } from "./src/monocle.mjs";
3
- import { SpanAllOptions, SpanOptions } from "./decorators.mjs";
1
+ import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./src/types/config.mjs";
2
+ import { SpanAllOptions, SpanOptions } from "./src/types/decorators.mjs";
3
+ import { MonocleUser } from "./src/types/monocle.mjs";
4
4
  import { DestinationConfig, DestinationMap, DestinationSignal, DestinationSignals, HeadersCarrier, OtelLoggingPresetOptions, OtlpDestinationConfig, OtlpDestinationOptions, UserContextResult } from "@adonisjs/otel/types";
5
5
  export { type BatchConfig, type CliTracingConfig, type DestinationConfig, type DestinationMap, type DestinationSignal, type DestinationSignals, type HeadersCarrier, type HostMetricsConfig, type MonocleConfig, type MonocleUser, type OtelLoggingPresetOptions, type OtlpDestinationConfig, type OtlpDestinationOptions, type SpanAllOptions, type SpanOptions, type UserContextResult };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monocle.sh/adonisjs-agent",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Monocle agent for AdonisJS - sends telemetry to Monocle cloud",
5
5
  "keywords": [
6
6
  "adonisjs",
@@ -24,6 +24,7 @@
24
24
  "types": "./dist/index.d.mts",
25
25
  "exports": {
26
26
  ".": "./dist/index.mjs",
27
+ "./ai": "./dist/ai.mjs",
27
28
  "./decorators": "./dist/decorators.mjs",
28
29
  "./helpers": "./dist/helpers.mjs",
29
30
  "./init": "./dist/init.mjs",
@@ -52,8 +53,10 @@
52
53
  "@sindresorhus/is": "^7.2.0",
53
54
  "error-stack-parser-es": "^1.0.5",
54
55
  "import-in-the-middle": "^3.0.0",
56
+ "@monocle.sh/instrumentation-bullmq": "^0.2.0",
55
57
  "@monocle.sh/instrumentation-mcp": "^1.0.0",
56
- "@monocle.sh/otel-utils": "^1.0.0"
58
+ "@monocle.sh/instrumentation-vercel-ai": "^1.1.0",
59
+ "@monocle.sh/otel-utils": "^1.0.1"
57
60
  },
58
61
  "devDependencies": {
59
62
  "@adonisjs/core": "^7.1.1",