Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bugsnag/core-performance

Package Overview
Dependencies
Maintainers
10
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bugsnag/core-performance - npm Package Compare versions

Comparing version 0.0.2 to 0.1.0-alpha.0

dist/probability-fetcher.js

4

dist/attributes.js

@@ -0,1 +1,3 @@

import { isNumber } from './validation.js';
class SpanAttributes {

@@ -6,3 +8,3 @@ constructor(initialValues) {

set(name, value) {
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
if (typeof value === 'string' || typeof value === 'boolean' || isNumber(value)) {
this.attributes.set(name, value);

@@ -9,0 +11,0 @@ }

import { spanToJson } from './span.js';
class BatchProcessor {
constructor(delivery, configuration, resourceAttributeSource, clock, retryQueue, sampler) {
constructor(delivery, configuration, resourceAttributeSource, clock, retryQueue, sampler, probabilityManager) {
this.batch = [];
this.timeout = null;
this.delivery = delivery;

@@ -11,4 +13,3 @@ this.configuration = configuration;

this.sampler = sampler;
this.batch = [];
this.timeout = null;
this.probabilityManager = probabilityManager;
this.flush = this.flush.bind(this);

@@ -46,2 +47,3 @@ }

}
const resourceAttributes = await this.resourceAttributeSource(this.configuration);
const payload = {

@@ -51,3 +53,3 @@ resourceSpans: [

resource: {
attributes: this.resourceAttributeSource(this.configuration).toJson()
attributes: resourceAttributes.toJson()
},

@@ -62,3 +64,3 @@ scopeSpans: [{ spans: batch }]

if (response.samplingProbability !== undefined) {
this.sampler.probability = response.samplingProbability;
this.probabilityManager.setProbability(response.samplingProbability);
}

@@ -65,0 +67,0 @@ switch (response.state) {

@@ -1,2 +0,2 @@

import { isStringWithLength, isString, isLogger, isStringArray, isObject } from './validation.js';
import { isStringWithLength, isString, isLogger, isStringArray, isNumber, isObject } from './validation.js';

@@ -42,3 +42,3 @@ const schema = {

message: 'should be a number between 0 and 1',
validate: (value) => typeof value === 'number' && value >= 0 && value <= 1
validate: (value) => isNumber(value) && value >= 0 && value <= 1
}

@@ -45,0 +45,0 @@ };

import { BatchProcessor } from './batch-processor.js';
import { validateConfig } from './config.js';
import ProbabilityFetcher from './probability-fetcher.js';
import ProbabilityManager from './probability-manager.js';
import { BufferingProcessor } from './processor.js';
import { InMemoryQueue } from './retry-queue.js';
import Sampler from './sampler.js';
import { SpanFactory } from './span.js';
import { timeToNumber } from './time.js';
import { DefaultSpanContextStorage } from './span-context.js';
import { SpanFactory } from './span-factory.js';

@@ -12,4 +14,5 @@ function createClient(options) {

let processor = bufferingProcessor;
const spanContextStorage = options.spanContextStorage || new DefaultSpanContextStorage(options.backgroundingListener);
const sampler = new Sampler(1.0);
const spanFactory = new SpanFactory(processor, sampler, options.idGenerator, options.spanAttributesSource, options.clock, options.backgroundingListener);
const spanFactory = new SpanFactory(processor, sampler, options.idGenerator, options.spanAttributesSource, options.clock, options.backgroundingListener, options.schema.logger.defaultValue, spanContextStorage);
const plugins = options.plugins(spanFactory);

@@ -20,16 +23,17 @@ return {

const delivery = options.deliveryFactory(configuration.apiKey, configuration.endpoint);
sampler.initialise(configuration.samplingProbability, delivery);
processor = new BatchProcessor(delivery, configuration, options.resourceAttributesSource, options.clock, new InMemoryQueue(delivery, configuration.retryQueueMaxSize), sampler);
// ensure all spans started before .start() are added to the batch
bufferingProcessor.spans.forEach(span => {
processor.add(span);
ProbabilityManager.create(options.persistence, sampler, new ProbabilityFetcher(delivery)).then((manager) => {
processor = new BatchProcessor(delivery, configuration, options.resourceAttributesSource, options.clock, new InMemoryQueue(delivery, configuration.retryQueueMaxSize), sampler, manager);
// ensure all spans started before .start() are added to the batch
for (const span of bufferingProcessor.spans) {
processor.add(span);
}
// register with the backgrounding listener - we do this in 'start' as
// there's nothing to do if we're backgrounded before start is called
// e.g. we can't trigger delivery until we have the apiKey and endpoint
// from configuration
options.backgroundingListener.onStateChange(state => {
processor.flush();
});
spanFactory.configure(processor, configuration.logger);
});
// register with the backgrounding listener - we do this in 'start' as
// there's nothing to do if we're backgrounded before start is called
// e.g. we can't trigger delivery until we have the apiKey and endpoint
// from configuration
options.backgroundingListener.onStateChange(state => {
processor.flush();
});
spanFactory.updateProcessor(processor);
for (const plugin of plugins) {

@@ -41,8 +45,6 @@ plugin.configure(configuration);

const span = spanFactory.startSpan(name, spanOptions);
return {
end: (endTime) => {
const safeEndTime = timeToNumber(options.clock, endTime);
spanFactory.endSpan(span, safeEndTime);
}
};
return spanFactory.toPublicApi(span);
},
get currentSpanContext() {
return spanContextStorage.current;
}

@@ -55,3 +57,4 @@ };

start: noop,
startSpan: () => ({ end: noop })
startSpan: () => ({ id: '', traceId: '', end: noop, isValid: () => false }),
currentSpanContext: undefined
};

@@ -58,0 +61,0 @@ }

@@ -10,5 +10,7 @@ export { ResourceAttributes, SpanAttributes, attributeToJson } from './attributes.js';

export { InMemoryQueue } from './retry-queue.js';
export { SpanFactory, SpanInternal, spanToJson } from './span.js';
export { SpanInternal, spanToJson } from './span.js';
export { DefaultSpanContextStorage, spanContextEquals } from './span-context.js';
export { SpanFactory } from './span-factory.js';
export { timeToNumber } from './time.js';
export { isLogger, isObject, isPersistedProbabilty, isString, isStringArray, isStringOrRegExpArray, isStringWithLength } from './validation.js';
export { isBoolean, isLogger, isNumber, isObject, isPersistedProbabilty, isSpanContext, isString, isStringArray, isStringOrRegExpArray, isStringWithLength } from './validation.js';
export { default as traceIdToSamplingRate } from './trace-id-to-sampling-rate.js';

@@ -1,3 +0,1 @@

const PROBABILITY_REFRESH_INTERVAL = 24 * 60 * 60000; // 24 hours in ms
const PROBABILITY_REFRESH_RETRY_INTERVAL = 30000; // 30 seconds
// sampling rates are stored as a number between 0 and 2^32 - 1 (i.e. they are

@@ -11,22 +9,2 @@ // u32s) so we need to scale the probability value to match this range as they

constructor(initialProbability) {
this.fetchSamplingProbability = async () => {
if (!this.delivery)
return;
try {
const payload = { resourceSpans: [] };
const response = await this.delivery.send(payload);
// if the response doesn't contain a valid probability
// or the request failed, retry in 30 seconds
if (response.samplingProbability !== undefined) {
this.probability = response.samplingProbability;
}
else {
this.resetTimer(true);
}
}
catch (err) {
// request failed - retry
this.resetTimer(true);
}
};
// we could just do 'this.probability = initialProbability' but TypeScript

@@ -47,4 +25,2 @@ // doesn't like that as it doesn't directly initialise these properties in

this.scaledProbability = scaleProbabilityToMatchSamplingRate(probability);
// reset the timer whenever we receive a new probability value
this.resetTimer();
}

@@ -63,21 +39,7 @@ /**

}
initialise(configuredProbability, delivery) {
this._probability = configuredProbability;
this.scaledProbability = scaleProbabilityToMatchSamplingRate(configuredProbability);
this.delivery = delivery;
// make an initial request for the probability value
// when this completes a timer will be setup to make periodic requests
this.fetchSamplingProbability();
}
sample(span) {
return span.samplingRate <= span.samplingProbability;
}
resetTimer(isRetry = false) {
if (this.interval) {
clearInterval(this.interval);
}
this.interval = setInterval(this.fetchSamplingProbability, isRetry ? PROBABILITY_REFRESH_RETRY_INTERVAL : PROBABILITY_REFRESH_INTERVAL);
}
}
export { Sampler as default };

@@ -1,4 +0,2 @@

import { SpanAttributes } from './attributes.js';
import { SpanEvents } from './events.js';
import { timeToNumber } from './time.js';
import traceIdToSamplingRate from './trace-id-to-sampling-rate.js';

@@ -12,2 +10,3 @@

traceId: span.traceId,
parentSpanId: span.parentSpanId,
startTimeUnixNano: clock.toUnixTimestampNanoseconds(span.startTime),

@@ -20,3 +19,3 @@ endTimeUnixNano: clock.toUnixTimestampNanoseconds(span.endTime),

class SpanInternal {
constructor(id, traceId, name, startTime, attributes) {
constructor(id, traceId, name, startTime, attributes, parentSpanId) {
this.kind = 3 /* Kind.Client */; // TODO: How do we define the initial Kind?

@@ -26,2 +25,3 @@ this.events = new SpanEvents();

this.traceId = traceId;
this.parentSpanId = parentSpanId;
this.name = name;

@@ -39,2 +39,3 @@ this.startTime = startTime;

end(endTime, samplingProbability) {
this.endTime = endTime;
return {

@@ -50,50 +51,11 @@ id: this.id,

endTime,
samplingProbability
samplingProbability,
parentSpanId: this.parentSpanId
};
}
}
class SpanFactory {
constructor(processor, sampler, idGenerator, spanAttributesSource, clock, backgroundingListener) {
this.openSpans = new WeakSet();
this.isInForeground = true;
this.onBackgroundStateChange = (state) => {
this.isInForeground = state === 'in-foreground';
// clear all open spans regardless of the new background state
// since spans are only valid if they start and end while the app is in the foreground
this.openSpans = new WeakSet();
};
this.processor = processor;
this.sampler = sampler;
this.idGenerator = idGenerator;
this.spanAttributesSource = spanAttributesSource;
this.clock = clock;
// this will fire immediately if the app is already backgrounded
backgroundingListener.onStateChange(this.onBackgroundStateChange);
isValid() {
return this.endTime === undefined;
}
startSpan(name, options = {}) {
const safeStartTime = timeToNumber(this.clock, options ? options.startTime : undefined);
const spanId = this.idGenerator.generate(64);
const traceId = this.idGenerator.generate(128);
const attributes = new SpanAttributes(this.spanAttributesSource());
const span = new SpanInternal(spanId, traceId, name, safeStartTime, attributes);
// don't track spans that are started while the app is backgrounded
if (this.isInForeground) {
this.openSpans.add(span);
}
return span;
}
updateProcessor(processor) {
this.processor = processor;
}
endSpan(span, endTime) {
// if the span doesn't exist here it shouldn't be processed
if (!this.openSpans.delete(span))
return;
const spanEnded = span.end(endTime, this.sampler.spanProbability);
if (this.sampler.sample(spanEnded)) {
this.processor.add(spanEnded);
}
}
}
export { SpanFactory, SpanInternal, spanToJson };
export { SpanInternal, spanToJson };

@@ -0,3 +1,5 @@

import { isNumber } from './validation.js';
function timeToNumber(clock, time) {
if (typeof time === 'number') {
if (isNumber(time)) {
// no need to change anything - we want to store numbers anyway

@@ -4,0 +6,0 @@ // we assume this is nanosecond precision

@@ -14,3 +14,3 @@ import { type InternalConfiguration, type Configuration } from './config';

}
export type ResourceAttributeSource<C extends Configuration> = (configuration: InternalConfiguration<C>) => ResourceAttributes;
export type ResourceAttributeSource<C extends Configuration> = (configuration: InternalConfiguration<C>) => Promise<ResourceAttributes>;
export interface JsonAttribute {

@@ -17,0 +17,0 @@ key: string;

@@ -6,15 +6,18 @@ import { type ResourceAttributeSource } from './attributes';

import { type Processor } from './processor';
import type ProbabilityManager from './probability-manager';
import { type RetryQueue } from './retry-queue';
import type Sampler from './sampler';
import { type ReadonlySampler } from './sampler';
import { type SpanEnded } from './span';
type MinimalProbabilityManager = Pick<ProbabilityManager, 'setProbability'>;
export declare class BatchProcessor<C extends Configuration> implements Processor {
private delivery;
private configuration;
private resourceAttributeSource;
private clock;
private retryQueue;
private sampler;
private readonly delivery;
private readonly configuration;
private readonly resourceAttributeSource;
private readonly clock;
private readonly retryQueue;
private readonly sampler;
private readonly probabilityManager;
private batch;
private timeout;
constructor(delivery: Delivery, configuration: InternalConfiguration<C>, resourceAttributeSource: ResourceAttributeSource<C>, clock: Clock, retryQueue: RetryQueue, sampler: Sampler);
constructor(delivery: Delivery, configuration: InternalConfiguration<C>, resourceAttributeSource: ResourceAttributeSource<C>, clock: Clock, retryQueue: RetryQueue, sampler: ReadonlySampler, probabilityManager: MinimalProbabilityManager);
private stop;

@@ -26,2 +29,3 @@ private start;

}
export {};
//# sourceMappingURL=batch-processor.d.ts.map

@@ -7,7 +7,11 @@ import { type ResourceAttributeSource, type SpanAttributesSource } from './attributes';

import { type IdGenerator } from './id-generator';
import { type Persistence } from './persistence';
import { type Plugin } from './plugin';
import { SpanFactory, type Span, type SpanOptions } from './span';
import { type Span, type SpanOptions } from './span';
import { type SpanContext, type SpanContextStorage } from './span-context';
import { SpanFactory } from './span-factory';
export interface BugsnagPerformance<C extends Configuration> {
start: (config: C | string) => void;
startSpan: (name: string, options?: SpanOptions) => Span;
readonly currentSpanContext: SpanContext | undefined;
}

@@ -23,2 +27,4 @@ export interface ClientOptions<S extends CoreSchema, C extends Configuration> {

plugins: (spanFactory: SpanFactory) => Array<Plugin<C>>;
persistence: Persistence;
spanContextStorage?: SpanContextStorage;
}

@@ -25,0 +31,0 @@ export declare function createClient<S extends CoreSchema, C extends Configuration>(options: ClientOptions<S, C>): BugsnagPerformance<C>;

@@ -31,2 +31,3 @@ import { type JsonAttribute } from './attributes';

traceId: string;
parentSpanId?: string;
startTimeUnixNano: string;

@@ -33,0 +34,0 @@ endTimeUnixNano: string;

@@ -14,2 +14,4 @@ export * from './attributes';

export * from './span';
export * from './span-context';
export * from './span-factory';
export * from './time';

@@ -16,0 +18,0 @@ export * from './validation';

@@ -7,2 +7,3 @@ export interface PersistedProbability {

'bugsnag-sampling-probability': PersistedProbability;
'bugsnag-anonymous-id': string;
}

@@ -9,0 +10,0 @@ export type PersistenceKey = keyof PersistencePayloadMap;

@@ -1,7 +0,12 @@

import { type Delivery } from './delivery';
import { type SpanEnded, type SpanProbability } from './span';
interface ReadonlySampler {
readonly probability: number;
readonly spanProbability: SpanProbability;
readonly sample: (span: SpanEnded) => boolean;
}
interface ReadWriteSampler extends ReadonlySampler {
probability: number;
}
declare class Sampler {
private _probability;
private delivery?;
private interval?;
/**

@@ -29,8 +34,6 @@ * The current probability scaled to match sampling rate

get spanProbability(): SpanProbability;
initialise(configuredProbability: number, delivery: Delivery): void;
sample(span: SpanEnded): boolean;
private fetchSamplingProbability;
private resetTimer;
}
export default Sampler;
export { type ReadonlySampler, type ReadWriteSampler };
//# sourceMappingURL=sampler.d.ts.map

@@ -1,11 +0,8 @@

import { SpanAttributes, type SpanAttribute, type SpanAttributesSource } from './attributes';
import { type BackgroundingListener } from './backgrounding-listener';
import { type SpanAttribute, type SpanAttributes } from './attributes';
import { type Clock } from './clock';
import { type DeliverySpan } from './delivery';
import { SpanEvents } from './events';
import { type IdGenerator } from './id-generator';
import { type Processor } from './processor';
import type Sampler from './sampler';
import { type SpanContext } from './span-context';
import { type Time } from './time';
export interface Span {
export interface Span extends SpanContext {
end: (endTime?: Time) => void;

@@ -36,7 +33,9 @@ }

samplingProbability: SpanProbability;
readonly parentSpanId?: string;
}
export declare function spanToJson(span: SpanEnded, clock: Clock): DeliverySpan;
export declare class SpanInternal {
private readonly id;
private readonly traceId;
export declare class SpanInternal implements SpanContext {
readonly id: string;
readonly traceId: string;
private readonly parentSpanId?;
private readonly startTime;

@@ -47,26 +46,17 @@ private readonly samplingRate;

private readonly attributes;
private readonly name;
constructor(id: string, traceId: string, name: string, startTime: number, attributes: SpanAttributes);
name: string;
private endTime?;
constructor(id: string, traceId: string, name: string, startTime: number, attributes: SpanAttributes, parentSpanId?: string);
addEvent(name: string, time: number): void;
setAttribute(name: string, value: SpanAttribute): void;
end(endTime: number, samplingProbability: SpanProbability): SpanEnded;
isValid(): boolean;
}
export interface SpanOptions {
startTime?: Time;
makeCurrentContext?: boolean;
parentContext?: SpanContext | null;
isFirstClass?: boolean;
}
export declare class SpanFactory {
private readonly idGenerator;
private readonly spanAttributesSource;
private processor;
private readonly sampler;
private readonly clock;
private openSpans;
private isInForeground;
constructor(processor: Processor, sampler: Sampler, idGenerator: IdGenerator, spanAttributesSource: SpanAttributesSource, clock: Clock, backgroundingListener: BackgroundingListener);
private onBackgroundStateChange;
startSpan(name: string, options?: SpanOptions): SpanInternal;
updateProcessor(processor: Processor): void;
endSpan(span: SpanInternal, endTime: number): void;
}
export {};
//# sourceMappingURL=span.d.ts.map
import { type Logger } from './config';
import { type PersistedProbability } from './persistence';
import { type SpanContext } from './span-context';
export declare const isBoolean: (value: unknown) => value is boolean;
export declare const isObject: (value: unknown) => value is Record<string, unknown>;
export declare const isNumber: (value: unknown) => value is number;
export declare const isString: (value: unknown) => value is string;

@@ -10,2 +13,3 @@ export declare const isStringWithLength: (value: unknown) => value is string;

export declare function isPersistedProbabilty(value: unknown): value is PersistedProbability;
export declare const isSpanContext: (value: unknown) => value is SpanContext;
//# sourceMappingURL=validation.d.ts.map

@@ -0,2 +1,4 @@

const isBoolean = (value) => value === true || value === false;
const isObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value);
const isNumber = (value) => typeof value === 'number' && Number.isFinite(value) && !Number.isNaN(value);
const isString = (value) => typeof value === 'string';

@@ -13,6 +15,10 @@ const isStringWithLength = (value) => isString(value) && value.length > 0;

return isObject(value) &&
typeof value.value === 'number' &&
typeof value.time === 'number';
isNumber(value.value) &&
isNumber(value.time);
}
const isSpanContext = (value) => isObject(value) &&
typeof value.id === 'string' &&
typeof value.traceId === 'string' &&
typeof value.isValid === 'function';
export { isLogger, isObject, isPersistedProbabilty, isString, isStringArray, isStringOrRegExpArray, isStringWithLength };
export { isBoolean, isLogger, isNumber, isObject, isPersistedProbabilty, isSpanContext, isString, isStringArray, isStringOrRegExpArray, isStringWithLength };
{
"name": "@bugsnag/core-performance",
"version": "0.0.2",
"version": "0.1.0-alpha.0",
"description": "Core performance client",

@@ -23,2 +23,3 @@ "keywords": [

"build": "rollup --config",
"build:cdn": "npm run build",
"clean": "rm -rf dist/*"

@@ -35,3 +36,3 @@ },

],
"gitHead": "339a055dca4f3fcc17d9d6b4d2a73434495228d5"
"gitHead": "e9a704d8984c0402e41e73510095b4f5708967e4"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc