perf(coding-agent): deferred heavy module imports to startup paths
- Lazy-loaded OTEL SDK, HTML export, TTSR, and autoresearch modules. - Made resolveMemoryBackend async to import backends on demand. - Replaced backend resolution with direct settings reads for rekey checks.
This commit is contained in:
@@ -771,7 +771,6 @@ function resolveCanonicalIdForModel(
|
||||
return { id: claudeFamilyAlias, source: claudeFamilyAlias === model.id ? "bundled" : "heuristic" };
|
||||
}
|
||||
|
||||
|
||||
const heuristicCandidates = getHeuristicCanonicalCandidates(model.id, referenceData.officialIds);
|
||||
const officialMatches = new Set<string>();
|
||||
for (const candidate of heuristicCandidates) {
|
||||
|
||||
@@ -40,7 +40,6 @@ import {
|
||||
resolveActiveProjectRegistryPath,
|
||||
} from "./discovery/helpers";
|
||||
import { injectOmpExtensionCliRoots } from "./discovery/omp-extension-roots";
|
||||
import { exportFromFile } from "./export/html";
|
||||
import { ExtensionRunner } from "./extensibility/extensions/runner";
|
||||
import type { ExtensionUIContext } from "./extensibility/extensions/types";
|
||||
import { scheduleMarketplaceAutoUpdate } from "./extensibility/plugins/marketplace-auto-update";
|
||||
@@ -784,6 +783,7 @@ export async function runRootCommand(
|
||||
let result: string;
|
||||
try {
|
||||
const outputPath = parsedArgs.messages.length > 0 ? parsedArgs.messages[0] : undefined;
|
||||
const { exportFromFile } = await import("./export/html");
|
||||
result = await exportFromFile(parsedArgs.export, outputPath);
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : "Failed to export session";
|
||||
@@ -977,7 +977,7 @@ export async function runRootCommand(
|
||||
// Both are no-ops when OTEL_EXPORTER_OTLP_ENDPOINT is unset. An empty config
|
||||
// is enough to enable telemetry — content capture is governed by the
|
||||
// standard OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT env var.
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
if (isTelemetryExportEnabled()) {
|
||||
sessionOptions.telemetry = {};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
export * from "../mnemopi";
|
||||
export type {
|
||||
MnemopiBackendConfig,
|
||||
MnemopiLlmMode,
|
||||
MnemopiProviderOptions,
|
||||
MnemopiScoping,
|
||||
} from "../mnemopi/config";
|
||||
export type {
|
||||
MnemopiMemoryEditOperation,
|
||||
MnemopiMemoryEditOptions,
|
||||
MnemopiMemoryEditResult,
|
||||
MnemopiSessionState,
|
||||
MnemopiSessionStateOptions,
|
||||
} from "../mnemopi/state";
|
||||
export * from "./local-backend";
|
||||
export * from "./off-backend";
|
||||
export * from "./resolve";
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import type { Settings } from "../config/settings";
|
||||
import { hindsightBackend } from "../hindsight";
|
||||
import { mnemopiBackend } from "../mnemopi";
|
||||
import { localBackend } from "./local-backend";
|
||||
import { offBackend } from "./off-backend";
|
||||
import type { MemoryBackend } from "./types";
|
||||
@@ -18,10 +16,10 @@ import type { MemoryBackend } from "./types";
|
||||
* `memories.enabled` remains accepted only as a legacy migration input. Once
|
||||
* a config is loaded, `memory.backend` is the sole runtime selector.
|
||||
*/
|
||||
export function resolveMemoryBackend(settings: Settings): MemoryBackend {
|
||||
export async function resolveMemoryBackend(settings: Settings): Promise<MemoryBackend> {
|
||||
const id = settings.get("memory.backend");
|
||||
if (id === "hindsight") return hindsightBackend;
|
||||
if (id === "mnemopi") return mnemopiBackend;
|
||||
if (id === "hindsight") return (await import("../hindsight/backend")).hindsightBackend;
|
||||
if (id === "mnemopi") return (await import("../mnemopi/backend")).mnemopiBackend;
|
||||
if (id === "local") return localBackend;
|
||||
return offBackend;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Memory backend abstraction.
|
||||
*
|
||||
* Backends are mutually exclusive — `resolveMemoryBackend(settings)` returns
|
||||
* Backends are mutually exclusive — `await resolveMemoryBackend(settings)` resolves
|
||||
* exactly one. Implementations MUST be self-contained: they own the per-session
|
||||
* state they create in `start()` and tear it down on `clear()`.
|
||||
*/
|
||||
|
||||
@@ -13,7 +13,6 @@ import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@oh-my-pi
|
||||
import { formatDuration, Snowflake } from "@oh-my-pi/pi-utils";
|
||||
import { $ } from "bun";
|
||||
import { shouldEnableAppendOnlyContext } from "../../config/append-only-context-mode";
|
||||
import { loadCustomShare } from "../../export/custom-share";
|
||||
import type { CompactOptions } from "../../extensibility/extensions/types";
|
||||
import {
|
||||
diffMentalModelContent,
|
||||
@@ -131,6 +130,7 @@ export class CommandController {
|
||||
}
|
||||
|
||||
try {
|
||||
const { loadCustomShare } = await import("../../export/custom-share");
|
||||
const customShare = await loadCustomShare();
|
||||
if (customShare) {
|
||||
const loader = new BorderedLoader(this.ctx.ui, theme, "Sharing...");
|
||||
@@ -465,7 +465,7 @@ export class CommandController {
|
||||
const argumentText = text.slice(7).trim();
|
||||
const action = argumentText.split(/\s+/, 1)[0]?.toLowerCase() || "view";
|
||||
const agentDir = this.ctx.settings.getAgentDir();
|
||||
const backend = resolveMemoryBackend(this.ctx.settings);
|
||||
const backend = await resolveMemoryBackend(this.ctx.settings);
|
||||
|
||||
if (action === "view") {
|
||||
const payload = await backend.buildDeveloperInstructions(agentDir, this.ctx.settings, this.ctx.session);
|
||||
|
||||
@@ -7,7 +7,6 @@ import { getAgentDbPath, getProjectDir, normalizePathForComparison } from "@oh-m
|
||||
import { getRoleInfo } from "../../config/model-registry";
|
||||
import { formatModelSelectorValue } from "../../config/model-resolver";
|
||||
import { settings } from "../../config/settings";
|
||||
import { DebugSelectorComponent } from "../../debug";
|
||||
import { disableProvider, enableProvider } from "../../discovery";
|
||||
import { clearPluginRootsAndCaches, resolveActiveProjectRegistryPath } from "../../discovery/helpers";
|
||||
import {
|
||||
@@ -1080,7 +1079,8 @@ export class SelectorController {
|
||||
});
|
||||
}
|
||||
|
||||
showDebugSelector(): void {
|
||||
async showDebugSelector(): Promise<void> {
|
||||
const { DebugSelectorComponent } = await import("../../debug");
|
||||
this.showSelector(done => {
|
||||
const selector = new DebugSelectorComponent(this.ctx, done);
|
||||
return { component: selector, focus: selector };
|
||||
|
||||
@@ -2844,8 +2844,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
||||
}
|
||||
}
|
||||
|
||||
showDebugSelector(): void {
|
||||
this.#selectorController.showDebugSelector();
|
||||
async showDebugSelector(): Promise<void> {
|
||||
await this.#selectorController.showDebugSelector();
|
||||
}
|
||||
|
||||
showSessionObserver(): void {
|
||||
|
||||
@@ -269,7 +269,7 @@ export interface InteractiveModeContext {
|
||||
handleSessionDeleteCommand(): Promise<void>;
|
||||
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
||||
showHookConfirm(title: string, message: string): Promise<boolean>;
|
||||
showDebugSelector(): void;
|
||||
showDebugSelector(): Promise<void>;
|
||||
showSessionObserver(): void;
|
||||
resetObserverRegistry(): void;
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ import {
|
||||
} from "@oh-my-pi/pi-utils";
|
||||
import chalk from "chalk";
|
||||
import { type AsyncJob, AsyncJobManager, isBackgroundJobSupportEnabled } from "./async";
|
||||
import { createAutoresearchExtension } from "./autoresearch";
|
||||
import { loadCapability } from "./capability";
|
||||
import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
|
||||
import { bucketRules } from "./capability/rule-buckets";
|
||||
@@ -57,7 +56,6 @@ import { resolveConfigValue } from "./config/resolve-config-value";
|
||||
import { initializeWithSettings } from "./discovery";
|
||||
import { disposeAllKernelSessions, disposeKernelSessionsByOwner } from "./eval/py/executor";
|
||||
import { defaultEvalSessionId } from "./eval/session-id";
|
||||
import { TtsrManager } from "./export/ttsr";
|
||||
import {
|
||||
type CustomCommandsLoadResult,
|
||||
type LoadedCustomCommand,
|
||||
@@ -90,7 +88,7 @@ import { LocalProtocolHandler, type LocalProtocolOptions } from "./internal-urls
|
||||
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "./lsp/startup-events";
|
||||
import { discoverAndLoadMCPTools, MCPManager, type MCPToolsLoadResult } from "./mcp";
|
||||
import { resolveMemoryBackend } from "./memory-backend";
|
||||
import { getMnemopiSessionState, type MnemopiSessionState } from "./mnemopi/state";
|
||||
import type { MnemopiSessionState } from "./mnemopi/state";
|
||||
import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" };
|
||||
import { AgentRegistry, MAIN_AGENT_ID } from "./registry/agent-registry";
|
||||
import {
|
||||
@@ -1150,6 +1148,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
|
||||
// Discover rules and bucket them in one pass to avoid repeated scans over large rule sets.
|
||||
const { ttsrManager, rulebookRules, alwaysApplyRules } = await logger.time("discoverTtsrRules", async () => {
|
||||
const { TtsrManager } = await import("./export/ttsr");
|
||||
const ttsrSettings = settings.getGroup("ttsr");
|
||||
const ttsrManager = new TtsrManager(ttsrSettings);
|
||||
const rulesResult =
|
||||
@@ -1295,7 +1294,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
session ? session.trackEvalExecution(execution, abortController) : execution,
|
||||
getSessionId: () => sessionManager.getSessionId?.() ?? null,
|
||||
getHindsightSessionState: () => session?.getHindsightSessionState(),
|
||||
getMnemopiSessionState: () => getMnemopiSessionState(session),
|
||||
getMnemopiSessionState: () => session?.getMnemopiSessionState(),
|
||||
getAgentId: () => resolvedAgentId,
|
||||
getToolByName: name => session?.getToolByName(name),
|
||||
agentRegistry,
|
||||
@@ -1472,7 +1471,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
}
|
||||
|
||||
const inlineExtensions: ExtensionFactory[] = options.extensions ? [...options.extensions] : [];
|
||||
inlineExtensions.push(createAutoresearchExtension);
|
||||
inlineExtensions.push((await import("./autoresearch")).createAutoresearchExtension);
|
||||
if (customTools.length > 0) {
|
||||
inlineExtensions.push(createCustomToolsExtension(customTools));
|
||||
}
|
||||
@@ -1607,9 +1606,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
// `ExtensionToolWrapper` installed below is the only place the per-tool approval gate runs.
|
||||
// A conditional runner means the approval system silently disappears for users with no
|
||||
// extensions, contradicting non-yolo `tools.approvalMode` settings without feedback.
|
||||
// (Today `createAutoresearchExtension` is unconditionally pushed below, so this scenario
|
||||
// is unreachable; the unconditional construction makes that invariant explicit instead of
|
||||
// implicit, so a future change to make autoresearch optional cannot silently re-open the hole.)
|
||||
// (The builtin autoresearch extension is unconditionally loaded above, so this scenario
|
||||
// is unreachable; unconditional runner construction keeps that invariant explicit and
|
||||
// prevents future optional extensions from silently re-opening the hole.)
|
||||
const extensionRunner: ExtensionRunner = new ExtensionRunner(
|
||||
extensionsResult.extensions,
|
||||
extensionsResult.runtime,
|
||||
@@ -1749,7 +1748,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
const promptTools = buildSystemPromptToolMetadata(tools, {
|
||||
search_tool_bm25: { description: renderSearchToolBm25Description(discoverableToolsForDesc) },
|
||||
});
|
||||
const memoryBackend = resolveMemoryBackend(settings);
|
||||
const memoryBackend = await resolveMemoryBackend(settings);
|
||||
const memoryInstructions = await memoryBackend.buildDeveloperInstructions(agentDir, settings, session);
|
||||
|
||||
// Build combined append prompt: memory instructions + MCP server instructions
|
||||
@@ -2267,19 +2266,18 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
}
|
||||
}
|
||||
|
||||
logger.time("startMemoryStartupTask", () =>
|
||||
Promise.resolve(
|
||||
resolveMemoryBackend(settings).start({
|
||||
session,
|
||||
settings,
|
||||
modelRegistry,
|
||||
agentDir,
|
||||
taskDepth,
|
||||
parentHindsightSessionState: options.parentHindsightSessionState,
|
||||
parentMnemopiSessionState: options.parentMnemopiSessionState,
|
||||
}),
|
||||
),
|
||||
);
|
||||
logger.time("startMemoryStartupTask", async () => {
|
||||
const memoryBackend = await resolveMemoryBackend(settings);
|
||||
await memoryBackend.start({
|
||||
session,
|
||||
settings,
|
||||
modelRegistry,
|
||||
agentDir,
|
||||
taskDepth,
|
||||
parentHindsightSessionState: options.parentHindsightSessionState,
|
||||
parentMnemopiSessionState: options.parentMnemopiSessionState,
|
||||
});
|
||||
});
|
||||
|
||||
// Wire MCP manager callbacks to session for reactive tool updates.
|
||||
// Skip when reusing a parent's manager — the parent owns the callbacks.
|
||||
|
||||
@@ -128,7 +128,6 @@ import {
|
||||
} from "../eval/py/executor";
|
||||
import { defaultEvalSessionId } from "../eval/session-id";
|
||||
import { type BashResult, executeBash as executeBashCommand } from "../exec/bash-executor";
|
||||
import { exportSessionToHtml } from "../export/html";
|
||||
import type { TtsrManager, TtsrMatchContext } from "../export/ttsr";
|
||||
import type { LoadedCustomCommand } from "../extensibility/custom-commands";
|
||||
import type { CustomTool, CustomToolContext } from "../extensibility/custom-tools/types";
|
||||
@@ -2967,14 +2966,14 @@ export class AgentSession {
|
||||
}
|
||||
|
||||
#rekeyHindsightMemoryForCurrentSessionId(): void {
|
||||
if (resolveMemoryBackend(this.settings).id !== "hindsight") return;
|
||||
if (this.settings.get("memory.backend") !== "hindsight") return;
|
||||
const sid = this.agent.sessionId;
|
||||
if (!sid) return;
|
||||
this.getHindsightSessionState()?.setSessionId(sid);
|
||||
}
|
||||
|
||||
#rekeyMnemopiMemoryForCurrentSessionId(): void {
|
||||
if (resolveMemoryBackend(this.settings).id !== "mnemopi") return;
|
||||
if (this.settings.get("memory.backend") !== "mnemopi") return;
|
||||
const sid = this.agent.sessionId;
|
||||
if (!sid) return;
|
||||
this.getMnemopiSessionState()?.setSessionId(sid);
|
||||
@@ -2982,14 +2981,14 @@ export class AgentSession {
|
||||
|
||||
/** New session file: reset auto-recall / retain-threshold counters for the new transcript. */
|
||||
#resetHindsightConversationTrackingIfHindsight(): void {
|
||||
if (resolveMemoryBackend(this.settings).id !== "hindsight") return;
|
||||
if (this.settings.get("memory.backend") !== "hindsight") return;
|
||||
const state = this.getHindsightSessionState();
|
||||
if (!state || state.aliasOf) return;
|
||||
state.resetConversationTracking();
|
||||
}
|
||||
|
||||
#resetMnemopiConversationTrackingIfMnemopi(): void {
|
||||
if (resolveMemoryBackend(this.settings).id !== "mnemopi") return;
|
||||
if (this.settings.get("memory.backend") !== "mnemopi") return;
|
||||
const state = this.getMnemopiSessionState();
|
||||
if (!state || state.aliasOf) return;
|
||||
state.resetConversationTracking();
|
||||
@@ -3670,7 +3669,7 @@ export class AgentSession {
|
||||
}
|
||||
|
||||
async #buildSystemPromptForAgentStart(promptText: string): Promise<string[]> {
|
||||
const backend = resolveMemoryBackend(this.settings);
|
||||
const backend = await resolveMemoryBackend(this.settings);
|
||||
if (!backend.beforeAgentStartPrompt) return this.#baseSystemPrompt;
|
||||
|
||||
try {
|
||||
@@ -6096,7 +6095,7 @@ export class AgentSession {
|
||||
messagesToSummarize: AgentMessage[];
|
||||
turnPrefixMessages: AgentMessage[];
|
||||
}): Promise<string | undefined> {
|
||||
const backend = resolveMemoryBackend(this.settings);
|
||||
const backend = await resolveMemoryBackend(this.settings);
|
||||
if (!backend.preCompactionContext) return undefined;
|
||||
const messages = preparation.messagesToSummarize.concat(preparation.turnPrefixMessages);
|
||||
try {
|
||||
@@ -9588,6 +9587,7 @@ export class AgentSession {
|
||||
*/
|
||||
async exportToHtml(outputPath?: string): Promise<string> {
|
||||
const themeName = getCurrentThemeName();
|
||||
const { exportSessionToHtml } = await import("../export/html");
|
||||
return exportSessionToHtml(this.sessionManager, this.state, { outputPath, themeName });
|
||||
}
|
||||
|
||||
|
||||
@@ -934,7 +934,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
|
||||
allowArgs: true,
|
||||
handle: async (command, runtime) => {
|
||||
const verb = (command.args.trim().split(/\s+/)[0] ?? "").toLowerCase() || "view";
|
||||
const backend = resolveMemoryBackend(runtime.settings);
|
||||
const backend = await resolveMemoryBackend(runtime.settings);
|
||||
switch (verb) {
|
||||
case "view": {
|
||||
const payload = await backend.buildDeveloperInstructions(
|
||||
|
||||
@@ -23,11 +23,7 @@
|
||||
* `sdk-trace-base@2.7` exports cleanly on Bun.
|
||||
*/
|
||||
import { logger, postmortem } from "@oh-my-pi/pi-utils";
|
||||
import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
|
||||
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
|
||||
import { resourceFromAttributes } from "@opentelemetry/resources";
|
||||
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
||||
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
||||
import type * as TraceNode from "@opentelemetry/sdk-trace-node";
|
||||
|
||||
/**
|
||||
* Periodic flush interval. A long-lived `omp` process (the ACP server is
|
||||
@@ -36,7 +32,8 @@ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
||||
*/
|
||||
const FLUSH_INTERVAL_MS = 30_000;
|
||||
|
||||
let provider: NodeTracerProvider | undefined;
|
||||
let provider: TraceNode.NodeTracerProvider | undefined;
|
||||
let initPromise: Promise<void> | undefined;
|
||||
|
||||
/**
|
||||
* Whether {@link initTelemetryExport} registered a real provider. The CLI uses
|
||||
@@ -53,8 +50,10 @@ export function isTelemetryExportEnabled(): boolean {
|
||||
* the OTEL kill-switches are engaged), so it is safe to call unconditionally at
|
||||
* startup.
|
||||
*/
|
||||
export function initTelemetryExport(): void {
|
||||
export async function initTelemetryExport(): Promise<void> {
|
||||
if (provider) return;
|
||||
if (initPromise) return initPromise;
|
||||
|
||||
// The OTEL env contract parses booleans and enum lists case-insensitively, so
|
||||
// OTEL_SDK_DISABLED=TRUE and OTEL_TRACES_EXPORTER=None must also disable export.
|
||||
if (process.env.OTEL_SDK_DISABLED?.trim().toLowerCase() === "true") return;
|
||||
@@ -77,6 +76,25 @@ export function initTelemetryExport(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
initPromise = registerProvider();
|
||||
return initPromise;
|
||||
}
|
||||
|
||||
async function registerProvider(): Promise<void> {
|
||||
const [
|
||||
{ AsyncLocalStorageContextManager },
|
||||
{ OTLPTraceExporter },
|
||||
{ resourceFromAttributes },
|
||||
{ BatchSpanProcessor },
|
||||
{ NodeTracerProvider },
|
||||
] = await Promise.all([
|
||||
import("@opentelemetry/context-async-hooks"),
|
||||
import("@opentelemetry/exporter-trace-otlp-proto"),
|
||||
import("@opentelemetry/resources"),
|
||||
import("@opentelemetry/sdk-trace-base"),
|
||||
import("@opentelemetry/sdk-trace-node"),
|
||||
]);
|
||||
|
||||
// The exporter reads endpoint/headers/timeout from OTEL_EXPORTER_OTLP_* itself,
|
||||
// so there is nothing to thread through here.
|
||||
const exporter = new OTLPTraceExporter();
|
||||
|
||||
@@ -11,10 +11,10 @@ describe("resolveMemoryBackend", () => {
|
||||
resetSettingsForTest();
|
||||
});
|
||||
|
||||
it("returns the hindsight backend when memory.backend is hindsight, regardless of legacy memories.enabled", () => {
|
||||
it("returns the hindsight backend when memory.backend is hindsight, regardless of legacy memories.enabled", async () => {
|
||||
const a = Settings.isolated({ "memory.backend": "hindsight", "memories.enabled": false });
|
||||
const b = Settings.isolated({ "memory.backend": "hindsight", "memories.enabled": true });
|
||||
expect(resolveMemoryBackend(a).id).toBe("hindsight");
|
||||
expect(resolveMemoryBackend(b).id).toBe("hindsight");
|
||||
expect((await resolveMemoryBackend(a)).id).toBe("hindsight");
|
||||
expect((await resolveMemoryBackend(b)).id).toBe("hindsight");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@ const server = Bun.serve({
|
||||
process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = `http://localhost:${server.port}/v1/traces`;
|
||||
process.env.OTEL_SERVICE_NAME = "oh-my-pi-export-probe";
|
||||
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
if (!isTelemetryExportEnabled()) {
|
||||
console.error("PROBE: provider did not register");
|
||||
await server.stop(true);
|
||||
|
||||
@@ -33,45 +33,45 @@ afterEach(() => {
|
||||
});
|
||||
|
||||
describe("initTelemetryExport gating", () => {
|
||||
it("stays disabled when no OTLP endpoint is configured", () => {
|
||||
initTelemetryExport();
|
||||
it("stays disabled when no OTLP endpoint is configured", async () => {
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("stays disabled when OTEL_SDK_DISABLED=true even with an endpoint", () => {
|
||||
it("stays disabled when OTEL_SDK_DISABLED=true even with an endpoint", async () => {
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318";
|
||||
process.env.OTEL_SDK_DISABLED = "true";
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("stays disabled when OTEL_TRACES_EXPORTER=none even with an endpoint", () => {
|
||||
it("stays disabled when OTEL_TRACES_EXPORTER=none even with an endpoint", async () => {
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318";
|
||||
process.env.OTEL_TRACES_EXPORTER = "none";
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("declines unsupported OTLP protocols instead of misrouting spans", () => {
|
||||
it("declines unsupported OTLP protocols instead of misrouting spans", async () => {
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4317";
|
||||
process.env.OTEL_EXPORTER_OTLP_PROTOCOL = "grpc";
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
|
||||
process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "http/json";
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it("honors the kill-switches case-insensitively per the OTEL env contract", () => {
|
||||
it("honors the kill-switches case-insensitively per the OTEL env contract", async () => {
|
||||
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = "http://localhost:4318";
|
||||
process.env.OTEL_SDK_DISABLED = "TRUE";
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
|
||||
delete process.env.OTEL_SDK_DISABLED;
|
||||
process.env.OTEL_TRACES_EXPORTER = "otlp,None";
|
||||
initTelemetryExport();
|
||||
await initTelemetryExport();
|
||||
expect(isTelemetryExportEnabled()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user