UNPKG

@mastra/core

Version:
294 lines (293 loc) • 10.6 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const require_rolldown_runtime = require("../rolldown-runtime-uwYp4b74.cjs"); let crypto = require("crypto"); let os = require("os"); os = require_rolldown_runtime.__toESM(os, 1); let posthog_node = require("posthog-node"); let fs = require("fs"); let path = require("path"); path = require_rolldown_runtime.__toESM(path, 1); //#region src/telemetry/posthog.ts const POSTHOG_API_KEY = "phc_SBLpZVAB6jmHOct9CABq3PF0Yn5FU3G2FgT4xUr2XrT"; const POSTHOG_HOST = "https://us.posthog.com"; const TRUTHY_DISABLED_VALUES = /* @__PURE__ */ new Set([ "1", "true", "yes" ]); let client = null; function isTelemetryEnabled() { const value = process.env["MASTRA_TELEMETRY_DISABLED"]; if (!value) return true; return !TRUTHY_DISABLED_VALUES.has(value.trim().toLowerCase()); } function hashTelemetryValue(value) { return (0, crypto.createHash)("sha256").update(value).digest("hex"); } function getHashedHostname() { return hashTelemetryValue(os.default.hostname() || "unknown-host").slice(0, 16); } function getEETelemetryFallbackDistinctId() { return `mastra-${getHashedHostname()}`; } function getClient() { if (!isTelemetryEnabled()) return null; if (!client) client = new posthog_node.PostHog(POSTHOG_API_KEY, { host: POSTHOG_HOST, flushAt: 1, flushInterval: 0, disableGeoip: false }); return client; } function getSystemProperties() { return { os: process.platform, os_version: os.default.release(), node_version: process.version, platform: process.arch, machine_id: getHashedHostname(), mastra_version: process.env["npm_package_version"] || "unknown" }; } function captureTelemetryEvent(event, distinctId, properties) { try { const posthog = getClient(); if (!posthog) return; posthog.capture({ distinctId: distinctId || getEETelemetryFallbackDistinctId(), event, properties: { ...getSystemProperties(), ...properties } }); } catch {} } //#endregion //#region src/telemetry/context.ts function getServerTelemetryContext() { return { projectId: hashTelemetryValue(process.env.MASTRA_PROJECT_ROOT || process.cwd()).slice(0, 16), distinctId: process.env.MASTRA_CLI_DISTINCT_ID || void 0, command: process.env.MASTRA_TELEMETRY_COMMAND || "server", nodeEnv: process.env.NODE_ENV || "development" }; } //#endregion //#region src/telemetry/feature-telemetry.ts const FEATURE_USAGE_EVENT = "mastra_feature_usage"; function countCollection(collection) { if (!collection || typeof collection !== "object") return 0; if (collection instanceof Map || collection instanceof Set) return collection.size; return Object.keys(collection).length; } function countAgentsWithMemory(agents) { if (!agents || typeof agents !== "object") return 0; return Object.values(agents).filter((agent) => { try { return agent?.hasOwnMemory?.() === true; } catch { return false; } }).length; } function bucketStorageType(storage) { if (!storage) return null; const constructorName = storage.constructor?.name?.toLowerCase(); if (!constructorName) return "unknown"; if (constructorName.includes("memory")) return "in-memory"; if (constructorName.includes("libsql")) return "libsql"; if (constructorName.includes("postgres")) return "postgres"; if (constructorName.includes("mongo")) return "mongo"; if (constructorName.includes("upstash")) return "upstash"; if (constructorName.includes("dynamodb")) return "dynamodb"; if (constructorName.includes("redis")) return "redis"; return "unknown"; } function trackFeatureUsage(name, metadata) { try { if (!isTelemetryEnabled()) return; const { projectId, distinctId, command, nodeEnv } = getServerTelemetryContext(); captureTelemetryEvent(FEATURE_USAGE_EVENT, distinctId, { feature_name: name, project_id: projectId, command, node_env: nodeEnv, ...metadata }); } catch {} } function syncFeatureUsageTelemetry(mastra) { try { if (!isTelemetryEnabled()) return; const agents = mastra.listAgents?.(); const agentsWithMemoryCount = countAgentsWithMemory(agents); const memory = mastra.listMemory?.(); const workspaces = mastra.listWorkspaces?.(); const tts = mastra.getTTS?.(); const promptBlocks = mastra.listPromptBlocks?.(); const processorConfigurations = mastra.listProcessorConfigurations?.(); const agentChannels = mastra.getChannels?.(); const storage = mastra.getStorage?.(); trackFeatureUsage("mastra_instance_summary", { agent_count: countCollection(agents), agents_with_memory_count: agentsWithMemoryCount, agent_controller_count: countCollection(mastra.listAgentControllers?.()), workflow_count: countCollection(mastra.listWorkflows?.()), tool_count: countCollection(mastra.listTools?.()), processor_count: countCollection(mastra.listProcessors?.()), processor_configuration_count: countCollection(processorConfigurations), memory_count: countCollection(memory), vector_count: countCollection(mastra.listVectors?.()), scorer_count: countCollection(mastra.listScorers?.()), workspace_count: countCollection(workspaces), mcp_server_count: countCollection(mastra.listMCPServers?.()), gateway_count: countCollection(mastra.listGateways?.()), channel_count: countCollection(mastra.getChannelProviders?.()), agent_channel_count: countCollection(agentChannels), tts_count: countCollection(tts), prompt_block_count: countCollection(promptBlocks), editor_enabled: !!mastra.getEditor?.(), studio_enabled: !!mastra.getStudio?.(), server_middleware_enabled: !!mastra.getServerMiddleware?.(), storage_type: bucketStorageType(storage), observability_enabled: !!storage?.stores?.observability }); } catch {} } //#endregion //#region src/telemetry/usage-telemetry.ts const INPUT_TOKENS_METRIC = "mastra_model_total_input_tokens"; const OUTPUT_TOKENS_METRIC = "mastra_model_total_output_tokens"; const BREAKDOWN_LIMIT = 200; const USAGE_TELEMETRY_EVENT = "mastra_model_token_usage"; function getDefaultCursorPath() { return path.default.join(os.default.homedir(), ".mastra", "usage-telemetry.json"); } function readCursors(cursorPath) { try { const parsed = JSON.parse((0, fs.readFileSync)(cursorPath, "utf-8")); if (parsed && typeof parsed === "object" && parsed.projects && typeof parsed.projects === "object") return { projects: parsed.projects }; } catch {} return { projects: {} }; } function readCursor(cursorPath, projectId) { const value = readCursors(cursorPath).projects[projectId]; if (!value) return; const date = new Date(value); return Number.isNaN(date.getTime()) ? void 0 : date; } function writeCursor(cursorPath, projectId, syncedAt) { const cursors = readCursors(cursorPath); cursors.projects[projectId] = syncedAt.toISOString(); (0, fs.mkdirSync)(path.default.dirname(cursorPath), { recursive: true }); (0, fs.writeFileSync)(cursorPath, JSON.stringify(cursors)); } function applyBreakdown(rows, response, field) { for (const group of response.groups) { const provider = group.dimensions.provider ?? null; const model = group.dimensions.model ?? null; const key = `${provider}\u0000${model}`; let row = rows.get(key); if (!row) { row = { provider, model, inputTokens: 0, outputTokens: 0, totalInputTokens: 0, totalOutputTokens: 0 }; rows.set(key, row); } row[field] += group.value ?? 0; } } /** * Sends aggregated model token usage (input/output tokens per provider+model) to * Mastra's anonymous telemetry when the project has observability metrics enabled. * * Sync strategy: deltas since the last successful sync, tracked per project via a * cursor file in `~/.mastra/usage-telemetry.json`. Each event also carries lifetime * totals so consumers can read either incremental or cumulative usage. Runs once at * server startup; respects `MASTRA_TELEMETRY_DISABLED`. Never throws. */ async function syncUsageTelemetry(mastra, options = {}) { try { if (!isTelemetryEnabled()) return; const observability = mastra.getStorage()?.stores?.observability; if (!observability || typeof observability.getMetricBreakdown !== "function") return; const { projectId, distinctId, command, nodeEnv } = getServerTelemetryContext(); const cursorPath = options.cursorPath ?? getDefaultCursorPath(); const lastSyncedAt = readCursor(cursorPath, projectId); const now = options.now ?? /* @__PURE__ */ new Date(); if (lastSyncedAt && lastSyncedAt.getTime() >= now.getTime()) return; const baseArgs = { groupBy: ["provider", "model"], aggregation: "sum", limit: BREAKDOWN_LIMIT }; const deltaFilters = { timestamp: { ...lastSyncedAt ? { start: lastSyncedAt, startExclusive: true } : {}, end: now } }; const totalFilters = { timestamp: { end: now } }; const [inputDelta, outputDelta, inputTotal, outputTotal] = await Promise.all([ observability.getMetricBreakdown({ ...baseArgs, name: [INPUT_TOKENS_METRIC], filters: deltaFilters }), observability.getMetricBreakdown({ ...baseArgs, name: [OUTPUT_TOKENS_METRIC], filters: deltaFilters }), observability.getMetricBreakdown({ ...baseArgs, name: [INPUT_TOKENS_METRIC], filters: totalFilters }), observability.getMetricBreakdown({ ...baseArgs, name: [OUTPUT_TOKENS_METRIC], filters: totalFilters }) ]); const rows = /* @__PURE__ */ new Map(); applyBreakdown(rows, inputDelta, "inputTokens"); applyBreakdown(rows, outputDelta, "outputTokens"); applyBreakdown(rows, inputTotal, "totalInputTokens"); applyBreakdown(rows, outputTotal, "totalOutputTokens"); const isFirstSync = !lastSyncedAt; for (const row of rows.values()) { if (row.inputTokens <= 0 && row.outputTokens <= 0) continue; captureTelemetryEvent(USAGE_TELEMETRY_EVENT, distinctId, { provider: row.provider, model: row.model, input_tokens: row.inputTokens, output_tokens: row.outputTokens, total_input_tokens: row.totalInputTokens, total_output_tokens: row.totalOutputTokens, command, node_env: nodeEnv, project_id: projectId, is_first_sync: isFirstSync, window_start: lastSyncedAt?.toISOString() ?? null, window_end: now.toISOString() }); } writeCursor(cursorPath, projectId, now); } catch {} } //#endregion exports.FEATURE_USAGE_EVENT = FEATURE_USAGE_EVENT; exports.USAGE_TELEMETRY_EVENT = USAGE_TELEMETRY_EVENT; exports.syncFeatureUsageTelemetry = syncFeatureUsageTelemetry; exports.syncUsageTelemetry = syncUsageTelemetry; exports.trackFeatureUsage = trackFeatureUsage; //# sourceMappingURL=index.cjs.map