123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- import { css } from '@emotion/css';
- import { TopOfViewRefType } from '@jaegertracing/jaeger-ui-components/src/TraceTimelineViewer/VirtualizedTraceView';
- import React, { RefObject, useCallback, useMemo, useState } from 'react';
- import { useDispatch, useSelector } from 'react-redux';
- import {
- DataFrame,
- DataLink,
- DataQuery,
- DataSourceApi,
- DataSourceJsonData,
- Field,
- GrafanaTheme2,
- LinkModel,
- mapInternalLinkToExplore,
- PanelData,
- SplitOpen,
- } from '@grafana/data';
- import { getTemplateSrv } from '@grafana/runtime';
- import { useStyles2 } from '@grafana/ui';
- import { Trace, TracePageHeader, TraceTimelineViewer, TTraceTimeline } from '@jaegertracing/jaeger-ui-components';
- import { TraceToLogsData } from 'app/core/components/TraceToLogs/TraceToLogsSettings';
- import { TraceToMetricsData } from 'app/core/components/TraceToMetrics/TraceToMetricsSettings';
- import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
- import { getTimeZone } from 'app/features/profile/state/selectors';
- import { StoreState } from 'app/types';
- import { ExploreId } from 'app/types/explore';
- import { changePanelState } from '../state/explorePane';
- import { createSpanLinkFactory } from './createSpanLink';
- import { useChildrenState } from './useChildrenState';
- import { useDetailState } from './useDetailState';
- import { useHoverIndentGuide } from './useHoverIndentGuide';
- import { useViewRange } from './useViewRange';
- const getStyles = (theme: GrafanaTheme2) => ({
- noDataMsg: css`
- height: 100%;
- width: 100%;
- display: grid;
- place-items: center;
- font-size: ${theme.typography.h4.fontSize};
- color: ${theme.colors.text.secondary};
- `,
- });
- function noop(): {} {
- return {};
- }
- type Props = {
- dataFrames: DataFrame[];
- splitOpenFn?: SplitOpen;
- exploreId?: ExploreId;
- scrollElement?: Element;
- traceProp: Trace;
- spanFindMatches?: Set<string>;
- search: string;
- focusedSpanIdForSearch: string;
- queryResponse: PanelData;
- datasource: DataSourceApi<DataQuery, DataSourceJsonData, {}> | undefined;
- topOfViewRef: RefObject<HTMLDivElement>;
- topOfViewRefType: TopOfViewRefType;
- };
- export function TraceView(props: Props) {
- const { spanFindMatches, traceProp, datasource, topOfViewRef, topOfViewRefType } = props;
- const {
- detailStates,
- toggleDetail,
- detailLogItemToggle,
- detailLogsToggle,
- detailProcessToggle,
- detailReferencesToggle,
- detailReferenceItemToggle,
- detailTagsToggle,
- detailWarningsToggle,
- detailStackTracesToggle,
- } = useDetailState(props.dataFrames[0]);
- const { removeHoverIndentGuideId, addHoverIndentGuideId, hoverIndentGuideIds } = useHoverIndentGuide();
- const { viewRange, updateViewRangeTime, updateNextViewRangeTime } = useViewRange();
- const { expandOne, collapseOne, childrenToggle, collapseAll, childrenHiddenIDs, expandAll } = useChildrenState();
- const styles = useStyles2(getStyles);
- /**
- * Keeps state of resizable name column width
- */
- const [spanNameColumnWidth, setSpanNameColumnWidth] = useState(0.25);
- /**
- * State of the top minimap, slim means it is collapsed.
- */
- const [slim, setSlim] = useState(false);
- const [focusedSpanId, createFocusSpanLink] = useFocusSpanLink({
- refId: props.dataFrames[0]?.refId,
- exploreId: props.exploreId!,
- datasource,
- });
- const createLinkToExternalSpan = (traceId: string, spanId: string) => {
- const link = createFocusSpanLink(traceId, spanId);
- return link.href;
- };
- const traceTimeline: TTraceTimeline = useMemo(
- () => ({
- childrenHiddenIDs,
- detailStates,
- hoverIndentGuideIds,
- shouldScrollToFirstUiFindMatch: false,
- spanNameColumnWidth,
- traceID: props.traceProp?.traceID,
- }),
- [childrenHiddenIDs, detailStates, hoverIndentGuideIds, spanNameColumnWidth, props.traceProp?.traceID]
- );
- const instanceSettings = getDatasourceSrv().getInstanceSettings(datasource?.name);
- const traceToLogsOptions = (instanceSettings?.jsonData as TraceToLogsData)?.tracesToLogs;
- const traceToMetricsOptions = (instanceSettings?.jsonData as TraceToMetricsData)?.tracesToMetrics;
- const createSpanLink = useMemo(
- () =>
- createSpanLinkFactory({
- splitOpenFn: props.splitOpenFn!,
- traceToLogsOptions,
- traceToMetricsOptions,
- dataFrame: props.dataFrames[0],
- createFocusSpanLink,
- }),
- [props.splitOpenFn, traceToLogsOptions, traceToMetricsOptions, props.dataFrames, createFocusSpanLink]
- );
- const onSlimViewClicked = useCallback(() => setSlim(!slim), [slim]);
- const timeZone = useSelector((state: StoreState) => getTimeZone(state.user));
- const datasourceType = datasource ? datasource?.type : 'unknown';
- return (
- <>
- {props.dataFrames?.length && props.dataFrames[0]?.meta?.preferredVisualisationType === 'trace' && traceProp ? (
- <>
- <TracePageHeader
- canCollapse={false}
- hideMap={false}
- hideSummary={false}
- onSlimViewClicked={onSlimViewClicked}
- onTraceGraphViewClicked={noop}
- slimView={slim}
- trace={traceProp}
- updateNextViewRangeTime={updateNextViewRangeTime}
- updateViewRangeTime={updateViewRangeTime}
- viewRange={viewRange}
- timeZone={timeZone}
- />
- <TraceTimelineViewer
- registerAccessors={noop}
- scrollToFirstVisibleSpan={noop}
- findMatchesIDs={spanFindMatches}
- trace={traceProp}
- datasourceType={datasourceType}
- traceTimeline={traceTimeline}
- updateNextViewRangeTime={updateNextViewRangeTime}
- updateViewRangeTime={updateViewRangeTime}
- viewRange={viewRange}
- focusSpan={noop}
- createLinkToExternalSpan={createLinkToExternalSpan}
- setSpanNameColumnWidth={setSpanNameColumnWidth}
- collapseAll={collapseAll}
- collapseOne={collapseOne}
- expandAll={expandAll}
- expandOne={expandOne}
- childrenToggle={childrenToggle}
- clearShouldScrollToFirstUiFindMatch={noop}
- detailLogItemToggle={detailLogItemToggle}
- detailLogsToggle={detailLogsToggle}
- detailWarningsToggle={detailWarningsToggle}
- detailStackTracesToggle={detailStackTracesToggle}
- detailReferencesToggle={detailReferencesToggle}
- detailReferenceItemToggle={detailReferenceItemToggle}
- detailProcessToggle={detailProcessToggle}
- detailTagsToggle={detailTagsToggle}
- detailToggle={toggleDetail}
- setTrace={noop}
- addHoverIndentGuideId={addHoverIndentGuideId}
- removeHoverIndentGuideId={removeHoverIndentGuideId}
- linksGetter={noop as any}
- uiFind={props.search}
- createSpanLink={createSpanLink}
- scrollElement={props.scrollElement}
- focusedSpanId={focusedSpanId}
- focusedSpanIdForSearch={props.focusedSpanIdForSearch!}
- createFocusSpanLink={createFocusSpanLink}
- topOfViewRef={topOfViewRef}
- topOfViewRefType={topOfViewRefType}
- />
- </>
- ) : (
- <div className={styles.noDataMsg}>No data</div>
- )}
- </>
- );
- }
- /**
- * Handles focusing a span. Returns the span id to focus to based on what is in current explore state and also a
- * function to change the focused span id.
- * @param options
- */
- function useFocusSpanLink(options: {
- exploreId: ExploreId;
- refId?: string;
- datasource?: DataSourceApi;
- }): [string | undefined, (traceId: string, spanId: string) => LinkModel<Field>] {
- const panelState = useSelector((state: StoreState) => state.explore[options.exploreId]?.panelsState.trace);
- const focusedSpanId = panelState?.spanId;
- const dispatch = useDispatch();
- const setFocusedSpanId = (spanId?: string) =>
- dispatch(
- changePanelState(options.exploreId, 'trace', {
- ...panelState,
- spanId,
- })
- );
- const query = useSelector((state: StoreState) =>
- state.explore[options.exploreId]?.queries.find((query) => query.refId === options.refId)
- );
- const createFocusSpanLink = (traceId: string, spanId: string) => {
- const link: DataLink = {
- title: 'Deep link to this span',
- url: '',
- internal: {
- datasourceUid: options.datasource?.uid!,
- datasourceName: options.datasource?.name!,
- query: query,
- panelsState: {
- trace: {
- spanId,
- },
- },
- },
- };
- return mapInternalLinkToExplore({
- link,
- internalLink: link.internal!,
- scopedVars: {},
- range: {} as any,
- field: {} as Field,
- onClickFn: () => setFocusedSpanId(focusedSpanId === spanId ? undefined : spanId),
- replaceVariables: getTemplateSrv().replace.bind(getTemplateSrv()),
- });
- };
- return [focusedSpanId, createFocusSpanLink];
- }
|