This commit is contained in:
MarSeventh
2024-07-19 23:26:06 +08:00
commit 4e0c55d1f9
1401 changed files with 69819 additions and 0 deletions

174
node_modules/@sentry/core/cjs/metrics/aggregator.js generated vendored Normal file
View File

@@ -0,0 +1,174 @@
Object.defineProperty(exports, '__esModule', { value: true });
const utils$1 = require('@sentry/utils');
const constants = require('./constants.js');
const instance = require('./instance.js');
const metricSummary = require('./metric-summary.js');
const utils = require('./utils.js');
/**
* A metrics aggregator that aggregates metrics in memory and flushes them periodically.
*/
class MetricsAggregator {
// TODO(@anonrig): Use FinalizationRegistry to have a proper way of flushing the buckets
// when the aggregator is garbage collected.
// Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry
// Different metrics have different weights. We use this to limit the number of metrics
// that we store in memory.
// Cast to any so that it can use Node.js timeout
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// SDKs are required to shift the flush interval by random() * rollup_in_seconds.
// That shift is determined once per startup to create jittering.
// An SDK is required to perform force flushing ahead of scheduled time if the memory
// pressure is too high. There is no rule for this other than that SDKs should be tracking
// abstract aggregation complexity (eg: a counter only carries a single float, whereas a
// distribution is a float per emission).
//
// Force flush is used on either shutdown, flush() or when we exceed the max weight.
constructor( _client) {this._client = _client;
this._buckets = new Map();
this._bucketsTotalWeight = 0;
this._interval = setInterval(() => this._flush(), constants.DEFAULT_FLUSH_INTERVAL) ;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (this._interval.unref) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
this._interval.unref();
}
this._flushShift = Math.floor((Math.random() * constants.DEFAULT_FLUSH_INTERVAL) / 1000);
this._forceFlush = false;
}
/**
* @inheritDoc
*/
add(
metricType,
unsanitizedName,
value,
unsanitizedUnit = 'none',
unsanitizedTags = {},
maybeFloatTimestamp = utils$1.timestampInSeconds(),
) {
const timestamp = Math.floor(maybeFloatTimestamp);
const name = utils.sanitizeMetricKey(unsanitizedName);
const tags = utils.sanitizeTags(unsanitizedTags);
const unit = utils.sanitizeUnit(unsanitizedUnit );
const bucketKey = utils.getBucketKey(metricType, name, unit, tags);
let bucketItem = this._buckets.get(bucketKey);
// If this is a set metric, we need to calculate the delta from the previous weight.
const previousWeight = bucketItem && metricType === constants.SET_METRIC_TYPE ? bucketItem.metric.weight : 0;
if (bucketItem) {
bucketItem.metric.add(value);
// TODO(abhi): Do we need this check?
if (bucketItem.timestamp < timestamp) {
bucketItem.timestamp = timestamp;
}
} else {
bucketItem = {
// @ts-expect-error we don't need to narrow down the type of value here, saves bundle size.
metric: new instance.METRIC_MAP[metricType](value),
timestamp,
metricType,
name,
unit,
tags,
};
this._buckets.set(bucketKey, bucketItem);
}
// If value is a string, it's a set metric so calculate the delta from the previous weight.
const val = typeof value === 'string' ? bucketItem.metric.weight - previousWeight : value;
metricSummary.updateMetricSummaryOnActiveSpan(metricType, name, val, unit, unsanitizedTags, bucketKey);
// We need to keep track of the total weight of the buckets so that we can
// flush them when we exceed the max weight.
this._bucketsTotalWeight += bucketItem.metric.weight;
if (this._bucketsTotalWeight >= constants.MAX_WEIGHT) {
this.flush();
}
}
/**
* Flushes the current metrics to the transport via the transport.
*/
flush() {
this._forceFlush = true;
this._flush();
}
/**
* Shuts down metrics aggregator and clears all metrics.
*/
close() {
this._forceFlush = true;
clearInterval(this._interval);
this._flush();
}
/**
* Flushes the buckets according to the internal state of the aggregator.
* If it is a force flush, which happens on shutdown, it will flush all buckets.
* Otherwise, it will only flush buckets that are older than the flush interval,
* and according to the flush shift.
*
* This function mutates `_forceFlush` and `_bucketsTotalWeight` properties.
*/
_flush() {
// TODO(@anonrig): Add Atomics for locking to avoid having force flush and regular flush
// running at the same time.
// Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics
// This path eliminates the need for checking for timestamps since we're forcing a flush.
// Remember to reset the flag, or it will always flush all metrics.
if (this._forceFlush) {
this._forceFlush = false;
this._bucketsTotalWeight = 0;
this._captureMetrics(this._buckets);
this._buckets.clear();
return;
}
const cutoffSeconds = Math.floor(utils$1.timestampInSeconds()) - constants.DEFAULT_FLUSH_INTERVAL / 1000 - this._flushShift;
// TODO(@anonrig): Optimization opportunity.
// Convert this map to an array and store key in the bucketItem.
const flushedBuckets = new Map();
for (const [key, bucket] of this._buckets) {
if (bucket.timestamp <= cutoffSeconds) {
flushedBuckets.set(key, bucket);
this._bucketsTotalWeight -= bucket.metric.weight;
}
}
for (const [key] of flushedBuckets) {
this._buckets.delete(key);
}
this._captureMetrics(flushedBuckets);
}
/**
* Only captures a subset of the buckets passed to this function.
* @param flushedBuckets
*/
_captureMetrics(flushedBuckets) {
if (flushedBuckets.size > 0 && this._client.captureAggregateMetrics) {
// TODO(@anonrig): Optimization opportunity.
// This copy operation can be avoided if we store the key in the bucketItem.
const buckets = Array.from(flushedBuckets).map(([, bucketItem]) => bucketItem);
this._client.captureAggregateMetrics(buckets);
}
}
}
exports.MetricsAggregator = MetricsAggregator;
//# sourceMappingURL=aggregator.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,99 @@
Object.defineProperty(exports, '__esModule', { value: true });
const utils$1 = require('@sentry/utils');
const constants = require('./constants.js');
const instance = require('./instance.js');
const metricSummary = require('./metric-summary.js');
const utils = require('./utils.js');
/**
* A simple metrics aggregator that aggregates metrics in memory and flushes them periodically.
* Default flush interval is 5 seconds.
*
* @experimental This API is experimental and might change in the future.
*/
class BrowserMetricsAggregator {
// TODO(@anonrig): Use FinalizationRegistry to have a proper way of flushing the buckets
// when the aggregator is garbage collected.
// Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry
constructor( _client) {this._client = _client;
this._buckets = new Map();
this._interval = setInterval(() => this.flush(), constants.DEFAULT_BROWSER_FLUSH_INTERVAL);
}
/**
* @inheritDoc
*/
add(
metricType,
unsanitizedName,
value,
unsanitizedUnit = 'none',
unsanitizedTags = {},
maybeFloatTimestamp = utils$1.timestampInSeconds(),
) {
const timestamp = Math.floor(maybeFloatTimestamp);
const name = utils.sanitizeMetricKey(unsanitizedName);
const tags = utils.sanitizeTags(unsanitizedTags);
const unit = utils.sanitizeUnit(unsanitizedUnit );
const bucketKey = utils.getBucketKey(metricType, name, unit, tags);
let bucketItem = this._buckets.get(bucketKey);
// If this is a set metric, we need to calculate the delta from the previous weight.
const previousWeight = bucketItem && metricType === constants.SET_METRIC_TYPE ? bucketItem.metric.weight : 0;
if (bucketItem) {
bucketItem.metric.add(value);
// TODO(abhi): Do we need this check?
if (bucketItem.timestamp < timestamp) {
bucketItem.timestamp = timestamp;
}
} else {
bucketItem = {
// @ts-expect-error we don't need to narrow down the type of value here, saves bundle size.
metric: new instance.METRIC_MAP[metricType](value),
timestamp,
metricType,
name,
unit,
tags,
};
this._buckets.set(bucketKey, bucketItem);
}
// If value is a string, it's a set metric so calculate the delta from the previous weight.
const val = typeof value === 'string' ? bucketItem.metric.weight - previousWeight : value;
metricSummary.updateMetricSummaryOnActiveSpan(metricType, name, val, unit, unsanitizedTags, bucketKey);
}
/**
* @inheritDoc
*/
flush() {
// short circuit if buckets are empty.
if (this._buckets.size === 0) {
return;
}
if (this._client.captureAggregateMetrics) {
// TODO(@anonrig): Use Object.values() when we support ES6+
const metricBuckets = Array.from(this._buckets).map(([, bucketItem]) => bucketItem);
this._client.captureAggregateMetrics(metricBuckets);
}
this._buckets.clear();
}
/**
* @inheritDoc
*/
close() {
clearInterval(this._interval);
this.flush();
}
}
exports.BrowserMetricsAggregator = BrowserMetricsAggregator;
//# sourceMappingURL=browser-aggregator.js.map

