Skip to content
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

[Backport 2.x] TraceView - Optimization of queries #2352

Merged
merged 2 commits into from
Feb 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
cy.get('[data-test-subj="searchAutocompleteTextArea"]').click();
cy.focused().type(' source = ');
cy.focused().type('{enter}');
cy.get('[data-test-subj="createAndSetButton"]').click({ force: true });

Check warning on line 224 in .cypress/integration/app_analytics_test/app_analytics.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
cy.get('.euiTableRow').should('have.length.lessThan', 1);
cy.get('[data-test-subj="applicationTitle"]').should('contain', nameThree);
cy.get('.euiBreadcrumb[href="#/"]').click();
Expand Down Expand Up @@ -308,8 +308,8 @@
cy.get('[data-test-subj="Number of connected servicesDescriptionList"]').should('contain', '3');
cy.get('[data-text="Errors"]').eq(1).click(); // Selecting errors tab within flyout
cy.get('.ytitle').contains('Error rate').should('exist');
cy.get('[data-test-subj="dataGridRowCell"]').eq(0).click({ force: true }); // absolutely doesn't click no matter what unless theres a double click

Check warning on line 311 in .cypress/integration/app_analytics_test/app_analytics.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
cy.get('button[data-test-subj="spanId-link"]').eq(0).click({ force: true });

Check warning on line 312 in .cypress/integration/app_analytics_test/app_analytics.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
cy.get('[data-test-subj="spanDetailFlyout"]').contains('Span detail').should('be.visible');
cy.get('[data-test-subj="ServiceDescriptionList"]').should('contain', 'authentication');
cy.get('[data-test-subj="euiFlyoutCloseButton"]').click();
Expand All @@ -322,7 +322,7 @@
cy.get('[title="03f9c770db5ee2f1caac0afc36db49ba"]').click();
cy.get('[data-test-subj="traceDetailFlyoutTitle"]').should('be.visible');
cy.get('[data-test-subj="traceDetailFlyout"]').within(($flyout) => {
cy.get('[data-test-subj="LatencyDescriptionList"]').should('contain', '224.99');
cy.get('[data-test-subj="LatencyDescriptionList"]').should('contain', '225.00');
});
cy.get('[data-test-subj="euiFlyoutCloseButton"]').click();
cy.get('[data-test-subj="traceDetailFlyout"]').should('not.exist');
Expand Down Expand Up @@ -396,7 +396,7 @@
cy.get('.euiTab[id="availability-panel"]').click();

cy.get('[data-test-subj="comboBoxInput"]').click();
cy.get('[data-test-subj="comboBoxOptionsList "] button span')

Check warning on line 399 in .cypress/integration/app_analytics_test/app_analytics.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
.contains('Time series')
.click({ force: true });
cy.focused().type('{enter}');
Expand Down Expand Up @@ -440,7 +440,7 @@
cy.get('[data-test-subj="main-content-visTab"]').click();
cy.get('.euiTab[id="availability-panel"]').click();
cy.get('[data-test-subj="comboBoxInput"]').click();
cy.get('[data-test-subj="comboBoxOptionsList "] button span')

Check warning on line 443 in .cypress/integration/app_analytics_test/app_analytics.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
.contains('Time series')
.click({ force: true });
cy.get('[data-test-subj="addAvailabilityButton"]').click();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,17 @@

