Skip to content
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

feat(browser): Add browser metrics sdk #9794

Merged
merged 21 commits into from
Dec 14, 2023
Merged

Conversation

AbhiPrasad
Copy link
Member

@AbhiPrasad AbhiPrasad commented Dec 11, 2023

Please read the following before reviewing:

ref #9691

This PR introduces functionality for a browser metrics SDK in an alpha state. Via the newly introduced APIs, you can now flush metrics directly to Sentry in the browser.

To enable capturing metrics, you first need to add the Metrics integration. This is done for treeshaking purposes.

Sentry.init({
  dsn: '__DSN__',
  integrations: [
    new Sentry.metrics.MetricsAggregator(),
  ],
});

Then you'll be able to add counters, sets, distributions, and gauges under the Sentry.metrics namespace.

// Add 4 to a counter named `hits`
Sentry.metrics.increment('hits', 4);

// Add 2 to gauge named `parallel_requests`, tagged with `happy: "no"`
Sentry.metrics.gauge('parallel_requests', 2, { tags: { happy: 'no' } });

// Add 4.6 to a distribution named `response_time` with unit seconds
Sentry.metrics.distribution('response_time', 4.6, { unit: 'seconds' });

// Add 2 to a set named `valuable.ids`
Sentry.metrics.set('valuable.ids', 2);

Under the hood, adding the Metrics integration adds a SimpleMetricsAggregator. This is a bundle-sized efficient metrics aggregator that aggregates metrics and flushes them out every 5 seconds. This does not use any weight based logic - this will be implemented in the MetricsAggregator that is used for server runtimes (node, deno, vercel-edge).

To make metrics conditional, it is defined on the client as public metricsAggregator: MetricsAggregator | undefined.

Next step is to add some integration tests for this functionality, and then add server-runtime logic for it.

Many of the decisions taken for this aggregator + flushing implementation was to try to be as bundle size efficient as possible, happy to answer any specific questions.

@AbhiPrasad AbhiPrasad mentioned this pull request Dec 11, 2023
@AbhiPrasad AbhiPrasad self-assigned this Dec 11, 2023
packages/core/src/baseclient.ts Outdated Show resolved Hide resolved
packages/core/src/baseclient.ts Show resolved Hide resolved
packages/core/src/baseclient.ts Show resolved Hide resolved
packages/core/src/metrics/constants.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/constants.ts Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/core/src/metrics/types.ts Outdated Show resolved Hide resolved
Copy link
Member

@lforst lforst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general: 👍

packages/core/src/metrics/constants.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/constants.ts Show resolved Hide resolved
packages/core/src/metrics/envelope.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/exports.ts Outdated Show resolved Hide resolved
Comment on lines 1 to 4
export const COUNTER_METRIC_TYPE = 'c';
export const GAUGE_METRIC_TYPE = 'g';
export const SET_METRIC_TYPE = 's';
export const DISTRIBUTION_METRIC_TYPE = 'd';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m: Since we are not using these anywhere as actual values, should we just define them as types instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ended up using the constants and caught a bug f5d6333

packages/core/src/metrics/simpleaggregator.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/types/src/client.ts Outdated Show resolved Hide resolved
Copy link
Contributor

github-actions bot commented Dec 11, 2023

size-limit report 📦

Path Size
@sentry/browser (incl. Tracing, Replay, Feedback) - Webpack (gzipped) 75.17 KB (+0.19% 🔺)
@sentry/browser (incl. Tracing, Replay) - Webpack (gzipped) 66.56 KB (+0.27% 🔺)
@sentry/browser (incl. Tracing, Replay) - Webpack with treeshaking flags (gzipped) 60.17 KB (+0.29% 🔺)
@sentry/browser (incl. Tracing) - Webpack (gzipped) 31.3 KB (+0.54% 🔺)
@sentry/browser (incl. Feedback) - Webpack (gzipped) 29.9 KB (+0.54% 🔺)
@sentry/browser - Webpack (gzipped) 21.56 KB (+0.78% 🔺)
@sentry/browser (incl. Tracing, Replay, Feedback) - ES6 CDN Bundle (gzipped) 72.53 KB (+1.3% 🔺)
@sentry/browser (incl. Tracing, Replay) - ES6 CDN Bundle (gzipped) 64.28 KB (+1.49% 🔺)
@sentry/browser (incl. Tracing) - ES6 CDN Bundle (gzipped) 30.58 KB (+3.09% 🔺)
@sentry/browser - ES6 CDN Bundle (gzipped) 22.61 KB (+4.11% 🔺)
@sentry/browser (incl. Tracing, Replay) - ES6 CDN Bundle (minified & uncompressed) 202.29 KB (+1.36% 🔺)
@sentry/browser (incl. Tracing) - ES6 CDN Bundle (minified & uncompressed) 92.65 KB (+3.02% 🔺)
@sentry/browser - ES6 CDN Bundle (minified & uncompressed) 67.63 KB (+4.18% 🔺)
@sentry/browser (incl. Tracing) - ES5 CDN Bundle (gzipped) 33.47 KB (+3.51% 🔺)
@sentry/react (incl. Tracing, Replay) - Webpack (gzipped) 66.91 KB (+0.25% 🔺)
@sentry/react - Webpack (gzipped) 21.6 KB (+0.78% 🔺)
@sentry/nextjs Client (incl. Tracing, Replay) - Webpack (gzipped) 83.66 KB (+0.22% 🔺)
@sentry/nextjs Client - Webpack (gzipped) 48.41 KB (+0.38% 🔺)
@sentry-internal/feedback - Webpack (gzipped) 16.19 KB (+0.02% 🔺)