File diff suppressed because one or more lines are too long

32
node_modules/@sentry/core/cjs/metrics/constants.js generated vendored Normal file
View File

@@ -0,0 +1,32 @@
Object.defineProperty(exports, '__esModule', { value: true });
const COUNTER_METRIC_TYPE = 'c' ;
const GAUGE_METRIC_TYPE = 'g' ;
const SET_METRIC_TYPE = 's' ;
const DISTRIBUTION_METRIC_TYPE = 'd' ;
/**
* This does not match spec in https://develop.sentry.dev/sdk/metrics
* but was chosen to optimize for the most common case in browser environments.
*/
const DEFAULT_BROWSER_FLUSH_INTERVAL = 5000;
/**
* SDKs are required to bucket into 10 second intervals (rollup in seconds)
* which is the current lower bound of metric accuracy.
*/
const DEFAULT_FLUSH_INTERVAL = 10000;
/**
* The maximum number of metrics that should be stored in memory.
*/
const MAX_WEIGHT = 10000;
exports.COUNTER_METRIC_TYPE = COUNTER_METRIC_TYPE;
exports.DEFAULT_BROWSER_FLUSH_INTERVAL = DEFAULT_BROWSER_FLUSH_INTERVAL;
exports.DEFAULT_FLUSH_INTERVAL = DEFAULT_FLUSH_INTERVAL;
exports.DISTRIBUTION_METRIC_TYPE = DISTRIBUTION_METRIC_TYPE;
exports.GAUGE_METRIC_TYPE = GAUGE_METRIC_TYPE;
exports.MAX_WEIGHT = MAX_WEIGHT;
exports.SET_METRIC_TYPE = SET_METRIC_TYPE;
//# sourceMappingURL=constants.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"constants.js","sources":["../../../src/metrics/constants.ts"],"sourcesContent":["export const COUNTER_METRIC_TYPE = 'c' as const;\nexport const GAUGE_METRIC_TYPE = 'g' as const;\nexport const SET_METRIC_TYPE = 's' as const;\nexport const DISTRIBUTION_METRIC_TYPE = 'd' as const;\n\n/**\n * This does not match spec in https://develop.sentry.dev/sdk/metrics\n * but was chosen to optimize for the most common case in browser environments.\n */\nexport const DEFAULT_BROWSER_FLUSH_INTERVAL = 5000;\n\n/**\n * SDKs are required to bucket into 10 second intervals (rollup in seconds)\n * which is the current lower bound of metric accuracy.\n */\nexport const DEFAULT_FLUSH_INTERVAL = 10000;\n\n/**\n * The maximum number of metrics that should be stored in memory.\n */\nexport const MAX_WEIGHT = 10000;\n"],"names":[],"mappings":";;AAAO,MAAM,mBAAoB,GAAE,GAAI,EAAA;AAChC,MAAM,iBAAkB,GAAE,GAAI,EAAA;AAC9B,MAAM,eAAgB,GAAE,GAAI,EAAA;AAC5B,MAAM,wBAAyB,GAAE,GAAI,EAAA;AAC5C;AACA;AACA;AACA;AACA;AACO,MAAM,8BAA+B,GAAE,KAAI;AAClD;AACA;AACA;AACA;AACA;AACO,MAAM,sBAAuB,GAAE,MAAK;AAC3C;AACA;AACA;AACA;AACO,MAAM,UAAW,GAAE;;;;;;;;;;"}

