diff --git a/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.test.ts b/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.test.ts new file mode 100644 index 0000000000000..d7131b942a50f --- /dev/null +++ b/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { getRedirectToTransactionDetailPageUrl } from './get_redirect_to_transaction_detail_page_url'; +import { parse } from 'url'; + +describe('getRedirectToTransactionDetailPageUrl', () => { + const transaction = ({ + '@timestamp': '2020-01-01T00:01:00.000Z', + service: { name: 'opbeans-node' }, + trace: { id: 'trace_id' }, + transaction: { + id: 'transaction_id', + name: 'transaction_name', + type: 'request', + duration: { us: 5000 }, + }, + } as unknown) as any; + + const url = getRedirectToTransactionDetailPageUrl({ transaction }); + + it('rounds the start time down', () => { + expect(parse(url, true).query.rangeFrom).toBe('2020-01-01T00:00:00.000Z'); + }); + + it('rounds the end time up', () => { + expect(parse(url, true).query.rangeTo).toBe('2020-01-01T00:05:00.000Z'); + }); + + it('formats url correctly', () => { + expect(url).toBe( + '/services/opbeans-node/transactions/view?traceId=trace_id&transactionId=transaction_id&transactionName=transaction_name&transactionType=request&rangeFrom=2020-01-01T00%3A00%3A00.000Z&rangeTo=2020-01-01T00%3A05%3A00.000Z' + ); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.ts b/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.ts index 4738622aa9c31..6e22addf429d0 100644 --- a/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.ts +++ b/x-pack/plugins/apm/public/components/app/TraceLink/get_redirect_to_transaction_detail_page_url.ts @@ -14,15 +14,48 @@ export const getRedirectToTransactionDetailPageUrl = ({ transaction: Transaction; rangeFrom?: string; rangeTo?: string; -}) => - format({ +}) => { + return format({ pathname: `/services/${transaction.service.name}/transactions/view`, query: { traceId: transaction.trace.id, transactionId: transaction.transaction.id, transactionName: transaction.transaction.name, transactionType: transaction.transaction.type, - rangeFrom, - rangeTo, + rangeFrom: + rangeFrom || + roundToNearestMinute({ + timestamp: transaction['@timestamp'], + direction: 'down', + }), + rangeTo: + rangeTo || + roundToNearestMinute({ + timestamp: transaction['@timestamp'], + diff: transaction.transaction.duration.us / 1000, + direction: 'up', + }), }, }); +}; + +function roundToNearestMinute({ + timestamp, + diff = 0, + direction = 'up', +}: { + timestamp: string; + diff?: number; + direction?: 'up' | 'down'; +}) { + const date = new Date(timestamp); + const fiveMinutes = 1000 * 60 * 5; // round to 5 min + + const ms = date.getTime() + diff; + + return new Date( + direction === 'down' + ? Math.floor(ms / fiveMinutes) * fiveMinutes + : Math.ceil(ms / fiveMinutes) * fiveMinutes + ).toISOString(); +}