@monocle-app/agent 1.0.0-beta.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/README.md +3 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +4 -0
- package/dist/init.d.mts +8 -0
- package/dist/init.mjs +111 -0
- package/dist/monocle_middleware.d.mts +2 -0
- package/dist/monocle_middleware.mjs +7 -0
- package/dist/monocle_provider.d.mts +20 -0
- package/dist/monocle_provider.mjs +56 -0
- package/dist/src/cli_instrumentation.mjs +90 -0
- package/dist/src/define_config.d.mts +12 -0
- package/dist/src/define_config.mjs +21 -0
- package/dist/src/host_metrics.mjs +27 -0
- package/dist/src/monocle.d.mts +30 -0
- package/dist/src/monocle.mjs +42 -0
- package/dist/src/types.d.mts +108 -0
- package/package.json +77 -0
package/README.md
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig } from "./src/types.mjs";
|
|
2
|
+
import { defineConfig } from "./src/define_config.mjs";
|
|
3
|
+
import { Monocle } from "./src/monocle.mjs";
|
|
4
|
+
export { type BatchConfig, type CliTracingConfig, type HostMetricsConfig, Monocle, type MonocleConfig, defineConfig };
|
package/dist/index.mjs
ADDED
package/dist/init.d.mts
ADDED
package/dist/init.mjs
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { register } from "node:module";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createAddHookMessageChannel } from "import-in-the-middle";
|
|
4
|
+
|
|
5
|
+
//#region src/init.ts
|
|
6
|
+
/**
|
|
7
|
+
* Also stolen and tweaked from @adonisjs/otel in order to use our own config file.
|
|
8
|
+
* Need to be able to remove this file in the future.
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_BATCH_CONFIG = {
|
|
11
|
+
maxExportBatchSize: 512,
|
|
12
|
+
scheduledDelayMillis: 5e3,
|
|
13
|
+
exportTimeoutMillis: 3e4,
|
|
14
|
+
maxQueueSize: 2048
|
|
15
|
+
};
|
|
16
|
+
async function loadConfig(path) {
|
|
17
|
+
return await import(path).then((mod) => mod.default || mod).catch((error) => {
|
|
18
|
+
throw new Error(`Failed to load Monocle config file at "${path}": ${error.message}`);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function setupHooks() {
|
|
22
|
+
const { registerOptions, waitForAllMessagesAcknowledged } = createAddHookMessageChannel();
|
|
23
|
+
register("import-in-the-middle/hook.mjs", import.meta.url, registerOptions);
|
|
24
|
+
return waitForAllMessagesAcknowledged;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a metric reader for exporting metrics via OTLP
|
|
28
|
+
*/
|
|
29
|
+
async function createMetricReader(config) {
|
|
30
|
+
const { PeriodicExportingMetricReader } = await import("@opentelemetry/sdk-metrics");
|
|
31
|
+
const { OTLPMetricExporter } = await import("@opentelemetry/exporter-metrics-otlp-http");
|
|
32
|
+
return new PeriodicExportingMetricReader({
|
|
33
|
+
exporter: new OTLPMetricExporter({ compression: config.compression !== false ? "gzip" : void 0 }),
|
|
34
|
+
exportIntervalMillis: 15e3
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a BatchSpanProcessor for efficient trace export with compression
|
|
39
|
+
*/
|
|
40
|
+
async function createSpanProcessor(config) {
|
|
41
|
+
const { BatchSpanProcessor } = await import("@opentelemetry/sdk-trace-base");
|
|
42
|
+
const { OTLPTraceExporter } = await import("@opentelemetry/exporter-trace-otlp-http");
|
|
43
|
+
const compression = config.compression !== false ? "gzip" : void 0;
|
|
44
|
+
const batchConfig = {
|
|
45
|
+
...DEFAULT_BATCH_CONFIG,
|
|
46
|
+
...config.batch
|
|
47
|
+
};
|
|
48
|
+
return new BatchSpanProcessor(new OTLPTraceExporter({ compression }), {
|
|
49
|
+
maxExportBatchSize: batchConfig.maxExportBatchSize,
|
|
50
|
+
scheduledDelayMillis: batchConfig.scheduledDelayMillis,
|
|
51
|
+
exportTimeoutMillis: batchConfig.exportTimeoutMillis,
|
|
52
|
+
maxQueueSize: batchConfig.maxQueueSize
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function init(dirname) {
|
|
56
|
+
const waitForAllMessagesAcknowledged = setupHooks();
|
|
57
|
+
const { OtelManager } = await import("@adonisjs/otel/manager");
|
|
58
|
+
const config = await loadConfig(join(dirname, "config/monocle.js"));
|
|
59
|
+
if (!config) return;
|
|
60
|
+
if (!OtelManager.isEnabled(config)) return;
|
|
61
|
+
const metricReader = await createMetricReader(config);
|
|
62
|
+
const spanProcessor = await createSpanProcessor(config);
|
|
63
|
+
const configWithProcessors = {
|
|
64
|
+
...config,
|
|
65
|
+
metricReader,
|
|
66
|
+
spanProcessors: [spanProcessor, ...config.spanProcessors || []]
|
|
67
|
+
};
|
|
68
|
+
const manager = OtelManager.create(configWithProcessors);
|
|
69
|
+
manager?.start();
|
|
70
|
+
const shutdown = async () => {
|
|
71
|
+
await manager?.shutdown().catch(() => {
|
|
72
|
+
console.error("Error during OTEL shutdown");
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
process.on("beforeExit", shutdown);
|
|
76
|
+
process.on("SIGINT", async () => {
|
|
77
|
+
await shutdown();
|
|
78
|
+
process.exit(0);
|
|
79
|
+
});
|
|
80
|
+
process.on("SIGTERM", async () => {
|
|
81
|
+
await shutdown();
|
|
82
|
+
process.exit(0);
|
|
83
|
+
});
|
|
84
|
+
const hostMetricsConfig = config.hostMetrics;
|
|
85
|
+
if (hostMetricsConfig !== false) {
|
|
86
|
+
const { startHostMetrics } = await import("./src/host_metrics.mjs");
|
|
87
|
+
startHostMetrics(hostMetricsConfig === void 0 ? {} : hostMetricsConfig);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* CLI Command Instrumentation
|
|
91
|
+
*
|
|
92
|
+
* When enabled, this patches AdonisJS Ace commands to create OTEL spans.
|
|
93
|
+
* The `dirname` parameter is passed so the instrumentation can resolve
|
|
94
|
+
* @adonisjs/core/ace from the app's node_modules (pnpm isolation).
|
|
95
|
+
*
|
|
96
|
+
* Prerequisites for this to work:
|
|
97
|
+
* 1. App's `bin/console.ts` must import `otel.ts` FIRST (before reflect-metadata)
|
|
98
|
+
* 2. Config must have `cli.enabled: true`
|
|
99
|
+
*
|
|
100
|
+
* @see ./cli_instrumentation.ts for implementation details
|
|
101
|
+
*/
|
|
102
|
+
const cliConfig = config.cli;
|
|
103
|
+
if (cliConfig !== false && cliConfig?.enabled) {
|
|
104
|
+
const { instrumentCliCommands } = await import("./src/cli_instrumentation.mjs");
|
|
105
|
+
await instrumentCliCommands(cliConfig, dirname);
|
|
106
|
+
}
|
|
107
|
+
await waitForAllMessagesAcknowledged();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
//#endregion
|
|
111
|
+
export { init };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ApplicationService } from "@adonisjs/core/types";
|
|
2
|
+
|
|
3
|
+
//#region providers/monocle_provider.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Stolen from @Adonisjs/otel to use another config filename. we need to expose this
|
|
7
|
+
* option from @adonis/otel so we can remove this file in the future.
|
|
8
|
+
*/
|
|
9
|
+
declare class OtelProvider {
|
|
10
|
+
#private;
|
|
11
|
+
protected app: ApplicationService;
|
|
12
|
+
constructor(app: ApplicationService);
|
|
13
|
+
register(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Gracefully flush pending spans
|
|
16
|
+
*/
|
|
17
|
+
shutdown(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { OtelProvider as default };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { SpanStatusCode } from "@opentelemetry/api";
|
|
2
|
+
import OtelMiddleware from "@adonisjs/otel/otel_middleware";
|
|
3
|
+
import { getCurrentSpan } from "@adonisjs/otel/helpers";
|
|
4
|
+
import { OtelManager } from "@adonisjs/otel";
|
|
5
|
+
import { ExceptionHandler } from "@adonisjs/core/http";
|
|
6
|
+
import { configProvider } from "@adonisjs/core";
|
|
7
|
+
|
|
8
|
+
//#region providers/monocle_provider.ts
|
|
9
|
+
/**
|
|
10
|
+
* Stolen from @Adonisjs/otel to use another config filename. we need to expose this
|
|
11
|
+
* option from @adonis/otel so we can remove this file in the future.
|
|
12
|
+
*/
|
|
13
|
+
var OtelProvider = class {
|
|
14
|
+
constructor(app) {
|
|
15
|
+
this.app = app;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hook into ExceptionHandler to record exceptions in spans
|
|
19
|
+
*/
|
|
20
|
+
#registerExceptionHandler() {
|
|
21
|
+
const originalReport = ExceptionHandler.prototype.report;
|
|
22
|
+
ExceptionHandler.macro("report", async function(error, ctx) {
|
|
23
|
+
const span = getCurrentSpan();
|
|
24
|
+
if (span && error instanceof Error) {
|
|
25
|
+
span.recordException(error);
|
|
26
|
+
span.setStatus({
|
|
27
|
+
code: SpanStatusCode.ERROR,
|
|
28
|
+
message: error.message
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
return originalReport.call(this, error, ctx);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
register() {
|
|
35
|
+
this.#registerExceptionHandler();
|
|
36
|
+
this.#registerMiddleware();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Register the OtelMiddleware as a singleton in the container
|
|
40
|
+
*/
|
|
41
|
+
#registerMiddleware() {
|
|
42
|
+
this.app.container.singleton(OtelMiddleware, async () => {
|
|
43
|
+
const otelConfigProvider = this.app.config.get("monocle", {});
|
|
44
|
+
return new OtelMiddleware({ userContext: (await configProvider.resolve(this.app, otelConfigProvider))?.userContext });
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Gracefully flush pending spans
|
|
49
|
+
*/
|
|
50
|
+
async shutdown() {
|
|
51
|
+
await OtelManager.getInstance()?.shutdown();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
//#endregion
|
|
56
|
+
export { OtelProvider as default };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { SpanKind, SpanStatusCode, context, trace } from "@opentelemetry/api";
|
|
3
|
+
|
|
4
|
+
//#region src/cli_instrumentation.ts
|
|
5
|
+
/**
|
|
6
|
+
* Default commands to exclude from tracing.
|
|
7
|
+
* These are typically scaffolding commands or long-running workers.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_EXCLUDE = [
|
|
10
|
+
"make:*",
|
|
11
|
+
"generate:*",
|
|
12
|
+
"queue:work",
|
|
13
|
+
"queue:listen"
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Simple glob pattern matcher supporting only '*' wildcard
|
|
17
|
+
*/
|
|
18
|
+
function matchPattern(commandName, pattern) {
|
|
19
|
+
if (pattern === "*") return true;
|
|
20
|
+
if (!pattern.includes("*")) return commandName === pattern;
|
|
21
|
+
return (/* @__PURE__ */ new RegExp(`^${pattern.replace(/\*/g, ".*")}$`)).test(commandName);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if a command should be traced based on include/exclude patterns
|
|
25
|
+
*/
|
|
26
|
+
function shouldTraceCommand(commandName, config) {
|
|
27
|
+
if ((config.exclude ?? DEFAULT_EXCLUDE).some((pattern) => matchPattern(commandName, pattern))) return false;
|
|
28
|
+
if (config.include && config.include.length > 0) return config.include.some((pattern) => matchPattern(commandName, pattern));
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Instrument AdonisJS Ace CLI commands with OpenTelemetry tracing.
|
|
33
|
+
*
|
|
34
|
+
* Uses monkey-patching of BaseCommand.prototype.exec to wrap command
|
|
35
|
+
* execution with an active OTEL span context. This ensures all child
|
|
36
|
+
* spans created during command execution are properly linked to the
|
|
37
|
+
* CLI command span.
|
|
38
|
+
*
|
|
39
|
+
* @param config - CLI tracing configuration
|
|
40
|
+
* @param appRoot - Application root directory path
|
|
41
|
+
*/
|
|
42
|
+
async function instrumentCliCommands(config, appRoot) {
|
|
43
|
+
const tracer = trace.getTracer("@monocle-app/agent", "1.0.0");
|
|
44
|
+
const BaseCommand = (await import(createRequire(appRoot ? `file://${appRoot}/package.json` : import.meta.url).resolve("@adonisjs/core/ace"))).BaseCommand;
|
|
45
|
+
const originalExec = BaseCommand.prototype.exec;
|
|
46
|
+
BaseCommand.prototype.exec = async function() {
|
|
47
|
+
const commandName = this.constructor.commandName;
|
|
48
|
+
const commandDescription = this.constructor.description;
|
|
49
|
+
if (!shouldTraceCommand(commandName, config)) return originalExec.call(this);
|
|
50
|
+
const span = tracer.startSpan(`cli ${commandName}`, {
|
|
51
|
+
kind: SpanKind.INTERNAL,
|
|
52
|
+
attributes: {
|
|
53
|
+
"entry_point.type": "cli",
|
|
54
|
+
"cli.command.name": commandName,
|
|
55
|
+
"cli.command.description": commandDescription || ""
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const ctx = trace.setSpan(context.active(), span);
|
|
59
|
+
/**
|
|
60
|
+
* CRITICAL: Execute within context.with()
|
|
61
|
+
*
|
|
62
|
+
* This is what makes child spans work! Without this wrapper:
|
|
63
|
+
* - Child spans would have no parent
|
|
64
|
+
* - All spans would be root spans with different traceIds
|
|
65
|
+
* - The trace would be fragmented
|
|
66
|
+
*
|
|
67
|
+
* context.with() sets our span as the "active" span for all async
|
|
68
|
+
* operations within the callback, enabling proper trace propagation.
|
|
69
|
+
*/
|
|
70
|
+
return context.with(ctx, async () => {
|
|
71
|
+
try {
|
|
72
|
+
return await originalExec.call(this);
|
|
73
|
+
} catch (error) {
|
|
74
|
+
if (error instanceof Error) {
|
|
75
|
+
span.recordException(error);
|
|
76
|
+
span.setStatus({
|
|
77
|
+
code: SpanStatusCode.ERROR,
|
|
78
|
+
message: error.message
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
throw error;
|
|
82
|
+
} finally {
|
|
83
|
+
span.end();
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
export { instrumentCliCommands };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { MonocleConfig } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/define_config.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Define and validate Monocle agent configuration.
|
|
7
|
+
* Sets up environment variables for OTEL exporters to point to Monocle.
|
|
8
|
+
* Returns undefined if no API key is provided (telemetry will be disabled).
|
|
9
|
+
*/
|
|
10
|
+
declare function defineConfig(config: MonocleConfig): MonocleConfig | undefined;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { defineConfig };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/define_config.ts
|
|
2
|
+
/**
|
|
3
|
+
* Define and validate Monocle agent configuration.
|
|
4
|
+
* Sets up environment variables for OTEL exporters to point to Monocle.
|
|
5
|
+
* Returns undefined if no API key is provided (telemetry will be disabled).
|
|
6
|
+
*/
|
|
7
|
+
function defineConfig(config) {
|
|
8
|
+
if (!config.apiKey) return void 0;
|
|
9
|
+
const endpoint = config.endpoint || "https://ingest.monocle.adonisjs.com";
|
|
10
|
+
const environment = config.environment || process.env.NODE_ENV || "development";
|
|
11
|
+
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = endpoint;
|
|
12
|
+
process.env.OTEL_EXPORTER_OTLP_HEADERS = `x-api-key=${config.apiKey},x-monocle-env=${environment}`;
|
|
13
|
+
return {
|
|
14
|
+
...config,
|
|
15
|
+
endpoint,
|
|
16
|
+
environment
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { defineConfig };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { metrics } from "@opentelemetry/api";
|
|
2
|
+
import { HostMetrics } from "@opentelemetry/host-metrics";
|
|
3
|
+
|
|
4
|
+
//#region src/host_metrics.ts
|
|
5
|
+
let hostMetricsInstance = null;
|
|
6
|
+
/**
|
|
7
|
+
* Start collecting host metrics (CPU, Memory, Network, etc.)
|
|
8
|
+
*
|
|
9
|
+
* Uses @opentelemetry/host-metrics to collect:
|
|
10
|
+
* - system.cpu.time / system.cpu.utilization
|
|
11
|
+
* - system.memory.usage / system.memory.utilization
|
|
12
|
+
* - system.network.io / system.network.errors / system.network.dropped
|
|
13
|
+
* - process.cpu.time / process.cpu.utilization
|
|
14
|
+
* - process.memory.usage
|
|
15
|
+
*/
|
|
16
|
+
function startHostMetrics(config = {}) {
|
|
17
|
+
if (hostMetricsInstance) return hostMetricsInstance;
|
|
18
|
+
hostMetricsInstance = new HostMetrics({
|
|
19
|
+
meterProvider: metrics.getMeterProvider(),
|
|
20
|
+
name: config.name || "monocle-host-metrics"
|
|
21
|
+
});
|
|
22
|
+
hostMetricsInstance.start();
|
|
23
|
+
return hostMetricsInstance;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
export { startHostMetrics };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/monocle.d.ts
|
|
2
|
+
interface CaptureExceptionContext {
|
|
3
|
+
user?: {
|
|
4
|
+
id: string;
|
|
5
|
+
email?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
};
|
|
8
|
+
tags?: Record<string, string>;
|
|
9
|
+
extra?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Monocle helper class for manual instrumentation.
|
|
13
|
+
*/
|
|
14
|
+
declare class Monocle {
|
|
15
|
+
/**
|
|
16
|
+
* Capture an exception and record it on the current active span.
|
|
17
|
+
* If no span is active, the exception is silently ignored.
|
|
18
|
+
*/
|
|
19
|
+
static captureException(error: unknown, context?: CaptureExceptionContext): void;
|
|
20
|
+
/**
|
|
21
|
+
* Set user information on the current active span.
|
|
22
|
+
*/
|
|
23
|
+
static setUser(user: {
|
|
24
|
+
id: string;
|
|
25
|
+
email?: string;
|
|
26
|
+
name?: string;
|
|
27
|
+
}): void;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { Monocle };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SpanStatusCode, trace } from "@opentelemetry/api";
|
|
2
|
+
|
|
3
|
+
//#region src/monocle.ts
|
|
4
|
+
/**
|
|
5
|
+
* Monocle helper class for manual instrumentation.
|
|
6
|
+
*/
|
|
7
|
+
var Monocle = class {
|
|
8
|
+
/**
|
|
9
|
+
* Capture an exception and record it on the current active span.
|
|
10
|
+
* If no span is active, the exception is silently ignored.
|
|
11
|
+
*/
|
|
12
|
+
static captureException(error, context$1) {
|
|
13
|
+
const span = trace.getActiveSpan();
|
|
14
|
+
if (!span) return;
|
|
15
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
16
|
+
span.recordException(err);
|
|
17
|
+
span.setStatus({
|
|
18
|
+
code: SpanStatusCode.ERROR,
|
|
19
|
+
message: err.message
|
|
20
|
+
});
|
|
21
|
+
if (context$1?.user) {
|
|
22
|
+
if (context$1.user.id) span.setAttribute("user.id", context$1.user.id);
|
|
23
|
+
if (context$1.user.email) span.setAttribute("user.email", context$1.user.email);
|
|
24
|
+
if (context$1.user.name) span.setAttribute("user.name", context$1.user.name);
|
|
25
|
+
}
|
|
26
|
+
if (context$1?.tags) for (const [key, value] of Object.entries(context$1.tags)) span.setAttribute(`monocle.tag.${key}`, value);
|
|
27
|
+
if (context$1?.extra) for (const [key, value] of Object.entries(context$1.extra)) span.setAttribute(`monocle.extra.${key}`, JSON.stringify(value));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Set user information on the current active span.
|
|
31
|
+
*/
|
|
32
|
+
static setUser(user) {
|
|
33
|
+
const span = trace.getActiveSpan();
|
|
34
|
+
if (!span) return;
|
|
35
|
+
span.setAttribute("user.id", user.id);
|
|
36
|
+
if (user.email) span.setAttribute("user.email", user.email);
|
|
37
|
+
if (user.name) span.setAttribute("user.name", user.name);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//#endregion
|
|
42
|
+
export { Monocle };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { OtelConfig } from "@adonisjs/otel/types";
|
|
2
|
+
|
|
3
|
+
//#region src/types.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for CLI command tracing
|
|
7
|
+
*/
|
|
8
|
+
interface CliTracingConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Enable CLI command tracing.
|
|
11
|
+
* @default false
|
|
12
|
+
*/
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Commands to include in tracing. Supports glob patterns.
|
|
16
|
+
* If not specified, all commands are traced (except excluded ones).
|
|
17
|
+
* @example ['migration:*', 'db:*', 'my-custom:*']
|
|
18
|
+
*/
|
|
19
|
+
include?: string[];
|
|
20
|
+
/**
|
|
21
|
+
* Commands to exclude from tracing. Supports glob patterns.
|
|
22
|
+
* @default ['make:*', 'generate:*', 'queue:work', 'queue:listen']
|
|
23
|
+
* @example ['make:*', 'generate:*']
|
|
24
|
+
*/
|
|
25
|
+
exclude?: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Configuration for host metrics collection
|
|
29
|
+
*/
|
|
30
|
+
interface HostMetricsConfig {
|
|
31
|
+
/**
|
|
32
|
+
* Enable host metrics collection.
|
|
33
|
+
* @default true
|
|
34
|
+
*/
|
|
35
|
+
enabled?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Custom name for the meter.
|
|
38
|
+
* @default 'monocle-host-metrics'
|
|
39
|
+
*/
|
|
40
|
+
name?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Configuration for trace batching. Controls how spans are batched before export.
|
|
44
|
+
*/
|
|
45
|
+
interface BatchConfig {
|
|
46
|
+
/**
|
|
47
|
+
* Maximum number of spans to include in a single batch.
|
|
48
|
+
* @default 512
|
|
49
|
+
*/
|
|
50
|
+
maxExportBatchSize?: number;
|
|
51
|
+
/**
|
|
52
|
+
* Maximum time (ms) to wait before exporting a batch.
|
|
53
|
+
* @default 5000
|
|
54
|
+
*/
|
|
55
|
+
scheduledDelayMillis?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Maximum time (ms) to wait for a batch export to complete.
|
|
58
|
+
* @default 30000
|
|
59
|
+
*/
|
|
60
|
+
exportTimeoutMillis?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Maximum queue size. Spans will be dropped if the queue is full.
|
|
63
|
+
* @default 2048
|
|
64
|
+
*/
|
|
65
|
+
maxQueueSize?: number;
|
|
66
|
+
}
|
|
67
|
+
interface MonocleConfig extends Omit<OtelConfig, 'traceExporter' | 'metricExporter'> {
|
|
68
|
+
/**
|
|
69
|
+
* Your Monocle API key. If not provided, telemetry will be disabled.
|
|
70
|
+
* Format: mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
|
71
|
+
*/
|
|
72
|
+
apiKey?: string;
|
|
73
|
+
/**
|
|
74
|
+
* Monocle ingestion endpoint.
|
|
75
|
+
* @default 'https://ingest.monocle.adonisjs.com'
|
|
76
|
+
*/
|
|
77
|
+
endpoint?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Environment name sent with telemetry data.
|
|
80
|
+
* @default process.env.NODE_ENV || 'development'
|
|
81
|
+
*/
|
|
82
|
+
environment?: string;
|
|
83
|
+
/**
|
|
84
|
+
* Host metrics configuration (CPU, Memory, Network, etc.).
|
|
85
|
+
* Set to `false` to disable, or pass config object.
|
|
86
|
+
* @default { enabled: true }
|
|
87
|
+
*/
|
|
88
|
+
hostMetrics?: false | HostMetricsConfig;
|
|
89
|
+
/**
|
|
90
|
+
* Trace batching configuration. Batching reduces network overhead
|
|
91
|
+
* by grouping multiple spans into single requests.
|
|
92
|
+
*/
|
|
93
|
+
batch?: BatchConfig;
|
|
94
|
+
/**
|
|
95
|
+
* Enable gzip compression for OTLP exports.
|
|
96
|
+
* Reduces bandwidth usage significantly.
|
|
97
|
+
* @default true
|
|
98
|
+
*/
|
|
99
|
+
compression?: boolean;
|
|
100
|
+
/**
|
|
101
|
+
* CLI command tracing configuration.
|
|
102
|
+
* Set to `false` to disable, or pass config object.
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
cli?: false | CliTracingConfig;
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { BatchConfig, CliTracingConfig, HostMetricsConfig, MonocleConfig };
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@monocle-app/agent",
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
|
+
"description": "Monocle agent for AdonisJS - sends telemetry to Monocle cloud",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"adonisjs",
|
|
7
|
+
"monocle",
|
|
8
|
+
"observability",
|
|
9
|
+
"opentelemetry",
|
|
10
|
+
"tracing"
|
|
11
|
+
],
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"author": "Julien Ripouteau <julien@ripouteau.com>",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/index.mjs",
|
|
16
|
+
"module": "./dist/index.mjs",
|
|
17
|
+
"types": "./dist/index.d.mts",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"dev": "./index.ts",
|
|
24
|
+
"default": "./dist/index.mjs"
|
|
25
|
+
},
|
|
26
|
+
"./init": {
|
|
27
|
+
"dev": "./src/init.ts",
|
|
28
|
+
"default": "./dist/init.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./monocle_middleware": {
|
|
31
|
+
"dev": "./middleware/monocle_middleware.ts",
|
|
32
|
+
"default": "./dist/monocle_middleware.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./monocle_provider": {
|
|
35
|
+
"dev": "./providers/monocle_provider.ts",
|
|
36
|
+
"default": "./dist/monocle_provider.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"tag": "beta",
|
|
42
|
+
"access": "public",
|
|
43
|
+
"exports": {
|
|
44
|
+
".": "./dist/index.mjs",
|
|
45
|
+
"./init": "./dist/init.mjs",
|
|
46
|
+
"./monocle_middleware": "./dist/monocle_middleware.mjs",
|
|
47
|
+
"./monocle_provider": "./dist/monocle_provider.mjs",
|
|
48
|
+
"./package.json": "./package.json"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "tsdown",
|
|
53
|
+
"dev": "tsdown",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"release": "release-it",
|
|
56
|
+
"prepublishOnly": "pnpm run build"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@adonisjs/otel": "1.0.0",
|
|
60
|
+
"@opentelemetry/api": "^1.9.0",
|
|
61
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.208.0",
|
|
62
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.208.0",
|
|
63
|
+
"@opentelemetry/host-metrics": "^0.38.0",
|
|
64
|
+
"@opentelemetry/sdk-metrics": "^2.2.0",
|
|
65
|
+
"@opentelemetry/sdk-trace-base": "^2.2.0",
|
|
66
|
+
"import-in-the-middle": "^2.0.1"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@adonisjs/core": "catalog:",
|
|
70
|
+
"@adonisjs/tsconfig": "catalog:",
|
|
71
|
+
"release-it": "^19.2.2"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@adonisjs/core": "^6.2.0 || ^7.0.0"
|
|
75
|
+
},
|
|
76
|
+
"packageManager": "pnpm@10.26.1"
|
|
77
|
+
}
|