44
node_modules/@sentry/core/cjs/metrics/envelope.js generated vendored Normal file
View File

@@ -0,0 +1,44 @@
Object.defineProperty(exports, '__esModule', { value: true });
const utils = require('@sentry/utils');
const utils$1 = require('./utils.js');
/**
* Create envelope from a metric aggregate.
*/
function createMetricEnvelope(
metricBucketItems,
dsn,
metadata,
tunnel,
) {
const headers = {
sent_at: new Date().toISOString(),
};
if (metadata && metadata.sdk) {
headers.sdk = {
name: metadata.sdk.name,
version: metadata.sdk.version,
};
}
if (!!tunnel && dsn) {
headers.dsn = utils.dsnToString(dsn);
}
const item = createMetricEnvelopeItem(metricBucketItems);
return utils.createEnvelope(headers, [item]);
}
function createMetricEnvelopeItem(metricBucketItems) {
const payload = utils$1.serializeMetricBuckets(metricBucketItems);
const metricHeaders = {
type: 'statsd',
length: payload.length,
};
return [metricHeaders, payload];
}
exports.createMetricEnvelope = createMetricEnvelope;
//# sourceMappingURL=envelope.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"envelope.js","sources":["../../../src/metrics/envelope.ts"],"sourcesContent":["import type { DsnComponents, MetricBucketItem, SdkMetadata, StatsdEnvelope, StatsdItem } from '@sentry/types';\nimport { createEnvelope, dsnToString } from '@sentry/utils';\nimport { serializeMetricBuckets } from './utils';\n\n/**\n * Create envelope from a metric aggregate.\n */\nexport function createMetricEnvelope(\n metricBucketItems: Array<MetricBucketItem>,\n dsn?: DsnComponents,\n metadata?: SdkMetadata,\n tunnel?: string,\n): StatsdEnvelope {\n const headers: StatsdEnvelope[0] = {\n sent_at: new Date().toISOString(),\n };\n\n if (metadata && metadata.sdk) {\n headers.sdk = {\n name: metadata.sdk.name,\n version: metadata.sdk.version,\n };\n }\n\n if (!!tunnel && dsn) {\n headers.dsn = dsnToString(dsn);\n }\n\n const item = createMetricEnvelopeItem(metricBucketItems);\n return createEnvelope<StatsdEnvelope>(headers, [item]);\n}\n\nfunction createMetricEnvelopeItem(metricBucketItems: MetricBucketItem[]): StatsdItem {\n const payload = serializeMetricBuckets(metricBucketItems);\n const metricHeaders: StatsdItem[0] = {\n type: 'statsd',\n length: payload.length,\n };\n return [metricHeaders, payload];\n}\n"],"names":["dsnToString","createEnvelope","serializeMetricBuckets"],"mappings":";;;;;AAIA;AACA;AACA;AACO,SAAS,oBAAoB;AACpC,EAAE,iBAAiB;AACnB,EAAE,GAAG;AACL,EAAE,QAAQ;AACV,EAAE,MAAM;AACR,EAAkB;AAClB,EAAE,MAAM,OAAO,GAAsB;AACrC,IAAI,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACrC,GAAG,CAAA;AACH;AACA,EAAE,IAAI,QAAA,IAAY,QAAQ,CAAC,GAAG,EAAE;AAChC,IAAI,OAAO,CAAC,GAAA,GAAM;AAClB,MAAM,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI;AAC7B,MAAM,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO;AACnC,KAAK,CAAA;AACL,GAAE;AACF;AACA,EAAE,IAAI,CAAC,CAAC,MAAO,IAAG,GAAG,EAAE;AACvB,IAAI,OAAO,CAAC,GAAA,GAAMA,iBAAW,CAAC,GAAG,CAAC,CAAA;AAClC,GAAE;AACF;AACA,EAAE,MAAM,IAAK,GAAE,wBAAwB,CAAC,iBAAiB,CAAC,CAAA;AAC1D,EAAE,OAAOC,oBAAc,CAAiB,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;AACxD,CAAA;AACA;AACA,SAAS,wBAAwB,CAAC,iBAAiB,EAAkC;AACrF,EAAE,MAAM,OAAQ,GAAEC,8BAAsB,CAAC,iBAAiB,CAAC,CAAA;AAC3D,EAAE,MAAM,aAAa,GAAkB;AACvC,IAAI,IAAI,EAAE,QAAQ;AAClB,IAAI,MAAM,EAAE,OAAO,CAAC,MAAM;AAC1B,GAAG,CAAA;AACH,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;AACjC;;;;"}