it('Renders data grid, flyout and filters', () => {
cy.get('.panel-title-count').contains('(11)').should('exist');
cy.get('.euiButton__text[title="Span list"]').click({ force: true });

Check warning on line 100 in .cypress/integration/trace_analytics_test/trace_analytics_traces.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
cy.contains('2 columns hidden').should('exist');

cy.get('.euiLink').contains(SPAN_ID).trigger('mouseover', { force: true });

Check warning on line 103 in .cypress/integration/trace_analytics_test/trace_analytics_traces.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
cy.get('button[data-datagrid-interactable="true"]').eq(0).click({ force: true });

Check warning on line 104 in .cypress/integration/trace_analytics_test/trace_analytics_traces.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls
cy.get('button[data-datagrid-interactable="true"]').eq(0).click({ force: true }); // first click doesn't go through eui data grid

Check warning on line 105 in .cypress/integration/trace_analytics_test/trace_analytics_traces.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls

cy.contains('Span detail').should('exist');
cy.contains('Span attributes').should('exist');
cy.get('.euiTextColor').contains('Span ID').trigger('mouseover');
cy.get('.euiButtonIcon[aria-label="span-flyout-filter-icon"').click({ force: true });

Check warning on line 110 in .cypress/integration/trace_analytics_test/trace_analytics_traces.spec.js

View workflow job for this annotation

GitHub Actions / Lint

Do not use force on click and type calls

cy.get('.euiBadge__text').contains('spanId: ').should('exist');
cy.contains('Spans (1)').should('exist');
Expand Down Expand Up @@ -282,4 +282,21 @@
cy.contains('Time spent by service').should('exist');
cy.get("[data-test-subj='span-gantt-chart-panel']").should('exist');
});

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.greaterThan', 1);
});
});

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import { HttpStart } from '../../../../../../../src/core/public';
import { TraceAnalyticsMode } from '../../../../../common/types/trace_analytics';
import { ServiceBreakdownPanel } from '../../../trace_analytics/components/traces/service_breakdown_panel';
import { SpanDetailPanel } from '../../../trace_analytics/components/traces/span_detail_panel';
import {
handlePayloadRequest,
handleServicesPieChartRequest,
handleTraceViewRequest,
} from '../../../trace_analytics/requests/traces_request_handler';
import { handlePayloadRequest } from '../../../trace_analytics/requests/traces_request_handler';
import { getListItem } from '../../helpers/utils';
import {
getOverviewFields,
getServiceBreakdownData,
} from '../../../trace_analytics/components/traces/trace_view_helpers';

