UNPKG

@shopify/cli-kit

Version:

A set of utilities, interfaces, and models that are common across all the platform features

131 lines 5.12 kB
import { MetricInstrumentType } from '../../public/node/vendor/otel-js/service/types.js'; import { outputContent, outputDebug, outputToken } from '../../public/node/output.js'; import { DefaultOtelService, } from '../../public/node/vendor/otel-js/service/DefaultOtelService/DefaultOtelService.js'; import { isUnitTest, opentelemetryDomain } from '../../public/node/context/local.js'; import { isSpinEnvironment } from '../../public/node/context/spin.js'; import { ValueType } from '@opentelemetry/api'; var Name; (function (Name) { Name["Counter"] = "cli_commands_total"; Name["Duration"] = "cli_commands_duration_ms"; Name["Elapsed"] = "cli_commands_wall_clock_elapsed_ms"; })(Name || (Name = {})); /** * Record reliability metrics. */ export async function recordMetrics(options, timing, recorderFactory = createMetricRecorder) { const recorder = recorderFactory({ skipMetricAnalytics: options.skipMetricAnalytics, otelOptions: defaultOtelOptions(), }); let regularisedCliVersion = options.cliVersion; if (options.cliVersion.includes('nightly')) { regularisedCliVersion = 'nightly'; } else if (options.cliVersion.includes('pre')) { regularisedCliVersion = 'pre'; } const labels = { exit: options.exitMode, job: `${options.owningPlugin}::${options.command}`, cli_version: regularisedCliVersion, }; recordCommandCounter(recorder, labels); recordCommandTiming(recorder, labels, timing); } /** * Get the default options for the OTEL service. These are the same across environments. */ function defaultOtelOptions() { return { serviceName: 'shopify-cli', throttleLimit: 1000, prefixMetric: false, metrics: { [Name.Counter]: { type: MetricInstrumentType.Counter, description: 'Total number of CLI commands executed', valueType: ValueType.INT, }, [Name.Duration]: { type: MetricInstrumentType.Histogram, description: 'Total time spent in execution of CLI commands. Does not include time spent waiting for network, prompts, etc.', valueType: ValueType.INT, boundaries: [0, 100, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000], }, [Name.Elapsed]: { type: MetricInstrumentType.Histogram, description: 'Total time elapsed from start to finish of CLI commands. Includes time spent waiting for network, prompts, etc.', valueType: ValueType.INT, boundaries: [0, 100, 250, 500, 1000, 2000, 5000, 10000, 20000, 50000], }, }, }; } /** * Create the metric recorder for this command. * * If metric logging is disabled, or we are running in a unit test or Spin, we record to the console. * */ function createMetricRecorder(options) { let recorder = 'console'; if (!(options.skipMetricAnalytics || isUnitTest() || isSpinEnvironment())) { recorder = { type: 'otel', otel: globalOtelService(options), }; } return recorder; } let _otelService; /** * OTEL service singleton. * * The service is a singleton as it uses a global diagnostic logger that assumes its the only one in the process. */ function globalOtelService(options) { if (!_otelService) { _otelService = new DefaultOtelService({ ...options.otelOptions, env: undefined, otelEndpoint: `${opentelemetryDomain()}/v1/metrics`, }); } return _otelService; } /** * Log command counter metrics. */ function recordCommandCounter(recorder, labels) { if (recorder === 'console') { outputDebug(outputContent `[OTEL] record ${Name.Counter} counter ${outputToken.json({ labels })}`); return; } recorder.otel.record(Name.Counter, 1, labels); } /** * Log command timing metrics. */ function recordCommandTiming(recorder, labels, timing) { if (recorder === 'console') { outputDebug(outputContent `[OTEL] record ${Name.Duration} histogram ${timing.active.toString()}ms ${outputToken.json({ labels, })}`); outputDebug(outputContent `[OTEL] record ${Name.Elapsed} histogram stage="active" ${timing.active.toString()}ms`); outputDebug(outputContent `[OTEL] record ${Name.Elapsed} histogram stage="network" ${timing.network.toString()}ms`); outputDebug(outputContent `[OTEL] record ${Name.Elapsed} histogram stage="prompt" ${timing.prompt.toString()}ms`); return; } if (timing.active > 0) { recorder.otel.record(Name.Duration, timing.active, labels); recorder.otel.record(Name.Elapsed, timing.active, { ...labels, stage: 'active' }); } if (timing.network > 0) { recorder.otel.record(Name.Elapsed, timing.network, { ...labels, stage: 'network' }); } if (timing.prompt > 0) { recorder.otel.record(Name.Elapsed, timing.prompt, { ...labels, stage: 'prompt' }); } } //# sourceMappingURL=otel-metrics.js.map