




























@@ -1,4 +1,4 @@
1-import { beforeEach, describe, expect, test, vi } from "vitest";
1+import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
2233const telemetryState = vi.hoisted(() => {
44const counters = new Map<string, { add: ReturnType<typeof vi.fn> }>();
@@ -125,6 +125,7 @@ const GRANDCHILD_SPAN_ID = "2222222222222222";
125125const PROTO_KEY = "__proto__";
126126const MAX_TEST_OTEL_CONTENT_ATTRIBUTE_CHARS = 4096;
127127const OTEL_TRUNCATED_SUFFIX_MAX_CHARS = 20;
128+const ORIGINAL_OPENCLAW_OTEL_PRELOADED = process.env.OPENCLAW_OTEL_PRELOADED;
128129129130function createLogger() {
130131return {
@@ -194,6 +195,7 @@ function flushDiagnosticEvents() {
194195195196describe("diagnostics-otel service", () => {
196197beforeEach(() => {
198+delete process.env.OPENCLAW_OTEL_PRELOADED;
197199telemetryState.counters.clear();
198200telemetryState.histograms.clear();
199201telemetryState.spans.length = 0;
@@ -208,6 +210,14 @@ describe("diagnostics-otel service", () => {
208210traceExporterCtor.mockClear();
209211});
210212213+afterEach(() => {
214+if (ORIGINAL_OPENCLAW_OTEL_PRELOADED === undefined) {
215+delete process.env.OPENCLAW_OTEL_PRELOADED;
216+} else {
217+process.env.OPENCLAW_OTEL_PRELOADED = ORIGINAL_OPENCLAW_OTEL_PRELOADED;
218+}
219+});
220+211221test("records message-flow metrics and spans", async () => {
212222const service = createDiagnosticsOtelService();
213223const ctx = createOtelContext(OTEL_TEST_ENDPOINT, { traces: true, metrics: true, logs: true });
@@ -318,6 +328,84 @@ describe("diagnostics-otel service", () => {
318328expect(telemetryState.tracer.startSpan).not.toHaveBeenCalled();
319329});
320330331+test("uses a preloaded OpenTelemetry SDK without dropping diagnostic listeners", async () => {
332+process.env.OPENCLAW_OTEL_PRELOADED = "1";
333+const service = createDiagnosticsOtelService();
334+const ctx = createOtelContext(OTEL_TEST_ENDPOINT, { traces: true, metrics: true, logs: true });
335+await service.start(ctx);
336+337+expect(sdkStart).not.toHaveBeenCalled();
338+expect(traceExporterCtor).not.toHaveBeenCalled();
339+expect(ctx.logger.info).toHaveBeenCalledWith(
340+"diagnostics-otel: using preloaded OpenTelemetry SDK",
341+);
342+343+emitDiagnosticEvent({
344+type: "run.completed",
345+runId: "run-1",
346+provider: "openai",
347+model: "gpt-5.4",
348+outcome: "completed",
349+durationMs: 100,
350+});
351+emitDiagnosticEvent({
352+type: "log.record",
353+level: "INFO",
354+message: "preloaded log",
355+});
356+await flushDiagnosticEvents();
357+358+expect(telemetryState.histograms.get("openclaw.run.duration_ms")?.record).toHaveBeenCalledWith(
359+100,
360+expect.objectContaining({
361+"openclaw.provider": "openai",
362+"openclaw.model": "gpt-5.4",
363+}),
364+);
365+expect(telemetryState.tracer.startSpan).toHaveBeenCalledWith(
366+"openclaw.run",
367+expect.objectContaining({
368+attributes: expect.objectContaining({
369+"openclaw.outcome": "completed",
370+}),
371+}),
372+undefined,
373+);
374+expect(logEmit).toHaveBeenCalled();
375+376+await service.stop?.(ctx);
377+expect(sdkShutdown).not.toHaveBeenCalled();
378+expect(logShutdown).toHaveBeenCalledTimes(1);
379+});
380+381+test("honors disabled traces when an OpenTelemetry SDK is preloaded", async () => {
382+process.env.OPENCLAW_OTEL_PRELOADED = "1";
383+const service = createDiagnosticsOtelService();
384+const ctx = createOtelContext(OTEL_TEST_ENDPOINT, { traces: false, metrics: true });
385+await service.start(ctx);
386+387+emitDiagnosticEvent({
388+type: "run.completed",
389+runId: "run-1",
390+provider: "openai",
391+model: "gpt-5.4",
392+outcome: "completed",
393+durationMs: 100,
394+});
395+396+expect(sdkStart).not.toHaveBeenCalled();
397+expect(telemetryState.histograms.get("openclaw.run.duration_ms")?.record).toHaveBeenCalledWith(
398+100,
399+expect.objectContaining({
400+"openclaw.provider": "openai",
401+}),
402+);
403+expect(telemetryState.tracer.startSpan).not.toHaveBeenCalled();
404+405+await service.stop?.(ctx);
406+expect(sdkShutdown).not.toHaveBeenCalled();
407+});
408+321409test("tears down active handles when restarted with diagnostics disabled", async () => {
322410const service = createDiagnosticsOtelService();
323411const enabledCtx = createOtelContext(OTEL_TEST_ENDPOINT, {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。