-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
ref(node): Remove query strings from transaction and span names #2857
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
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
4f0e22b
add stripQueryString function and use it in extractUrl
lobsterkatie 352ae4f
add tests for extractUrl
lobsterkatie 801ad8b
strip query string from handlers urls in span names
lobsterkatie ffb5517
add method to handle url edge cases
lobsterkatie b81f5d8
clarify description and variable names
lobsterkatie 56977ca
strip fragments also
lobsterkatie d8659e2
move internal route cleaning to extractUrl
lobsterkatie d268649
simplify url trimming function
lobsterkatie 8cc2638
add tests for tracing handler
lobsterkatie 05f7c5c
move stripUrlPath to utils
lobsterkatie aa0b078
change name of url-stripping method
lobsterkatie 1483e67
fix missing method when cleaning description
lobsterkatie 4f38ffa
escape ? in regex
lobsterkatie c10cfd9
Merge branch 'master' into kmclb-simplify-transaction-names
kamilogorek File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,14 @@ | ||
import { Runtime } from '@sentry/types'; | ||
import * as sentryCore from '@sentry/core'; | ||
import { Hub } from '@sentry/hub'; | ||
import * as sentryHub from '@sentry/hub'; | ||
import { SpanStatus, Transaction } from '@sentry/tracing'; | ||
import { Runtime, Transaction as TransactionType } from '@sentry/types'; | ||
import * as http from 'http'; | ||
import * as net from 'net'; | ||
|
||
import { Event, Request, User } from '../src'; | ||
import { parseRequest } from '../src/handlers'; | ||
import { NodeClient } from '../src/client'; | ||
import { parseRequest, tracingHandler } from '../src/handlers'; | ||
|
||
describe('parseRequest', () => { | ||
let mockReq: { [key: string]: any }; | ||
|
@@ -164,4 +171,133 @@ describe('parseRequest', () => { | |
expect(parsedRequest.transaction).toEqual('routeHandler'); | ||
}); | ||
}); | ||
}); | ||
}); // end describe('parseRequest()') | ||
|
||
describe('tracingHandler', () => { | ||
const urlString = 'http://dogs.are.great:1231/yay/'; | ||
const queryString = '?furry=yes&funny=very'; | ||
const fragment = '#adoptnotbuy'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. <3 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
const sentryTracingMiddleware = tracingHandler(); | ||
|
||
let req: http.IncomingMessage, res: http.ServerResponse, next: () => undefined; | ||
|
||
function createNoOpSpy() { | ||
const noop = { noop: () => undefined }; // this is wrapped in an object so jest can spy on it | ||
return jest.spyOn(noop, 'noop') as any; | ||
} | ||
|
||
beforeEach(() => { | ||
req = new http.IncomingMessage(new net.Socket()); | ||
req.url = `${urlString}`; | ||
req.method = 'GET'; | ||
res = new http.ServerResponse(req); | ||
next = createNoOpSpy(); | ||
}); | ||
|
||
afterEach(() => { | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
it('creates a transaction when handling a request', () => { | ||
const startTransaction = jest.spyOn(sentryCore, 'startTransaction'); | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
|
||
expect(startTransaction).toHaveBeenCalled(); | ||
}); | ||
|
||
it("pulls parent's data from tracing header on the request", () => { | ||
req.headers = { 'sentry-trace': '12312012123120121231201212312012-1121201211212012-0' }; | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
|
||
const transaction = (res as any).__sentry_transaction; | ||
|
||
expect(transaction.traceId).toEqual('12312012123120121231201212312012'); | ||
expect(transaction.parentSpanId).toEqual('1121201211212012'); | ||
expect(transaction.sampled).toEqual(false); | ||
}); | ||
|
||
it('puts its transaction on the scope', () => { | ||
const hub = new Hub(new NodeClient({ tracesSampleRate: 1.0 })); | ||
// we need to mock both of these because the tracing handler relies on `@sentry/core` while the sampler relies on | ||
// `@sentry/hub`, and mocking breaks the link between the two | ||
jest.spyOn(sentryCore, 'getCurrentHub').mockReturnValue(hub); | ||
jest.spyOn(sentryHub, 'getCurrentHub').mockReturnValue(hub); | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
|
||
const transaction = sentryCore | ||
.getCurrentHub() | ||
.getScope() | ||
?.getTransaction(); | ||
|
||
expect(transaction).toBeDefined(); | ||
expect(transaction).toEqual(expect.objectContaining({ name: `GET ${urlString}`, op: 'http.server' })); | ||
}); | ||
|
||
it('puts its transaction on the response object', () => { | ||
sentryTracingMiddleware(req, res, next); | ||
|
||
const transaction = (res as any).__sentry_transaction; | ||
|
||
expect(transaction).toBeDefined(); | ||
expect(transaction).toEqual(expect.objectContaining({ name: `GET ${urlString}`, op: 'http.server' })); | ||
}); | ||
|
||
it('pulls status code from the response', async () => { | ||
const transaction = new Transaction({ name: 'mockTransaction' }); | ||
jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as TransactionType); | ||
const finishTransaction = jest.spyOn(transaction, 'finish'); | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
res.statusCode = 200; | ||
res.emit('finish'); | ||
|
||
expect(finishTransaction).toHaveBeenCalled(); | ||
expect(transaction.status).toBe(SpanStatus.Ok); | ||
expect(transaction.tags).toEqual(expect.objectContaining({ 'http.status_code': '200' })); | ||
}); | ||
|
||
it('strips query string from request path', () => { | ||
req.url = `${urlString}${queryString}`; | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
|
||
const transaction = (res as any).__sentry_transaction; | ||
|
||
expect(transaction?.name).toBe(`GET ${urlString}`); | ||
}); | ||
|
||
it('strips fragment from request path', () => { | ||
req.url = `${urlString}${fragment}`; | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
|
||
const transaction = (res as any).__sentry_transaction; | ||
|
||
expect(transaction?.name).toBe(`GET ${urlString}`); | ||
}); | ||
|
||
it('strips query string and fragment from request path', () => { | ||
req.url = `${urlString}${queryString}${fragment}`; | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
|
||
const transaction = (res as any).__sentry_transaction; | ||
|
||
expect(transaction?.name).toBe(`GET ${urlString}`); | ||
}); | ||
|
||
it('closes the transaction when request processing is done', () => { | ||
const transaction = new Transaction({ name: 'mockTransaction' }); | ||
jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as TransactionType); | ||
const finishTransaction = jest.spyOn(transaction, 'finish'); | ||
|
||
sentryTracingMiddleware(req, res, next); | ||
res.emit('finish'); | ||
|
||
expect(finishTransaction).toHaveBeenCalled(); | ||
}); | ||
}); // end describe('tracingHandler') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { RequestOptions } from 'http'; | ||
|
||
import { extractUrl } from './../../src/integrations/http'; | ||
|
||
describe('extractUrl()', () => { | ||
const urlString = 'http://dogs.are.great:1231/yay/'; | ||
const urlParts: RequestOptions = { | ||
protocol: 'http:', | ||
host: 'dogs.are.great', | ||
method: 'GET', | ||
path: '/yay/', | ||
port: 1231, | ||
}; | ||
const queryString = '?furry=yes&funny=very'; | ||
const fragment = '#adoptnotbuy'; | ||
|
||
it('accepts a url string', () => { | ||
expect(extractUrl(urlString)).toBe(urlString); | ||
}); | ||
|
||
it('accepts a http.RequestOptions object and returns a string with everything in the right place', () => { | ||
expect(extractUrl(urlParts)).toBe('http://dogs.are.great:1231/yay/'); | ||
}); | ||
|
||
it('strips query string from url string', () => { | ||
const urlWithQueryString = `${urlString}${queryString}`; | ||
expect(extractUrl(urlWithQueryString)).toBe(urlString); | ||
}); | ||
|
||
it('strips query string from path in http.RequestOptions object', () => { | ||
const urlPartsWithQueryString = { ...urlParts, path: `${urlParts.path}${queryString}` }; | ||
expect(extractUrl(urlPartsWithQueryString)).toBe(urlString); | ||
}); | ||
|
||
it('strips fragment from url string', () => { | ||
const urlWithFragment = `${urlString}${fragment}`; | ||
expect(extractUrl(urlWithFragment)).toBe(urlString); | ||
}); | ||
|
||
it('strips fragment from path in http.RequestOptions object', () => { | ||
const urlPartsWithFragment = { ...urlParts, path: `${urlParts.path}${fragment}` }; | ||
expect(extractUrl(urlPartsWithFragment)).toBe(urlString); | ||
}); | ||
|
||
it('strips query string and fragment from url string', () => { | ||
const urlWithQueryStringAndFragment = `${urlString}${queryString}${fragment}`; | ||
expect(extractUrl(urlWithQueryStringAndFragment)).toBe(urlString); | ||
}); | ||
|
||
it('strips query string and fragment from path in http.RequestOptions object', () => { | ||
const urlPartsWithQueryStringAndFragment = { ...urlParts, path: `${urlParts.path}${queryString}${fragment}` }; | ||
expect(extractUrl(urlPartsWithQueryStringAndFragment)).toBe(urlString); | ||
}); | ||
}); // end describe('extractUrl()') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very poor-man's slash normalization.
We'd get this for free if using
new Url(...)
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you say more here? I couldn't find any reference to a
Url
class in the MDN docs, and theURL
class doesn't seem to be able to deal with just a path (even if it starts with three slashes):There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When do we even have the case when we have too many slashes? Afaik
ClientRequest
is printinghttp
orhttps
, without any slashesThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my reply below: #2857 (comment)