@monocle.sh/adonisjs-agent 1.0.0-beta.9 → 1.0.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 +11 -3
- package/dist/configure.d.mts +0 -1
- package/dist/configure.mjs +1 -3
- package/dist/decorators.d.mts +83 -0
- package/dist/decorators.mjs +108 -0
- package/dist/helpers.d.mts +49 -0
- package/dist/helpers.mjs +84 -0
- package/dist/index.d.mts +4 -1
- package/dist/index.mjs +4 -2
- package/dist/init.mjs +32 -49
- package/dist/mcp.d.mts +2 -0
- package/dist/mcp.mjs +2 -0
- package/dist/monocle_middleware.mjs +1 -3
- package/dist/monocle_provider.d.mts +0 -1
- package/dist/monocle_provider.mjs +2 -4
- package/dist/src/cli_instrumentation.mjs +48 -11
- package/dist/src/define_config.d.mts +0 -2
- package/dist/src/define_config.mjs +31 -6
- package/dist/src/exception_reporter.mjs +2 -40
- package/dist/src/host_metrics.mjs +1 -3
- package/dist/src/instrumentations/cache/instrumentation.mjs +53 -0
- package/dist/src/instrumentations/mail/instrumentation.mjs +157 -0
- package/dist/src/instrumentations/mail/types.mjs +20 -0
- package/dist/src/monocle.d.mts +20 -4
- package/dist/src/monocle.mjs +49 -6
- package/dist/src/types.d.mts +36 -2
- package/dist/stubs/main.mjs +1 -3
- package/dist/types.d.mts +5 -0
- package/dist/types.mjs +1 -0
- package/package.json +58 -24
- package/dist/src/context_lines.mjs +0 -269
- package/dist/src/error_serializer.mjs +0 -77
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ try {
|
|
|
81
81
|
The `config/monocle.ts` file supports the following options:
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
|
-
import { defineConfig } from '@monocle.sh/adonisjs-agent'
|
|
84
|
+
import { defineConfig, destinations } from '@monocle.sh/adonisjs-agent'
|
|
85
85
|
import env from '#start/env'
|
|
86
86
|
|
|
87
87
|
export default defineConfig({
|
|
@@ -96,6 +96,14 @@ export default defineConfig({
|
|
|
96
96
|
serviceVersion: env.get('APP_VERSION'),
|
|
97
97
|
environment: env.get('APP_ENV'),
|
|
98
98
|
|
|
99
|
+
// Additional OTLP destinations (Monocle is always injected automatically)
|
|
100
|
+
destinations: {
|
|
101
|
+
grafana: destinations.otlp({
|
|
102
|
+
endpoint: env.get('GRAFANA_OTLP_ENDPOINT'),
|
|
103
|
+
signals: 'all',
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
|
|
99
107
|
// Host metrics (CPU, Memory, Network, etc.)
|
|
100
108
|
// Set to false to disable
|
|
101
109
|
hostMetrics: {
|
|
@@ -108,13 +116,13 @@ export default defineConfig({
|
|
|
108
116
|
exclude: ['make:*', 'generate:*', 'queue:work', 'queue:listen'],
|
|
109
117
|
},
|
|
110
118
|
|
|
111
|
-
// Trace batching configuration
|
|
119
|
+
// Trace/log batching configuration for Monocle destination
|
|
112
120
|
batch: {
|
|
113
121
|
maxExportBatchSize: 512,
|
|
114
122
|
scheduledDelayMillis: 5000,
|
|
115
123
|
},
|
|
116
124
|
|
|
117
|
-
// Enable gzip compression (default: true)
|
|
125
|
+
// Enable gzip compression for Monocle destination (default: true)
|
|
118
126
|
compression: true,
|
|
119
127
|
})
|
|
120
128
|
```
|
package/dist/configure.d.mts
CHANGED
package/dist/configure.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { stubsRoot } from "./stubs/main.mjs";
|
|
2
|
-
|
|
3
2
|
//#region configure.ts
|
|
4
3
|
async function configure(command) {
|
|
5
4
|
const codemods = await command.createCodemods();
|
|
@@ -56,6 +55,5 @@ async function configure(command) {
|
|
|
56
55
|
MONOCLE_API_KEY: "Env.schema.string.optional()"
|
|
57
56
|
} });
|
|
58
57
|
}
|
|
59
|
-
|
|
60
58
|
//#endregion
|
|
61
|
-
export { configure };
|
|
59
|
+
export { configure };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Attributes } from "@opentelemetry/api";
|
|
2
|
+
|
|
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
|
+
/**
|
|
13
|
+
* Decorator to create a span around a method.
|
|
14
|
+
*
|
|
15
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
16
|
+
* to capture exceptions with source context lines.
|
|
17
|
+
*
|
|
18
|
+
* Automatically handles:
|
|
19
|
+
* - Creating and closing the span
|
|
20
|
+
* - Capturing exceptions with context frames
|
|
21
|
+
* - Setting error status
|
|
22
|
+
* - Async/await support
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { span } from '@monocle.sh/adonisjs-agent'
|
|
27
|
+
*
|
|
28
|
+
* class UserService {
|
|
29
|
+
* @span()
|
|
30
|
+
* async findById(id: string) {
|
|
31
|
+
* // Span name: "UserService.findById"
|
|
32
|
+
* return db.users.find(id)
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* @span({ name: 'user.create', attributes: { operation: 'create' } })
|
|
36
|
+
* async create(data: UserData) {
|
|
37
|
+
* return db.users.create(data)
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function span(options?: SpanOptions): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
|
|
43
|
+
/**
|
|
44
|
+
* Decorator to create spans around all methods of a class.
|
|
45
|
+
*
|
|
46
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
47
|
+
* to capture exceptions with source context lines.
|
|
48
|
+
*
|
|
49
|
+
* Automatically handles:
|
|
50
|
+
* - Creating and closing spans for each method
|
|
51
|
+
* - Capturing exceptions with context frames
|
|
52
|
+
* - Setting error status
|
|
53
|
+
* - Async/await support
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* import { spanAll } from '@monocle.sh/adonisjs-agent'
|
|
58
|
+
*
|
|
59
|
+
* @spanAll()
|
|
60
|
+
* class OrderService {
|
|
61
|
+
* async create(data: OrderData) {
|
|
62
|
+
* // Span name: "OrderService.create"
|
|
63
|
+
* return db.orders.create(data)
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* async findById(id: string) {
|
|
67
|
+
* // Span name: "OrderService.findById"
|
|
68
|
+
* return db.orders.find(id)
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
*
|
|
72
|
+
* @spanAll({ prefix: 'order' })
|
|
73
|
+
* class OrderService {
|
|
74
|
+
* async create(data: OrderData) {
|
|
75
|
+
* // Span name: "order.create"
|
|
76
|
+
* return db.orders.create(data)
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare function spanAll(options?: SpanAllOptions): <T extends new (...args: any[]) => any>(constructor: T) => T;
|
|
82
|
+
//#endregion
|
|
83
|
+
export { SpanAllOptions, SpanOptions, span, spanAll };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { record } from "./helpers.mjs";
|
|
2
|
+
//#region src/decorators.ts
|
|
3
|
+
/**
|
|
4
|
+
* Wrap a method to create a span around its execution.
|
|
5
|
+
*/
|
|
6
|
+
function wrapMethod(target, propertyKey, descriptor, options) {
|
|
7
|
+
const originalMethod = descriptor.value;
|
|
8
|
+
const className = target.constructor.name;
|
|
9
|
+
descriptor.value = function(...args) {
|
|
10
|
+
return record(options?.name ?? `${className}.${propertyKey}`, (activeSpan) => {
|
|
11
|
+
if (options?.attributes) activeSpan.setAttributes(options.attributes);
|
|
12
|
+
return originalMethod.apply(this, args);
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
return descriptor;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Decorator to create a span around a method.
|
|
19
|
+
*
|
|
20
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
21
|
+
* to capture exceptions with source context lines.
|
|
22
|
+
*
|
|
23
|
+
* Automatically handles:
|
|
24
|
+
* - Creating and closing the span
|
|
25
|
+
* - Capturing exceptions with context frames
|
|
26
|
+
* - Setting error status
|
|
27
|
+
* - Async/await support
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { span } from '@monocle.sh/adonisjs-agent'
|
|
32
|
+
*
|
|
33
|
+
* class UserService {
|
|
34
|
+
* @span()
|
|
35
|
+
* async findById(id: string) {
|
|
36
|
+
* // Span name: "UserService.findById"
|
|
37
|
+
* return db.users.find(id)
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* @span({ name: 'user.create', attributes: { operation: 'create' } })
|
|
41
|
+
* async create(data: UserData) {
|
|
42
|
+
* return db.users.create(data)
|
|
43
|
+
* }
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
function span(options) {
|
|
48
|
+
return function(target, propertyKey, descriptor) {
|
|
49
|
+
return wrapMethod(target, propertyKey, descriptor, options);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Decorator to create spans around all methods of a class.
|
|
54
|
+
*
|
|
55
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
56
|
+
* to capture exceptions with source context lines.
|
|
57
|
+
*
|
|
58
|
+
* Automatically handles:
|
|
59
|
+
* - Creating and closing spans for each method
|
|
60
|
+
* - Capturing exceptions with context frames
|
|
61
|
+
* - Setting error status
|
|
62
|
+
* - Async/await support
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* import { spanAll } from '@monocle.sh/adonisjs-agent'
|
|
67
|
+
*
|
|
68
|
+
* @spanAll()
|
|
69
|
+
* class OrderService {
|
|
70
|
+
* async create(data: OrderData) {
|
|
71
|
+
* // Span name: "OrderService.create"
|
|
72
|
+
* return db.orders.create(data)
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* async findById(id: string) {
|
|
76
|
+
* // Span name: "OrderService.findById"
|
|
77
|
+
* return db.orders.find(id)
|
|
78
|
+
* }
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* @spanAll({ prefix: 'order' })
|
|
82
|
+
* class OrderService {
|
|
83
|
+
* async create(data: OrderData) {
|
|
84
|
+
* // Span name: "order.create"
|
|
85
|
+
* return db.orders.create(data)
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
function spanAll(options) {
|
|
91
|
+
return function(constructor) {
|
|
92
|
+
const prototype = constructor.prototype;
|
|
93
|
+
const propertyNames = Object.getOwnPropertyNames(prototype);
|
|
94
|
+
for (const propertyName of propertyNames) {
|
|
95
|
+
if (propertyName === "constructor") continue;
|
|
96
|
+
const descriptor = Object.getOwnPropertyDescriptor(prototype, propertyName);
|
|
97
|
+
if (!descriptor || typeof descriptor.value !== "function") continue;
|
|
98
|
+
const wrappedDescriptor = wrapMethod(prototype, propertyName, descriptor, {
|
|
99
|
+
name: options?.prefix ? `${options.prefix}.${propertyName}` : void 0,
|
|
100
|
+
attributes: options?.attributes
|
|
101
|
+
});
|
|
102
|
+
Object.defineProperty(prototype, propertyName, wrappedDescriptor);
|
|
103
|
+
}
|
|
104
|
+
return constructor;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { span, spanAll };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Span } from "@opentelemetry/api";
|
|
2
|
+
import { extractTraceContext, getCurrentSpan, injectTraceContext, otelLoggingPreset, recordEvent, setAttributes } from "@adonisjs/otel/helpers";
|
|
3
|
+
|
|
4
|
+
//#region src/helpers.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Handle an error by reporting it with context frames extraction.
|
|
7
|
+
*
|
|
8
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
9
|
+
* to extract source context lines from the stack trace.
|
|
10
|
+
*/
|
|
11
|
+
declare function handleError(span: Span, error: Error): Promise<never>;
|
|
12
|
+
/**
|
|
13
|
+
* Record a code section as a span in your traces.
|
|
14
|
+
*
|
|
15
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
16
|
+
* to capture exceptions with source context lines (pre/post context around
|
|
17
|
+
* the error location).
|
|
18
|
+
*
|
|
19
|
+
* Preserves sync/async semantics: if the callback is synchronous, the return
|
|
20
|
+
* type is `T`. If the callback returns a Promise, the return type
|
|
21
|
+
* is async-compatible.
|
|
22
|
+
*
|
|
23
|
+
* Automatically handles:
|
|
24
|
+
* - Creating and closing the span
|
|
25
|
+
* - Capturing exceptions with context frames
|
|
26
|
+
* - Setting error status
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { record } from '@monocle.sh/adonisjs-agent'
|
|
31
|
+
*
|
|
32
|
+
* // Sync callback returns T directly
|
|
33
|
+
* const value = record('compute.hash', () => computeHash(data))
|
|
34
|
+
*
|
|
35
|
+
* // Async callback returns Promise<T>
|
|
36
|
+
* const user = await record('user.fetch', async () => {
|
|
37
|
+
* return await userService.findById(id)
|
|
38
|
+
* })
|
|
39
|
+
*
|
|
40
|
+
* // With attributes
|
|
41
|
+
* const order = await record('order.process', async (span) => {
|
|
42
|
+
* span.setAttributes({ 'order.id': orderId })
|
|
43
|
+
* return await processOrder(orderId)
|
|
44
|
+
* })
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
declare function record<T>(name: string, callback: (span: Span) => T): T;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes };
|
package/dist/helpers.mjs
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ExceptionReporter } from "./src/exception_reporter.mjs";
|
|
2
|
+
import { trace } from "@opentelemetry/api";
|
|
3
|
+
import { extractTraceContext, getCurrentSpan, injectTraceContext, otelLoggingPreset, recordEvent, setAttributes } from "@adonisjs/otel/helpers";
|
|
4
|
+
//#region src/helpers.ts
|
|
5
|
+
function isNativePromise(value) {
|
|
6
|
+
if (!value) return false;
|
|
7
|
+
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
8
|
+
return value instanceof Promise || Object.prototype.toString.call(value) === "[object Promise]";
|
|
9
|
+
}
|
|
10
|
+
async function reportErrorAndEndSpan(span, error, endTime) {
|
|
11
|
+
const reporter = new ExceptionReporter();
|
|
12
|
+
try {
|
|
13
|
+
await reporter.report({
|
|
14
|
+
span,
|
|
15
|
+
error,
|
|
16
|
+
shouldReport: true
|
|
17
|
+
});
|
|
18
|
+
} catch {} finally {
|
|
19
|
+
span.end(endTime);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Handle an error by reporting it with context frames extraction.
|
|
24
|
+
*
|
|
25
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
26
|
+
* to extract source context lines from the stack trace.
|
|
27
|
+
*/
|
|
28
|
+
async function handleError(span, error) {
|
|
29
|
+
await reportErrorAndEndSpan(span, error, /* @__PURE__ */ new Date());
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Record a code section as a span in your traces.
|
|
34
|
+
*
|
|
35
|
+
* Unlike the @adonisjs/otel version, this uses Monocle's ExceptionReporter
|
|
36
|
+
* to capture exceptions with source context lines (pre/post context around
|
|
37
|
+
* the error location).
|
|
38
|
+
*
|
|
39
|
+
* Preserves sync/async semantics: if the callback is synchronous, the return
|
|
40
|
+
* type is `T`. If the callback returns a Promise, the return type
|
|
41
|
+
* is async-compatible.
|
|
42
|
+
*
|
|
43
|
+
* Automatically handles:
|
|
44
|
+
* - Creating and closing the span
|
|
45
|
+
* - Capturing exceptions with context frames
|
|
46
|
+
* - Setting error status
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { record } from '@monocle.sh/adonisjs-agent'
|
|
51
|
+
*
|
|
52
|
+
* // Sync callback returns T directly
|
|
53
|
+
* const value = record('compute.hash', () => computeHash(data))
|
|
54
|
+
*
|
|
55
|
+
* // Async callback returns Promise<T>
|
|
56
|
+
* const user = await record('user.fetch', async () => {
|
|
57
|
+
* return await userService.findById(id)
|
|
58
|
+
* })
|
|
59
|
+
*
|
|
60
|
+
* // With attributes
|
|
61
|
+
* const order = await record('order.process', async (span) => {
|
|
62
|
+
* span.setAttributes({ 'order.id': orderId })
|
|
63
|
+
* return await processOrder(orderId)
|
|
64
|
+
* })
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function record(name, callback) {
|
|
68
|
+
return trace.getTracer("@monocle.sh/agent").startActiveSpan(name, (span) => {
|
|
69
|
+
try {
|
|
70
|
+
const result = callback(span);
|
|
71
|
+
if (isNativePromise(result)) return Promise.resolve(result).then((value) => {
|
|
72
|
+
span.end();
|
|
73
|
+
return value;
|
|
74
|
+
}).catch((error) => handleError(span, error));
|
|
75
|
+
span.end();
|
|
76
|
+
return result;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
reportErrorAndEndSpan(span, error, /* @__PURE__ */ new Date());
|
|
79
|
+
throw error;
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes };
|
package/dist/index.d.mts
CHANGED
|
@@ -2,4 +2,7 @@ import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from
|
|
|
2
2
|
import { defineConfig } from "./src/define_config.mjs";
|
|
3
3
|
import { Monocle } from "./src/monocle.mjs";
|
|
4
4
|
import { configure } from "./configure.mjs";
|
|
5
|
-
|
|
5
|
+
import { extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes } from "./helpers.mjs";
|
|
6
|
+
import { SpanAllOptions, SpanOptions, span, spanAll } from "./decorators.mjs";
|
|
7
|
+
import { destinations } from "@adonisjs/otel";
|
|
8
|
+
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/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { defineConfig } from "./src/define_config.mjs";
|
|
2
2
|
import { Monocle } from "./src/monocle.mjs";
|
|
3
3
|
import { configure } from "./configure.mjs";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes } from "./helpers.mjs";
|
|
5
|
+
import { span, spanAll } from "./decorators.mjs";
|
|
6
|
+
import { destinations } from "@adonisjs/otel";
|
|
7
|
+
export { Monocle, configure, defineConfig, destinations, extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes, span, spanAll };
|
package/dist/init.mjs
CHANGED
|
@@ -2,18 +2,11 @@ import { register } from "node:module";
|
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { createAddHookMessageChannel } from "import-in-the-middle";
|
|
5
|
-
|
|
6
5
|
//#region src/init.ts
|
|
7
6
|
/**
|
|
8
7
|
* Also stolen and tweaked from @adonisjs/otel in order to use our own config file.
|
|
9
8
|
* Need to be able to remove this file in the future.
|
|
10
9
|
*/
|
|
11
|
-
const DEFAULT_BATCH_CONFIG = {
|
|
12
|
-
maxExportBatchSize: 512,
|
|
13
|
-
scheduledDelayMillis: 5e3,
|
|
14
|
-
exportTimeoutMillis: 3e4,
|
|
15
|
-
maxQueueSize: 2048
|
|
16
|
-
};
|
|
17
10
|
async function loadConfig(path) {
|
|
18
11
|
return await import(pathToFileURL(path).href).then((mod) => mod.default || mod).catch((error) => {
|
|
19
12
|
throw new Error(`Failed to load Monocle config file at "${path}"`, { cause: error });
|
|
@@ -24,49 +17,13 @@ function setupHooks() {
|
|
|
24
17
|
register("import-in-the-middle/hook.mjs", import.meta.url, registerOptions);
|
|
25
18
|
return waitForAllMessagesAcknowledged;
|
|
26
19
|
}
|
|
27
|
-
|
|
28
|
-
* Create a metric reader for exporting metrics via OTLP
|
|
29
|
-
*/
|
|
30
|
-
async function createMetricReader(config) {
|
|
31
|
-
const { PeriodicExportingMetricReader } = await import("@opentelemetry/sdk-metrics");
|
|
32
|
-
const { OTLPMetricExporter } = await import("@opentelemetry/exporter-metrics-otlp-http");
|
|
33
|
-
return new PeriodicExportingMetricReader({
|
|
34
|
-
exporter: new OTLPMetricExporter({ compression: config.compression !== false ? "gzip" : void 0 }),
|
|
35
|
-
exportIntervalMillis: 6e4
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Create a BatchSpanProcessor for efficient trace export with compression
|
|
40
|
-
*/
|
|
41
|
-
async function createSpanProcessor(config) {
|
|
42
|
-
const { BatchSpanProcessor } = await import("@opentelemetry/sdk-trace-base");
|
|
43
|
-
const { OTLPTraceExporter } = await import("@opentelemetry/exporter-trace-otlp-http");
|
|
44
|
-
const compression = config.compression !== false ? "gzip" : void 0;
|
|
45
|
-
const batchConfig = {
|
|
46
|
-
...DEFAULT_BATCH_CONFIG,
|
|
47
|
-
...config.batch
|
|
48
|
-
};
|
|
49
|
-
return new BatchSpanProcessor(new OTLPTraceExporter({ compression }), {
|
|
50
|
-
maxExportBatchSize: batchConfig.maxExportBatchSize,
|
|
51
|
-
scheduledDelayMillis: batchConfig.scheduledDelayMillis,
|
|
52
|
-
exportTimeoutMillis: batchConfig.exportTimeoutMillis,
|
|
53
|
-
maxQueueSize: batchConfig.maxQueueSize
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
async function init(dirname$1) {
|
|
20
|
+
async function init(dirname) {
|
|
57
21
|
const waitForAllMessagesAcknowledged = setupHooks();
|
|
58
22
|
const { OtelManager } = await import("@adonisjs/otel/manager");
|
|
59
|
-
const config = await loadConfig(join(dirname
|
|
23
|
+
const config = await loadConfig(join(dirname, "config/monocle.js"));
|
|
60
24
|
if (!config) return;
|
|
61
25
|
if (!OtelManager.isEnabled(config)) return;
|
|
62
|
-
const
|
|
63
|
-
const spanProcessor = await createSpanProcessor(config);
|
|
64
|
-
const configWithProcessors = {
|
|
65
|
-
...config,
|
|
66
|
-
metricReader,
|
|
67
|
-
spanProcessors: [spanProcessor, ...config.spanProcessors || []]
|
|
68
|
-
};
|
|
69
|
-
const manager = OtelManager.create(configWithProcessors);
|
|
26
|
+
const manager = OtelManager.create(config);
|
|
70
27
|
manager?.start();
|
|
71
28
|
const shutdown = async () => {
|
|
72
29
|
await manager?.shutdown().catch(() => {});
|
|
@@ -101,10 +58,36 @@ async function init(dirname$1) {
|
|
|
101
58
|
const cliConfig = config.cli;
|
|
102
59
|
if (cliConfig !== false && cliConfig?.enabled) {
|
|
103
60
|
const { instrumentCliCommands } = await import("./src/cli_instrumentation.mjs");
|
|
104
|
-
await instrumentCliCommands(cliConfig, dirname
|
|
61
|
+
await instrumentCliCommands(cliConfig, dirname);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Mail Instrumentation
|
|
65
|
+
*
|
|
66
|
+
* Automatically instruments @adonisjs/mail if installed.
|
|
67
|
+
* Creates spans for email send operations with metadata attributes.
|
|
68
|
+
*
|
|
69
|
+
* @see ./instrumentations/mail/instrumentation.ts for implementation details
|
|
70
|
+
*/
|
|
71
|
+
const mailConfig = config.mail;
|
|
72
|
+
if (mailConfig !== false) {
|
|
73
|
+
const { instrumentMail } = await import("./src/instrumentations/mail/instrumentation.mjs");
|
|
74
|
+
await instrumentMail(mailConfig ?? { enabled: true }, dirname);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Cache Instrumentation
|
|
78
|
+
*
|
|
79
|
+
* Automatically instruments @adonisjs/cache (bentocache) if installed.
|
|
80
|
+
* Creates spans for cache operations (get, set, getOrSet, delete, etc.)
|
|
81
|
+
* and suppresses internal Redis/L2/bus spans.
|
|
82
|
+
*
|
|
83
|
+
* @see ./instrumentations/cache/instrumentation.ts for implementation details
|
|
84
|
+
*/
|
|
85
|
+
const cacheConfig = config.cache;
|
|
86
|
+
if (cacheConfig !== false) {
|
|
87
|
+
const { instrumentCache } = await import("./src/instrumentations/cache/instrumentation.mjs");
|
|
88
|
+
await instrumentCache(cacheConfig ?? { enabled: true }, dirname);
|
|
105
89
|
}
|
|
106
90
|
await waitForAllMessagesAcknowledged();
|
|
107
91
|
}
|
|
108
|
-
|
|
109
92
|
//#endregion
|
|
110
|
-
export { init };
|
|
93
|
+
export { init };
|
package/dist/mcp.d.mts
ADDED
package/dist/mcp.mjs
ADDED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import OtelMiddleware from "@adonisjs/otel/otel_middleware";
|
|
2
|
-
|
|
3
2
|
//#region middleware/monocle_middleware.ts
|
|
4
3
|
var monocle_middleware_default = OtelMiddleware;
|
|
5
|
-
|
|
6
4
|
//#endregion
|
|
7
|
-
export { monocle_middleware_default as default };
|
|
5
|
+
export { monocle_middleware_default as default };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ApplicationService } from "@adonisjs/core/types";
|
|
2
2
|
|
|
3
3
|
//#region providers/monocle_provider.d.ts
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* Stolen from @Adonisjs/otel to use another config filename. we need to expose this
|
|
7
6
|
* option from @adonis/otel so we can remove this file in the future.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ExceptionReporter, toHttpError } from "./src/exception_reporter.mjs";
|
|
2
|
+
import { OtelManager } from "@adonisjs/otel";
|
|
2
3
|
import { getCurrentSpan } from "@adonisjs/otel/helpers";
|
|
3
4
|
import OtelMiddleware from "@adonisjs/otel/otel_middleware";
|
|
4
|
-
import { OtelManager } from "@adonisjs/otel";
|
|
5
5
|
import { ExceptionHandler } from "@adonisjs/core/http";
|
|
6
6
|
import { configProvider } from "@adonisjs/core";
|
|
7
|
-
|
|
8
7
|
//#region providers/monocle_provider.ts
|
|
9
8
|
/**
|
|
10
9
|
* Stolen from @Adonisjs/otel to use another config filename. we need to expose this
|
|
@@ -61,6 +60,5 @@ var OtelProvider = class {
|
|
|
61
60
|
await OtelManager.getInstance()?.shutdown();
|
|
62
61
|
}
|
|
63
62
|
};
|
|
64
|
-
|
|
65
63
|
//#endregion
|
|
66
|
-
export { OtelProvider as default };
|
|
64
|
+
export { OtelProvider as default };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ExceptionReporter } from "./exception_reporter.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { SpanKind, context, trace } from "@opentelemetry/api";
|
|
4
|
-
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
5
|
//#region src/cli_instrumentation.ts
|
|
6
6
|
/**
|
|
7
7
|
* Default commands to exclude from tracing.
|
|
@@ -19,7 +19,34 @@ const DEFAULT_EXCLUDE = [
|
|
|
19
19
|
function matchPattern(commandName, pattern) {
|
|
20
20
|
if (pattern === "*") return true;
|
|
21
21
|
if (!pattern.includes("*")) return commandName === pattern;
|
|
22
|
-
|
|
22
|
+
const escaped = pattern.replace(/[.+?^${}()|[\]\\]/g, "\\$&");
|
|
23
|
+
return new RegExp(`^${escaped.replace(/\*/g, ".*")}$`).test(commandName);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract command arguments from the instance
|
|
27
|
+
*/
|
|
28
|
+
function extractArgs(command) {
|
|
29
|
+
const argsDef = command.constructor.args;
|
|
30
|
+
if (!argsDef || !Array.isArray(argsDef)) return {};
|
|
31
|
+
const result = {};
|
|
32
|
+
for (const arg of argsDef) {
|
|
33
|
+
const value = command[arg.name];
|
|
34
|
+
if (value !== void 0 && value !== null) result[arg.argumentName] = String(value);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Extract command flags from the instance
|
|
40
|
+
*/
|
|
41
|
+
function extractFlags(command) {
|
|
42
|
+
const flagsDef = command.constructor.flags;
|
|
43
|
+
if (!flagsDef || !Array.isArray(flagsDef)) return {};
|
|
44
|
+
const result = {};
|
|
45
|
+
for (const flag of flagsDef) {
|
|
46
|
+
const value = command[flag.name];
|
|
47
|
+
if (value !== void 0 && value !== null && value !== false) result[flag.flagName] = String(value);
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
23
50
|
}
|
|
24
51
|
/**
|
|
25
52
|
* Check if a command should be traced based on include/exclude patterns
|
|
@@ -42,19 +69,24 @@ function shouldTraceCommand(commandName, config) {
|
|
|
42
69
|
*/
|
|
43
70
|
async function instrumentCliCommands(config, appRoot) {
|
|
44
71
|
const tracer = trace.getTracer("@monocle.sh/adonisjs-agent", "1.0.0");
|
|
45
|
-
const BaseCommand = (await import(createRequire(appRoot ?
|
|
72
|
+
const BaseCommand = (await import(pathToFileURL(createRequire(appRoot ? pathToFileURL(`${appRoot}/package.json`).href : import.meta.url).resolve("@adonisjs/core/ace")).href)).BaseCommand;
|
|
46
73
|
const originalExec = BaseCommand.prototype.exec;
|
|
47
74
|
BaseCommand.prototype.exec = async function() {
|
|
48
75
|
const commandName = this.constructor.commandName;
|
|
49
76
|
const commandDescription = this.constructor.description;
|
|
50
77
|
if (!shouldTraceCommand(commandName, config)) return originalExec.call(this);
|
|
78
|
+
const args = extractArgs(this);
|
|
79
|
+
const flags = extractFlags(this);
|
|
80
|
+
const attributes = {
|
|
81
|
+
"entry_point.type": "cli",
|
|
82
|
+
"cli.command.name": commandName,
|
|
83
|
+
"cli.command.description": commandDescription || ""
|
|
84
|
+
};
|
|
85
|
+
for (const [key, value] of Object.entries(args)) attributes[`cli.args.${key}`] = value;
|
|
86
|
+
for (const [key, value] of Object.entries(flags)) attributes[`cli.flags.${key}`] = value;
|
|
51
87
|
const span = tracer.startSpan(`cli ${commandName}`, {
|
|
52
88
|
kind: SpanKind.INTERNAL,
|
|
53
|
-
attributes
|
|
54
|
-
"entry_point.type": "cli",
|
|
55
|
-
"cli.command.name": commandName,
|
|
56
|
-
"cli.command.description": commandDescription || ""
|
|
57
|
-
}
|
|
89
|
+
attributes
|
|
58
90
|
});
|
|
59
91
|
const ctx = trace.setSpan(context.active(), span);
|
|
60
92
|
/**
|
|
@@ -70,7 +102,13 @@ async function instrumentCliCommands(config, appRoot) {
|
|
|
70
102
|
*/
|
|
71
103
|
return context.with(ctx, async () => {
|
|
72
104
|
try {
|
|
73
|
-
|
|
105
|
+
const result = await originalExec.call(this);
|
|
106
|
+
if (this.error) await new ExceptionReporter().report({
|
|
107
|
+
span,
|
|
108
|
+
error: this.error,
|
|
109
|
+
shouldReport: true
|
|
110
|
+
});
|
|
111
|
+
return result;
|
|
74
112
|
} catch (error) {
|
|
75
113
|
await new ExceptionReporter().report({
|
|
76
114
|
span,
|
|
@@ -84,6 +122,5 @@ async function instrumentCliCommands(config, appRoot) {
|
|
|
84
122
|
});
|
|
85
123
|
};
|
|
86
124
|
}
|
|
87
|
-
|
|
88
125
|
//#endregion
|
|
89
|
-
export { instrumentCliCommands };
|
|
126
|
+
export { instrumentCliCommands };
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { MonocleConfig } from "./types.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/define_config.d.ts
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* Define and validate Monocle agent configuration.
|
|
7
|
-
* Sets up environment variables for OTEL exporters to point to Monocle.
|
|
8
6
|
* Returns undefined if no API key is provided (telemetry will be disabled).
|
|
9
7
|
*/
|
|
10
8
|
declare function defineConfig(config: MonocleConfig): MonocleConfig | undefined;
|