interface TraceDetailRenderProps {
traceId: string;
Expand Down Expand Up @@ -78,6 +78,7 @@ export const TraceDetailRender = ({
mode={mode}
dataSourceMDSId={dataSourceMDSId}
isApplicationFlyout={true}
payloadData={payloadData}
/>
<EuiSpacer size="xs" />
<EuiHorizontalRule margin="s" />
Expand All @@ -95,10 +96,29 @@ export const TraceDetailRender = ({
}, [traceId, fields, serviceBreakdownData, colorMap, payloadData]);

useEffect(() => {
handleTraceViewRequest(traceId, http, fields, setFields, mode);
handleServicesPieChartRequest(traceId, http, setServiceBreakdownData, setColorMap, mode);
handlePayloadRequest(traceId, http, payloadData, setPayloadData, mode);
}, [traceId]);

useEffect(() => {
if (!payloadData) return;

try {
const parsedPayload = JSON.parse(payloadData);
const overview = getOverviewFields(parsedPayload, mode);
if (overview) {
setFields(overview);
}

const {
serviceBreakdownData: queryServiceBreakdownData,
colorMap: queryColorMap,
} = getServiceBreakdownData(parsedPayload, mode);
setServiceBreakdownData(queryServiceBreakdownData);
setColorMap(queryColorMap);
} catch (error) {
console.error('Error processing payloadData:', error);
}
}, [payloadData, mode]);

return renderContent;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

// Conversion factor for nanoseconds to milliseconds
export const NANOS_TO_MS = 1e6;

export const MILI_TO_SEC = 1000;

export const pieChartColors = [
'#7492e7',
'#c33d69',
'#2ea597',
'#8456ce',
'#e07941',
'#3759ce',
'#ce567c',
'#9469d6',
'#4066df',
'#da7596',
];

export 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;
};
}

export interface ParsedHit {
_index: string;
_id: string;
_score: number;
_source: Span;
sort?: any[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { FieldCapResponse } from '../../../common/types';
import { serviceMapColorPalette } from './color_palette';
import { FilterType } from './filters/filters';
import { ServiceObject } from './plots/service_map';
import { NANOS_TO_MS, ParsedHit } from './constants';

const missingJaegerTracesConfigurationMessage = `The indices required for trace analytics (${JAEGER_INDEX_NAME} and ${JAEGER_SERVICE_INDEX_NAME}) do not exist or you do not have permission to access them.`;

Expand Down Expand Up @@ -615,3 +616,39 @@ export const generateServiceUrl = (

return url;
};

/*
* Parse an ISO timestamp with up to nanosecond precision.
* For example, "2025-01-28T03:12:37.293990144Z" will be converted
* to a number representing the total nanoseconds since the Unix epoch.
*/
export function parseIsoToNano(iso: string): number {
const match = iso.match(/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d+))?Z$/);
if (!match) {
throw new Error(`Invalid ISO timestamp: ${iso}`);
}
// Parse the base part using Date.parse (which gives ms)
const baseMs = new Date(match[1] + 'Z').getTime();
// Get the fractional part (if any), pad to 9 digits for nanosecond precision
let fraction = match[2] || '0';
fraction = fraction.padEnd(9, '0'); // ensure it has 9 digits
return baseMs * NANOS_TO_MS + Number(fraction);
}

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 [];
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ exports[`Service breakdown panel component renders service breakdown panel 1`] =
data={
Array [
Object {
"hoverinfo": "label+percent",
"hovertemplate": "%{label}<br>%{value:.2f}%<extra></extra>",
"labels": Array [
"inventory",
Expand Down Expand Up @@ -177,6 +178,7 @@ exports[`Service breakdown panel component renders service breakdown panel 1`] =
data={
Array [
Object {
"hoverinfo": "label+percent",
"hovertemplate": "%{label}<br>%{value:.2f}%<extra></extra>",
"labels": Array [
"inventory",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
<EuiFlexItem>
<PanelTitle
title="Spans"
totalItems={0.5}
totalItems={0}
/>
</EuiFlexItem>
<EuiFlexItem
Expand All @@ -42,7 +42,6 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
>
<EuiButtonGroup
idSelected="timeline"
isDisabled={false}
legend="Select view of spans"
onChange={[Function]}
options={
Expand Down Expand Up @@ -74,26 +73,7 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
grow={false}
>
<Plt
data={
Array [
Object {
"hoverinfo": "none",
"marker": Object {
"color": "#fff",
},
"orientation": "h",
"showlegend": false,
"type": "bar",
"width": 0.4,
"x": Array [
10,
],
"y": Array [
"service1",
],
},
]
}
data={Array []}
layout={
Object {
"dragmode": "select",
Expand All @@ -116,7 +96,7 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
},
"type": "rect",
"x0": 0,
"x1": 22,
"x1": 0,
"xref": "x",
"y0": 0,
"y1": 1,
Expand All @@ -128,7 +108,7 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
"color": "#91989c",
"range": Array [
0,
22,
0,
],
"showline": true,
"side": "top",
Expand All @@ -153,31 +133,10 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
}
>
<Plt
data={
Array [
Object {
"hoverinfo": "none",
"marker": Object {
"color": "#fff",
},
"orientation": "h",
"showlegend": false,
"text": "10.00 ms",
"textposition": "outside",
"type": "bar",
"width": 0.4,
"x": Array [
10,
],
"y": Array [
"service1",
],
},
]
}
data={Array []}
layout={
Object {
"height": 85,
"height": 60,
"margin": Object {
"b": 30,
"l": 150,
Expand All @@ -191,7 +150,7 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
"color": "#91989c",
"range": Array [
0,
22,
0,
],
"showline": true,
"side": "top",
Expand All @@ -200,12 +159,8 @@ exports[`SpanDetailPanel component renders correctly with default props 1`] = `
"yaxis": Object {
"fixedrange": true,
"showgrid": false,
"ticktext": Array [
"",
],
"tickvals": Array [
"service1",
],
"ticktext": Array [],
"tickvals": Array [],
},
}
}
Expand Down
Loading
Loading