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

@opentelemetry/metrics

Package Overview
Dependencies
Maintainers
5
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@opentelemetry/metrics - npm Package Compare versions

Comparing version 0.4.0 to 0.5.0

build/src/ObserverResult.d.ts

55

build/src/BoundInstrument.d.ts

@@ -17,3 +17,3 @@ /*!

import * as types from '@opentelemetry/api';
import { TimeSeries } from './export/types';
import { Aggregator } from './export/types';
/**

@@ -24,12 +24,12 @@ * This class represent the base to BoundInstrument, which is responsible for generating

export declare class BaseBoundInstrument {
protected _data: number;
private readonly _disabled;
private readonly _valueType;
private readonly _aggregator;
protected _labelSet: types.LabelSet;
constructor(labelSet: types.LabelSet);
/**
* Returns the TimeSeries with one or more Point.
*
* @param timestamp The time at which the instrument is recorded.
* @returns The TimeSeries.
*/
getTimeSeries(timestamp: types.HrTime): TimeSeries;
protected _logger: types.Logger;
protected _monotonic: boolean;
constructor(labelSet: types.LabelSet, logger: types.Logger, monotonic: boolean, _disabled: boolean, _valueType: types.ValueType, _aggregator: Aggregator);
update(value: number): void;
getLabelSet(): types.LabelSet;
getAggregator(): Aggregator;
}

@@ -41,34 +41,19 @@ /**

export declare class BoundCounter extends BaseBoundInstrument implements types.BoundCounter {
private readonly _disabled;
private readonly _monotonic;
private readonly _valueType;
private readonly _logger;
private readonly _onUpdate;
constructor(labelSet: types.LabelSet, _disabled: boolean, _monotonic: boolean, _valueType: types.ValueType, _logger: types.Logger, _onUpdate: Function);
constructor(labelSet: types.LabelSet, disabled: boolean, monotonic: boolean, valueType: types.ValueType, logger: types.Logger, aggregator: Aggregator);
add(value: number): void;
}
/**
* BoundGauge allows the SDK to observe/record a single metric event. The
* value of single instrument in the `Gauge` associated with specified LabelSet.
*/
export declare class BoundGauge extends BaseBoundInstrument implements types.BoundGauge {
private readonly _disabled;
private readonly _monotonic;
private readonly _valueType;
private readonly _logger;
private readonly _onUpdate;
constructor(labelSet: types.LabelSet, _disabled: boolean, _monotonic: boolean, _valueType: types.ValueType, _logger: types.Logger, _onUpdate: Function);
set(value: number): void;
}
/**
* BoundMeasure is an implementation of the {@link BoundMeasure} interface.
*/
export declare class BoundMeasure extends BaseBoundInstrument implements types.BoundMeasure {
private readonly _disabled;
private readonly _absolute;
private readonly _valueType;
private readonly _logger;
private readonly _onUpdate;
constructor(labelSet: types.LabelSet, _disabled: boolean, _absolute: boolean, _valueType: types.ValueType, _logger: types.Logger, _onUpdate: Function);
record(value: number, distContext?: types.DistributedContext, spanContext?: types.SpanContext): void;
constructor(labelSet: types.LabelSet, disabled: boolean, monotonic: boolean, absolute: boolean, valueType: types.ValueType, logger: types.Logger, aggregator: Aggregator);
record(value: number, correlationContext?: types.CorrelationContext, spanContext?: types.SpanContext): void;
}
/**
* BoundObserver is an implementation of the {@link BoundObserver} interface.
*/
export declare class BoundObserver extends BaseBoundInstrument implements types.BoundObserver {
constructor(labelSet: types.LabelSet, disabled: boolean, monotonic: boolean, valueType: types.ValueType, logger: types.Logger, aggregator: Aggregator);
setCallback(callback: (observerResult: types.ObserverResult) => {}): void;
}

@@ -19,2 +19,3 @@ "use strict";

const types = require("@opentelemetry/api");
const ObserverResult_1 = require("./ObserverResult");
/**

@@ -25,20 +26,25 @@ * This class represent the base to BoundInstrument, which is responsible for generating

class BaseBoundInstrument {
constructor(labelSet) {
this._data = 0;
constructor(labelSet, logger, monotonic, _disabled, _valueType, _aggregator) {
this._disabled = _disabled;
this._valueType = _valueType;
this._aggregator = _aggregator;
this._labelSet = labelSet;
this._logger = logger;
this._monotonic = monotonic;
}
/**
* Returns the TimeSeries with one or more Point.
*
* @param timestamp The time at which the instrument is recorded.
* @returns The TimeSeries.
*/
getTimeSeries(timestamp) {
return {
labelValues: Object.values(this._labelSet.labels).map(value => ({
value,
})),
points: [{ value: this._data, timestamp }],
};
update(value) {
if (this._disabled)
return;
if (this._valueType === types.ValueType.INT && !Number.isInteger(value)) {
this._logger.warn(`INT value type cannot accept a floating-point value for ${Object.values(this._labelSet.labels)}, ignoring the fractional digits.`);
value = Math.trunc(value);
}
this._aggregator.update(value);
}
getLabelSet() {
return this._labelSet;
}
getAggregator() {
return this._aggregator;
}
}

@@ -51,13 +57,6 @@ exports.BaseBoundInstrument = BaseBoundInstrument;