96
node_modules/@sentry/core/cjs/metrics/exports.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
Object.defineProperty(exports, '__esModule', { value: true });
const utils = require('@sentry/utils');
const debugBuild = require('../debug-build.js');
const exports$1 = require('../exports.js');
const spanUtils = require('../utils/spanUtils.js');
const constants = require('./constants.js');
const integration = require('./integration.js');
function addToMetricsAggregator(
metricType,
name,
value,
data = {},
) {
const client = exports$1.getClient();
const scope = exports$1.getCurrentScope();
if (client) {
if (!client.metricsAggregator) {
debugBuild.DEBUG_BUILD &&
utils.logger.warn('No metrics aggregator enabled. Please add the MetricsAggregator integration to use metrics APIs');
return;
}
const { unit, tags, timestamp } = data;
const { release, environment } = client.getOptions();
// eslint-disable-next-line deprecation/deprecation
const transaction = scope.getTransaction();
const metricTags = {};
if (release) {
metricTags.release = release;
}
if (environment) {
metricTags.environment = environment;
}
if (transaction) {
metricTags.transaction = spanUtils.spanToJSON(transaction).description || '';
}
debugBuild.DEBUG_BUILD && utils.logger.log(`Adding value of ${value} to ${metricType} metric ${name}`);
client.metricsAggregator.add(metricType, name, value, unit, { ...metricTags, ...tags }, timestamp);
}
}
/**
* Adds a value to a counter metric
*
* @experimental This API is experimental and might have breaking changes in the future.
*/
function increment(name, value = 1, data) {
addToMetricsAggregator(constants.COUNTER_METRIC_TYPE, name, value, data);
}
/**
* Adds a value to a distribution metric
*
* @experimental This API is experimental and might have breaking changes in the future.
*/
function distribution(name, value, data) {
addToMetricsAggregator(constants.DISTRIBUTION_METRIC_TYPE, name, value, data);
}
/**
* Adds a value to a set metric. Value must be a string or integer.
*
* @experimental This API is experimental and might have breaking changes in the future.
*/
function set(name, value, data) {
addToMetricsAggregator(constants.SET_METRIC_TYPE, name, value, data);
}
/**
* Adds a value to a gauge metric
*
* @experimental This API is experimental and might have breaking changes in the future.
*/
function gauge(name, value, data) {
addToMetricsAggregator(constants.GAUGE_METRIC_TYPE, name, value, data);
}
const metrics = {
increment,
distribution,
set,
gauge,
/** @deprecated Use `metrics.metricsAggregratorIntegration()` instead. */
// eslint-disable-next-line deprecation/deprecation
MetricsAggregator: integration.MetricsAggregator,
metricsAggregatorIntegration: integration.metricsAggregatorIntegration,
};
exports.distribution = distribution;
exports.gauge = gauge;
exports.increment = increment;
exports.metrics = metrics;
exports.set = set;
//# sourceMappingURL=exports.js.map

