@monocle.sh/adonisjs-agent 1.0.0-beta.12 → 1.0.0-beta.14
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/helpers.d.mts +7 -7
- package/dist/helpers.mjs +40 -20
- package/dist/init.mjs +14 -0
- package/dist/src/exception_reporter.mjs +17 -0
- package/dist/src/instrumentations/cache/instrumentation.mjs +55 -0
- package/dist/src/monocle.d.mts +12 -2
- package/dist/src/monocle.mjs +2 -0
- package/dist/src/types.d.mts +12 -0
- package/dist/stubs/config.stub +1 -9
- package/dist/types.d.mts +2 -1
- package/package.json +2 -1
package/dist/helpers.d.mts
CHANGED
|
@@ -9,7 +9,6 @@ import { extractTraceContext, getCurrentSpan, injectTraceContext, otelLoggingPre
|
|
|
9
9
|
* to extract source context lines from the stack trace.
|
|
10
10
|
*/
|
|
11
11
|
declare function handleError(span: Span, error: Error): Promise<never>;
|
|
12
|
-
type RecordCallback<T> = (span: Span) => T | Promise<T>;
|
|
13
12
|
/**
|
|
14
13
|
* Record a code section as a span in your traces.
|
|
15
14
|
*
|
|
@@ -17,8 +16,9 @@ type RecordCallback<T> = (span: Span) => T | Promise<T>;
|
|
|
17
16
|
* to capture exceptions with source context lines (pre/post context around
|
|
18
17
|
* the error location).
|
|
19
18
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
19
|
+
* Preserves sync/async semantics: if the callback is synchronous, the return
|
|
20
|
+
* type is `T`. If the callback returns a Promise-like value, the return type
|
|
21
|
+
* is async-compatible.
|
|
22
22
|
*
|
|
23
23
|
* Automatically handles:
|
|
24
24
|
* - Creating and closing the span
|
|
@@ -29,10 +29,10 @@ type RecordCallback<T> = (span: Span) => T | Promise<T>;
|
|
|
29
29
|
* ```ts
|
|
30
30
|
* import { record } from '@monocle.sh/adonisjs-agent'
|
|
31
31
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* })
|
|
32
|
+
* // Sync callback returns T directly
|
|
33
|
+
* const value = record('compute.hash', () => computeHash(data))
|
|
35
34
|
*
|
|
35
|
+
* // Async callback returns Promise<T>
|
|
36
36
|
* const user = await record('user.fetch', async () => {
|
|
37
37
|
* return await userService.findById(id)
|
|
38
38
|
* })
|
|
@@ -44,6 +44,6 @@ type RecordCallback<T> = (span: Span) => T | Promise<T>;
|
|
|
44
44
|
* })
|
|
45
45
|
* ```
|
|
46
46
|
*/
|
|
47
|
-
declare function record<T>(name: string, callback:
|
|
47
|
+
declare function record<T>(name: string, callback: (span: Span) => T): T;
|
|
48
48
|
//#endregion
|
|
49
49
|
export { extractTraceContext, getCurrentSpan, handleError, injectTraceContext, otelLoggingPreset, record, recordEvent, setAttributes };
|
package/dist/helpers.mjs
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
import { ExceptionReporter } from "./src/exception_reporter.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { trace } from "@opentelemetry/api";
|
|
3
3
|
import { extractTraceContext, getCurrentSpan, injectTraceContext, otelLoggingPreset, recordEvent, setAttributes } from "@adonisjs/otel/helpers";
|
|
4
4
|
|
|
5
5
|
//#region src/helpers.ts
|
|
6
|
+
function isPromiseLike(value) {
|
|
7
|
+
if (!value) return false;
|
|
8
|
+
if (typeof value !== "object" && typeof value !== "function") return false;
|
|
9
|
+
return typeof value.then === "function";
|
|
10
|
+
}
|
|
11
|
+
async function reportErrorAndEndSpan(span, error, endTime) {
|
|
12
|
+
const reporter = new ExceptionReporter();
|
|
13
|
+
try {
|
|
14
|
+
await reporter.report({
|
|
15
|
+
span,
|
|
16
|
+
error,
|
|
17
|
+
shouldReport: true
|
|
18
|
+
});
|
|
19
|
+
} catch {
|
|
20
|
+
reporter.reportSync({
|
|
21
|
+
span,
|
|
22
|
+
error,
|
|
23
|
+
shouldReport: true
|
|
24
|
+
});
|
|
25
|
+
} finally {
|
|
26
|
+
span.end(endTime);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
6
29
|
/**
|
|
7
30
|
* Handle an error by reporting it with context frames extraction.
|
|
8
31
|
*
|
|
@@ -10,16 +33,7 @@ import { extractTraceContext, getCurrentSpan, injectTraceContext, otelLoggingPre
|
|
|
10
33
|
* to extract source context lines from the stack trace.
|
|
11
34
|
*/
|
|
12
35
|
async function handleError(span, error) {
|
|
13
|
-
await new
|
|
14
|
-
span,
|
|
15
|
-
error,
|
|
16
|
-
shouldReport: true
|
|
17
|
-
});
|
|
18
|
-
span.setStatus({
|
|
19
|
-
code: SpanStatusCode.ERROR,
|
|
20
|
-
message: error?.message
|
|
21
|
-
});
|
|
22
|
-
span.end();
|
|
36
|
+
await reportErrorAndEndSpan(span, error, /* @__PURE__ */ new Date());
|
|
23
37
|
throw error;
|
|
24
38
|
}
|
|
25
39
|
/**
|
|
@@ -29,8 +43,9 @@ async function handleError(span, error) {
|
|
|
29
43
|
* to capture exceptions with source context lines (pre/post context around
|
|
30
44
|
* the error location).
|
|
31
45
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
46
|
+
* Preserves sync/async semantics: if the callback is synchronous, the return
|
|
47
|
+
* type is `T`. If the callback returns a Promise-like value, the return type
|
|
48
|
+
* is async-compatible.
|
|
34
49
|
*
|
|
35
50
|
* Automatically handles:
|
|
36
51
|
* - Creating and closing the span
|
|
@@ -41,10 +56,10 @@ async function handleError(span, error) {
|
|
|
41
56
|
* ```ts
|
|
42
57
|
* import { record } from '@monocle.sh/adonisjs-agent'
|
|
43
58
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* })
|
|
59
|
+
* // Sync callback returns T directly
|
|
60
|
+
* const value = record('compute.hash', () => computeHash(data))
|
|
47
61
|
*
|
|
62
|
+
* // Async callback returns Promise<T>
|
|
48
63
|
* const user = await record('user.fetch', async () => {
|
|
49
64
|
* return await userService.findById(id)
|
|
50
65
|
* })
|
|
@@ -56,14 +71,19 @@ async function handleError(span, error) {
|
|
|
56
71
|
* })
|
|
57
72
|
* ```
|
|
58
73
|
*/
|
|
59
|
-
|
|
60
|
-
return trace.getTracer("@monocle.sh/agent").startActiveSpan(name,
|
|
74
|
+
function record(name, callback) {
|
|
75
|
+
return trace.getTracer("@monocle.sh/agent").startActiveSpan(name, (span) => {
|
|
61
76
|
try {
|
|
62
|
-
const result =
|
|
77
|
+
const result = callback(span);
|
|
78
|
+
if (isPromiseLike(result)) return Promise.resolve(result).then((value) => {
|
|
79
|
+
span.end();
|
|
80
|
+
return value;
|
|
81
|
+
}).catch((error) => handleError(span, error));
|
|
63
82
|
span.end();
|
|
64
83
|
return result;
|
|
65
84
|
} catch (error) {
|
|
66
|
-
|
|
85
|
+
reportErrorAndEndSpan(span, error, /* @__PURE__ */ new Date());
|
|
86
|
+
throw error;
|
|
67
87
|
}
|
|
68
88
|
});
|
|
69
89
|
}
|
package/dist/init.mjs
CHANGED
|
@@ -74,6 +74,20 @@ async function init(dirname) {
|
|
|
74
74
|
const { instrumentMail } = await import("./src/instrumentations/mail/instrumentation.mjs");
|
|
75
75
|
await instrumentMail(mailConfig ?? { enabled: true }, dirname);
|
|
76
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Cache Instrumentation
|
|
79
|
+
*
|
|
80
|
+
* Automatically instruments @adonisjs/cache (bentocache) if installed.
|
|
81
|
+
* Creates spans for cache operations (get, set, getOrSet, delete, etc.)
|
|
82
|
+
* and suppresses internal Redis/L2/bus spans.
|
|
83
|
+
*
|
|
84
|
+
* @see ./instrumentations/cache/instrumentation.ts for implementation details
|
|
85
|
+
*/
|
|
86
|
+
const cacheConfig = config.cache;
|
|
87
|
+
if (cacheConfig !== false) {
|
|
88
|
+
const { instrumentCache } = await import("./src/instrumentations/cache/instrumentation.mjs");
|
|
89
|
+
await instrumentCache(cacheConfig ?? { enabled: true }, dirname);
|
|
90
|
+
}
|
|
77
91
|
await waitForAllMessagesAcknowledged();
|
|
78
92
|
}
|
|
79
93
|
|
|
@@ -33,6 +33,23 @@ var ExceptionReporter = class {
|
|
|
33
33
|
const attributes = this.#buildAttributes(error, causeChain);
|
|
34
34
|
span.addEvent("exception", attributes);
|
|
35
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Synchronous version of report. Uses buildCauseChain (no file I/O)
|
|
38
|
+
* so source context frames won't be available, but the full stack trace,
|
|
39
|
+
* cause chain, error status, and exception event are still recorded.
|
|
40
|
+
*/
|
|
41
|
+
reportSync(options) {
|
|
42
|
+
const { span, shouldReport } = options;
|
|
43
|
+
const error = toHttpError(options.error);
|
|
44
|
+
span.setStatus({
|
|
45
|
+
code: SpanStatusCode.ERROR,
|
|
46
|
+
message: error.message
|
|
47
|
+
});
|
|
48
|
+
span.setAttribute("monocle.exception.should_report", shouldReport);
|
|
49
|
+
const causeChain = buildCauseChain(error);
|
|
50
|
+
const attributes = this.#buildAttributes(error, causeChain);
|
|
51
|
+
span.addEvent("exception", attributes);
|
|
52
|
+
}
|
|
36
53
|
#buildAttributes(error, causeChain) {
|
|
37
54
|
const hasCauses = causeChain.length > 1;
|
|
38
55
|
const attributes = {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { BentoCacheInstrumentation } from "@bentocache/otel";
|
|
4
|
+
|
|
5
|
+
//#region src/instrumentations/cache/instrumentation.ts
|
|
6
|
+
const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
7
|
+
const numericPattern = /^\d+$/;
|
|
8
|
+
const hexPattern = /^[0-9a-f]{8,}$/i;
|
|
9
|
+
/**
|
|
10
|
+
* Replaces dynamic-looking segments (UUIDs, numeric IDs, hex hashes)
|
|
11
|
+
* with `*` to reduce cardinality in span attributes.
|
|
12
|
+
*/
|
|
13
|
+
function defaultKeySanitizer(key) {
|
|
14
|
+
if (!key) return key;
|
|
15
|
+
return key.split(":").map((segment) => {
|
|
16
|
+
if (uuidPattern.test(segment)) return "*";
|
|
17
|
+
if (numericPattern.test(segment)) return "*";
|
|
18
|
+
if (hexPattern.test(segment)) return "*";
|
|
19
|
+
return segment;
|
|
20
|
+
}).join(":");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Auto-instruments @adonisjs/cache (bentocache) with OpenTelemetry spans
|
|
24
|
+
* for cache operations (get, set, getOrSet, delete, etc.).
|
|
25
|
+
* Internal Redis/L2/bus spans are suppressed via `suppressInternalOperations`.
|
|
26
|
+
*/
|
|
27
|
+
async function instrumentCache(config, appRoot) {
|
|
28
|
+
if (config.enabled === false) return void 0;
|
|
29
|
+
const appRequire = createRequire(appRoot ? pathToFileURL(`${appRoot}/package.json`).href : import.meta.url);
|
|
30
|
+
try {
|
|
31
|
+
appRequire.resolve("@adonisjs/cache");
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const instrumentation = new BentoCacheInstrumentation({
|
|
36
|
+
requireParentSpan: config.requireParentSpan ?? false,
|
|
37
|
+
includeKeys: config.includeKeys ?? true,
|
|
38
|
+
keySanitizer: config.keySanitizer ?? defaultKeySanitizer,
|
|
39
|
+
suppressInternalOperations: true
|
|
40
|
+
});
|
|
41
|
+
instrumentation.enable();
|
|
42
|
+
/**
|
|
43
|
+
* Eagerly import bentocache to trigger the ESM hook.
|
|
44
|
+
* If the hook didn't patch BentoCache (e.g. race condition),
|
|
45
|
+
* fall back to manual registration.
|
|
46
|
+
*/
|
|
47
|
+
try {
|
|
48
|
+
const bentocache = await import("bentocache");
|
|
49
|
+
if (bentocache.BentoCache.name !== "BentoCachePatched") instrumentation.manuallyRegister(bentocache);
|
|
50
|
+
} catch {}
|
|
51
|
+
return instrumentation;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
export { instrumentCache };
|
package/dist/src/monocle.d.mts
CHANGED
|
@@ -15,6 +15,14 @@ interface CaptureMessageContext extends CaptureContext {
|
|
|
15
15
|
level?: MessageLevel;
|
|
16
16
|
}
|
|
17
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
|
+
}
|
|
18
26
|
/**
|
|
19
27
|
* Monocle helper class for manual instrumentation.
|
|
20
28
|
*/
|
|
@@ -41,8 +49,10 @@ declare class Monocle {
|
|
|
41
49
|
static captureMessage(message: string, levelOrContext?: MessageLevel | CaptureMessageContext): Promise<void>;
|
|
42
50
|
/**
|
|
43
51
|
* Set user information on the current active span.
|
|
52
|
+
* `name` is displayed with priority over `email` in the Monocle UI.
|
|
53
|
+
* Falls back to `email`, then `id`.
|
|
44
54
|
*/
|
|
45
|
-
static setUser(user:
|
|
55
|
+
static setUser(user: MonocleUser): void;
|
|
46
56
|
}
|
|
47
57
|
//#endregion
|
|
48
|
-
export { Monocle };
|
|
58
|
+
export { Monocle, MonocleUser };
|
package/dist/src/monocle.mjs
CHANGED
|
@@ -100,6 +100,8 @@ var Monocle = class {
|
|
|
100
100
|
}
|
|
101
101
|
/**
|
|
102
102
|
* Set user information on the current active span.
|
|
103
|
+
* `name` is displayed with priority over `email` in the Monocle UI.
|
|
104
|
+
* Falls back to `email`, then `id`.
|
|
103
105
|
*/
|
|
104
106
|
static setUser(user) {
|
|
105
107
|
setUser(user);
|
package/dist/src/types.d.mts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { DestinationMap, OtelConfig } from "@adonisjs/otel/types";
|
|
2
|
+
import { BentoCacheInstrumentationConfig } from "@bentocache/otel/types";
|
|
2
3
|
|
|
3
4
|
//#region src/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for cache instrumentation
|
|
7
|
+
*/
|
|
8
|
+
interface CacheInstrumentationConfig extends BentoCacheInstrumentationConfig {}
|
|
4
9
|
/**
|
|
5
10
|
* Configuration for mail instrumentation
|
|
6
11
|
*/
|
|
@@ -131,6 +136,13 @@ interface MonocleConfig extends Omit<OtelConfig, 'traceExporter' | 'metricExport
|
|
|
131
136
|
* @default { enabled: true }
|
|
132
137
|
*/
|
|
133
138
|
mail?: false | MailInstrumentationConfig;
|
|
139
|
+
/**
|
|
140
|
+
* Cache instrumentation configuration.
|
|
141
|
+
* Automatically instruments @adonisjs/cache (bentocache) if installed.
|
|
142
|
+
* Set to `false` to disable.
|
|
143
|
+
* @default { enabled: true }
|
|
144
|
+
*/
|
|
145
|
+
cache?: false | CacheInstrumentationConfig;
|
|
134
146
|
}
|
|
135
147
|
//#endregion
|
|
136
148
|
export { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig };
|
package/dist/stubs/config.stub
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{{{
|
|
2
2
|
exports({ to: app.configPath('monocle.ts') })
|
|
3
3
|
}}}
|
|
4
|
-
import { defineConfig
|
|
4
|
+
import { defineConfig } from '@monocle.sh/adonisjs-agent'
|
|
5
5
|
import env from '#start/env'
|
|
6
6
|
|
|
7
7
|
export default defineConfig({
|
|
@@ -10,12 +10,4 @@ export default defineConfig({
|
|
|
10
10
|
serviceName: env.get('APP_NAME'),
|
|
11
11
|
serviceVersion: env.get('APP_VERSION'),
|
|
12
12
|
environment: env.get('APP_ENV'),
|
|
13
|
-
|
|
14
|
-
// Optional: Additional OTLP destinations (Monocle is injected automatically)
|
|
15
|
-
// destinations: {
|
|
16
|
-
// grafana: destinations.otlp({
|
|
17
|
-
// endpoint: env.get('GRAFANA_OTLP_ENDPOINT'),
|
|
18
|
-
// signals: 'all',
|
|
19
|
-
// }),
|
|
20
|
-
// },
|
|
21
13
|
})
|
package/dist/types.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./src/types.mjs";
|
|
2
|
+
import { MonocleUser } from "./src/monocle.mjs";
|
|
2
3
|
import { SpanAllOptions, SpanOptions } from "./decorators.mjs";
|
|
3
4
|
import { DestinationConfig, DestinationMap, DestinationSignal, DestinationSignals, HeadersCarrier, OtelLoggingPresetOptions, OtlpDestinationConfig, OtlpDestinationOptions, UserContextResult } from "@adonisjs/otel/types";
|
|
4
|
-
export { type BatchConfig, type CliTracingConfig, type DestinationConfig, type DestinationMap, type DestinationSignal, type DestinationSignals, type HeadersCarrier, type HostMetricsConfig, type MonocleConfig, type OtelLoggingPresetOptions, type OtlpDestinationConfig, type OtlpDestinationOptions, type SpanAllOptions, type SpanOptions, type UserContextResult };
|
|
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.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.14",
|
|
4
4
|
"description": "Monocle agent for AdonisJS - sends telemetry to Monocle cloud",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adonisjs",
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@adonisjs/otel": "^1.2.0",
|
|
35
|
+
"@bentocache/otel": "^0.1.2",
|
|
35
36
|
"@opentelemetry/api": "^1.9.0",
|
|
36
37
|
"@opentelemetry/core": "^2.5.0",
|
|
37
38
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.211.0",
|