class BoundCounter extends BaseBoundInstrument {
constructor(labelSet, _disabled, _monotonic, _valueType, _logger, _onUpdate) {
super(labelSet);
this._disabled = _disabled;
this._monotonic = _monotonic;
this._valueType = _valueType;
this._logger = _logger;
this._onUpdate = _onUpdate;
constructor(labelSet, disabled, monotonic, valueType, logger, aggregator) {
super(labelSet, logger, monotonic, disabled, valueType, aggregator);
}
add(value) {
if (this._disabled)
return;
if (this._monotonic && value < 0) {

@@ -67,8 +66,3 @@ this._logger.error(`Monotonic counter cannot descend for ${Object.values(this._labelSet.labels)}`);

}
if (this._valueType === types.ValueType.INT && !Number.isInteger(value)) {
this._logger.warn(`INT counter cannot accept a floating-point value for ${Object.values(this._labelSet.labels)}, ignoring the fractional digits.`);
value = Math.trunc(value);
}
this._data = this._data + value;
this._onUpdate();
this.update(value);
}

@@ -78,58 +72,31 @@ }

/**
* BoundGauge allows the SDK to observe/record a single metric event. The
* value of single instrument in the `Gauge` associated with specified LabelSet.
* BoundMeasure is an implementation of the {@link BoundMeasure} interface.
*/
class BoundGauge extends BaseBoundInstrument {
constructor(labelSet, _disabled, _monotonic, _valueType, _logger, _onUpdate) {
super(labelSet);
this._disabled = _disabled;
this._monotonic = _monotonic;
this._valueType = _valueType;
this._logger = _logger;
this._onUpdate = _onUpdate;
class BoundMeasure extends BaseBoundInstrument {
constructor(labelSet, disabled, monotonic, absolute, valueType, logger, aggregator) {
super(labelSet, logger, monotonic, disabled, valueType, aggregator);
this._absolute = absolute;
}
set(value) {
if (this._disabled)
record(value, correlationContext, spanContext) {
if (this._absolute && value < 0) {
this._logger.error(`Absolute measure cannot contain negative values for ${Object.values(this._labelSet.labels)}}`);
return;
if (this._monotonic && value < this._data) {
this._logger.error(`Monotonic gauge cannot descend for ${Object.values(this._labelSet.labels)}`);
return;
}
if (this._valueType === types.ValueType.INT && !Number.isInteger(value)) {
this._logger.warn(`INT gauge cannot accept a floating-point value for ${Object.values(this._labelSet.labels)}, ignoring the fractional digits.`);
value = Math.trunc(value);
}
this._data = value;
this._onUpdate();
this.update(value);
}
}
exports.BoundGauge = BoundGauge;
exports.BoundMeasure = BoundMeasure;
/**
* BoundMeasure is an implementation of the {@link BoundMeasure} interface.
* BoundObserver is an implementation of the {@link BoundObserver} interface.
*/
class BoundMeasure extends BaseBoundInstrument {
constructor(labelSet, _disabled, _absolute, _valueType, _logger, _onUpdate) {
super(labelSet);
this._disabled = _disabled;
this._absolute = _absolute;
this._valueType = _valueType;
this._logger = _logger;
this._onUpdate = _onUpdate;
class BoundObserver extends BaseBoundInstrument {
constructor(labelSet, disabled, monotonic, valueType, logger, aggregator) {
super(labelSet, logger, monotonic, disabled, valueType, aggregator);
}
record(value, distContext, spanContext) {
if (this._disabled)
return;
if (this._absolute && value < 0) {
this._logger.error(`Absolute measure cannot contain negative values for ${Object.values(this._labelSet.labels)}}`);
return;
}
if (this._valueType === types.ValueType.INT && !Number.isInteger(value)) {
this._logger.warn(`INT measure cannot accept a floating-point value for ${Object.values(this._labelSet.labels)}; truncating the value.`);
value = Math.trunc(value);
}
//@todo: implement this._data logic
this._onUpdate();
setCallback(callback) {
const observerResult = new ObserverResult_1.ObserverResult();
callback(observerResult);
}
}
exports.BoundMeasure = BoundMeasure;
exports.BoundObserver = BoundObserver;
//# sourceMappingURL=BoundInstrument.js.map

@@ -16,13 +16,3 @@ /*!

*/
import { Distribution, Sum, LastValue } from './types';
/**
* Base interface for aggregators. Aggregators are responsible for holding
* aggregated values and taking a snapshot of these values upon export.
*/
export interface Aggregator {
/** Updates the current with the new value. */
update(value: number): void;
/** Returns snapshot of the current value. */
value(): Sum | LastValue | Distribution;
}
import { Aggregator, Distribution, LastValue, Sum } from './types';
/** Basic aggregator which calculates a Sum from individual measurements. */

@@ -34,6 +24,5 @@ export declare class CounterSumAggregator implements Aggregator {

}
/** Basic aggregator which keeps the last recorded value and timestamp. */
export declare class GaugeAggregator implements Aggregator {
/** Basic aggregator for Observer which keeps the last recorded value. */
export declare class ObserverAggregator implements Aggregator {
private _current;
private _timestamp;
update(value: number): void;

@@ -40,0 +29,0 @@ value(): LastValue;

@@ -18,3 +18,2 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const core_1 = require("@opentelemetry/core");
/** Basic aggregator which calculates a Sum from individual measurements. */

@@ -33,20 +32,15 @@ class CounterSumAggregator {

exports.CounterSumAggregator = CounterSumAggregator;
/** Basic aggregator which keeps the last recorded value and timestamp. */
class GaugeAggregator {
/** Basic aggregator for Observer which keeps the last recorded value. */
class ObserverAggregator {
constructor() {
this._current = 0;
this._timestamp = core_1.hrTime();
}
update(value) {
this._current = value;
this._timestamp = core_1.hrTime();
}
value() {
return {
value: this._current,
timestamp: this._timestamp,
};
return this._current;
}
}
exports.GaugeAggregator = GaugeAggregator;
exports.ObserverAggregator = ObserverAggregator;
/** Basic aggregator keeping all raw values (events, sum, max and min). */

@@ -53,0 +47,0 @@ class MeasureExactAggregator {

@@ -16,4 +16,3 @@ /*!

*/
import { Aggregator } from './Aggregator';
import { MetricRecord, MetricKind } from './types';
import { MetricRecord, MetricKind, Aggregator } from './types';
/**

@@ -20,0 +19,0 @@ * Base class for all batcher types.

@@ -45,4 +45,4 @@ "use strict";

return new Aggregator_1.CounterSumAggregator();
case types_1.MetricKind.GAUGE:
return new Aggregator_1.GaugeAggregator();
case types_1.MetricKind.OBSERVER:
return new Aggregator_1.ObserverAggregator();
default:

@@ -49,0 +49,0 @@ return new Aggregator_1.MeasureExactAggregator();

@@ -16,3 +16,3 @@ /*!

*/
import { MetricExporter, ReadableMetric } from './types';
import { MetricExporter, MetricRecord } from './types';
import { ExportResult } from '@opentelemetry/base';

@@ -24,4 +24,4 @@ /**

export declare class ConsoleMetricExporter implements MetricExporter {
export(metrics: ReadableMetric[], resultCallback: (result: ExportResult) => void): void;
export(metrics: MetricRecord[], resultCallback: (result: ExportResult) => void): void;
shutdown(): void;
}

@@ -18,2 +18,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("./types");
const base_1 = require("@opentelemetry/base");

@@ -27,15 +28,20 @@ /**

for (const metric of metrics) {
const descriptor = metric.descriptor;
const timeseries = metric.timeseries;
console.log({
name: descriptor.name,
description: descriptor.description,
});
for (const ts of timeseries) {
const labels = descriptor.labelKeys
.map((k, i) => [k, ts.labelValues[i]])
.reduce((p, c) => (Object.assign(Object.assign({}, p), { [c[0]]: typeof c[1] === 'string' ? c[1] : c[1].value })), {});
for (const point of ts.points) {
console.log({ labels, value: point.value });
}
console.log(metric.descriptor);
console.log(metric.labels.labels);
switch (metric.descriptor.metricKind) {
case types_1.MetricKind.COUNTER:
const sum = metric.aggregator.value();
console.log('value: ' + sum);
break;
default:
const distribution = metric.aggregator.value();
console.log('min: ' +
distribution.min +
', max: ' +
distribution.max +
', count: ' +
distribution.count +
', sum: ' +
distribution.sum);
break;
}

@@ -42,0 +48,0 @@ }

@@ -16,296 +16,53 @@ /*!

*/
/**
* This is based on
* opencensus-node/packages/opencensus-core/src/metrics/export/types.ts
*
* Proto definition:
* opentelemetry-proto/opentelemetry/proto/metrics/v1/metrics.proto
*/
import { HrTime } from '@opentelemetry/api';
import { Resource, ExportResult } from '@opentelemetry/base';
export interface ReadableMetric {
/**
* The descriptor of the Metric. This is an optimization for network wire
* size, from data-model perspective a Metric contains always
* a MetricDescriptor.
* In case of a streaming RPC can be sent only
* the first time a metric is reported to save network traffic.
*/
import { ValueType } from '@opentelemetry/api';
import { ExportResult } from '@opentelemetry/base';
import { LabelSet } from '../LabelSet';
/** The kind of metric. */
export declare enum MetricKind {
COUNTER = 0,
MEASURE = 1,
OBSERVER = 2
}
/** Sum returns an aggregated sum. */
export declare type Sum = number;
/** LastValue returns last value. */
export declare type LastValue = number;
export interface Distribution {
min: number;
max: number;
count: number;
sum: number;
}
export interface MetricRecord {
readonly descriptor: MetricDescriptor;
/**
* One or more timeseries for a single metric, where each timeseries has
* one or more points.
*/
readonly timeseries: TimeSeries[];
resource?: Resource;
readonly labels: LabelSet;
readonly aggregator: Aggregator;
}
/** Properties of a Metric type and its schema */
export interface MetricDescriptor {
/** The metric type, including its DNS name prefix. It must be unique. */
readonly name: string;
/**
* A detailed description of the metric, which can be used in documentation.
*/
readonly description: string;
/**
* The unit in which the metric value is reported. Follows the format
* described by http://unitsofmeasure.org/ucum.html.
*/
readonly unit: string;
/** MetricDescriptor type */
readonly type: MetricDescriptorType;
/**
* Metric may only increase
*
* This property is not in the .proto file, but is included here because
* it is required for correct export of prometheus metrics
*/
readonly metricKind: MetricKind;
readonly valueType: ValueType;
readonly labelKeys: string[];
readonly monotonic: boolean;
/** The label keys associated with the metric descriptor. */
readonly labelKeys: string[];
}
/**
* The kind of metric. It describes how the data is reported.
*
* A gauge is an instantaneous measurement of a value.
*
* A cumulative measurement is a value accumulated over a time interval. In
* a time series, cumulative measurements should have the same start time,
* increasing values and increasing end times, until an event resets the
* cumulative value to zero and sets a new start time for the following
* points.
*/
export declare enum MetricDescriptorType {
/** Do not use this default value. */
UNSPECIFIED = 0,
/** Integer gauge. The value can go both up and down. */
GAUGE_INT64 = 1,
/** Floating point gauge. The value can go both up and down. */
GAUGE_DOUBLE = 2,
/**
* Distribution gauge measurement aka histogram.
* The count and sum can go both up and
* down. Recorded values are always >= 0.
* Used in scenarios like a snapshot of time the current items in a queue
* have spent there.
*/
GAUGE_HISTOGRAM = 3,
/**
* Integer counter measurement. The value cannot decrease, if resets
* then the start_time should also be reset.
*/
COUNTER_INT64 = 4,
/**
* Floating point counter measurement. The value cannot decrease, if
* resets then the start_time should also be reset. Recorded values are
* always >= 0.
*/
COUNTER_DOUBLE = 5,
/**
* Histogram cumulative measurement. The count and sum cannot decrease,
* if reset then the start_time should also be reset.
*/
CUMULATIVE_HISTOGRAM = 6,
/**
* Some frameworks implemented Histograms as a summary of observations
* (usually things like request durations and response sizes). While it
* also provides a total count of observations and a sum of all observed
* values, it calculates configurable percentiles over a sliding time
* window. This is not recommended, since it cannot be aggregated.
*/
SUMMARY = 7,
/**
* Integer measure. The value can be positive or negative.
*/
MEASURE_INT64 = 8,
/**
* Floating point measure. The value can be positive or negative.
*/
MEASURE_DOUBLE = 9
}
/**
* A collection of data points that describes the time-varying values
* of a metric.
*/
export interface TimeSeries {
/**
* The set of label values that uniquely identify this timeseries. Applies to
* all points. The order of label values must match that of LabelSet keys in the
* metric descriptor.
*/
readonly labelValues: LabelValue[];
/**
* The data points of this timeseries. Point.value type MUST match the
* MetricDescriptor.type.
*/
readonly points: Point[];
}
/** The LabelValue type. null value indicates an unset. */
export interface LabelValue {
/** The value for the label. */
readonly value: string | null;
}
/** A timestamped measurement. */
export interface Point {
/**
* Must be present for counter/cumulative metrics. The time when the
* cumulative value was reset to zero. The cumulative value is over the time
* interval (start_timestamp, timestamp]. If not specified, the backend can
* use the previous recorded value.
*/
readonly startTimestamp?: HrTime;
/**
* The moment when this point was recorded. Inclusive.
* If not specified, the timestamp will be decided by the backend.
*/
readonly timestamp: HrTime;
/**
* The actual point value.
* 64-bit integer or 64-bit double-precision floating-point number
* or distribution value
* or summary value. This is not recommended, since it cannot be aggregated.
*/
readonly value: number | HistogramValue | SummaryValue;
}
/**
* Histograms contains summary statistics for a population of values. It
* optionally contains a histogram representing the distribution of those
* values across a set of buckets.
*/
export interface HistogramValue {
/**
* The number of values in the population. Must be non-negative. This value
* must equal the sum of the values in bucket_counts if a histogram is
* provided.
*/
readonly count: number;
/**
* The sum of values in this population. Optional since some systems don't
* expose this. If count is zero then this field must be zero or not set
* (if not supported).
*/
readonly sum?: number;
/**
* Don't change bucket boundaries within a TimeSeries if your backend doesn't
* support this. To save network bandwidth this field can be sent only the
* first time a metric is sent when using a streaming RPC.
*/
readonly bucketOptions?: BucketOptions;
/** DistributionValue buckets */
readonly buckets: Bucket[];
}
/**
* The start_timestamp only applies to the count and sum in the SummaryValue.
*/
export interface SummaryValue {
/**
* The total number of recorded values since start_time. Optional since
* some systems don't expose this.
*/
readonly count: number;
/**
* The total sum of recorded values since start_time. Optional since some
* systems don't expose this. If count is zero then this field must be zero.
* This field must be unset if the sum is not available.
*/
readonly sum?: number;
/** Values calculated over an arbitrary time window. */
readonly snapshot?: Snapshot;
}
/**
* Properties of a BucketOptions.
* A Distribution may optionally contain a histogram of the values in the
* population. The bucket boundaries for that histogram are described by
* BucketOptions.
*
* If bucket_options has no type, then there is no histogram associated with
* the Distribution.
*/
export interface BucketOptions {
/** Bucket with explicit bounds. */
readonly explicit: Explicit;
}
/**
* Properties of an Explicit.
* Specifies a set of buckets with arbitrary upper-bounds.
* This defines size(bounds) + 1 (= N) buckets. The boundaries for bucket
* index i are:
*
* [0, bucket_bounds[i]) for i == 0
* [bucket_bounds[i-1], bucket_bounds[i]) for 0 < i < N-1
* [bucket_bounds[i-1], +infinity) for i == N-1
*/
export interface Explicit {
/** The values must be strictly increasing and > 0. */
readonly bounds: number[];
}
/** Properties of a Bucket. */
export interface Bucket {
/**
* The number of values in each bucket of the histogram, as described in
* bucket_bounds.
*/
readonly count: number;
/**
* If the distribution does not have a histogram, then omit this field.
*/
readonly exemplar?: Exemplar;
}
/**
* Exemplars are example points that may be used to annotate aggregated
* Distribution values. They are metadata that gives information about a
* particular value added to a Distribution bucket.
*/
export interface Exemplar {
/**
* Value of the exemplar point. It determines which bucket the exemplar
* belongs to.
*/
readonly value: number;
/** The observation (sampling) time of the above value. */
readonly timestamp: HrTime;
/** Contextual information about the example value. */
readonly attachments: {
[key: string]: string;
};
}
/**
* The values in this message can be reset at arbitrary unknown times, with
* the requirement that all of them are reset at the same time.
*/
export interface Snapshot {
/**
* The number of values in the snapshot. Optional since some systems don't
* expose this.
*/
readonly count: number;
/**
* The sum of values in the snapshot. Optional since some systems don't
* expose this. If count is zero then this field must be zero or not set
* (if not supported).
*/
readonly sum?: number;
/**
* A list of values at different percentiles of the distribution calculated
* from the current snapshot. The percentiles must be strictly increasing.
*/
readonly percentileValues: ValueAtPercentile[];
}
/**
* Represents the value at a given percentile of a distribution.
*/
export interface ValueAtPercentile {
/** The percentile of a distribution. Must be in the interval (0.0, 100.0]. */
readonly percentile: number;
/** The value at the given percentile of a distribution. */
readonly value: number;
}
/**
* Base interface that represents a metric exporter
*/
export interface MetricExporter {
/** Exports the list of a given {@link ReadableMetric} */
export(metrics: ReadableMetric[], resultCallback: (result: ExportResult) => void): void;
/** Exports the list of a given {@link MetricRecord} */
export(metrics: MetricRecord[], resultCallback: (result: ExportResult) => void): void;
/** Stops the exporter. */
shutdown(): void;
}
/**
* Base interface for aggregators. Aggregators are responsible for holding
* aggregated values and taking a snapshot of these values upon export.
*/
export interface Aggregator {
/** Updates the current with the new value. */
update(value: number): void;
/** Returns snapshot of the current value. */
value(): Sum | Distribution;
}

@@ -18,62 +18,9 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
/**
* The kind of metric. It describes how the data is reported.
*
* A gauge is an instantaneous measurement of a value.
*
* A cumulative measurement is a value accumulated over a time interval. In
* a time series, cumulative measurements should have the same start time,
* increasing values and increasing end times, until an event resets the
* cumulative value to zero and sets a new start time for the following
* points.
*/
var MetricDescriptorType;
(function (MetricDescriptorType) {
/** Do not use this default value. */
MetricDescriptorType[MetricDescriptorType["UNSPECIFIED"] = 0] = "UNSPECIFIED";
/** Integer gauge. The value can go both up and down. */
MetricDescriptorType[MetricDescriptorType["GAUGE_INT64"] = 1] = "GAUGE_INT64";
/** Floating point gauge. The value can go both up and down. */
MetricDescriptorType[MetricDescriptorType["GAUGE_DOUBLE"] = 2] = "GAUGE_DOUBLE";
/**
* Distribution gauge measurement aka histogram.
* The count and sum can go both up and
* down. Recorded values are always >= 0.
* Used in scenarios like a snapshot of time the current items in a queue
* have spent there.
*/
MetricDescriptorType[MetricDescriptorType["GAUGE_HISTOGRAM"] = 3] = "GAUGE_HISTOGRAM";
/**
* Integer counter measurement. The value cannot decrease, if resets
* then the start_time should also be reset.
*/
MetricDescriptorType[MetricDescriptorType["COUNTER_INT64"] = 4] = "COUNTER_INT64";
/**
* Floating point counter measurement. The value cannot decrease, if
* resets then the start_time should also be reset. Recorded values are
* always >= 0.
*/
MetricDescriptorType[MetricDescriptorType["COUNTER_DOUBLE"] = 5] = "COUNTER_DOUBLE";
/**
* Histogram cumulative measurement. The count and sum cannot decrease,
* if reset then the start_time should also be reset.
*/
MetricDescriptorType[MetricDescriptorType["CUMULATIVE_HISTOGRAM"] = 6] = "CUMULATIVE_HISTOGRAM";
/**
* Some frameworks implemented Histograms as a summary of observations
* (usually things like request durations and response sizes). While it
* also provides a total count of observations and a sum of all observed
* values, it calculates configurable percentiles over a sliding time
* window. This is not recommended, since it cannot be aggregated.
*/
MetricDescriptorType[MetricDescriptorType["SUMMARY"] = 7] = "SUMMARY";
/**
* Integer measure. The value can be positive or negative.
*/
MetricDescriptorType[MetricDescriptorType["MEASURE_INT64"] = 8] = "MEASURE_INT64";
/**
* Floating point measure. The value can be positive or negative.
*/
MetricDescriptorType[MetricDescriptorType["MEASURE_DOUBLE"] = 9] = "MEASURE_DOUBLE";
})(MetricDescriptorType = exports.MetricDescriptorType || (exports.MetricDescriptorType = {}));
/** The kind of metric. */
var MetricKind;
(function (MetricKind) {
MetricKind[MetricKind["COUNTER"] = 0] = "COUNTER";
MetricKind[MetricKind["MEASURE"] = 1] = "MEASURE";
MetricKind[MetricKind["OBSERVER"] = 2] = "OBSERVER";
})(MetricKind = exports.MetricKind || (exports.MetricKind = {}));
//# sourceMappingURL=types.js.map

@@ -16,2 +16,3 @@ /*!

*/
export * from './LabelSet';
export * from './BoundInstrument';

@@ -21,3 +22,5 @@ export * from './Meter';

export * from './MeterProvider';
export * from './export/Aggregator';
export * from './export/ConsoleMetricExporter';
export * from './export/types';
export * from './export/Aggregator';

@@ -21,2 +21,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
__export(require("./LabelSet"));
__export(require("./BoundInstrument"));

@@ -26,4 +27,6 @@ __export(require("./Meter"));

__export(require("./MeterProvider"));
__export(require("./export/Aggregator"));
__export(require("./export/ConsoleMetricExporter"));
__export(require("./export/types"));
__export(require("./export/Aggregator"));
//# sourceMappingURL=index.js.map

@@ -18,3 +18,3 @@ /*!

import { MeterConfig } from './types';
import { ReadableMetric, MetricExporter } from './export/types';
import { Batcher } from './export/Batcher';
/**

@@ -26,3 +26,4 @@ * Meter is an implementation of the {@link Meter} interface.

private readonly _metrics;
private readonly _exporters;
private readonly _batcher;
private readonly _resource;
readonly labels: typeof Meter.labels;

@@ -48,21 +49,16 @@ /**

/**
* Creates a new gauge metric. Generally, this kind of metric should be used
* when the metric cannot be expressed as a sum or because the measurement
* interval is arbitrary. Use this kind of metric when the measurement is not
* a quantity, and the sum and event count are not of interest.
* Creates a new observer metric.
* @param name the name of the metric.
* @param [options] the metric options.
*/
createGauge(name: string, options?: types.MetricOptions): types.Metric<types.BoundGauge>;
createObserver(name: string, options?: types.MetricOptions): types.Metric<types.BoundObserver>;
/**
* Gets a collection of Metrics to be exported.
* @returns The list of metrics.
*/
getMetrics(): ReadableMetric[];
/**
* Add an exporter to the list of registered exporters
* Collects all the metrics created with this `Meter` for export.
*
* @param exporter {@Link MetricExporter} to add to the list of registered exporters
* Utilizes the batcher to create checkpoints of the current values in
* each aggregator belonging to the metrics that were created with this
* meter instance.
*/
addExporter(exporter: MetricExporter): void;
collect(): void;
getBatcher(): Batcher;
/**

@@ -76,6 +72,2 @@ * Provide a pre-computed re-useable LabelSet by

/**
* Send a single metric by name to all registered exporters
*/
private _exportOneMetric;
/**
* Registers metric to register.

@@ -82,0 +74,0 @@ * @param name The name of the metric.

@@ -20,7 +20,9 @@ "use strict";

const core_1 = require("@opentelemetry/core");
const resources_1 = require("@opentelemetry/resources");
const Metric_1 = require("./Metric");
const types_1 = require("./types");
const LabelSet_1 = require("./LabelSet");
const Utils_1 = require("./Utils");
const base_1 = require("@opentelemetry/base");
const Batcher_1 = require("./export/Batcher");
const Controller_1 = require("./export/Controller");
const Exporter_1 = require("../test/mocks/Exporter");
/**

@@ -35,5 +37,10 @@ * Meter is an implementation of the {@link Meter} interface.

this._metrics = new Map();
this._exporters = [];
this.labels = Meter.labels;
this._logger = config.logger || new core_1.ConsoleLogger(config.logLevel);
this._batcher = new Batcher_1.UngroupedBatcher();
this._resource = config.resource || resources_1.Resource.createTelemetrySDKResource();
// start the push controller
const exporter = config.exporter || new Exporter_1.NoopExporter();
const interval = config.interval;
new Controller_1.PushController(this, exporter, interval);
}

@@ -50,8 +57,4 @@ /**

}
const opt = Object.assign(Object.assign({
// Measures are defined as absolute by default
absolute: true, monotonic: false, logger: this._logger }, types_1.DEFAULT_METRIC_OPTIONS), options);
const measure = new Metric_1.MeasureMetric(name, opt, () => {
this._exportOneMetric(name);
});
const opt = Object.assign(Object.assign({ absolute: true, monotonic: false, logger: this._logger }, types_1.DEFAULT_METRIC_OPTIONS), options);
const measure = new Metric_1.MeasureMetric(name, opt, this._batcher, this._resource);
this._registerMetric(name, measure);

@@ -72,8 +75,4 @@ return measure;

}
const opt = Object.assign(Object.assign({
// Counters are defined as monotonic by default
monotonic: true, absolute: false, logger: this._logger }, types_1.DEFAULT_METRIC_OPTIONS), options);
const counter = new Metric_1.CounterMetric(name, opt, () => {
this._exportOneMetric(name);
});
const opt = Object.assign(Object.assign({ monotonic: true, absolute: false, logger: this._logger }, types_1.DEFAULT_METRIC_OPTIONS), options);
const counter = new Metric_1.CounterMetric(name, opt, this._batcher, this._resource);
this._registerMetric(name, counter);

@@ -83,40 +82,33 @@ return counter;

/**
* Creates a new gauge metric. Generally, this kind of metric should be used
* when the metric cannot be expressed as a sum or because the measurement
* interval is arbitrary. Use this kind of metric when the measurement is not
* a quantity, and the sum and event count are not of interest.
* Creates a new observer metric.
* @param name the name of the metric.
* @param [options] the metric options.
*/
createGauge(name, options) {
createObserver(name, options) {
if (!this._isValidName(name)) {
this._logger.warn(`Invalid metric name ${name}. Defaulting to noop metric implementation.`);
return types.NOOP_GAUGE_METRIC;
return types.NOOP_OBSERVER_METRIC;
}
const opt = Object.assign(Object.assign({
// Gauges are defined as non-monotonic by default
monotonic: false, absolute: false, logger: this._logger }, types_1.DEFAULT_METRIC_OPTIONS), options);
const gauge = new Metric_1.GaugeMetric(name, opt, () => {
this._exportOneMetric(name);
});
this._registerMetric(name, gauge);
return gauge;
const opt = Object.assign(Object.assign({ monotonic: false, absolute: false, logger: this._logger }, types_1.DEFAULT_METRIC_OPTIONS), options);
const observer = new Metric_1.ObserverMetric(name, opt, this._batcher, this._resource);
this._registerMetric(name, observer);
return observer;
}
/**
* Gets a collection of Metrics to be exported.
* @returns The list of metrics.
*/
getMetrics() {
return Array.from(this._metrics.values())
.map(metric => metric.get())
.filter(Utils_1.notNull);
}
/**
* Add an exporter to the list of registered exporters
* Collects all the metrics created with this `Meter` for export.
*
* @param exporter {@Link MetricExporter} to add to the list of registered exporters
* Utilizes the batcher to create checkpoints of the current values in
* each aggregator belonging to the metrics that were created with this
* meter instance.
*/
addExporter(exporter) {
this._exporters.push(exporter);
collect() {
Array.from(this._metrics.values()).forEach(metric => {
metric.getMetricRecord().forEach(record => {
this._batcher.process(record);
});
});
}
getBatcher() {
return this._batcher;
}
/**

@@ -143,20 +135,2 @@ * Provide a pre-computed re-useable LabelSet by

/**
* Send a single metric by name to all registered exporters
*/
_exportOneMetric(name) {
const metric = this._metrics.get(name);
if (!metric)
return;
const readableMetric = metric.get();
if (!readableMetric)
return;
for (const exporter of this._exporters) {
exporter.export([readableMetric], result => {
if (result !== base_1.ExportResult.SUCCESS) {
this._logger.error(`Failed to export ${name}`);
}
});
}
}
/**
* Registers metric to register.

@@ -163,0 +137,0 @@ * @param name The name of the metric.

@@ -17,2 +17,3 @@ /*!

import * as types from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
import { Meter } from '.';

@@ -26,2 +27,3 @@ import { MeterConfig } from './types';

private readonly _meters;
readonly resource: Resource;
readonly logger: types.Logger;

@@ -28,0 +30,0 @@ constructor(_config?: MeterConfig);

@@ -19,2 +19,3 @@ "use strict";

const core_1 = require("@opentelemetry/core");
const resources_1 = require("@opentelemetry/resources");
const _1 = require(".");

@@ -29,2 +30,3 @@ const types_1 = require("./types");

this._meters = new Map();
this.resource = resources_1.Resource.createTelemetrySDKResource();
this.logger = _config.logger || new core_1.ConsoleLogger(_config.logLevel);

@@ -31,0 +33,0 @@ }

@@ -17,5 +17,7 @@ /*!

import * as types from '@opentelemetry/api';
import { BoundCounter, BoundGauge, BaseBoundInstrument, BoundMeasure } from './BoundInstrument';
import { Resource } from '@opentelemetry/resources';
import { BoundCounter, BaseBoundInstrument, BoundMeasure, BoundObserver } from './BoundInstrument';
import { MetricOptions } from './types';
import { ReadableMetric, MetricDescriptorType } from './export/types';
import { MetricKind, MetricRecord } from './export/types';
import { Batcher } from './export/Batcher';
/** This is a SDK implementation of {@link Metric} interface. */

@@ -25,3 +27,4 @@ export declare abstract class Metric<T extends BaseBoundInstrument> implements types.Metric<T> {

private readonly _options;
private readonly _type;
private readonly _kind;
readonly resource: Resource;
protected readonly _monotonic: boolean;

@@ -31,5 +34,5 @@ protected readonly _disabled: boolean;

protected readonly _logger: types.Logger;
private readonly _metricDescriptor;
private readonly _descriptor;
private readonly _instruments;
constructor(_name: string, _options: MetricOptions, _type: MetricDescriptorType);
constructor(_name: string, _options: MetricOptions, _kind: MetricKind, resource: Resource);
/**

@@ -43,8 +46,5 @@ * Returns an Instrument associated with specified LabelSet.

/**
* Returns a Instrument for a metric with all labels not set.
*/
getDefaultBound(): T;
/**
* Removes the Instrument from the metric, if it is present.
* @param labelSet the canonicalized LabelSet used to associate with this metric instrument.
* @param labelSet the canonicalized LabelSet used to associate with this
* metric instrument.
*/

@@ -56,9 +56,3 @@ unbind(labelSet: types.LabelSet): void;

clear(): void;
setCallback(fn: () => void): void;
/**
* Provides a ReadableMetric with one or more TimeSeries.
* @returns The ReadableMetric, or null if TimeSeries is not present in
* Metric.
*/
get(): ReadableMetric | null;
getMetricRecord(): MetricRecord[];
private _getMetricDescriptor;

@@ -69,4 +63,4 @@ protected abstract _makeInstrument(labelSet: types.LabelSet): T;

export declare class CounterMetric extends Metric<BoundCounter> implements Pick<types.MetricUtils, 'add'> {
private readonly _onUpdate;
constructor(name: string, options: MetricOptions, _onUpdate: Function);
private readonly _batcher;
constructor(name: string, options: MetricOptions, _batcher: Batcher, resource: Resource);
protected _makeInstrument(labelSet: types.LabelSet): BoundCounter;

@@ -80,20 +74,21 @@ /**

}
/** This is a SDK implementation of Gauge Metric. */
export declare class GaugeMetric extends Metric<BoundGauge> implements Pick<types.MetricUtils, 'set'> {
private readonly _onUpdate;
constructor(name: string, options: MetricOptions, _onUpdate: Function);
protected _makeInstrument(labelSet: types.LabelSet): BoundGauge;
/**
* Sets the given value. Values can be negative.
* @param value the new value.
* @param labelSet the canonicalized LabelSet used to associate with this metric's instrument.
*/
set(value: number, labelSet: types.LabelSet): void;
}
export declare class MeasureMetric extends Metric<BoundMeasure> implements Pick<types.MetricUtils, 'record'> {
private readonly _onUpdate;
private readonly _batcher;
protected readonly _absolute: boolean;
constructor(name: string, options: MetricOptions, _onUpdate: Function);
constructor(name: string, options: MetricOptions, _batcher: Batcher, resource: Resource);
protected _makeInstrument(labelSet: types.LabelSet): BoundMeasure;
record(value: number, labelSet: types.LabelSet): void;
}
/** This is a SDK implementation of Observer Metric. */
export declare class ObserverMetric extends Metric<BoundObserver> implements Pick<types.MetricUtils, 'setCallback'> {
private readonly _batcher;
private _observerResult;
constructor(name: string, options: MetricOptions, _batcher: Batcher, resource: Resource);
protected _makeInstrument(labelSet: types.LabelSet): BoundObserver;
getMetricRecord(): MetricRecord[];
/**
* Sets a callback where user can observe value for certain labels
* @param callback
*/
setCallback(callback: (observerResult: types.ObserverResult) => void): void;
}

@@ -18,12 +18,12 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
const types = require("@opentelemetry/api");
const core_1 = require("@opentelemetry/core");
const BoundInstrument_1 = require("./BoundInstrument");
const ObserverResult_1 = require("./ObserverResult");
const types_1 = require("./export/types");
/** This is a SDK implementation of {@link Metric} interface. */
class Metric {
constructor(_name, _options, _type) {
constructor(_name, _options, _kind, resource) {
this._name = _name;
this._options = _options;
this._type = _type;
this._kind = _kind;
this.resource = resource;
this._instruments = new Map();

@@ -34,3 +34,3 @@ this._monotonic = _options.monotonic;

this._logger = _options.logger;
this._metricDescriptor = this._getMetricDescriptor();
this._descriptor = this._getMetricDescriptor();
}

@@ -51,12 +51,5 @@ /**

/**
* Returns a Instrument for a metric with all labels not set.
*/
getDefaultBound() {
// @todo: implement this method
this._logger.error('not implemented yet');
throw new Error('not implemented yet');
}
/**
* Removes the Instrument from the metric, if it is present.
* @param labelSet the canonicalized LabelSet used to associate with this metric instrument.
* @param labelSet the canonicalized LabelSet used to associate with this
* metric instrument.
*/

@@ -72,21 +65,9 @@ unbind(labelSet) {

}
setCallback(fn) {
// @todo: implement this method
this._logger.error('not implemented yet');
return;
getMetricRecord() {
return Array.from(this._instruments.values()).map(instrument => ({
descriptor: this._descriptor,
labels: instrument.getLabelSet(),
aggregator: instrument.getAggregator(),
}));
}
/**
* Provides a ReadableMetric with one or more TimeSeries.
* @returns The ReadableMetric, or null if TimeSeries is not present in
* Metric.
*/
get() {
if (this._instruments.size === 0)
return null;
const timestamp = core_1.hrTime();
return {
descriptor: this._metricDescriptor,
timeseries: Array.from(this._instruments, ([_, instrument]) => instrument.getTimeSeries(timestamp)),
};
}
_getMetricDescriptor() {

@@ -97,4 +78,5 @@ return {

unit: this._options.unit,
metricKind: this._kind,
valueType: this._valueType,
labelKeys: this._options.labelKeys,
type: this._type,
monotonic: this._monotonic,

@@ -107,10 +89,10 @@ };

class CounterMetric extends Metric {
constructor(name, options, _onUpdate) {
super(name, options, options.valueType === types.ValueType.DOUBLE
? types_1.MetricDescriptorType.COUNTER_DOUBLE
: types_1.MetricDescriptorType.COUNTER_INT64);
this._onUpdate = _onUpdate;
constructor(name, options, _batcher, resource) {
super(name, options, types_1.MetricKind.COUNTER, resource);
this._batcher = _batcher;
}
_makeInstrument(labelSet) {
return new BoundInstrument_1.BoundCounter(labelSet, this._disabled, this._monotonic, this._valueType, this._logger, this._onUpdate);
return new BoundInstrument_1.BoundCounter(labelSet, this._disabled, this._monotonic, this._valueType, this._logger,
// @todo: consider to set to CounterSumAggregator always.
this._batcher.aggregatorFor(types_1.MetricKind.COUNTER));
}

@@ -127,39 +109,42 @@ /**

exports.CounterMetric = CounterMetric;
/** This is a SDK implementation of Gauge Metric. */
class GaugeMetric extends Metric {
constructor(name, options, _onUpdate) {
super(name, options, options.valueType === types.ValueType.DOUBLE
? types_1.MetricDescriptorType.GAUGE_DOUBLE
: types_1.MetricDescriptorType.GAUGE_INT64);
this._onUpdate = _onUpdate;
class MeasureMetric extends Metric {
constructor(name, options, _batcher, resource) {
super(name, options, types_1.MetricKind.MEASURE, resource);
this._batcher = _batcher;
this._absolute = options.absolute !== undefined ? options.absolute : true; // Absolute default is true
}
_makeInstrument(labelSet) {
return new BoundInstrument_1.BoundGauge(labelSet, this._disabled, this._monotonic, this._valueType, this._logger, this._onUpdate);
return new BoundInstrument_1.BoundMeasure(labelSet, this._disabled, this._monotonic, this._absolute, this._valueType, this._logger, this._batcher.aggregatorFor(types_1.MetricKind.MEASURE));
}
/**
* Sets the given value. Values can be negative.
* @param value the new value.
* @param labelSet the canonicalized LabelSet used to associate with this metric's instrument.
*/
set(value, labelSet) {
this.bind(labelSet).set(value);
record(value, labelSet) {
this.bind(labelSet).record(value);
}
}
exports.GaugeMetric = GaugeMetric;
class MeasureMetric extends Metric {
constructor(name, options, _onUpdate) {
super(name, options, options.valueType === types.ValueType.DOUBLE
? types_1.MetricDescriptorType.MEASURE_DOUBLE
: types_1.MetricDescriptorType.MEASURE_INT64);
this._onUpdate = _onUpdate;
this._absolute = options.absolute !== undefined ? options.absolute : true; // Absolute default is true
exports.MeasureMetric = MeasureMetric;
/** This is a SDK implementation of Observer Metric. */
class ObserverMetric extends Metric {
constructor(name, options, _batcher, resource) {
super(name, options, types_1.MetricKind.OBSERVER, resource);
this._batcher = _batcher;
this._observerResult = new ObserverResult_1.ObserverResult();
}
_makeInstrument(labelSet) {
return new BoundInstrument_1.BoundMeasure(labelSet, this._disabled, this._absolute, this._valueType, this._logger, this._onUpdate);
return new BoundInstrument_1.BoundObserver(labelSet, this._disabled, this._monotonic, this._valueType, this._logger, this._batcher.aggregatorFor(types_1.MetricKind.OBSERVER));
}
record(value, labelSet) {
this.bind(labelSet).record(value);
getMetricRecord() {
this._observerResult.observers.forEach((callback, labelSet) => {
const instrument = this.bind(labelSet);
instrument.update(callback());
});
return super.getMetricRecord();
}
/**
* Sets a callback where user can observe value for certain labels
* @param callback
*/
setCallback(callback) {
callback(this._observerResult);
}
}
exports.MeasureMetric = MeasureMetric;
exports.ObserverMetric = ObserverMetric;
//# sourceMappingURL=Metric.js.map

@@ -18,2 +18,4 @@ /*!

import { Logger, ValueType } from '@opentelemetry/api';
import { MetricExporter } from './export/types';
import { Resource } from '@opentelemetry/resources';
/** Options needed for SDK metric creation. */

@@ -46,4 +48,10 @@ export interface MetricOptions {

logger?: Logger;
/** level of logger. */
/** level of logger. */
logLevel?: LogLevel;
/** Metric exporter. */
exporter?: MetricExporter;
/** Metric collect interval */
interval?: number;
/** Resource associated with metric telemetry */
resource?: Resource;
}

@@ -50,0 +58,0 @@ /** Default Meter configuration. */

@@ -22,3 +22,3 @@ "use strict";

exports.DEFAULT_CONFIG = {
logLevel: core_1.LogLevel.DEBUG,
logLevel: core_1.LogLevel.INFO,
};

@@ -25,0 +25,0 @@ /** The default metric creation options value. */

@@ -16,2 +16,2 @@ /*!

*/
export declare const VERSION = "0.4.0";
export declare const VERSION = "0.5.0";

@@ -19,3 +19,3 @@ "use strict";

// this is autogenerated file, see scripts/version-update.js
exports.VERSION = '0.4.0';
exports.VERSION = '0.5.0';
//# sourceMappingURL=version.js.map
{
"name": "@opentelemetry/metrics",
"version": "0.4.0",
"version": "0.5.0",
"description": "OpenTelemetry metrics SDK",

@@ -9,12 +9,13 @@ "main": "build/src/index.js",

"scripts": {
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.ts'",
"test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
"tdd": "npm run test -- --watch-extensions ts --watch",
"codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
"clean": "rimraf build/*",
"check": "gts check",
"lint": "gts check",
"lint:fix": "gts fix",
"precompile": "tsc --version",
"version:update": "node ../../scripts/version-update.js",
"compile": "npm run version:update && tsc -p .",
"fix": "gts fix",
"prepare": "npm run compile"
"prepare": "npm run compile",
"watch": "tsc -w"
},

@@ -60,6 +61,7 @@ "keywords": [

"dependencies": {
"@opentelemetry/api": "^0.4.0",
"@opentelemetry/base": "^0.4.0",
"@opentelemetry/core": "^0.4.0"
"@opentelemetry/api": "^0.5.0",
"@opentelemetry/base": "^0.5.0",
"@opentelemetry/core": "^0.5.0",
"@opentelemetry/resources": "^0.5.0"
}
}

@@ -39,23 +39,2 @@ # OpenTelemetry Metrics SDK

### Gauge
Gauge metrics express a pre-calculated value. Generally, this kind of metric should be used when the metric cannot be expressed as a sum or because the measurement interval is arbitrary. Use this kind of metric when the measurement is not a quantity, and the sum and event count are not of interest. Gauges are defined as `Monotonic = false` by default, meaning that new values are permitted to make positive or negative changes to the gauge. There is no restriction on the sign of the input for gauges.
```js
const { MeterProvider } = require('@opentelemetry/metrics');
// Initialize the Meter to capture measurements in various ways.
const meter = new MeterProvider().getMeter('your-meter-name');
const gauge = meter.createGauge('metric_name', {
labelKeys: ["pid"],
description: "Example of a gauge"
});
const labels = meter.labels({ pid: process.pid });
// Create a BoundInstrument associated with specified label values.
const boundGauge = gauge.bind(labels);
boundGauge.set(10); // Set to 10
```
See [examples/prometheus](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/prometheus) for a short example.

@@ -62,0 +41,0 @@

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