diff --git a/src/lib/error-format.ts b/src/lib/error-format.ts new file mode 100644 index 0000000000..5c385ac210 --- /dev/null +++ b/src/lib/error-format.ts @@ -0,0 +1,12 @@ +export function abridgeErrorMessage( + msg: string, + maxLen: number, + ellipsis?: string, +): string { + if (msg.length <= maxLen) { + return msg; + } + const e = ellipsis || ' ... '; + const toKeep = (maxLen - e.length) / 2; + return msg.slice(0, toKeep) + e + msg.slice(msg.length - toKeep, msg.length); +} diff --git a/src/lib/monitor/index.ts b/src/lib/monitor/index.ts index b6fefea3ed..4c2743e5c5 100644 --- a/src/lib/monitor/index.ts +++ b/src/lib/monitor/index.ts @@ -51,9 +51,12 @@ import { } from './utils'; import { countPathsToGraphRoot } from '../utils'; import * as alerts from '../alerts'; +import { abridgeErrorMessage } from '../error-format'; const debug = Debug('snyk'); +const ANALYTICS_PAYLOAD_MAX_LENGTH = 1024; + // TODO(kyegupov): clean up the type, move to snyk-cli-interface repository interface MonitorBody { @@ -220,7 +223,13 @@ async function monitorDepTree( let callGraphPayload; if (options.reachableVulns && scannedProject.callGraph?.innerError) { const err = scannedProject.callGraph as CallGraphError; - analytics.add('callGraphError', err.innerError.toString()); + analytics.add( + 'callGraphError', + abridgeErrorMessage( + err.innerError.toString(), + ANALYTICS_PAYLOAD_MAX_LENGTH, + ), + ); alerts.registerAlerts([ { type: 'error', diff --git a/src/lib/snyk-test/run-test.ts b/src/lib/snyk-test/run-test.ts index ce9d5d34cb..8bb434e481 100644 --- a/src/lib/snyk-test/run-test.ts +++ b/src/lib/snyk-test/run-test.ts @@ -55,9 +55,12 @@ import { assembleIacLocalPayloads, parseIacTestResult } from './run-iac-test'; import { Payload, PayloadBody, DepTreeFromResolveDeps } from './types'; import { CallGraphError } from '@snyk/cli-interface/legacy/common'; import * as alerts from '../alerts'; +import { abridgeErrorMessage } from '../error-format'; const debug = debugModule('snyk'); +const ANALYTICS_PAYLOAD_MAX_LENGTH = 1024; + export = runTest; async function sendAndParseResults( @@ -520,7 +523,13 @@ async function assembleLocalPayloads( (scannedProject.callGraph as CallGraphError).innerError ) { const err = scannedProject.callGraph as CallGraphError; - analytics.add('callGraphError', err.innerError.toString()); + analytics.add( + 'callGraphError', + abridgeErrorMessage( + err.innerError.toString(), + ANALYTICS_PAYLOAD_MAX_LENGTH, + ), + ); alerts.registerAlerts([ { type: 'error', diff --git a/test/error-format.test.ts b/test/error-format.test.ts new file mode 100644 index 0000000000..fb72d8dcd9 --- /dev/null +++ b/test/error-format.test.ts @@ -0,0 +1,22 @@ +import { test } from 'tap'; +import { abridgeErrorMessage } from '../src/lib/error-format'; + +test('abridge empty string', async (t) => { + t.equal(abridgeErrorMessage('', 10), ''); +}); + +test('abridge shorter than max length', async (t) => { + t.equal(abridgeErrorMessage('hello', 10), 'hello'); +}); + +test('abridge same length as max length', async (t) => { + t.equal(abridgeErrorMessage('hello', 5), 'hello'); +}); + +test('abridge longer than max length', async (t) => { + t.equal(abridgeErrorMessage('hello there', 10), 'he ... ere'); +}); + +test('abridge longer than max length (custom ellipsis)', async (t) => { + t.equal(abridgeErrorMessage('hello there', 10, '--'), 'hell--here'); +});