Tracing: Span link feature tracking (#61022)

* Span link feature tracking

* Update interaction name
This commit is contained in:
Joey Tawadrous 2023-01-13 14:02:25 +00:00 committed by GitHub
parent 28dbbe9f5f
commit 2b6a5e2b3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 8 deletions

View File

@ -328,6 +328,7 @@ export type SpanBarRowProps = {
clippingLeft?: boolean;
clippingRight?: boolean;
createSpanLink?: SpanLinkFunc;
datasourceType: string;
};
/**
@ -377,6 +378,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
clippingRight,
theme,
createSpanLink,
datasourceType,
} = this.props;
const {
duration,
@ -515,7 +517,7 @@ export class UnthemedSpanBarRow extends React.PureComponent<SpanBarRowProps> {
</a>
);
} else if (links && count > 1) {
return <SpanLinksMenu links={links} />;
return <SpanLinksMenu links={links} datasourceType={datasourceType} />;
} else {
return null;
}

View File

@ -18,6 +18,7 @@ import React from 'react';
import IoLink from 'react-icons/lib/io/link';
import { dateTimeFormat, GrafanaTheme2, LinkModel, TimeZone } from '@grafana/data';
import { reportInteraction } from '@grafana/runtime';
import { DataLinkButton, TextArea, useStyles2 } from '@grafana/ui';
import { autoColor } from '../../Theme';
@ -121,6 +122,7 @@ export type SpanDetailProps = {
focusedSpanId?: string;
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel;
topOfViewRefType?: TopOfViewRefType;
datasourceType: string;
};
export default function SpanDetail(props: SpanDetailProps) {
@ -140,6 +142,7 @@ export default function SpanDetail(props: SpanDetailProps) {
createSpanLink,
createFocusSpanLink,
topOfViewRefType,
datasourceType,
} = props;
const {
isTagsOpen,
@ -193,6 +196,19 @@ export default function SpanDetail(props: SpanDetailProps) {
const styles = useStyles2(getStyles);
const links = createSpanLink?.(span);
const focusSpanLink = createFocusSpanLink(traceID, spanID);
const logLink = links?.logLinks?.[0]
? {
...links?.logLinks?.[0],
onClick: (event: React.MouseEvent) => {
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
datasourceType: datasourceType,
type: 'log',
location: 'spanDetails',
});
links?.logLinks?.[0].onClick!(event);
},
}
: undefined;
return (
<div data-testid="span-detail-component">
@ -203,10 +219,9 @@ export default function SpanDetail(props: SpanDetailProps) {
</div>
</div>
{links?.logLinks?.[0] ? (
<DataLinkButton
link={{ ...links?.logLinks?.[0], title: 'Logs for this span' } as any}
buttonProps={{ icon: 'gf-logs' }}
/>
<>
<DataLinkButton link={{ ...logLink, title: 'Logs for this span' } as any} buttonProps={{ icon: 'gf-logs' }} />
</>
) : null}
<Divider className={ubMy1} type={'horizontal'} />
<div>

View File

@ -96,6 +96,7 @@ export type SpanDetailRowProps = {
focusedSpanId?: string;
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel;
topOfViewRefType?: TopOfViewRefType;
datasourceType: string;
};
export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProps> {
@ -132,6 +133,7 @@ export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProp
focusedSpanId,
createFocusSpanLink,
topOfViewRefType,
datasourceType,
} = this.props;
const styles = getStyles(theme);
return (
@ -172,6 +174,7 @@ export class UnthemedSpanDetailRow extends React.PureComponent<SpanDetailRowProp
focusedSpanId={focusedSpanId}
createFocusSpanLink={createFocusSpanLink}
topOfViewRefType={topOfViewRefType}
datasourceType={datasourceType}
/>
</div>
</TimelineRow.Cell>

View File

@ -1,15 +1,22 @@
import { css } from '@emotion/css';
import React, { useState } from 'react';
import { reportInteraction } from '@grafana/runtime';
import { useStyles2, MenuGroup, MenuItem, Icon, ContextMenu } from '@grafana/ui';
import { SpanLinks } from '../types/links';
interface SpanLinksProps {
links: SpanLinks;
datasourceType: string;
}
const renderMenuItems = (links: SpanLinks, styles: ReturnType<typeof getStyles>, closeMenu: () => void) => {
const renderMenuItems = (
links: SpanLinks,
styles: ReturnType<typeof getStyles>,
closeMenu: () => void,
datasourceType: string
) => {
return (
<>
{!!links.logLinks?.length ? (
@ -21,6 +28,11 @@ const renderMenuItems = (links: SpanLinks, styles: ReturnType<typeof getStyles>,
onClick={
link.onClick
? (event) => {
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
datasourceType: datasourceType,
type: 'log',
location: 'menu',
});
event?.preventDefault();
link.onClick!(event);
closeMenu();
@ -42,6 +54,11 @@ const renderMenuItems = (links: SpanLinks, styles: ReturnType<typeof getStyles>,
onClick={
link.onClick
? (event) => {
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
datasourceType: datasourceType,
type: 'metric',
location: 'menu',
});
event?.preventDefault();
link.onClick!(event);
closeMenu();
@ -63,6 +80,11 @@ const renderMenuItems = (links: SpanLinks, styles: ReturnType<typeof getStyles>,
onClick={
link.onClick
? (event) => {
reportInteraction('grafana_traces_trace_view_span_link_clicked', {
datasourceType: datasourceType,
type: 'trace',
location: 'menu',
});
event?.preventDefault();
link.onClick!(event);
closeMenu();
@ -79,7 +101,7 @@ const renderMenuItems = (links: SpanLinks, styles: ReturnType<typeof getStyles>,
);
};
export const SpanLinksMenu = ({ links }: SpanLinksProps) => {
export const SpanLinksMenu = ({ links, datasourceType }: SpanLinksProps) => {
const styles = useStyles2(getStyles);
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [menuPosition, setMenuPosition] = useState({ x: 0, y: 0 });
@ -104,7 +126,7 @@ export const SpanLinksMenu = ({ links }: SpanLinksProps) => {
{isMenuOpen ? (
<ContextMenu
onClose={() => setIsMenuOpen(false)}
renderMenuItems={() => renderMenuItems(links, styles, closeMenu)}
renderMenuItems={() => renderMenuItems(links, styles, closeMenu, datasourceType)}
focusOnOpen={true}
x={menuPosition.x}
y={menuPosition.y}

View File

@ -115,6 +115,7 @@ type TVirtualizedTraceViewOwnProps = {
createFocusSpanLink: (traceId: string, spanId: string) => LinkModel;
topOfViewRef?: RefObject<HTMLDivElement>;
topOfViewRefType?: TopOfViewRefType;
datasourceType: string;
};
export type VirtualizedTraceViewProps = TVirtualizedTraceViewOwnProps & TExtractUiFindFromStateReturn & TTraceTimeline;
@ -396,6 +397,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
focusedSpanId,
focusedSpanIdForSearch,
theme,
datasourceType,
} = this.props;
// to avert flow error
if (!trace) {
@ -461,6 +463,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
addHoverIndentGuideId={addHoverIndentGuideId}
removeHoverIndentGuideId={removeHoverIndentGuideId}
createSpanLink={createSpanLink}
datasourceType={datasourceType}
/>
</div>
);
@ -492,6 +495,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
createFocusSpanLink,
topOfViewRefType,
theme,
datasourceType,
} = this.props;
const detailState = detailStates.get(spanID);
if (!trace || !detailState) {
@ -525,6 +529,7 @@ export class UnthemedVirtualizedTraceView extends React.Component<VirtualizedTra
focusedSpanId={focusedSpanId}
createFocusSpanLink={createFocusSpanLink}
topOfViewRefType={topOfViewRefType}
datasourceType={datasourceType}
/>
</div>
);