packages/browser/src/exports.ts Outdated Show resolved Hide resolved
packages/browser/src/exports.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/instance.ts Show resolved Hide resolved
@AbhiPrasad AbhiPrasad changed the title feat(browser): Add brower metrics sdk feat(browser): Add browser metrics sdk Dec 12, 2023
@AbhiPrasad
Copy link
Member Author

AbhiPrasad commented Dec 12, 2023

Updated the API:

// Add 4 to a counter named `hits`
Sentry.metrics.increment('hits', 4);

// Add 2 to gauge named `parallel_requests`, tagged with `happy: "no"`
Sentry.metrics.gauge('parallel_requests', 2, { tags: { happy: 'no' } });

// Add 4.6 to a distribution named `response_time` with unit seconds
Sentry.metrics.distribution('response_time', 4.6, { unit: 'seconds' });

// Add 2 to a set named `valuable.ids`
Sentry.metrics.set('valuable.ids', 2);

@AbhiPrasad
Copy link
Member Author

I went ahead and also refactored client and serialization logic as per @lforst feedback. It does have increased bundle size hit, but I believe it is waaaay more maintainable, thanks for keeping me honest!

#9794 (comment)

@AbhiPrasad
Copy link
Member Author

example envelope:

{"sent_at":"2023-12-12T16:38:53.929Z","sdk":{"name":"sentry.javascript.browser","version":"7.86.0"}}
{"type":"statsd","length":260}
hits@none:4|c|#environment:production,transaction:/|T1702399133
parallel_requests@none:4:4:4:4:1|g|#environment:production,transaction:/,happy:no|T1702399133
response_time@none:0.2521277168899102|d|#environment:production,transaction:/,happy:maybe|T1702399133

In the UI:

image

Copy link
Member

@Lms24 Lms24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! As you wrote in the description, integration tests would be great to have but I'm totally fine if we add them in a follow up PR.

};
}

if (!!tunnel && !!dsn) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: do we need the double !! here? we just check for definedness, no?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do not, will change.

packages/core/src/metrics/instance.ts Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
export const NAME_AND_TAG_KEY_NORMALIZATION_REGEX = /[^a-zA-Z0-9_/.-]+/g;

/**
* Normalization regex for metric tag balues.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Normalization regex for metric tag balues.
* Normalization regex for metric tag values.

@AbhiPrasad AbhiPrasad enabled auto-merge (squash) December 14, 2023 13:22
this._min = value;
this._max = value;
this._sum = value;
this._count = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be moved to line 30

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now it can't see #8700

packages/core/src/metrics/instance.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/instance.ts Outdated Show resolved Hide resolved
packages/browser/src/exports.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/core/src/metrics/simpleaggregator.ts Show resolved Hide resolved
packages/core/src/metrics/utils.ts Outdated Show resolved Hide resolved
packages/core/src/metrics/utils.ts Outdated Show resolved Hide resolved
/**
* Simple hash function for strings.
*/
export function simpleHash(s: string): number {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this function

@AbhiPrasad
Copy link
Member Author

Based on Yagiz's PR review I refactored the tag serialization logic and also did a rename of the metrics class.

Sentry.init({
  dsn: '__DSN__',
  integrations: [
    new Sentry.metrics.MetricsAggregator(),
  ],
});

Although the duplication of metrics is a little annoying, the namespacing makes intent very clear.

@AbhiPrasad AbhiPrasad merged commit 6c000b6 into develop Dec 14, 2023
92 checks passed
@AbhiPrasad AbhiPrasad deleted the abhi-browser-metrics branch December 14, 2023 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants