Logs: Add tracking for permalinking (#70334)
* add permalink tracking * move location override to beforeAll * add `logLevel` to tracking
This commit is contained in:
@@ -15,6 +15,34 @@ import { ExploreId } from 'app/types';
|
||||
|
||||
import { Logs } from './Logs';
|
||||
|
||||
const reportInteraction = jest.fn();
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
reportInteraction: (interactionName: string, properties?: Record<string, unknown> | undefined) =>
|
||||
reportInteraction(interactionName, properties),
|
||||
}));
|
||||
|
||||
const createAndCopyShortLink = jest.fn();
|
||||
jest.mock('app/core/utils/shortLinks', () => ({
|
||||
...jest.requireActual('app/core/utils/shortLinks'),
|
||||
createAndCopyShortLink: (url: string) => createAndCopyShortLink(url),
|
||||
}));
|
||||
|
||||
jest.mock('app/store/store', () => ({
|
||||
getState: jest.fn().mockReturnValue({
|
||||
explore: {
|
||||
panes: {
|
||||
left: {
|
||||
datasource: 'id',
|
||||
queries: [{ refId: 'A', expr: '', queryType: 'range', datasource: { type: 'loki', uid: 'id' } }],
|
||||
range: { raw: { from: 'now-1h', to: 'now' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
dispatch: jest.fn(),
|
||||
}));
|
||||
|
||||
const changePanelState = jest.fn();
|
||||
jest.mock('../state/explorePane', () => ({
|
||||
...jest.requireActual('../state/explorePane'),
|
||||
@@ -24,10 +52,30 @@ jest.mock('../state/explorePane', () => ({
|
||||
}));
|
||||
|
||||
describe('Logs', () => {
|
||||
let originalHref = window.location.href;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
href: 'http://localhost:3000/explore?test',
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
value: {
|
||||
href: originalHref,
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
});
|
||||
|
||||
const getComponent = (partialProps?: Partial<ComponentProps<typeof Logs>>, logs?: LogRowModel[]) => {
|
||||
const rows = [
|
||||
makeLog({ uid: '1', timeEpochMs: 1 }),
|
||||
@@ -243,6 +291,38 @@ describe('Logs', () => {
|
||||
|
||||
expect(scrollElementMock.scroll).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should call reportInteraction on permalinkClick', async () => {
|
||||
const panelState = { logs: { id: 'not-included' } };
|
||||
setup({ loading: false, panelState });
|
||||
|
||||
const row = screen.getAllByRole('row');
|
||||
await userEvent.hover(row[0]);
|
||||
|
||||
const linkButtons = row[1].querySelectorAll('button');
|
||||
await userEvent.click(linkButtons[2]);
|
||||
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_explore_logs_permalink_clicked', {
|
||||
datasourceType: 'unknown',
|
||||
logRowUid: '2',
|
||||
logRowLevel: 'debug',
|
||||
});
|
||||
});
|
||||
|
||||
it('should call createAndCopyShortLink on permalinkClick', async () => {
|
||||
const panelState = { logs: { id: 'not-included' } };
|
||||
setup({ loading: false, panelState });
|
||||
|
||||
const row = screen.getAllByRole('row');
|
||||
await userEvent.hover(row[0]);
|
||||
|
||||
const linkButtons = row[1].querySelectorAll('button');
|
||||
await userEvent.click(linkButtons[2]);
|
||||
|
||||
expect(createAndCopyShortLink).toHaveBeenCalledWith(
|
||||
'http://localhost:3000/explore?left=%7B%22datasource%22:%22%22,%22queries%22:%5B%7B%22refId%22:%22A%22,%22expr%22:%22%22,%22queryType%22:%22range%22,%22datasource%22:%7B%22type%22:%22loki%22,%22uid%22:%22id%22%7D%7D%5D,%22range%22:%7B%22from%22:%222019-01-01T10:00:00.000Z%22,%22to%22:%222019-01-01T16:00:00.000Z%22%7D,%22panelsState%22:%7B%22logs%22:%7B%22id%22:%222%22%7D%7D%7D'
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -368,6 +368,12 @@ class UnthemedLogs extends PureComponent<Props, State> {
|
||||
const baseUrl = /.*(?=\/explore)/.exec(`${window.location.href}`)![0];
|
||||
const url = urlUtil.renderUrl(`${baseUrl}/explore`, { left: serializedState });
|
||||
await createAndCopyShortLink(url);
|
||||
|
||||
reportInteraction('grafana_explore_logs_permalink_clicked', {
|
||||
datasourceType: row.datasourceType ?? 'unknown',
|
||||
logRowUid: row.uid,
|
||||
logRowLevel: row.logLevel,
|
||||
});
|
||||
};
|
||||
|
||||
scrollIntoView = (element: HTMLElement) => {
|
||||
|
||||
@@ -9,6 +9,13 @@ import { LogRow } from './LogRow';
|
||||
import { createLogRow } from './__mocks__/logRow';
|
||||
import { getLogRowStyles } from './getLogRowStyles';
|
||||
|
||||
const reportInteraction = jest.fn();
|
||||
jest.mock('@grafana/runtime', () => ({
|
||||
...jest.requireActual('@grafana/runtime'),
|
||||
reportInteraction: (interactionName: string, properties?: Record<string, unknown> | undefined) =>
|
||||
reportInteraction(interactionName, properties),
|
||||
}));
|
||||
|
||||
const theme = createTheme();
|
||||
const styles = getLogRowStyles(theme);
|
||||
const setup = (propOverrides?: Partial<ComponentProps<typeof LogRow>>, rowOverrides?: Partial<LogRowModel>) => {
|
||||
@@ -52,6 +59,15 @@ describe('LogRow', () => {
|
||||
});
|
||||
|
||||
describe('with permalinking', () => {
|
||||
it('reports via feature tracking when log line matches', () => {
|
||||
const scrollIntoView = jest.fn();
|
||||
setup({ permalinkedRowId: 'log-row-id', scrollIntoView });
|
||||
expect(reportInteraction).toHaveBeenCalledWith('grafana_explore_logs_permalink_opened', {
|
||||
logRowUid: 'log-row-id',
|
||||
datasourceType: 'unknown',
|
||||
});
|
||||
});
|
||||
|
||||
it('highlights row with same permalink-id', () => {
|
||||
const { container } = setup({ permalinkedRowId: 'log-row-id' });
|
||||
const row = container.querySelector('tr');
|
||||
|
||||
@@ -125,7 +125,9 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
scrollToLogRow = (prevState: State, mounted = false) => {
|
||||
if (this.props.permalinkedRowId !== this.props.row.uid) {
|
||||
const { row, permalinkedRowId, scrollIntoView } = this.props;
|
||||
|
||||
if (permalinkedRowId !== row.uid) {
|
||||
// only set the new state if the row is not permalinked anymore or if the component was mounted.
|
||||
if (prevState.highlightBackround || mounted) {
|
||||
this.setState({ highlightBackround: false });
|
||||
@@ -134,10 +136,14 @@ class UnThemedLogRow extends PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
// at this point this row is the permalinked row, so we need to scroll to it and highlight it if possible.
|
||||
if (this.logLineRef.current && this.props.scrollIntoView) {
|
||||
this.props.scrollIntoView(this.logLineRef.current);
|
||||
if (this.logLineRef.current && scrollIntoView) {
|
||||
scrollIntoView(this.logLineRef.current);
|
||||
}
|
||||
if (!this.state.highlightBackround) {
|
||||
reportInteraction('grafana_explore_logs_permalink_opened', {
|
||||
datasourceType: row.datasourceType ?? 'unknown',
|
||||
logRowUid: row.uid,
|
||||
});
|
||||
this.setState({ highlightBackround: true });
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user