-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
fix(sampling): Remove stray sampling data tags #3197
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
Changes from all commits
d8c2181
894566f
f6cda3e
31a7718
623584d
c69a371
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,30 @@ | ||
import { Event, TransactionSamplingMethod } from '@sentry/types'; | ||
import { DebugMeta, Event, SentryRequest, TransactionSamplingMethod } from '@sentry/types'; | ||
|
||
import { API } from '../../src/api'; | ||
import { eventToSentryRequest } from '../../src/request'; | ||
|
||
describe('eventToSentryRequest', () => { | ||
let api: API; | ||
function parseEnvelopeRequest(request: SentryRequest): any { | ||
const [envelopeHeaderString, itemHeaderString, eventString] = request.body.split('\n'); | ||
|
||
return { | ||
envelopeHeader: JSON.parse(envelopeHeaderString), | ||
itemHeader: JSON.parse(itemHeaderString), | ||
event: JSON.parse(eventString), | ||
}; | ||
} | ||
|
||
const api = new API('https://[email protected]/12312012', { | ||
sdk: { | ||
integrations: ['AWSLambda'], | ||
name: 'sentry.javascript.browser', | ||
version: `12.31.12`, | ||
packages: [{ name: 'npm:@sentry/browser', version: `12.31.12` }], | ||
}, | ||
}); | ||
let event: Event; | ||
|
||
beforeEach(() => { | ||
api = new API('https://[email protected]/12312012', { | ||
sdk: { | ||
integrations: ['AWSLambda'], | ||
name: 'sentry.javascript.browser', | ||
version: `12.31.12`, | ||
packages: [{ name: 'npm:@sentry/browser', version: `6.6.6` }], | ||
}, | ||
}); | ||
event = { | ||
contexts: { trace: { trace_id: '1231201211212012', span_id: '12261980', op: 'pageload' } }, | ||
environment: 'dogpark', | ||
|
@@ -28,68 +37,63 @@ describe('eventToSentryRequest', () => { | |
}; | ||
}); | ||
|
||
[ | ||
{ method: TransactionSamplingMethod.Rate, rate: '0.1121', dog: 'Charlie' }, | ||
{ method: TransactionSamplingMethod.Sampler, rate: '0.1231', dog: 'Maisey' }, | ||
{ method: TransactionSamplingMethod.Inheritance, dog: 'Cory' }, | ||
{ method: TransactionSamplingMethod.Explicit, dog: 'Bodhi' }, | ||
|
||
// this shouldn't ever happen (at least the method should always be included in tags), but good to know that things | ||
// won't blow up if it does | ||
{ dog: 'Lucy' }, | ||
].forEach(({ method, rate, dog }) => { | ||
it(`adds transaction sampling information to item header - ${method}, ${rate}, ${dog}`, () => { | ||
// TODO kmclb - once tag types are loosened, don't need to cast to string here | ||
event.tags = { __sentry_samplingMethod: String(method), __sentry_sampleRate: String(rate), dog }; | ||
|
||
const result = eventToSentryRequest(event, api); | ||
|
||
const [envelopeHeaderString, itemHeaderString, eventString] = result.body.split('\n'); | ||
|
||
const envelope = { | ||
envelopeHeader: JSON.parse(envelopeHeaderString), | ||
itemHeader: JSON.parse(itemHeaderString), | ||
event: JSON.parse(eventString), | ||
}; | ||
|
||
// the right stuff is added to the item header | ||
expect(envelope.itemHeader).toEqual({ | ||
type: 'transaction', | ||
// TODO kmclb - once tag types are loosened, don't need to cast to string here | ||
sample_rates: [{ id: String(method), rate: String(rate) }], | ||
}); | ||
|
||
// show that it pops the right tags and leaves the rest alone | ||
expect('__sentry_samplingMethod' in envelope.event.tags).toBe(false); | ||
expect('__sentry_sampleRate' in envelope.event.tags).toBe(false); | ||
expect('dog' in envelope.event.tags).toBe(true); | ||
}); | ||
it(`adds transaction sampling information to item header`, () => { | ||
event.debug_meta = { transactionSampling: { method: TransactionSamplingMethod.Rate, rate: 0.1121 } }; | ||
|
||
const result = eventToSentryRequest(event, api); | ||
const envelope = parseEnvelopeRequest(result); | ||
|
||
expect(envelope.itemHeader).toEqual( | ||
expect.objectContaining({ | ||
sample_rates: [{ id: TransactionSamplingMethod.Rate, rate: 0.1121 }], | ||
}), | ||
); | ||
}); | ||
|
||
it('adds sdk info to envelope header', () => { | ||
it('removes transaction sampling information (and only that) from debug_meta', () => { | ||
event.debug_meta = { | ||
transactionSampling: { method: TransactionSamplingMethod.Sampler, rate: 0.1121 }, | ||
dog: 'Charlie', | ||
} as DebugMeta; | ||
|
||
const result = eventToSentryRequest(event, api); | ||
const envelope = parseEnvelopeRequest(result); | ||
|
||
const envelopeHeaderString = result.body.split('\n')[0]; | ||
const parsedHeader = JSON.parse(envelopeHeaderString); | ||
expect('transactionSampling' in envelope.event.debug_meta).toBe(false); | ||
expect('dog' in envelope.event.debug_meta).toBe(true); | ||
}); | ||
|
||
expect(parsedHeader).toEqual( | ||
it('removes debug_meta entirely if it ends up empty', () => { | ||
event.debug_meta = { | ||
transactionSampling: { method: TransactionSamplingMethod.Rate, rate: 0.1121 }, | ||
} as DebugMeta; | ||
|
||
const result = eventToSentryRequest(event, api); | ||
const envelope = parseEnvelopeRequest(result); | ||
|
||
expect('debug_meta' in envelope.event).toBe(false); | ||
}); | ||
|
||
it('adds sdk info to envelope header', () => { | ||
const result = eventToSentryRequest(event, api); | ||
const envelope = parseEnvelopeRequest(result); | ||
|
||
expect(envelope.envelopeHeader).toEqual( | ||
expect.objectContaining({ sdk: { name: 'sentry.javascript.browser', version: '12.31.12' } }), | ||
); | ||
}); | ||
|
||
it('adds sdk info to event body', () => { | ||
const result = eventToSentryRequest(event, api); | ||
const envelope = parseEnvelopeRequest(result); | ||
|
||
const eventString = result.body.split('\n')[2]; | ||
const parsedEvent = JSON.parse(eventString); | ||
|
||
expect(parsedEvent).toEqual( | ||
expect(envelope.event).toEqual( | ||
expect.objectContaining({ | ||
sdk: { | ||
integrations: ['AWSLambda'], | ||
name: 'sentry.javascript.browser', | ||
version: `12.31.12`, | ||
packages: [{ name: 'npm:@sentry/browser', version: `6.6.6` }], | ||
packages: [{ name: 'npm:@sentry/browser', version: `12.31.12` }], | ||
}, | ||
}), | ||
); | ||
|
@@ -99,22 +103,21 @@ describe('eventToSentryRequest', () => { | |
event.sdk = { | ||
integrations: ['Clojure'], | ||
name: 'foo', | ||
packages: [{ name: 'npm:@sentry/clj', version: `6.6.6` }], | ||
packages: [{ name: 'npm:@sentry/clj', version: `12.31.12` }], | ||
version: '1337', | ||
}; | ||
const result = eventToSentryRequest(event, api); | ||
|
||
const eventString = result.body.split('\n')[2]; | ||
const parsedEvent = JSON.parse(eventString); | ||
const result = eventToSentryRequest(event, api); | ||
const envelope = parseEnvelopeRequest(result); | ||
|
||
expect(parsedEvent).toEqual( | ||
expect(envelope.event).toEqual( | ||
expect.objectContaining({ | ||
sdk: { | ||
integrations: ['Clojure', 'AWSLambda'], | ||
name: 'foo', | ||
packages: [ | ||
{ name: 'npm:@sentry/clj', version: `6.6.6` }, | ||
{ name: 'npm:@sentry/browser', version: `6.6.6` }, | ||
{ name: 'npm:@sentry/clj', version: `12.31.12` }, | ||
{ name: 'npm:@sentry/browser', version: `12.31.12` }, | ||
], | ||
version: '1337', | ||
}, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -45,7 +45,9 @@ function sample<T extends Transaction>(hub: Hub, transaction: T, samplingContext | |
|
||
// if the user has forced a sampling decision by passing a `sampled` value in their transaction context, go with that | ||
if (transaction.sampled !== undefined) { | ||
transaction.tags = { ...transaction.tags, __sentry_samplingMethod: TransactionSamplingMethod.Explicit }; | ||
transaction.setMetadata({ | ||
transactionSampling: { method: TransactionSamplingMethod.Explicit }, | ||
}); | ||
return transaction; | ||
} | ||
|
||
|
@@ -54,25 +56,27 @@ function sample<T extends Transaction>(hub: Hub, transaction: T, samplingContext | |
let sampleRate; | ||
if (typeof options.tracesSampler === 'function') { | ||
sampleRate = options.tracesSampler(samplingContext); | ||
// cast the rate to a number first in case it's a boolean | ||
transaction.tags = { | ||
...transaction.tags, | ||
__sentry_samplingMethod: TransactionSamplingMethod.Sampler, | ||
// TODO kmclb - once tag types are loosened, don't need to cast to string here | ||
__sentry_sampleRate: String(Number(sampleRate)), | ||
}; | ||
transaction.setMetadata({ | ||
transactionSampling: { | ||
method: TransactionSamplingMethod.Sampler, | ||
// cast to number in case it's a boolean | ||
rate: Number(sampleRate), | ||
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. @jan-auer Once consequence of this change is that rates will come through as numbers rather than strings. (When I did the original PR, tags had to be strings, which is why I stringified the value in the first place.) LMK if that's not good from a relay perspective and I can turn them back into strings. 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. Is this what you put into the type SampleRate = {
id: String,
rate: Number,
} If this goes into the header, let's rather keep it consistent to avoid mistakes please. As for the rate, that should be a number all along. |
||
}, | ||
}); | ||
} else if (samplingContext.parentSampled !== undefined) { | ||
sampleRate = samplingContext.parentSampled; | ||
transaction.tags = { ...transaction.tags, __sentry_samplingMethod: TransactionSamplingMethod.Inheritance }; | ||
transaction.setMetadata({ | ||
transactionSampling: { method: TransactionSamplingMethod.Inheritance }, | ||
}); | ||
} else { | ||
sampleRate = options.tracesSampleRate; | ||
// cast the rate to a number first in case it's a boolean | ||
transaction.tags = { | ||
...transaction.tags, | ||
__sentry_samplingMethod: TransactionSamplingMethod.Rate, | ||
// TODO kmclb - once tag types are loosened, don't need to cast to string here | ||
__sentry_sampleRate: String(Number(sampleRate)), | ||
}; | ||
transaction.setMetadata({ | ||
transactionSampling: { | ||
method: TransactionSamplingMethod.Rate, | ||
// cast to number in case it's a boolean | ||
rate: Number(sampleRate), | ||
}, | ||
}); | ||
} | ||
|
||
// Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
**/ | ||
export interface DebugMeta { | ||
images?: Array<DebugImage>; | ||
transactionSampling?: { rate?: number; method?: string }; | ||
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. If we call it 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. It would make object deconstruction easier. I didn't do it because 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. I totally agree, but why is Relay using it in the first place? :P 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. You'll have to take that up with @jan-auer 😛 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. See also #3197 (comment). Relay doesn't use this field, but it also sample in its own way. The Ultimately, this all ends up in Sentry and in our data pipeline. |
||
} | ||
|
||
/** | ||
|
Uh oh!
There was an error while loading. Please reload this page.