1
node_modules/@sentry/core/cjs/metrics/exports.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long

129
node_modules/@sentry/core/cjs/metrics/instance.js generated vendored Normal file
View File

@@ -0,0 +1,129 @@
Object.defineProperty(exports, '__esModule', { value: true });
const constants = require('./constants.js');
const utils = require('./utils.js');
/**
* A metric instance representing a counter.
*/
class CounterMetric {
constructor( _value) {this._value = _value;}
/** @inheritDoc */
get weight() {
return 1;
}
/** @inheritdoc */
add(value) {
this._value += value;
}
/** @inheritdoc */
toString() {
return `${this._value}`;
}
}
/**
* A metric instance representing a gauge.
*/
class GaugeMetric {
constructor(value) {
this._last = value;
this._min = value;
this._max = value;
this._sum = value;
this._count = 1;
}
/** @inheritDoc */
get weight() {
return 5;
}
/** @inheritdoc */
add(value) {
this._last = value;
if (value < this._min) {
this._min = value;
}
if (value > this._max) {
this._max = value;
}
this._sum += value;
this._count++;
}
/** @inheritdoc */
toString() {
return `${this._last}:${this._min}:${this._max}:${this._sum}:${this._count}`;
}
}
/**
* A metric instance representing a distribution.
*/
class DistributionMetric {
constructor(first) {
this._value = [first];
}
/** @inheritDoc */
get weight() {
return this._value.length;
}
/** @inheritdoc */
add(value) {
this._value.push(value);
}
/** @inheritdoc */
toString() {
return this._value.join(':');
}
}
/**
* A metric instance representing a set.
*/
class SetMetric {
constructor( first) {this.first = first;
this._value = new Set([first]);
}
/** @inheritDoc */
get weight() {
return this._value.size;
}
/** @inheritdoc */
add(value) {
this._value.add(value);
}
/** @inheritdoc */
toString() {
return Array.from(this._value)
.map(val => (typeof val === 'string' ? utils.simpleHash(val) : val))
.join(':');
}
}
const METRIC_MAP = {
[constants.COUNTER_METRIC_TYPE]: CounterMetric,
[constants.GAUGE_METRIC_TYPE]: GaugeMetric,
[constants.DISTRIBUTION_METRIC_TYPE]: DistributionMetric,
[constants.SET_METRIC_TYPE]: SetMetric,
};
exports.CounterMetric = CounterMetric;
exports.DistributionMetric = DistributionMetric;
exports.GaugeMetric = GaugeMetric;
exports.METRIC_MAP = METRIC_MAP;
exports.SetMetric = SetMetric;
//# sourceMappingURL=instance.js.map

File diff suppressed because one or more lines are too long

35
node_modules/@sentry/core/cjs/metrics/integration.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
Object.defineProperty(exports, '__esModule', { value: true });
const integration = require('../integration.js');
const browserAggregator = require('./browser-aggregator.js');
const INTEGRATION_NAME = 'MetricsAggregator';
const _metricsAggregatorIntegration = (() => {
return {
name: INTEGRATION_NAME,
// TODO v8: Remove this
setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function
setup(client) {
client.metricsAggregator = new browserAggregator.BrowserMetricsAggregator(client);
},
};
}) ;
const metricsAggregatorIntegration = integration.defineIntegration(_metricsAggregatorIntegration);
/**
* Enables Sentry metrics monitoring.
*
* @experimental This API is experimental and might having breaking changes in the future.
* @deprecated Use `metricsAggegratorIntegration()` instead.
*/
// eslint-disable-next-line deprecation/deprecation
const MetricsAggregator = integration.convertIntegrationFnToClass(
INTEGRATION_NAME,
metricsAggregatorIntegration,
) ;
exports.MetricsAggregator = MetricsAggregator;
exports.metricsAggregatorIntegration = metricsAggregatorIntegration;
//# sourceMappingURL=integration.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"integration.js","sources":["../../../src/metrics/integration.ts"],"sourcesContent":["import type { Client, ClientOptions, Integration, IntegrationClass, IntegrationFn } from '@sentry/types';\nimport type { BaseClient } from '../baseclient';\nimport { convertIntegrationFnToClass, defineIntegration } from '../integration';\nimport { BrowserMetricsAggregator } from './browser-aggregator';\n\nconst INTEGRATION_NAME = 'MetricsAggregator';\n\nconst _metricsAggregatorIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n // TODO v8: Remove this\n setupOnce() {}, // eslint-disable-line @typescript-eslint/no-empty-function\n setup(client: BaseClient<ClientOptions>) {\n client.metricsAggregator = new BrowserMetricsAggregator(client);\n },\n };\n}) satisfies IntegrationFn;\n\nexport const metricsAggregatorIntegration = defineIntegration(_metricsAggregatorIntegration);\n\n/**\n * Enables Sentry metrics monitoring.\n *\n * @experimental This API is experimental and might having breaking changes in the future.\n * @deprecated Use `metricsAggegratorIntegration()` instead.\n */\n// eslint-disable-next-line deprecation/deprecation\nexport const MetricsAggregator = convertIntegrationFnToClass(\n INTEGRATION_NAME,\n metricsAggregatorIntegration,\n) as IntegrationClass<Integration & { setup: (client: Client) => void }>;\n"],"names":["BrowserMetricsAggregator","defineIntegration","convertIntegrationFnToClass"],"mappings":";;;;;AAKA,MAAM,gBAAA,GAAmB,mBAAmB,CAAA;AAC5C;AACA,MAAM,6BAA8B,IAAG,MAAM;AAC7C,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,gBAAgB;AAC1B;AACA,IAAI,SAAS,GAAG,EAAE;AAClB,IAAI,KAAK,CAAC,MAAM,EAA6B;AAC7C,MAAM,MAAM,CAAC,iBAAkB,GAAE,IAAIA,0CAAwB,CAAC,MAAM,CAAC,CAAA;AACrE,KAAK;AACL,GAAG,CAAA;AACH,CAAC,CAAE,EAAA;AACH;MACa,4BAA6B,GAAEC,6BAAiB,CAAC,6BAA6B,EAAC;AAC5F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,iBAAkB,GAAEC,uCAA2B;AAC5D,EAAE,gBAAgB;AAClB,EAAE,4BAA4B;AAC9B,CAAE;;;;;"}

