@monocle.sh/adonisjs-agent 1.0.3 → 1.2.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 };
@@ -10,7 +10,12 @@ async function configure(command) {
10
10
  * Publish otel.ts at project root
11
11
  */
12
12
  await codemods.makeUsingStub(stubsRoot, "otel.stub", {});
13
- const serverFile = (await codemods.getTsMorphProject())?.getSourceFile(command.app.makePath("bin/server.ts"));
13
+ /**
14
+ * Add otel.ts import as the FIRST import in bin/server.ts
15
+ * This is critical for auto-instrumentation to work
16
+ */
17
+ const project = await codemods.getTsMorphProject();
18
+ const serverFile = project?.getSourceFile(command.app.makePath("bin/server.ts"));
14
19
  if (serverFile) {
15
20
  const insertIndex = serverFile.getImportDeclarations()[0]?.getChildIndex() ?? 0;
16
21
  serverFile.insertStatements(insertIndex, [
@@ -24,6 +29,23 @@ async function configure(command) {
24
29
  await serverFile.save();
25
30
  }
26
31
  /**
32
+ * Add otel.ts import as the FIRST import in bin/console.ts
33
+ * Required for CLI command tracing to work
34
+ */
35
+ const consoleFile = project?.getSourceFile(command.app.makePath("bin/console.ts"));
36
+ if (consoleFile) {
37
+ const insertIndex = consoleFile.getImportDeclarations()[0]?.getChildIndex() ?? 0;
38
+ consoleFile.insertStatements(insertIndex, [
39
+ "/**",
40
+ " * OpenTelemetry initialization - MUST be the first import",
41
+ " * @see https://opentelemetry.io/docs/languages/js/getting-started/nodejs/",
42
+ " */",
43
+ `import '../otel.js'`,
44
+ ""
45
+ ]);
46
+ await consoleFile.save();
47
+ }
48
+ /**
27
49
  * Register the provider in adonisrc.ts
28
50
  */
29
51
  await codemods.updateRcFile((rcFile) => {
@@ -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 () => {
@@ -51,14 +67,14 @@ async function init(dirname) {
51
67
  *
52
68
  * Prerequisites for this to work:
53
69
  * 1. App's `bin/console.ts` must import `otel.ts` FIRST (before reflect-metadata)
54
- * 2. Config must have `cli.enabled: true`
70
+ * 2. Config must not have `cli: false` or `cli.enabled: false`
55
71
  *
56
72
  * @see ./cli_instrumentation.ts for implementation details
57
73
  */
58
74
  const cliConfig = config.cli;
59
- if (cliConfig !== false && cliConfig?.enabled) {
75
+ if (cliConfig !== false && cliConfig?.enabled !== false) {
60
76
  const { instrumentCliCommands } = await import("./src/cli_instrumentation.mjs");
61
- await instrumentCliCommands(cliConfig, dirname);
77
+ await instrumentCliCommands(cliConfig ?? {}, dirname);
62
78
  }
63
79
  /**
64
80
  * Mail Instrumentation
@@ -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
  /**
@@ -20,30 +20,13 @@ function getHeader(response, name) {
20
20
  }
21
21
  }
22
22
  /**
23
- * Returns the raw HTTP header string from a ServerResponse.
24
- * After `writeHead()` is called with inline headers, `getHeader()` returns
25
- * undefined. Node.js stores the serialized headers in `_header` which is
26
- * the only reliable way to read them after they've been flushed.
27
- */
28
- function getRawHeader(response) {
29
- const raw = response._header;
30
- if (typeof raw === "string") return raw;
31
- }
32
- /**
33
23
  * Detects the connection type based on response headers.
34
24
  * Returns 'sse' for Server-Sent Events, 'websocket' for WebSocket upgrades,
35
25
  * or undefined for standard HTTP connections.
36
- *
37
- * Checks both `getHeader()` and the raw `_header` string to handle cases
38
- * where headers are passed inline to `writeHead()` (e.g. @hono/node-server).
39
26
  */
40
27
  function detectConnectionType(response) {
41
28
  if (getHeader(response, "content-type")?.includes("text/event-stream")) return "sse";
42
29
  if (getHeader(response, "upgrade")?.toLowerCase() === "websocket") return "websocket";
43
- const raw = getRawHeader(response);
44
- if (!raw) return;
45
- if (raw.includes("text/event-stream")) return "sse";
46
- if (raw.toLowerCase().includes("upgrade: websocket")) return "websocket";
47
30
  }
48
31
  /**
49
32
  * Creates a response hook that detects long-running HTTP connections
@@ -69,12 +52,18 @@ function extractUserResponseHook(httpConfig) {
69
52
  * Returns undefined if no API key is provided (telemetry will be disabled).
70
53
  */
71
54
  function defineConfig(config) {
72
- if (!config.apiKey) return;
73
- const endpoint = config.endpoint || "https://ingest.monocle.sh";
55
+ const isDev = config.dev ?? process.env.NODE_ENV === "development";
56
+ if (!isDev && !config.apiKey) return;
57
+ if (isDev) process.env.OTEL_EXPORTER_OTLP_PROTOCOL = "http/json";
58
+ const endpoint = isDev ? config.endpoint || "http://localhost:4200" : config.endpoint || "https://ingest.monocle.sh";
74
59
  const environment = config.environment || process.env.NODE_ENV || "development";
75
- const compression = config.compression === false ? "none" : "gzip";
76
- const batchConfig = {
60
+ const compression = isDev ? "none" : config.compression === false ? "none" : "gzip";
61
+ const devBatchConfig = {
77
62
  ...DEFAULT_BATCH_CONFIG,
63
+ scheduledDelayMillis: 100
64
+ };
65
+ const batchConfig = {
66
+ ...isDev ? devBatchConfig : DEFAULT_BATCH_CONFIG,
78
67
  ...config.batch
79
68
  };
80
69
  const httpConfig = config.instrumentations?.["@opentelemetry/instrumentation-http"];
@@ -86,14 +75,13 @@ function defineConfig(config) {
86
75
  responseHook: createConnectionTypeHook(userResponseHook)
87
76
  }
88
77
  };
78
+ const headers = { "x-monocle-env": environment };
79
+ if (config.apiKey) headers["x-api-key"] = config.apiKey;
89
80
  const monocleDestination = destinations.otlp({
90
81
  endpoint,
91
82
  signals: "all",
92
83
  compression,
93
- headers: {
94
- "x-api-key": config.apiKey,
95
- "x-monocle-env": environment
96
- },
84
+ headers,
97
85
  maxExportBatchSize: batchConfig.maxExportBatchSize,
98
86
  scheduledDelayMillis: batchConfig.scheduledDelayMillis,
99
87
  exportTimeoutMillis: batchConfig.exportTimeoutMillis,
@@ -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 };
@@ -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
  */
@@ -30,7 +31,7 @@ interface MailInstrumentationConfig {
30
31
  interface CliTracingConfig {
31
32
  /**
32
33
  * Enable CLI command tracing.
33
- * @default false
34
+ * @default true
34
35
  */
35
36
  enabled?: boolean;
36
37
  /**
@@ -86,7 +87,29 @@ 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'> {
107
+ /**
108
+ * Enable local DevTools mode.
109
+ * Sends telemetry to Monocle DevTools (localhost:4200) with no compression.
110
+ * No API key required.
111
+ */
112
+ dev?: boolean;
90
113
  /**
91
114
  * Your Monocle API key. If not provided, telemetry will be disabled.
92
115
  * Format: mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
@@ -134,7 +157,7 @@ interface MonocleConfig extends Omit<OtelConfig, 'traceExporter' | 'metricExport
134
157
  /**
135
158
  * CLI command tracing configuration.
136
159
  * Set to `false` to disable, or pass config object.
137
- * @default false
160
+ * @default { enabled: true, exclude: ['make:*', 'generate:*', 'queue:work', 'queue:listen'] }
138
161
  */
139
162
  cli?: false | CliTracingConfig;
140
163
  /**
@@ -158,6 +181,20 @@ interface MonocleConfig extends Omit<OtelConfig, 'traceExporter' | 'metricExport
158
181
  * @default { enabled: true }
159
182
  */
160
183
  queue?: false | QueueInstrumentationConfig;
184
+ /**
185
+ * BullMQ instrumentation configuration.
186
+ * Automatically instruments BullMQ if installed.
187
+ * Set to `false` to disable.
188
+ * @default { enabled: true }
189
+ */
190
+ bullmq?: false | BullMQAgentConfig;
191
+ /**
192
+ * AI SDK instrumentation configuration.
193
+ * Automatically instruments the Vercel AI SDK (`ai` package) if installed.
194
+ * Set to `false` to disable.
195
+ * @default { enabled: true }
196
+ */
197
+ ai?: false | AiInstrumentationConfig;
161
198
  }
162
199
  //#endregion
163
200
  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.3",
3
+ "version": "1.2.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",