@perses-dev/tempo-plugin 0.47.0 → 0.48.0-rc0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/TraceQLEditor.js +98 -0
- package/dist/cjs/components/TraceQLExtension.js +73 -0
- package/dist/cjs/components/complete.js +322 -0
- package/dist/cjs/components/highlight.js +41 -0
- package/dist/cjs/components/index.js +30 -0
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/model/tempo-client.js +28 -13
- package/dist/cjs/plugins/tempo-datasource.js +22 -4
- package/dist/cjs/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.js +6 -2
- package/dist/cjs/plugins/tempo-trace-query/get-trace-data.js +3 -13
- package/dist/components/TraceQLEditor.d.ts +7 -0
- package/dist/components/TraceQLEditor.d.ts.map +1 -0
- package/dist/{plugins/tempo-trace-query → components}/TraceQLEditor.js +20 -4
- package/dist/components/TraceQLEditor.js.map +1 -0
- package/dist/components/TraceQLExtension.d.ts +8 -0
- package/dist/components/TraceQLExtension.d.ts.map +1 -0
- package/dist/components/TraceQLExtension.js +65 -0
- package/dist/components/TraceQLExtension.js.map +1 -0
- package/dist/components/complete.d.ts +36 -0
- package/dist/components/complete.d.ts.map +1 -0
- package/dist/components/complete.js +313 -0
- package/dist/components/complete.js.map +1 -0
- package/dist/components/highlight.d.ts +2 -0
- package/dist/components/highlight.d.ts.map +1 -0
- package/dist/components/highlight.js +33 -0
- package/dist/components/highlight.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +15 -0
- package/dist/components/index.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model/api-types.d.ts +60 -9
- package/dist/model/api-types.d.ts.map +1 -1
- package/dist/model/api-types.js.map +1 -1
- package/dist/model/tempo-client.d.ts +18 -8
- package/dist/model/tempo-client.d.ts.map +1 -1
- package/dist/model/tempo-client.js +21 -8
- package/dist/model/tempo-client.js.map +1 -1
- package/dist/plugins/tempo-datasource.d.ts.map +1 -1
- package/dist/plugins/tempo-datasource.js +23 -5
- package/dist/plugins/tempo-datasource.js.map +1 -1
- package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.d.ts.map +1 -1
- package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.js +6 -2
- package/dist/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.js.map +1 -1
- package/dist/plugins/tempo-trace-query/get-trace-data.d.ts.map +1 -1
- package/dist/plugins/tempo-trace-query/get-trace-data.js +3 -13
- package/dist/plugins/tempo-trace-query/get-trace-data.js.map +1 -1
- package/dist/test/mock-data.d.ts +5 -5
- package/dist/test/mock-data.d.ts.map +1 -1
- package/dist/test/mock-data.js.map +1 -1
- package/package.json +8 -4
- package/dist/cjs/plugins/tempo-trace-query/TraceQLEditor.js +0 -46
- package/dist/plugins/tempo-trace-query/TraceQLEditor.d.ts +0 -4
- package/dist/plugins/tempo-trace-query/TraceQLEditor.d.ts.map +0 -1
- package/dist/plugins/tempo-trace-query/TraceQLEditor.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Stack, FormControl, InputLabel } from '@mui/material';\nimport { DatasourceSelect } from '@perses-dev/plugin-system';\nimport { DatasourceSelector } from '@perses-dev/core';\nimport { TempoDatasourceSelector, TEMPO_DATASOURCE_KIND } from '../../model/tempo-selectors';\nimport { TraceQLEditor } from '
|
|
1
|
+
{"version":3,"sources":["../../../src/plugins/tempo-trace-query/DashboardTempoTraceQueryEditor.tsx"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { Stack, FormControl, InputLabel } from '@mui/material';\nimport { DatasourceSelect, useDatasourceClient } from '@perses-dev/plugin-system';\nimport { DatasourceSelector } from '@perses-dev/core';\nimport { TempoDatasourceSelector, TEMPO_DATASOURCE_KIND } from '../../model/tempo-selectors';\nimport { TraceQLEditor } from '../../components';\nimport { TempoClient } from '../../model/tempo-client';\n\ninterface DashboardTempoTraceQueryEditorProps {\n selectedDatasource: TempoDatasourceSelector;\n handleDatasourceChange: (next: DatasourceSelector) => void;\n datasourceURL: string | undefined;\n query: string;\n handleQueryChange: (e: string) => void;\n handleQueryBlur: () => void;\n}\n\nexport function DashboardTempoTraceQueryEditor(props: DashboardTempoTraceQueryEditorProps) {\n const { selectedDatasource, handleDatasourceChange, query, handleQueryChange, handleQueryBlur } = props;\n const { data: client } = useDatasourceClient<TempoClient>(selectedDatasource);\n\n return (\n <Stack spacing={2}>\n <FormControl margin=\"dense\" fullWidth={false}>\n {/* TODO: How do we ensure unique ID values if there are multiple of these? Can we use React 18 useId and\n maintain 17 compatibility somehow with a polyfill/shim? */}\n <InputLabel id=\"tempo-datasource-label\">Tempo Datasource</InputLabel>\n <DatasourceSelect\n datasourcePluginKind={TEMPO_DATASOURCE_KIND}\n value={selectedDatasource}\n onChange={handleDatasourceChange}\n labelId=\"tempo-datasource-label\"\n label=\"Tempo Datasource\"\n />\n </FormControl>\n <TraceQLEditor completeConfig={{ client }} value={query} onChange={handleQueryChange} onBlur={handleQueryBlur} />\n </Stack>\n );\n}\n"],"names":["Stack","FormControl","InputLabel","DatasourceSelect","useDatasourceClient","TEMPO_DATASOURCE_KIND","TraceQLEditor","DashboardTempoTraceQueryEditor","props","selectedDatasource","handleDatasourceChange","query","handleQueryChange","handleQueryBlur","data","client","spacing","margin","fullWidth","id","datasourcePluginKind","value","onChange","labelId","label","completeConfig","onBlur"],"mappings":"AAAA,oCAAoC;AACpC,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;;AAEjC,SAASA,KAAK,EAAEC,WAAW,EAAEC,UAAU,QAAQ,gBAAgB;AAC/D,SAASC,gBAAgB,EAAEC,mBAAmB,QAAQ,4BAA4B;AAElF,SAAkCC,qBAAqB,QAAQ,8BAA8B;AAC7F,SAASC,aAAa,QAAQ,mBAAmB;AAYjD,OAAO,SAASC,+BAA+BC,KAA0C;IACvF,MAAM,EAAEC,kBAAkB,EAAEC,sBAAsB,EAAEC,KAAK,EAAEC,iBAAiB,EAAEC,eAAe,EAAE,GAAGL;IAClG,MAAM,EAAEM,MAAMC,MAAM,EAAE,GAAGX,oBAAiCK;IAE1D,qBACE,MAACT;QAAMgB,SAAS;;0BACd,MAACf;gBAAYgB,QAAO;gBAAQC,WAAW;;kCAGrC,KAAChB;wBAAWiB,IAAG;kCAAyB;;kCACxC,KAAChB;wBACCiB,sBAAsBf;wBACtBgB,OAAOZ;wBACPa,UAAUZ;wBACVa,SAAQ;wBACRC,OAAM;;;;0BAGV,KAAClB;gBAAcmB,gBAAgB;oBAAEV;gBAAO;gBAAGM,OAAOV;gBAAOW,UAAUV;gBAAmBc,QAAQb;;;;AAGpG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-trace-data.d.ts","sourceRoot":"","sources":["../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAEL,iBAAiB,EAMlB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAYpE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,iBAAiB;;;EAM5D;AAED,eAAO,MAAM,YAAY,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,cAAc,
|
|
1
|
+
{"version":3,"file":"get-trace-data.d.ts","sourceRoot":"","sources":["../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAEL,iBAAiB,EAMlB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAYpE,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,iBAAiB;;;EAM5D;AAED,eAAO,MAAM,YAAY,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,CAAC,cAAc,CAmD9E,CAAC"}
|
|
@@ -22,7 +22,6 @@ export function getUnixTimeRange(timeRange) {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
export const getTraceData = async (spec, context)=>{
|
|
25
|
-
var _client_options;
|
|
26
25
|
if (spec.query === undefined || spec.query === null || spec.query === '') {
|
|
27
26
|
// Do not make a request to the backend, instead return an empty TraceData
|
|
28
27
|
console.error('TempoTraceQuery is undefined, null, or an empty string.');
|
|
@@ -35,13 +34,6 @@ export const getTraceData = async (spec, context)=>{
|
|
|
35
34
|
};
|
|
36
35
|
var _spec_datasource;
|
|
37
36
|
const client = await context.datasourceStore.getDatasourceClient((_spec_datasource = spec.datasource) !== null && _spec_datasource !== void 0 ? _spec_datasource : defaultTempoDatasource);
|
|
38
|
-
const datasourceUrl = client === null || client === void 0 ? void 0 : (_client_options = client.options) === null || _client_options === void 0 ? void 0 : _client_options.datasourceUrl;
|
|
39
|
-
if (datasourceUrl === undefined || datasourceUrl === null || datasourceUrl === '') {
|
|
40
|
-
console.error('TempoDatasource is undefined, null, or an empty string.');
|
|
41
|
-
return {
|
|
42
|
-
searchResult: []
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
37
|
const getQuery = ()=>{
|
|
46
38
|
// if time range not defined -- only return the query from the spec
|
|
47
39
|
if (context.absoluteTimeRange === undefined) {
|
|
@@ -62,8 +54,8 @@ export const getTraceData = async (spec, context)=>{
|
|
|
62
54
|
* if the query is a valid traceId, fetch the trace by traceId
|
|
63
55
|
* otherwise, execute a TraceQL query
|
|
64
56
|
*/ if (isValidTraceId(spec.query)) {
|
|
65
|
-
const response = await client.
|
|
66
|
-
|
|
57
|
+
const response = await client.query({
|
|
58
|
+
traceId: spec.query
|
|
67
59
|
});
|
|
68
60
|
return {
|
|
69
61
|
trace: parseTraceResponse(response),
|
|
@@ -72,9 +64,7 @@ export const getTraceData = async (spec, context)=>{
|
|
|
72
64
|
}
|
|
73
65
|
};
|
|
74
66
|
} else {
|
|
75
|
-
const response = await client.
|
|
76
|
-
datasourceUrl
|
|
77
|
-
});
|
|
67
|
+
const response = await client.searchWithFallback(getQuery());
|
|
78
68
|
return {
|
|
79
69
|
searchResult: parseSearchResponse(response),
|
|
80
70
|
metadata: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { TraceQueryPlugin } from '@perses-dev/plugin-system';\nimport {\n TraceSearchResult,\n AbsoluteTimeRange,\n Trace,\n Span,\n isValidTraceId,\n TraceResource,\n SpanEvent,\n} from '@perses-dev/core';\nimport { getUnixTime } from 'date-fns';\nimport { sortedIndexBy } from 'lodash';\nimport { TempoTraceQuerySpec } from '../../model/trace-query-model';\nimport { TEMPO_DATASOURCE_KIND, TempoDatasourceSelector } from '../../model/tempo-selectors';\nimport { TempoClient } from '../../model/tempo-client';\nimport {\n SearchRequestParameters,\n SearchTraceIDResponse,\n SearchTraceQueryResponse,\n Resource as TempoResource,\n Span as TempoSpan,\n SpanEvent as TempoSpanEvent,\n} from '../../model/api-types';\n\nexport function getUnixTimeRange(timeRange: AbsoluteTimeRange) {\n const { start, end } = timeRange;\n return {\n start: Math.ceil(getUnixTime(start)),\n end: Math.ceil(getUnixTime(end)),\n };\n}\n\nexport const getTraceData: TraceQueryPlugin<TempoTraceQuerySpec>['getTraceData'] = async (spec, context) => {\n if (spec.query === undefined || spec.query === null || spec.query === '') {\n // Do not make a request to the backend, instead return an empty TraceData\n console.error('TempoTraceQuery is undefined, null, or an empty string.');\n return { searchResult: [] };\n }\n\n const defaultTempoDatasource: TempoDatasourceSelector = {\n kind: TEMPO_DATASOURCE_KIND,\n };\n\n const client: TempoClient = await context.datasourceStore.getDatasourceClient(\n spec.datasource ?? defaultTempoDatasource\n );\n\n const datasourceUrl = client?.options?.datasourceUrl;\n if (datasourceUrl === undefined || datasourceUrl === null || datasourceUrl === '') {\n console.error('TempoDatasource is undefined, null, or an empty string.');\n return { searchResult: [] };\n }\n\n const getQuery = (): SearchRequestParameters => {\n // if time range not defined -- only return the query from the spec\n if (context.absoluteTimeRange === undefined) {\n return { q: spec.query };\n }\n // handle time range selection from UI drop down (e.g. last 5 minutes, last 1 hour )\n const { start, end } = getUnixTimeRange(context?.absoluteTimeRange);\n return {\n q: spec.query,\n start,\n end,\n };\n };\n\n /**\n * determine type of query:\n * if the query is a valid traceId, fetch the trace by traceId\n * otherwise, execute a TraceQL query\n */\n if (isValidTraceId(spec.query)) {\n const response = await client.searchTraceID(spec.query, { datasourceUrl });\n return {\n trace: parseTraceResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n } else {\n const response = await client.searchTraceQueryFallback(getQuery(), { datasourceUrl });\n return {\n searchResult: parseSearchResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n }\n};\n\nfunction parseResource(resource: TempoResource): TraceResource {\n let serviceName = 'unknown';\n for (const attr of resource.attributes) {\n if (attr.key === 'service.name' && 'stringValue' in attr.value) {\n serviceName = attr.value.stringValue;\n break;\n }\n }\n\n return {\n serviceName,\n attributes: resource.attributes,\n };\n}\n\nfunction parseEvent(event: TempoSpanEvent): SpanEvent {\n return {\n timeUnixMs: parseInt(event.timeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n name: event.name,\n attributes: event.attributes || [],\n };\n}\n\n/**\n * parseSpan parses the Span API type to the internal representation\n * i.e. convert strings to numbers etc.\n */\nfunction parseSpan(span: TempoSpan) {\n return {\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n kind: span.kind,\n startTimeUnixMs: parseInt(span.startTimeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n endTimeUnixMs: parseInt(span.endTimeUnixNano) * 1e-6,\n attributes: span.attributes || [],\n events: (span.events || []).map(parseEvent),\n status: span.status,\n };\n}\n\n/**\n * parseTraceResponse builds a tree of spans from the Tempo API response\n * time complexity: O(2n)\n */\nfunction parseTraceResponse(response: SearchTraceIDResponse): Trace {\n // first pass: build lookup table <spanId, Span>\n const lookup = new Map<string, Span>();\n for (const batch of response.batches) {\n const resource = parseResource(batch.resource);\n\n for (const scopeSpan of batch.scopeSpans) {\n const scope = scopeSpan.scope;\n\n for (const tempoSpan of scopeSpan.spans) {\n const span: Span = {\n resource,\n scope,\n childSpans: [],\n ...parseSpan(tempoSpan),\n };\n lookup.set(tempoSpan.spanId, span);\n }\n }\n }\n\n // second pass: build tree based on parentSpanId property\n let rootSpan: Span | null = null;\n for (const [, span] of lookup) {\n if (!span.parentSpanId) {\n rootSpan = span;\n } else {\n const parent = lookup.get(span.parentSpanId);\n if (!parent) {\n console.error(`span ${span.spanId} has parent ${span.parentSpanId} which has not been received yet`);\n continue;\n }\n\n span.parentSpan = parent;\n const insertChildSpanAt = sortedIndexBy(parent.childSpans, span, (s) => s.startTimeUnixMs);\n parent.childSpans.splice(insertChildSpanAt, 0, span);\n }\n }\n\n if (!rootSpan) {\n throw new Error('root span not found');\n }\n\n return {\n rootSpan,\n };\n}\n\nfunction parseSearchResponse(response: SearchTraceQueryResponse): TraceSearchResult[] {\n return response.traces.map((trace) => ({\n startTimeUnixMs: parseInt(trace.startTimeUnixNano) * 1e-6, // convert to millisecond for eChart time format,\n durationMs: trace.durationMs ?? 0, // Tempo API doesn't return 0 values\n traceId: trace.traceID,\n rootServiceName: trace.rootServiceName,\n rootTraceName: trace.rootTraceName,\n serviceStats: trace.serviceStats || {},\n }));\n}\n"],"names":["isValidTraceId","getUnixTime","sortedIndexBy","TEMPO_DATASOURCE_KIND","getUnixTimeRange","timeRange","start","end","Math","ceil","getTraceData","spec","context","client","query","undefined","console","error","searchResult","defaultTempoDatasource","kind","datasourceStore","getDatasourceClient","datasource","datasourceUrl","options","getQuery","absoluteTimeRange","q","response","searchTraceID","trace","parseTraceResponse","metadata","executedQueryString","searchTraceQueryFallback","parseSearchResponse","parseResource","resource","serviceName","attr","attributes","key","value","stringValue","parseEvent","event","timeUnixMs","parseInt","timeUnixNano","name","parseSpan","span","traceId","spanId","parentSpanId","startTimeUnixMs","startTimeUnixNano","endTimeUnixMs","endTimeUnixNano","events","map","status","lookup","Map","batch","batches","scopeSpan","scopeSpans","scope","tempoSpan","spans","childSpans","set","rootSpan","parent","get","parentSpan","insertChildSpanAt","s","splice","Error","traces","durationMs","traceID","rootServiceName","rootTraceName","serviceStats"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/plugins/tempo-trace-query/get-trace-data.ts"],"sourcesContent":["// Copyright 2023 The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { TraceQueryPlugin } from '@perses-dev/plugin-system';\nimport {\n TraceSearchResult,\n AbsoluteTimeRange,\n Trace,\n Span,\n isValidTraceId,\n TraceResource,\n SpanEvent,\n} from '@perses-dev/core';\nimport { getUnixTime } from 'date-fns';\nimport { sortedIndexBy } from 'lodash';\nimport { TempoTraceQuerySpec } from '../../model/trace-query-model';\nimport { TEMPO_DATASOURCE_KIND, TempoDatasourceSelector } from '../../model/tempo-selectors';\nimport { TempoClient } from '../../model/tempo-client';\nimport {\n SearchRequestParameters,\n QueryResponse,\n SearchResponse,\n Resource as TempoResource,\n Span as TempoSpan,\n SpanEvent as TempoSpanEvent,\n} from '../../model/api-types';\n\nexport function getUnixTimeRange(timeRange: AbsoluteTimeRange) {\n const { start, end } = timeRange;\n return {\n start: Math.ceil(getUnixTime(start)),\n end: Math.ceil(getUnixTime(end)),\n };\n}\n\nexport const getTraceData: TraceQueryPlugin<TempoTraceQuerySpec>['getTraceData'] = async (spec, context) => {\n if (spec.query === undefined || spec.query === null || spec.query === '') {\n // Do not make a request to the backend, instead return an empty TraceData\n console.error('TempoTraceQuery is undefined, null, or an empty string.');\n return { searchResult: [] };\n }\n\n const defaultTempoDatasource: TempoDatasourceSelector = {\n kind: TEMPO_DATASOURCE_KIND,\n };\n\n const client: TempoClient = await context.datasourceStore.getDatasourceClient(\n spec.datasource ?? defaultTempoDatasource\n );\n\n const getQuery = (): SearchRequestParameters => {\n // if time range not defined -- only return the query from the spec\n if (context.absoluteTimeRange === undefined) {\n return { q: spec.query };\n }\n // handle time range selection from UI drop down (e.g. last 5 minutes, last 1 hour )\n const { start, end } = getUnixTimeRange(context?.absoluteTimeRange);\n return {\n q: spec.query,\n start,\n end,\n };\n };\n\n /**\n * determine type of query:\n * if the query is a valid traceId, fetch the trace by traceId\n * otherwise, execute a TraceQL query\n */\n if (isValidTraceId(spec.query)) {\n const response = await client.query({ traceId: spec.query });\n return {\n trace: parseTraceResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n } else {\n const response = await client.searchWithFallback(getQuery());\n return {\n searchResult: parseSearchResponse(response),\n metadata: {\n executedQueryString: spec.query,\n },\n };\n }\n};\n\nfunction parseResource(resource: TempoResource): TraceResource {\n let serviceName = 'unknown';\n for (const attr of resource.attributes) {\n if (attr.key === 'service.name' && 'stringValue' in attr.value) {\n serviceName = attr.value.stringValue;\n break;\n }\n }\n\n return {\n serviceName,\n attributes: resource.attributes,\n };\n}\n\nfunction parseEvent(event: TempoSpanEvent): SpanEvent {\n return {\n timeUnixMs: parseInt(event.timeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n name: event.name,\n attributes: event.attributes || [],\n };\n}\n\n/**\n * parseSpan parses the Span API type to the internal representation\n * i.e. convert strings to numbers etc.\n */\nfunction parseSpan(span: TempoSpan) {\n return {\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n kind: span.kind,\n startTimeUnixMs: parseInt(span.startTimeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n endTimeUnixMs: parseInt(span.endTimeUnixNano) * 1e-6,\n attributes: span.attributes || [],\n events: (span.events || []).map(parseEvent),\n status: span.status,\n };\n}\n\n/**\n * parseTraceResponse builds a tree of spans from the Tempo API response\n * time complexity: O(2n)\n */\nfunction parseTraceResponse(response: QueryResponse): Trace {\n // first pass: build lookup table <spanId, Span>\n const lookup = new Map<string, Span>();\n for (const batch of response.batches) {\n const resource = parseResource(batch.resource);\n\n for (const scopeSpan of batch.scopeSpans) {\n const scope = scopeSpan.scope;\n\n for (const tempoSpan of scopeSpan.spans) {\n const span: Span = {\n resource,\n scope,\n childSpans: [],\n ...parseSpan(tempoSpan),\n };\n lookup.set(tempoSpan.spanId, span);\n }\n }\n }\n\n // second pass: build tree based on parentSpanId property\n let rootSpan: Span | null = null;\n for (const [, span] of lookup) {\n if (!span.parentSpanId) {\n rootSpan = span;\n } else {\n const parent = lookup.get(span.parentSpanId);\n if (!parent) {\n console.error(`span ${span.spanId} has parent ${span.parentSpanId} which has not been received yet`);\n continue;\n }\n\n span.parentSpan = parent;\n const insertChildSpanAt = sortedIndexBy(parent.childSpans, span, (s) => s.startTimeUnixMs);\n parent.childSpans.splice(insertChildSpanAt, 0, span);\n }\n }\n\n if (!rootSpan) {\n throw new Error('root span not found');\n }\n\n return {\n rootSpan,\n };\n}\n\nfunction parseSearchResponse(response: SearchResponse): TraceSearchResult[] {\n return response.traces.map((trace) => ({\n startTimeUnixMs: parseInt(trace.startTimeUnixNano) * 1e-6, // convert to millisecond for eChart time format,\n durationMs: trace.durationMs ?? 0, // Tempo API doesn't return 0 values\n traceId: trace.traceID,\n rootServiceName: trace.rootServiceName,\n rootTraceName: trace.rootTraceName,\n serviceStats: trace.serviceStats || {},\n }));\n}\n"],"names":["isValidTraceId","getUnixTime","sortedIndexBy","TEMPO_DATASOURCE_KIND","getUnixTimeRange","timeRange","start","end","Math","ceil","getTraceData","spec","context","query","undefined","console","error","searchResult","defaultTempoDatasource","kind","client","datasourceStore","getDatasourceClient","datasource","getQuery","absoluteTimeRange","q","response","traceId","trace","parseTraceResponse","metadata","executedQueryString","searchWithFallback","parseSearchResponse","parseResource","resource","serviceName","attr","attributes","key","value","stringValue","parseEvent","event","timeUnixMs","parseInt","timeUnixNano","name","parseSpan","span","spanId","parentSpanId","startTimeUnixMs","startTimeUnixNano","endTimeUnixMs","endTimeUnixNano","events","map","status","lookup","Map","batch","batches","scopeSpan","scopeSpans","scope","tempoSpan","spans","childSpans","set","rootSpan","parent","get","parentSpan","insertChildSpanAt","s","splice","Error","traces","durationMs","traceID","rootServiceName","rootTraceName","serviceStats"],"mappings":"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"}
|
package/dist/test/mock-data.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { TraceData } from '@perses-dev/core';
|
|
2
|
-
import {
|
|
3
|
-
export declare const MOCK_TRACE_RESPONSE:
|
|
4
|
-
export declare const MOCK_TRACE_RESPONSE_SMALL:
|
|
5
|
-
export declare const MOCK_SEARCH_RESPONSE_VPARQUET3:
|
|
6
|
-
export declare const MOCK_SEARCH_RESPONSE_VPARQUET4:
|
|
2
|
+
import { QueryResponse, SearchResponse } from '../model/api-types';
|
|
3
|
+
export declare const MOCK_TRACE_RESPONSE: QueryResponse;
|
|
4
|
+
export declare const MOCK_TRACE_RESPONSE_SMALL: QueryResponse;
|
|
5
|
+
export declare const MOCK_SEARCH_RESPONSE_VPARQUET3: SearchResponse;
|
|
6
|
+
export declare const MOCK_SEARCH_RESPONSE_VPARQUET4: SearchResponse;
|
|
7
7
|
export declare const MOCK_TRACE_DATA_SEARCHRESULT: TraceData;
|
|
8
8
|
export declare const MOCK_TRACE_DATA_TRACE: TraceData;
|
|
9
9
|
//# sourceMappingURL=mock-data.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-data.d.ts","sourceRoot":"","sources":["../../src/test/mock-data.ts"],"names":[],"mappings":"AAaA,OAAO,EAAQ,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mock-data.d.ts","sourceRoot":"","sources":["../../src/test/mock-data.ts"],"names":[],"mappings":"AAaA,OAAO,EAAQ,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEnE,eAAO,MAAM,mBAAmB,EAAE,aA2gEjC,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,aA+IvC,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,cAkD5C,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,cAmE5C,CAAC;AAEF,eAAO,MAAM,4BAA4B,EAAE,SA4B1C,CAAC;AA6JF,eAAO,MAAM,qBAAqB,EAAE,SAKnC,CAAC"}
|