View File

@@ -0,0 +1,95 @@
Object.defineProperty(exports, '__esModule', { value: true });
const utils = require('@sentry/utils');
require('../debug-build.js');
require('../tracing/errors.js');
require('../tracing/spanstatus.js');
const trace = require('../tracing/trace.js');
/**
* key: bucketKey
* value: [exportKey, MetricSummary]
*/
let SPAN_METRIC_SUMMARY;
function getMetricStorageForSpan(span) {
return SPAN_METRIC_SUMMARY ? SPAN_METRIC_SUMMARY.get(span) : undefined;
}
/**
* Fetches the metric summary if it exists for the passed span
*/
function getMetricSummaryJsonForSpan(span) {
const storage = getMetricStorageForSpan(span);
if (!storage) {
return undefined;
}
const output = {};
for (const [, [exportKey, summary]] of storage) {
if (!output[exportKey]) {
output[exportKey] = [];
}
output[exportKey].push(utils.dropUndefinedKeys(summary));
}
return output;
}
/**
* Updates the metric summary on the currently active span
*/
function updateMetricSummaryOnActiveSpan(
metricType,
sanitizedName,
value,
unit,
tags,
bucketKey,
) {
const span = trace.getActiveSpan();
if (span) {
const storage = getMetricStorageForSpan(span) || new Map();
const exportKey = `${metricType}:${sanitizedName}@${unit}`;
const bucketItem = storage.get(bucketKey);
if (bucketItem) {
const [, summary] = bucketItem;
storage.set(bucketKey, [
exportKey,
{
min: Math.min(summary.min, value),
max: Math.max(summary.max, value),
count: (summary.count += 1),
sum: (summary.sum += value),
tags: summary.tags,
},
]);
} else {
storage.set(bucketKey, [
exportKey,
{
min: value,
max: value,
count: 1,
sum: value,
tags,
},
]);
}
if (!SPAN_METRIC_SUMMARY) {
SPAN_METRIC_SUMMARY = new WeakMap();
}
SPAN_METRIC_SUMMARY.set(span, storage);
}
}
exports.getMetricSummaryJsonForSpan = getMetricSummaryJsonForSpan;
exports.updateMetricSummaryOnActiveSpan = updateMetricSummaryOnActiveSpan;
//# sourceMappingURL=metric-summary.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"metric-summary.js","sources":["../../../src/metrics/metric-summary.ts"],"sourcesContent":["import type { MeasurementUnit, Span } from '@sentry/types';\nimport type { MetricSummary } from '@sentry/types';\nimport type { Primitive } from '@sentry/types';\nimport { dropUndefinedKeys } from '@sentry/utils';\nimport { getActiveSpan } from '../tracing';\nimport type { MetricType } from './types';\n\n/**\n * key: bucketKey\n * value: [exportKey, MetricSummary]\n */\ntype MetricSummaryStorage = Map<string, [string, MetricSummary]>;\n\nlet SPAN_METRIC_SUMMARY: WeakMap<Span, MetricSummaryStorage> | undefined;\n\nfunction getMetricStorageForSpan(span: Span): MetricSummaryStorage | undefined {\n return SPAN_METRIC_SUMMARY ? SPAN_METRIC_SUMMARY.get(span) : undefined;\n}\n\n/**\n * Fetches the metric summary if it exists for the passed span\n */\nexport function getMetricSummaryJsonForSpan(span: Span): Record<string, Array<MetricSummary>> | undefined {\n const storage = getMetricStorageForSpan(span);\n\n if (!storage) {\n return undefined;\n }\n const output: Record<string, Array<MetricSummary>> = {};\n\n for (const [, [exportKey, summary]] of storage) {\n if (!output[exportKey]) {\n output[exportKey] = [];\n }\n\n output[exportKey].push(dropUndefinedKeys(summary));\n }\n\n return output;\n}\n\n/**\n * Updates the metric summary on the currently active span\n */\nexport function updateMetricSummaryOnActiveSpan(\n metricType: MetricType,\n sanitizedName: string,\n value: number,\n unit: MeasurementUnit,\n tags: Record<string, Primitive>,\n bucketKey: string,\n): void {\n const span = getActiveSpan();\n if (span) {\n const storage = getMetricStorageForSpan(span) || new Map<string, [string, MetricSummary]>();\n\n const exportKey = `${metricType}:${sanitizedName}@${unit}`;\n const bucketItem = storage.get(bucketKey);\n\n if (bucketItem) {\n const [, summary] = bucketItem;\n storage.set(bucketKey, [\n exportKey,\n {\n min: Math.min(summary.min, value),\n max: Math.max(summary.max, value),\n count: (summary.count += 1),\n sum: (summary.sum += value),\n tags: summary.tags,\n },\n ]);\n } else {\n storage.set(bucketKey, [\n exportKey,\n {\n min: value,\n max: value,\n count: 1,\n sum: value,\n tags,\n },\n ]);\n }\n\n if (!SPAN_METRIC_SUMMARY) {\n SPAN_METRIC_SUMMARY = new WeakMap();\n }\n\n SPAN_METRIC_SUMMARY.set(span, storage);\n }\n}\n"],"names":["dropUndefinedKeys","getActiveSpan"],"mappings":";;;;;;;;AAOA;AACA;AACA;AACA;;AAGA,IAAI,mBAAmB,CAAA;AACvB;AACA,SAAS,uBAAuB,CAAC,IAAI,EAA0C;AAC/E,EAAE,OAAO,mBAAoB,GAAE,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAE,GAAE,SAAS,CAAA;AACxE,CAAA;AACA;AACA;AACA;AACA;AACO,SAAS,2BAA2B,CAAC,IAAI,EAA0D;AAC1G,EAAE,MAAM,OAAQ,GAAE,uBAAuB,CAAC,IAAI,CAAC,CAAA;AAC/C;AACA,EAAE,IAAI,CAAC,OAAO,EAAE;AAChB,IAAI,OAAO,SAAS,CAAA;AACpB,GAAE;AACF,EAAE,MAAM,MAAM,GAAyC,EAAE,CAAA;AACzD;AACA,EAAE,KAAK,MAAM,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAE,IAAG,OAAO,EAAE;AAClD,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE;AAC5B,MAAM,MAAM,CAAC,SAAS,CAAE,GAAE,EAAE,CAAA;AAC5B,KAAI;AACJ;AACA,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAACA,uBAAiB,CAAC,OAAO,CAAC,CAAC,CAAA;AACtD,GAAE;AACF;AACA,EAAE,OAAO,MAAM,CAAA;AACf,CAAA;AACA;AACA;AACA;AACA;AACO,SAAS,+BAA+B;AAC/C,EAAE,UAAU;AACZ,EAAE,aAAa;AACf,EAAE,KAAK;AACP,EAAE,IAAI;AACN,EAAE,IAAI;AACN,EAAE,SAAS;AACX,EAAQ;AACR,EAAE,MAAM,IAAA,GAAOC,mBAAa,EAAE,CAAA;AAC9B,EAAE,IAAI,IAAI,EAAE;AACZ,IAAI,MAAM,OAAQ,GAAE,uBAAuB,CAAC,IAAI,CAAA,IAAK,IAAI,GAAG,EAAmC,CAAA;AAC/F;AACA,IAAI,MAAM,SAAA,GAAY,CAAC,EAAA,UAAA,CAAA,CAAA,EAAA,aAAA,CAAA,CAAA,EAAA,IAAA,CAAA,CAAA,CAAA;AACA,IAAA,MAAA,UAAA,GAAA,OAAA,CAAA,GAAA,CAAA,SAAA,CAAA,CAAA;AACA;AACA,IAAA,IAAA,UAAA,EAAA;AACA,MAAA,MAAA,GAAA,OAAA,CAAA,GAAA,UAAA,CAAA;AACA,MAAA,OAAA,CAAA,GAAA,CAAA,SAAA,EAAA;AACA,QAAA,SAAA;AACA,QAAA;AACA,UAAA,GAAA,EAAA,IAAA,CAAA,GAAA,CAAA,OAAA,CAAA,GAAA,EAAA,KAAA,CAAA;AACA,UAAA,GAAA,EAAA,IAAA,CAAA,GAAA,CAAA,OAAA,CAAA,GAAA,EAAA,KAAA,CAAA;AACA,UAAA,KAAA,GAAA,OAAA,CAAA,KAAA,IAAA,CAAA,CAAA;AACA,UAAA,GAAA,GAAA,OAAA,CAAA,GAAA,IAAA,KAAA,CAAA;AACA,UAAA,IAAA,EAAA,OAAA,CAAA,IAAA;AACA,SAAA;AACA,OAAA,CAAA,CAAA;AACA,KAAA,MAAA;AACA,MAAA,OAAA,CAAA,GAAA,CAAA,SAAA,EAAA;AACA,QAAA,SAAA;AACA,QAAA;AACA,UAAA,GAAA,EAAA,KAAA;AACA,UAAA,GAAA,EAAA,KAAA;AACA,UAAA,KAAA,EAAA,CAAA;AACA,UAAA,GAAA,EAAA,KAAA;AACA,UAAA,IAAA;AACA,SAAA;AACA,OAAA,CAAA,CAAA;AACA,KAAA;AACA;AACA,IAAA,IAAA,CAAA,mBAAA,EAAA;AACA,MAAA,mBAAA,GAAA,IAAA,OAAA,EAAA,CAAA;AACA,KAAA;AACA;AACA,IAAA,mBAAA,CAAA,GAAA,CAAA,IAAA,EAAA,OAAA,CAAA,CAAA;AACA,GAAA;AACA;;;;;"}

