-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TraceView - Optimization of queries #2349
Conversation
Signed-off-by: Adam Tackett <[email protected]>
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2349 +/- ##
==========================================
- Coverage 56.53% 56.13% -0.40%
==========================================
Files 393 395 +2
Lines 15574 15807 +233
Branches 4284 4390 +106
==========================================
+ Hits 8804 8873 +69
- Misses 6705 6863 +158
- Partials 65 71 +6
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
public/components/trace_analytics/components/traces/trace_view_helpers.tsx
Outdated
Show resolved
Hide resolved
export function normalizePayload(parsed: any): any[] { | ||
if (Array.isArray(parsed)) { | ||
return parsed; | ||
} | ||
if (parsed.hits && Array.isArray(parsed.hits.hits)) { | ||
return parsed.hits.hits; | ||
} | ||
return []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this function to normalizePayload
? Since we are using just 1 request for all trace related details shouldn't we normalize this at source where we receive the request?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to traces_request_handler
and used in handlePayloadRequest
const normalizedData = normalizePayload(response);
setPayloadData(JSON.stringify(normalizedData, null, 2));
public/components/trace_analytics/components/traces/trace_view_helpers.tsx
Outdated
Show resolved
Hide resolved
public/components/trace_analytics/components/traces/trace_view_helpers.tsx
Outdated
Show resolved
Hide resolved
public/components/trace_analytics/components/traces/trace_view_helpers.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general, since we are moving lot of computation from OpenSearch to browser we need to manually do some sanity checks, to see if the calculation before and after is the same. May be use our sanity data and check the values in 2.18 (playground) and now with this PR in your local.
public/components/trace_analytics/components/traces/__tests__/trace_view_helpers.test.tsx
Outdated
Show resolved
Hide resolved
public/components/trace_analytics/components/traces/span_detail_table.tsx
Outdated
Show resolved
Hide resolved
const hitsArray = | ||
parsed.hits && Array.isArray(parsed.hits.hits) | ||
? parsed.hits.hits | ||
: Array.isArray(parsed) | ||
? parsed | ||
: []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason that this is different from
dashboards-observability/public/components/trace_analytics/components/traces/span_detail_panel.tsx
Lines 144 to 149 in 0fe0710
const parsed = JSON.parse(payloadData); | |
let hits: any[] = []; | |
if (parsed.hits && Array.isArray(parsed.hits.hits)) { | |
hits = parsed.hits.hits; | |
} else if (Array.isArray(parsed)) { | |
hits = parsed; |
if (!props.payloadData) { | ||
console.warn('No payloadData provided to SpanDetailPanel'); | ||
return; | ||
} | ||
|
||
try { | ||
const parsed = JSON.parse(props.payloadData); | ||
let hits: any[] = []; | ||
if (parsed.hits && Array.isArray(parsed.hits.hits)) { | ||
hits = parsed.hits.hits; | ||
} else if (Array.isArray(parsed)) { | ||
hits = parsed; | ||
} else { | ||
console.warn('Unexpected payload format:', parsed); | ||
return; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually, we'd want to keep useEffect lean and put the logic inside a function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved logic to helper above it
const parseAndFilterHits = (payloadData: string, mode: string, spanFilters: any[]) => {
try {
const parsed = JSON.parse(payloadData);
let hits: any[] = [];
if (parsed.hits && Array.isArray(parsed.hits.hits)) {
hits = parsed.hits.hits;
} else if (Array.isArray(parsed)) {
hits = parsed;
} else {
console.warn('Unexpected payload format:', parsed);
return [];
}
hits = hits.map((hit) => {
if (mode === 'jaeger') {
if (!hit.sort || !hit.sort[0]) {
return {
...hit,
sort: [Number(hit._source.startTime) * 1000], // Jaeger: startTime is in microseconds
};
}
} else {
if (!hit.sort || !hit.sort[0]) {
return {
...hit,
sort: [parseIsoToNano(hit._source.startTime)],
};
}
}
return hit;
});
hits.sort((a, b) => b.sort[0] - a.sort[0]);
if (spanFilters.length > 0) {
hits = hits.filter((hit) => {
return spanFilters.every(({ field, value }) => {
let fieldVal;
if (mode === 'jaeger' && field.startsWith('process.')) {
fieldVal = hit._source?.process?.[field.split('.')[1]];
} else {
fieldVal = hit._source?.[field];
}
return fieldVal === value;
});
});
}
hits = hits.filter((hit) => {
if (mode === 'jaeger') {
return Boolean(hit._source?.process?.serviceName);
} else {
return Boolean(hit._source?.serviceName);
}
});
return hits;
} catch (error) {
console.error('Error processing payloadData in parseAndFilterHits:', error);
return [];
}
};
useEffect(() => {
if (!props.payloadData) {
console.warn('No payloadData provided to SpanDetailPanel');
return;
}
const hits = parseAndFilterHits(props.payloadData, mode, spanFilters);
if (hits.length === 0) {
return;
}
hitsToSpanDetailData(hits, props.colorMap, mode)
.then((transformedData) => {
setData(transformedData);
})
.catch((error) => {
console.error('Error in hitsToSpanDetailData:', error);
})
.finally(() => {
if (props.setGanttChartLoading) {
props.setGanttChartLoading(false);
}
});
}, [props.payloadData, props.colorMap, mode, spanFilters]);
|
||
hits = hits.map((hit) => { | ||
if (mode === 'jaeger') { | ||
if (!hit.sort || !hit.sort[0]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we doing this check? hits won't have sort field by default?
public/components/trace_analytics/components/traces/span_detail_panel.tsx
Outdated
Show resolved
Hide resolved
Signed-off-by: Adam Tackett <[email protected]>
const firstSpan = hits[0]._source; | ||
if (!firstSpan) return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a small check here, that first span doesn't have a parentTraceId
? To account for cases we the OTel data might miss parent traces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
let computedLatency: number | null = null;
const tgDuration = get(firstSpan, 'traceGroupFields.durationInNanos');
if (firstSpan.traceGroupFields && firstSpan.traceGroupFields.durationInNanos != null) {
computedLatency = Number(firstSpan.traceGroupFields.durationInNanos) / NANOS_TO_MS;
} else if (tgDuration != null) {
computedLatency = Number(tgDuration) / NANOS_TO_MS;
} else {
const startTimes = parsed.map((span: any) => moment(span._source.startTime));
const endTimes = parsed.map((span: any) => moment(span._source.endTime));
const minStartTime = moment.min(startTimes);
const maxEndTime = moment.max(endTimes);
if (minStartTime && maxEndTime) {
computedLatency = maxEndTime.diff(minStartTime, 'milliseconds', true);
fallbackValueUsed = true;
}
}
So if the first span is not present we get a more accurate latency instead of 0 or a smaller number
Latency is now much more accurate when handling missing data
Signed-off-by: Adam Tackett <[email protected]>
…verview Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
public/components/trace_analytics/components/traces/span_detail_panel.tsx
Outdated
Show resolved
Hide resolved
[field]: value, | ||
}, | ||
} else { | ||
if (!hit.sort || !hit.sort[0]) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. since this if is the same for both modes, it might be better to check traceMode
inside this if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
hits = hits.map((hit) => {
if (!hit.sort || !hit.sort[0]) {
const time = traceMode === 'jaeger'
? Number(hit._source.startTime) * MILI_TO_SEC
: parseIsoToNano(hit._source.startTime);
return {
...hit,
sort: [time],
};
}
return hit;
});
return hit; | ||
}); | ||
|
||
hits.sort((a, b) => b.sort[0] - a.sort[0]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we use hit.sort
anywhere else? if not then probably just do hits.sort((a, b) => b._source.startTime - a._source.startTime);
here and remove the inserting sort logic above
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the inserting sort logic is needed for handling jaeger vrs data prepper. Using just the hits.sort you show fails to render the gantt visualization.
let fieldVal; | ||
if (traceMode === 'jaeger' && field.startsWith('process.')) { | ||
fieldVal = hit._source?.process?.[field.split('.')[1]]; | ||
} else { | ||
fieldVal = hit._source?.[field]; | ||
} | ||
return fieldVal === value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lodash can handle the nested and flattened fields when reading value
let fieldVal; | |
if (traceMode === 'jaeger' && field.startsWith('process.')) { | |
fieldVal = hit._source?.process?.[field.split('.')[1]]; | |
} else { | |
fieldVal = hit._source?.[field]; | |
} | |
return fieldVal === value; | |
return _.get(hit._source, field) === value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
if (payloadSpanFilters.length > 0) {
hits = hits.filter((hit) => {
return payloadSpanFilters.every(({ field, value }) => {
return _.get(hit._source, field) === value;
});
});
}
const hitsArray = | ||
parsed.hits && Array.isArray(parsed.hits.hits) | ||
? parsed.hits.hits | ||
: Array.isArray(parsed) | ||
? parsed | ||
: []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a reason that this is different from
dashboards-observability/public/components/trace_analytics/components/traces/span_detail_panel.tsx
Lines 144 to 149 in 0fe0710
const parsed = JSON.parse(payloadData); | |
let hits: any[] = []; | |
if (parsed.hits && Array.isArray(parsed.hits.hits)) { | |
hits = parsed.hits.hits; | |
} else if (Array.isArray(parsed)) { | |
hits = parsed; |
public/components/trace_analytics/components/traces/span_detail_table.tsx
Outdated
Show resolved
Hide resolved
if (props.filters.length > 0) { | ||
spans = spans.filter((span: any) => { | ||
return props.filters.every( | ||
({ field, value }: { field: string; value: any }) => span[field] === value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will there be negate filters like field a is not b
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rootSpans.push(spanMap[span[spanIdKey]]); | ||
alreadyAddedRootSpans.add(span[spanIdKey]); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this might need some unit tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added cypress test for jaeger tree view functionality
it('Checks tree view for specific traceId in Jaeger mode', () => {
cy.contains('15b0b4004a651c4c').click();
cy.get('[data-test-subj="globalLoadingIndicator"]').should('not.exist');
cy.get('.euiButtonGroup').contains('Tree view').click();
cy.get("[data-test-subj='treeExpandAll']").should('exist');
cy.get("[data-test-subj='treeCollapseAll']").should('exist');
// Waiting time for render to complete
cy.get("[data-test-subj='treeExpandAll']").click();
cy.get("[data-test-subj='treeCollapseAll']").click();
cy.get("[data-test-subj='treeViewExpandArrow']").should('have.length', 1);
cy.get("[data-test-subj='treeExpandAll']").click();
cy.get("[data-test-subj='treeViewExpandArrow']").should('have.length', 6);
});
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
try { | ||
const parsedPayload = JSON.parse(payloadData); | ||
const overview = getOverviewFields(parsedPayload, mode); | ||
if (overview) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Do we have a reset mechanism for these setters? If we previously loaded data with an overview, but a new payload arrives without an overview for some reason, it seems like the overview wouldn't be updated here, potentially leaving it with stale data. Should we handle this case explicitly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That one specifically is for application analytics and the useEffect triggers on payload change. As long as it is a valid payload the overview will get the new information from it. If the payload is successful from handlePayloadRequest causing new data the overview will always be generated from that information.
@@ -0,0 +1,22 @@ | |||
/* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit. Should we consider moving this common folder one level up? It seems like each logical component should have its own common folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think having it on the same level as our helper_functions makes sense as this would be for constants shared between trace_analytics including both traces and services as we continue to refactor.
export const parseHits = (payloadData: string) => { | ||
try { | ||
const parsed = JSON.parse(payloadData); | ||
let hits: any[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
interface Span {
traceId: string;
spanId: string;
traceState: string;
parentSpanId: string;
name: string;
kind: string;
startTime: string;
endTime: string;
durationInNanos: number;
serviceName: string;
events: any[];
links: any[];
droppedAttributesCount: number;
droppedEventsCount: number;
droppedLinksCount: number;
traceGroup: string;
traceGroupFields: {
endTime: string;
durationInNanos: number;
statusCode: number;
};
status: {
code: number;
};
instrumentationLibrary: {
name: string;
version: string;
};
}
interface ParsedHit {
_index: string;
_id: string;
_score: number;
_source: Span;
sort?: any[];
}
export const parseHits = (payloadData: string): ParsedHit[] => {
try {
const parsed = JSON.parse(payloadData);
let hits: ParsedHit[] = [];
if (parsed.hits && Array.isArray(parsed.hits.hits)) {
hits = parsed.hits.hits;
} else if (Array.isArray(parsed)) {
hits = parsed;
}
return hits;
} catch (error) {
console.error('Error processing payloadData:', error);
return [];
}
};
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; | ||
import useObservable from 'react-use/lib/useObservable'; | ||
import _ from 'lodash'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we are avoiding using lodash?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed, replaced with
if (payloadSpanFilters.length > 0) {
hits = hits.filter((hit) => {
return payloadSpanFilters.every(({ field, value }) => {
const fieldValue = field.split('.').reduce((acc, part) => acc?.[part], hit._source);
return fieldValue === value;
});
});
}
public/components/trace_analytics/components/traces/span_detail_table.tsx
Outdated
Show resolved
Hide resolved
} | ||
if (ref.refType === 'FOLLOWS_FROM') { | ||
if (!alreadyAddedRootSpans.has(span[spanIdKey])) { | ||
rootSpans.push(spanMap[span[spanIdKey]]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should be able to refactor these a little bit for example like extracting these duplicated root span handing to a function:
rootSpans.push(spanMap[span[spanIdKey]]);
alreadyAddedRootSpans.add(span[spanIdKey]);
and also for these nested if conditions, I don't see you are having any else if or else then why not to merge them like
if (ref.refType === 'FOLLOWS_FROM') {
if (!alreadyAddedRootSpans.has(span[spanIdKey])) {
...
to
if (ref.refType === 'FOLLOWS_FROM' && !alreadyAddedRootSpans.has(span[spanIdKey])) {
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
interface SpanReference {
refType: 'CHILD_OF' | 'FOLLOWS_FROM';
spanID: string;
}
const addRootSpan = (
spanId: string,
spanMap: SpanMap,
rootSpans: Span[],
alreadyAddedRootSpans: Set<string>
) => {
if (!alreadyAddedRootSpans.has(spanId)) {
rootSpans.push(spanMap[spanId]);
alreadyAddedRootSpans.add(spanId);
}
};
const buildHierarchy = (spans: Span[]): Span[] => {
const spanMap: SpanMap = {};
spans.forEach((span) => {
const spanIdKey = props.mode === 'jaeger' ? 'spanID' : 'spanId';
spanMap[span[spanIdKey]] = { ...span, children: [] };
});
const rootSpans: Span[] = [];
const alreadyAddedRootSpans: Set<string> = new Set(); // Track added root spans
spans.forEach((span) => {
const spanIdKey = props.mode === 'jaeger' ? 'spanID' : 'spanId';
const references: SpanReference[] = span.references || [];
if (props.mode === 'jaeger') {
references.forEach((ref: SpanReference) => {
if (ref.refType === 'CHILD_OF') {
const parentSpan = spanMap[ref.spanID];
if (parentSpan) {
parentSpan.children.push(spanMap[span[spanIdKey]]);
}
}
if (ref.refType === 'FOLLOWS_FROM' && !alreadyAddedRootSpans.has(span[spanIdKey])) {
addRootSpan(span[spanIdKey], spanMap, rootSpans, alreadyAddedRootSpans);
}
});
if (references.length === 0 || references.every((ref) => ref.refType === 'FOLLOWS_FROM')) {
addRootSpan(span[spanIdKey], spanMap, rootSpans, alreadyAddedRootSpans);
}
} else {
// Data Prepper handling
if (span.parentSpanId && spanMap[span.parentSpanId]) {
spanMap[span.parentSpanId].children.push(spanMap[span[spanIdKey]]);
} else {
addRootSpan(span[spanIdKey], spanMap, rootSpans, alreadyAddedRootSpans);
}
}
});
return rootSpans;
};
size="m" | ||
type="alert" | ||
color="warning" | ||
content="Latency may not be accurate due to missing or unexpected duration data." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i18n?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
<EuiIconTip
aria-label={i18n.translate('tracesOverview.iconTip.ariaLabel', {
defaultMessage: 'Warning',
})}
size="m"
type="alert"
color="warning"
content={i18n.translate('tracesOverview.iconTip.content', {
defaultMessage: 'Latency may not be accurate due to missing or unexpected duration data.',
})}
/>
@@ -472,6 +324,16 @@ const hitsToSpanDetailData = async (hits: any, colorMap: any, mode: TraceAnalyti | |||
return data; | |||
}; | |||
|
|||
export function normalizePayload(parsed: any): any[] { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
interface Hit {
_index: string;
_id: string;
_score: number;
_source: any;
sort?: any[];
}
interface ParsedResponse {
hits?: {
hits: Hit[];
};
[key: string]: any;
}
export function normalizePayload(parsed: ParsedResponse): Hit[] {
if (Array.isArray(parsed)) {
return parsed;
}
if (parsed.hits && Array.isArray(parsed.hits.hits)) {
return parsed.hits.hits;
}
return [];
}
@@ -370,7 +222,7 @@ export const handleSpansFlyoutRequest = ( | |||
}); | |||
}; | |||
|
|||
const hitsToSpanDetailData = async (hits: any, colorMap: any, mode: TraceAnalyticsMode) => { | |||
export const hitsToSpanDetailData = async (hits: any, colorMap: any, mode: TraceAnalyticsMode) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
type?
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import { get } from 'lodash'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid using lodash?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed and refactored to work without it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have a replacement for lodash? some of them like get
are useful and not trivial in plain js
https://github.com/you-dont-need/You-Dont-Need-Lodash-Underscore?tab=readme-ov-file#_get
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
export function normalizePayload(parsed: ParsedResponse): Hit[] { | ||
if (Array.isArray(parsed)) { | ||
return parsed; | ||
} | ||
if (parsed.hits && Array.isArray(parsed.hits.hits)) { | ||
return parsed.hits.hits; | ||
} | ||
return []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we still need this? If we know one check is for Jaeger and other is data prepper can we just use mode based if conditions instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated too
export function normalizePayload(parsed: ParsedResponse): Hit[] {
if (parsed.hits && Array.isArray(parsed.hits.hits)) {
return parsed.hits.hits;
}
return [];
}
Jaeger and data prepper should be under parsed.hits
interface Span { | ||
traceId: string; | ||
spanId: string; | ||
traceState: string; | ||
parentSpanId: string; | ||
name: string; | ||
kind: string; | ||
startTime: string; | ||
endTime: string; | ||
durationInNanos: number; | ||
serviceName: string; | ||
events: any[]; | ||
links: any[]; | ||
droppedAttributesCount: number; | ||
droppedEventsCount: number; | ||
droppedLinksCount: number; | ||
traceGroup: string; | ||
traceGroupFields: { | ||
endTime: string; | ||
durationInNanos: number; | ||
statusCode: number; | ||
}; | ||
status: { | ||
code: number; | ||
}; | ||
instrumentationLibrary: { | ||
name: string; | ||
version: string; | ||
}; | ||
} | ||
|
||
interface ParsedHit { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we please move these to common constants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved to constants
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
Signed-off-by: Adam Tackett <[email protected]>
* optimize trace veiw removing queries Signed-off-by: Adam Tackett <[email protected]> * fix date format Signed-off-by: Adam Tackett <[email protected]> * update app cypress for rounding Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * fix jaeger tree span and overview Signed-off-by: Adam Tackett <[email protected]> * match old behavior for jaeger, if an error is present display it in overview Signed-off-by: Adam Tackett <[email protected]> * update test to reflect error in jaeger trace Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * add cypress test for jaeger tree view Signed-off-by: Adam Tackett <[email protected]> * add fallback value for latency Signed-off-by: Adam Tackett <[email protected]> * fix sorting on span table Signed-off-by: Adam Tackett <[email protected]> * add back total use effect Signed-off-by: Adam Tackett <[email protected]> * status code of 2 indicates error Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * add sorting support to jaeger span table Signed-off-by: Adam Tackett <[email protected]> * address comments, refactor sorting Signed-off-by: Adam Tackett <[email protected]> * fix flaky cypress test Signed-off-by: Adam Tackett <[email protected]> * combine adding sort, and sorting action Signed-off-by: Adam Tackett <[email protected]> * fix jaeger sorting for errors, fix gantt chart error override from text Signed-off-by: Adam Tackett <[email protected]> --------- Signed-off-by: Adam Tackett <[email protected]> Co-authored-by: Adam Tackett <[email protected]> (cherry picked from commit 36311f5) Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* TraceView - Optimization of queries (#2349) * optimize trace veiw removing queries Signed-off-by: Adam Tackett <[email protected]> * fix date format Signed-off-by: Adam Tackett <[email protected]> * update app cypress for rounding Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * fix jaeger tree span and overview Signed-off-by: Adam Tackett <[email protected]> * match old behavior for jaeger, if an error is present display it in overview Signed-off-by: Adam Tackett <[email protected]> * update test to reflect error in jaeger trace Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * add cypress test for jaeger tree view Signed-off-by: Adam Tackett <[email protected]> * add fallback value for latency Signed-off-by: Adam Tackett <[email protected]> * fix sorting on span table Signed-off-by: Adam Tackett <[email protected]> * add back total use effect Signed-off-by: Adam Tackett <[email protected]> * status code of 2 indicates error Signed-off-by: Adam Tackett <[email protected]> * address comments Signed-off-by: Adam Tackett <[email protected]> * add sorting support to jaeger span table Signed-off-by: Adam Tackett <[email protected]> * address comments, refactor sorting Signed-off-by: Adam Tackett <[email protected]> * fix flaky cypress test Signed-off-by: Adam Tackett <[email protected]> * combine adding sort, and sorting action Signed-off-by: Adam Tackett <[email protected]> * fix jaeger sorting for errors, fix gantt chart error override from text Signed-off-by: Adam Tackett <[email protected]> --------- Signed-off-by: Adam Tackett <[email protected]> Co-authored-by: Adam Tackett <[email protected]> (cherry picked from commit 36311f5) Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> * update snapshots Signed-off-by: Adam Tackett <[email protected]> --------- Signed-off-by: Adam Tackett <[email protected]> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Adam Tackett <[email protected]>
Description
Fixed a bug where Jaeger overview was not being populated with information through edge case handiling in the helper function getOverviewFields()
Fixed Jaeger Tree Span table not working
Add sorting to Jaeger Span Table.
Fix gantt chart displaying errors. The time text we added to the right was overriding the error field. We now check if it has an error and display that as priority over the time.
Queries Before 8 request + 1 per table change
QueriesBefore.mov
Queries after 5 request + 0 per table change
QueriesAfter.mov
Jaeger Before:

Jaeger After:

Gantt chart error display fix:
Issues Resolved
#2334 - Trace View section
Check List
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.