From a814357d6d75ec2d2b72c483b3f6f44496bc19ad Mon Sep 17 00:00:00 2001 From: Andreas Christou Date: Fri, 10 Mar 2023 14:17:17 +0000 Subject: [PATCH] FalconLogScale: Traces to logs support (#64174) * Humio traces to logs support * Update tag formatting * Add tests for humio * Correct naming --- .../TraceToLogs/TraceToLogsSettings.tsx | 1 + .../explore/TraceView/createSpanLink.test.ts | 127 ++++++++++++++++++ .../explore/TraceView/createSpanLink.tsx | 32 +++++ 3 files changed, 160 insertions(+) diff --git a/public/app/core/components/TraceToLogs/TraceToLogsSettings.tsx b/public/app/core/components/TraceToLogs/TraceToLogsSettings.tsx index ff170527354..2a4d21744ca 100644 --- a/public/app/core/components/TraceToLogs/TraceToLogsSettings.tsx +++ b/public/app/core/components/TraceToLogs/TraceToLogsSettings.tsx @@ -75,6 +75,7 @@ export function TraceToLogsSettings({ options, onOptionsChange }: Props) { 'elasticsearch', 'grafana-splunk-datasource', // external 'grafana-opensearch-datasource', // external + 'grafana-falconlogscale-datasource', // external ]; const traceToLogs = useMemo( diff --git a/public/app/features/explore/TraceView/createSpanLink.test.ts b/public/app/features/explore/TraceView/createSpanLink.test.ts index f1ad205615a..d8fa3ab3c27 100644 --- a/public/app/features/explore/TraceView/createSpanLink.test.ts +++ b/public/app/features/explore/TraceView/createSpanLink.test.ts @@ -863,6 +863,133 @@ describe('createSpanLinkFactory', () => { expect(links?.logLinks).toBeUndefined(); }); }); + + describe('should return falconLogScale link', () => { + const falconLogScaleUID = 'falconLogScaleUID'; + + beforeAll(() => { + setDataSourceSrv({ + getInstanceSettings() { + return { + uid: falconLogScaleUID, + name: 'FalconLogScale', + type: 'grafana-falconlogscale-datasource', + } as unknown as DataSourceInstanceSettings; + }, + } as unknown as DataSourceSrv); + + setLinkSrv(new LinkSrv()); + setTemplateSrv(new TemplateSrv()); + }); + + it('the `lsql` keyword is used in the link', () => { + const createLink = setupSpanLinkFactory({ + datasourceUid: falconLogScaleUID, + }); + const links = createLink!(createTraceSpan()); + + const linkDef = links?.logLinks?.[0]; + expect(linkDef).toBeDefined(); + expect(linkDef!.href).toContain(`${encodeURIComponent('datasource":"falconLogScaleUID","queries":[{"lsql"')}`); + }); + + it('formats query correctly if filterByTraceID and or filterBySpanID is true', () => { + const createLink = setupSpanLinkFactory({ + datasourceUid: falconLogScaleUID, + filterByTraceID: true, + filterBySpanID: true, + }); + + expect(createLink).toBeDefined(); + const links = createLink!(createTraceSpan()); + + const linkDef = links?.logLinks?.[0]; + expect(linkDef).toBeDefined(); + expect(linkDef!.href).toBe( + `/explore?left=${encodeURIComponent( + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"cluster=\\"cluster1\\" OR hostname=\\"hostname1\\" or \\"7946b05c2e2e4e5a\\" or \\"6605c7b08e715d6c\\"","refId":""}]}' + )}` + ); + }); + + it('should format one tag correctly', () => { + const createLink = setupSpanLinkFactory({ + tags: [{ key: 'ip' }], + }); + expect(createLink).toBeDefined(); + const links = createLink!( + createTraceSpan({ + process: { + serviceName: 'service', + tags: [{ key: 'ip', value: '192.168.0.1' }], + }, + }) + ); + + const linkDef = links?.logLinks?.[0]; + expect(linkDef).toBeDefined(); + expect(linkDef!.href).toBe( + `/explore?left=${encodeURIComponent( + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"ip=\\"192.168.0.1\\"","refId":""}]}' + )}` + ); + }); + + it('should format multiple tags correctly', () => { + const createLink = setupSpanLinkFactory({ + tags: [{ key: 'ip' }, { key: 'hostname' }], + }); + expect(createLink).toBeDefined(); + const links = createLink!( + createTraceSpan({ + process: { + serviceName: 'service', + tags: [ + { key: 'hostname', value: 'hostname1' }, + { key: 'ip', value: '192.168.0.1' }, + ], + }, + }) + ); + + const linkDef = links?.logLinks?.[0]; + expect(linkDef).toBeDefined(); + expect(linkDef!.href).toBe( + `/explore?left=${encodeURIComponent( + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"hostname=\\"hostname1\\" OR ip=\\"192.168.0.1\\"","refId":""}]}' + )}` + ); + }); + + it('handles renamed tags', () => { + const createLink = setupSpanLinkFactory({ + tags: [ + { key: 'service.name', value: 'service' }, + { key: 'k8s.pod.name', value: 'pod' }, + ], + }); + expect(createLink).toBeDefined(); + const links = createLink!( + createTraceSpan({ + process: { + serviceName: 'service', + tags: [ + { key: 'service.name', value: 'serviceName' }, + { key: 'k8s.pod.name', value: 'podName' }, + ], + }, + }) + ); + + const linkDef = links?.logLinks?.[0]; + expect(linkDef).toBeDefined(); + expect(linkDef!.href).toBe( + `/explore?left=${encodeURIComponent( + '{"range":{"from":"2020-10-14T01:00:00.000Z","to":"2020-10-14T01:00:01.000Z"},"datasource":"falconLogScaleUID","queries":[{"lsql":"service=\\"serviceName\\" OR pod=\\"podName\\"","refId":""}]}' + )}` + ); + }); + }); }); function setupSpanLinkFactory(options: Partial = {}, datasourceUid = 'lokiUid') { diff --git a/public/app/features/explore/TraceView/createSpanLink.tsx b/public/app/features/explore/TraceView/createSpanLink.tsx index 3edbdf50e31..d529243b4ef 100644 --- a/public/app/features/explore/TraceView/createSpanLink.tsx +++ b/public/app/features/explore/TraceView/createSpanLink.tsx @@ -164,6 +164,9 @@ function legacyCreateSpanLinkFactory( tags = getFormattedTags(span, tagsToUse, { labelValueSign: ':', joinBy: ' AND ' }); query = getQueryForElasticsearchOrOpensearch(span, traceToLogsOptions, tags, customQuery); break; + case 'grafana-falconlogscale-datasource': + tags = getFormattedTags(span, tagsToUse, { joinBy: ' OR ' }); + query = getQueryForFalconLogScale(span, traceToLogsOptions, tags, customQuery); } // query can be false in case the simple UI tag mapping is used but none of them are present in the span. @@ -405,6 +408,35 @@ function getQueryForSplunk(span: TraceSpan, options: TraceToLogsOptionsV2, tags: }; } +function getQueryForFalconLogScale(span: TraceSpan, options: TraceToLogsOptionsV2, tags: string, customQuery?: string) { + const { filterByTraceID, filterBySpanID } = options; + + if (customQuery) { + return { + lsql: customQuery, + refId: '', + }; + } + + if (!tags) { + return undefined; + } + + let lsql = '${__tags}'; + if (filterByTraceID && span.traceID) { + lsql += ' or "${__span.traceId}"'; + } + + if (filterBySpanID && span.spanID) { + lsql += ' or "${__span.spanId}"'; + } + + return { + lsql, + refId: '', + }; +} + /** * Creates a string representing all the tags already formatted for use in the query. The tags are filtered so that * only intersection of tags that exist in a span and tags that you want are serialized into the string.