113
node_modules/@sentry/core/cjs/metrics/utils.js generated vendored Normal file
View File

@@ -0,0 +1,113 @@
Object.defineProperty(exports, '__esModule', { value: true });
const utils = require('@sentry/utils');
/**
* Generate bucket key from metric properties.
*/
function getBucketKey(
metricType,
name,
unit,
tags,
) {
const stringifiedTags = Object.entries(utils.dropUndefinedKeys(tags)).sort((a, b) => a[0].localeCompare(b[0]));
return `${metricType}${name}${unit}${stringifiedTags}`;
}
/* eslint-disable no-bitwise */
/**
* Simple hash function for strings.
*/
function simpleHash(s) {
let rv = 0;
for (let i = 0; i < s.length; i++) {
const c = s.charCodeAt(i);
rv = (rv << 5) - rv + c;
rv &= rv;
}
return rv >>> 0;
}
/* eslint-enable no-bitwise */
/**
* Serialize metrics buckets into a string based on statsd format.
*
* Example of format:
* metric.name@second:1:1.2|d|#a:value,b:anothervalue|T12345677
* Segments:
* name: metric.name
* unit: second
* value: [1, 1.2]
* type of metric: d (distribution)
* tags: { a: value, b: anothervalue }
* timestamp: 12345677
*/
function serializeMetricBuckets(metricBucketItems) {
let out = '';
for (const item of metricBucketItems) {
const tagEntries = Object.entries(item.tags);
const maybeTags = tagEntries.length > 0 ? `|#${tagEntries.map(([key, value]) => `${key}:${value}`).join(',')}` : '';
out += `${item.name}@${item.unit}:${item.metric}|${item.metricType}${maybeTags}|T${item.timestamp}\n`;
}
return out;
}
/** Sanitizes units */
function sanitizeUnit(unit) {
return unit.replace(/[^\w]+/gi, '_');
}
/** Sanitizes metric keys */
function sanitizeMetricKey(key) {
return key.replace(/[^\w\-.]+/gi, '_');
}
function sanitizeTagKey(key) {
return key.replace(/[^\w\-./]+/gi, '');
}
const tagValueReplacements = [
['\n', '\\n'],
['\r', '\\r'],
['\t', '\\t'],
['\\', '\\\\'],
['|', '\\u{7c}'],
[',', '\\u{2c}'],
];
function getCharOrReplacement(input) {
for (const [search, replacement] of tagValueReplacements) {
if (input === search) {
return replacement;
}
}
return input;
}
function sanitizeTagValue(value) {
return [...value].reduce((acc, char) => acc + getCharOrReplacement(char), '');
}
/**
* Sanitizes tags.
*/
function sanitizeTags(unsanitizedTags) {
const tags = {};
for (const key in unsanitizedTags) {
if (Object.prototype.hasOwnProperty.call(unsanitizedTags, key)) {
const sanitizedKey = sanitizeTagKey(key);
tags[sanitizedKey] = sanitizeTagValue(String(unsanitizedTags[key]));
}
}
return tags;
}
exports.getBucketKey = getBucketKey;
exports.sanitizeMetricKey = sanitizeMetricKey;
exports.sanitizeTags = sanitizeTags;
exports.sanitizeUnit = sanitizeUnit;
exports.serializeMetricBuckets = serializeMetricBuckets;
exports.simpleHash = simpleHash;
//# sourceMappingURL=utils.js.map

1
node_modules/@sentry/core/cjs/metrics/utils.js.map generated vendored Normal file

File diff suppressed because one or more lines are too long