From dfa269b88fa1b357ed992ba2f5937c9feff5831a Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Thu, 11 Jun 2020 10:55:02 -0700 Subject: [PATCH 01/22] chore: update renovate config (#1169) * chore: update renovate config * chore: add labels * chore: update schedule --- renovate.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/renovate.json b/renovate.json index f45d8f110c..a8a6b1bf32 100644 --- a/renovate.json +++ b/renovate.json @@ -1,5 +1,10 @@ { "extends": [ "config:base" - ] + ], + "rebaseWhen": "behind-base-branch", + "schedule": [ + "after 9pm and before 5am" + ], + "labels": ["dependencies"] } From 08dc8bea80924118e06c484bfd09dc650fcf9601 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 12 Jun 2020 03:56:44 +0200 Subject: [PATCH 02/22] chore(deps): update dependency eslint to v7 (#1164) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 78cd12033d..16394db88a 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "@commitlint/config-conventional": "8.3.4", "beautify-benchmark": "0.2.4", "benchmark": "2.1.4", - "eslint": "6.8.0", + "eslint": "7.2.0", "eslint-config-airbnb-base": "14.1.0", "eslint-plugin-import": "2.21.2", "eslint-plugin-header": "3.0.0", From 6ab798488bc214ca96ff96e2a5893f935e34ed1c Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 12 Jun 2020 04:27:50 +0200 Subject: [PATCH 03/22] chore(deps): update dependency eslint-config-airbnb-base to v14.2.0 (#1184) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 16394db88a..f2da39e7e6 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "beautify-benchmark": "0.2.4", "benchmark": "2.1.4", "eslint": "7.2.0", - "eslint-config-airbnb-base": "14.1.0", + "eslint-config-airbnb-base": "14.2.0", "eslint-plugin-import": "2.21.2", "eslint-plugin-header": "3.0.0", "@typescript-eslint/eslint-plugin": "3.2.0", From 469b759b999ed6704b1913ca2dec2d16c5abb857 Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Thu, 11 Jun 2020 23:08:36 -0700 Subject: [PATCH 04/22] feat: add the UpDownCounter instrument (#1120) --- .../opentelemetry-api/src/metrics/Meter.ts | 27 ++- .../opentelemetry-api/src/metrics/Metric.ts | 14 +- .../src/metrics/NoopMeter.ts | 10 + .../src/prometheus.ts | 7 +- .../test/prometheus.test.ts | 5 +- .../src/BoundInstrument.ts | 40 +++- packages/opentelemetry-metrics/src/Meter.ts | 46 +++- packages/opentelemetry-metrics/src/Metric.ts | 10 +- .../src/UpDownCounterMetric.ts | 55 +++++ .../src/export/Batcher.ts | 1 + .../opentelemetry-metrics/src/export/types.ts | 1 - packages/opentelemetry-metrics/src/index.ts | 1 + packages/opentelemetry-metrics/src/types.ts | 6 +- .../opentelemetry-metrics/test/Meter.test.ts | 215 ++++++++++++++++-- .../test/export/ConsoleMetricExporter.test.ts | 1 - 15 files changed, 374 insertions(+), 65 deletions(-) create mode 100644 packages/opentelemetry-metrics/src/UpDownCounterMetric.ts diff --git a/packages/opentelemetry-api/src/metrics/Meter.ts b/packages/opentelemetry-api/src/metrics/Meter.ts index 5ed8bbf3a9..687dea4603 100644 --- a/packages/opentelemetry-api/src/metrics/Meter.ts +++ b/packages/opentelemetry-api/src/metrics/Meter.ts @@ -14,7 +14,13 @@ * limitations under the License. */ -import { MetricOptions, Counter, ValueRecorder, Observer } from './Metric'; +import { + MetricOptions, + Counter, + ValueRecorder, + Observer, + UpDownCounter, +} from './Metric'; /** * An interface to allow the recording metrics. @@ -40,6 +46,25 @@ export interface Meter { */ createCounter(name: string, options?: MetricOptions): Counter; + /** + * Creates a new `UpDownCounter` metric. UpDownCounter is a synchronous + * instrument and very similar to Counter except that Add(increment) + * supports negative increments. It is generally useful for capturing changes + * in an amount of resources used, or any quantity that rises and falls + * during a request. + * Example uses for UpDownCounter: + *
    + *
  1. count the number of active requests.
  2. + *
  3. count memory in use by instrumenting new and delete.
  4. + *
  5. count queue size by instrumenting enqueue and dequeue.
  6. + *
  7. count semaphore up and down operations.
  8. + *
+ * + * @param name the name of the metric. + * @param [options] the metric options. + */ + createUpDownCounter(name: string, options?: MetricOptions): UpDownCounter; + /** * Creates a new `Observer` metric. * @param name the name of the metric. diff --git a/packages/opentelemetry-api/src/metrics/Metric.ts b/packages/opentelemetry-api/src/metrics/Metric.ts index 23118369fa..6effd30946 100644 --- a/packages/opentelemetry-api/src/metrics/Metric.ts +++ b/packages/opentelemetry-api/src/metrics/Metric.ts @@ -48,12 +48,7 @@ export interface MetricOptions { disabled?: boolean; /** - * Asserts that this metric may only increase (e.g. time spent). - */ - monotonic?: boolean; - - /** - * (ValueRecorder only, default true) Asserts that this metric will only accept + * (Measure only, default true) Asserts that this metric will only accept * non-negative values (e.g. disk usage). */ absolute?: boolean; @@ -125,6 +120,13 @@ export interface Counter extends UnboundMetric { add(value: number, labels?: Labels): void; } +export interface UpDownCounter extends UnboundMetric { + /** + * Adds the given value to the current value. Values can be negative. + */ + add(value: number, labels?: Labels): void; +} + export interface ValueRecorder extends UnboundMetric { /** * Records the given value to this value recorder. diff --git a/packages/opentelemetry-api/src/metrics/NoopMeter.ts b/packages/opentelemetry-api/src/metrics/NoopMeter.ts index eed8c4e9bf..3cd7e42ebd 100644 --- a/packages/opentelemetry-api/src/metrics/NoopMeter.ts +++ b/packages/opentelemetry-api/src/metrics/NoopMeter.ts @@ -22,6 +22,7 @@ import { Counter, ValueRecorder, Observer, + UpDownCounter, } from './Metric'; import { BoundValueRecorder, BoundCounter } from './BoundInstrument'; import { CorrelationContext } from '../correlation_context/CorrelationContext'; @@ -53,6 +54,15 @@ export class NoopMeter implements Meter { return NOOP_COUNTER_METRIC; } + /** + * Returns a constant noop UpDownCounter. + * @param name the name of the metric. + * @param [options] the metric options. + */ + createUpDownCounter(name: string, options?: MetricOptions): UpDownCounter { + return NOOP_COUNTER_METRIC; + } + /** * Returns constant noop observer. * @param name the name of the metric. diff --git a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts index fa1bdc3a35..1532717b48 100644 --- a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts +++ b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts @@ -191,10 +191,9 @@ export class PrometheusExporter implements MetricExporter { switch (record.descriptor.metricKind) { case MetricKind.COUNTER: - // there is no such thing as a non-monotonic counter in prometheus - return record.descriptor.monotonic - ? new Counter(metricObject) - : new Gauge(metricObject); + return new Counter(metricObject); + case MetricKind.UP_DOWN_COUNTER: + return new Gauge(metricObject); case MetricKind.OBSERVER: return new Gauge(metricObject); default: diff --git a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts index 5e1e426862..e31c154bae 100644 --- a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts +++ b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts @@ -384,10 +384,9 @@ describe('PrometheusExporter', () => { }); }); - it('should export a non-monotonic counter as a gauge', done => { - const counter = meter.createCounter('counter', { + it('should export a UpDownCounter as a gauge', done => { + const counter = meter.createUpDownCounter('counter', { description: 'a test description', - monotonic: false, }); counter.bind({ key1: 'labelValue1' }).add(20); diff --git a/packages/opentelemetry-metrics/src/BoundInstrument.ts b/packages/opentelemetry-metrics/src/BoundInstrument.ts index 8f660c3722..fd6966b1b3 100644 --- a/packages/opentelemetry-metrics/src/BoundInstrument.ts +++ b/packages/opentelemetry-metrics/src/BoundInstrument.ts @@ -24,19 +24,16 @@ import { Aggregator } from './export/types'; export class BaseBoundInstrument { protected _labels: api.Labels; protected _logger: api.Logger; - protected _monotonic: boolean; constructor( labels: api.Labels, logger: api.Logger, - monotonic: boolean, private readonly _disabled: boolean, private readonly _valueType: api.ValueType, private readonly _aggregator: Aggregator ) { this._labels = labels; this._logger = logger; - this._monotonic = monotonic; } update(value: number): void { @@ -72,18 +69,17 @@ export class BoundCounter extends BaseBoundInstrument constructor( labels: api.Labels, disabled: boolean, - monotonic: boolean, valueType: api.ValueType, logger: api.Logger, aggregator: Aggregator ) { - super(labels, logger, monotonic, disabled, valueType, aggregator); + super(labels, logger, disabled, valueType, aggregator); } add(value: number): void { - if (this._monotonic && value < 0) { + if (value < 0) { this._logger.error( - `Monotonic counter cannot descend for ${Object.values(this._labels)}` + `Counter cannot descend for ${Object.values(this._labels)}` ); return; } @@ -93,7 +89,29 @@ export class BoundCounter extends BaseBoundInstrument } /** - * BoundValueRecorder is an implementation of the {@link BoundValueRecorder} interface. + * BoundUpDownCounter allows the SDK to observe/record a single metric event. + * The value of single instrument in the `UpDownCounter` associated with + * specified Labels. + */ +export class BoundUpDownCounter extends BaseBoundInstrument + implements api.BoundCounter { + constructor( + labels: api.Labels, + disabled: boolean, + valueType: api.ValueType, + logger: api.Logger, + aggregator: Aggregator + ) { + super(labels, logger, disabled, valueType, aggregator); + } + + add(value: number): void { + this.update(value); + } +} + +/** + * BoundMeasure is an implementation of the {@link BoundMeasure} interface. */ export class BoundValueRecorder extends BaseBoundInstrument implements api.BoundValueRecorder { @@ -102,13 +120,12 @@ export class BoundValueRecorder extends BaseBoundInstrument constructor( labels: api.Labels, disabled: boolean, - monotonic: boolean, absolute: boolean, valueType: api.ValueType, logger: api.Logger, aggregator: Aggregator ) { - super(labels, logger, monotonic, disabled, valueType, aggregator); + super(labels, logger, disabled, valueType, aggregator); this._absolute = absolute; } @@ -137,11 +154,10 @@ export class BoundObserver extends BaseBoundInstrument { constructor( labels: api.Labels, disabled: boolean, - monotonic: boolean, valueType: api.ValueType, logger: api.Logger, aggregator: Aggregator ) { - super(labels, logger, monotonic, disabled, valueType, aggregator); + super(labels, logger, disabled, valueType, aggregator); } } diff --git a/packages/opentelemetry-metrics/src/Meter.ts b/packages/opentelemetry-metrics/src/Meter.ts index dd760cc5a2..a8678751df 100644 --- a/packages/opentelemetry-metrics/src/Meter.ts +++ b/packages/opentelemetry-metrics/src/Meter.ts @@ -18,6 +18,7 @@ import * as api from '@opentelemetry/api'; import { ConsoleLogger } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { BaseBoundInstrument } from './BoundInstrument'; +import { UpDownCounterMetric } from './UpDownCounterMetric'; import { Metric, CounterMetric, @@ -72,10 +73,9 @@ export class Meter implements api.Meter { return api.NOOP_VALUE_RECORDER_METRIC; } const opt: MetricOptions = { - absolute: true, // value recorders are defined as absolute by default - monotonic: false, // not applicable to value recorder, set to false logger: this._logger, ...DEFAULT_METRIC_OPTIONS, + absolute: true, // value recorders are defined as absolute by default ...options, }; @@ -104,8 +104,6 @@ export class Meter implements api.Meter { return api.NOOP_COUNTER_METRIC; } const opt: MetricOptions = { - monotonic: true, // Counters are defined as monotonic by default - absolute: false, // not applicable to counter, set to false logger: this._logger, ...DEFAULT_METRIC_OPTIONS, ...options, @@ -115,6 +113,41 @@ export class Meter implements api.Meter { return counter; } + /** + * Creates a new `UpDownCounter` metric. UpDownCounter is a synchronous + * instrument and very similar to Counter except that Add(increment) + * supports negative increments. It is generally useful for capturing changes + * in an amount of resources used, or any quantity that rises and falls + * during a request. + * + * @param name the name of the metric. + * @param [options] the metric options. + */ + createUpDownCounter( + name: string, + options?: api.MetricOptions + ): api.UpDownCounter { + if (!this._isValidName(name)) { + this._logger.warn( + `Invalid metric name ${name}. Defaulting to noop metric implementation.` + ); + return api.NOOP_COUNTER_METRIC; + } + const opt: MetricOptions = { + logger: this._logger, + ...DEFAULT_METRIC_OPTIONS, + ...options, + }; + const upDownCounter = new UpDownCounterMetric( + name, + opt, + this._batcher, + this._resource + ); + this._registerMetric(name, upDownCounter); + return upDownCounter; + } + /** * Creates a new observer metric. * @param name the name of the metric. @@ -128,8 +161,6 @@ export class Meter implements api.Meter { return api.NOOP_OBSERVER_METRIC; } const opt: MetricOptions = { - monotonic: false, // Observers are defined as non-monotonic by default - absolute: false, // not applicable to observer, set to false logger: this._logger, ...DEFAULT_METRIC_OPTIONS, ...options, @@ -188,7 +219,8 @@ export class Meter implements api.Meter { * * 2. The first character must be non-numeric, non-space, non-punctuation * - * 3. Subsequent characters must be belong to the alphanumeric characters, '_', '.', and '-'. + * 3. Subsequent characters must be belong to the alphanumeric characters, + * '_', '.', and '-'. * * Names are case insensitive * diff --git a/packages/opentelemetry-metrics/src/Metric.ts b/packages/opentelemetry-metrics/src/Metric.ts index 09aa518028..194971ba5e 100644 --- a/packages/opentelemetry-metrics/src/Metric.ts +++ b/packages/opentelemetry-metrics/src/Metric.ts @@ -31,7 +31,6 @@ import { hashLabels } from './Utils'; /** This is a SDK implementation of {@link Metric} interface. */ export abstract class Metric implements api.UnboundMetric { - protected readonly _monotonic: boolean; protected readonly _disabled: boolean; protected readonly _valueType: api.ValueType; protected readonly _logger: api.Logger; @@ -44,7 +43,6 @@ export abstract class Metric private readonly _kind: MetricKind, readonly resource: Resource ) { - this._monotonic = _options.monotonic; this._disabled = _options.disabled; this._valueType = _options.valueType; this._logger = _options.logger; @@ -98,7 +96,6 @@ export abstract class Metric unit: this._options.unit, metricKind: this._kind, valueType: this._valueType, - monotonic: this._monotonic, }; } @@ -119,7 +116,6 @@ export class CounterMetric extends Metric implements api.Counter { return new BoundCounter( labels, this._disabled, - this._monotonic, this._valueType, this._logger, // @todo: consider to set to CounterSumAggregator always. @@ -130,8 +126,8 @@ export class CounterMetric extends Metric implements api.Counter { /** * Adds the given value to the current value. Values cannot be negative. * @param value the value to add. - * @param [labels = {}] key-values pairs that are associated with a specific metric - * that you want to record. + * @param [labels = {}] key-values pairs that are associated with a specific + * metric that you want to record. */ add(value: number, labels: api.Labels = {}) { this.bind(labels).add(value); @@ -156,7 +152,6 @@ export class ValueRecorderMetric extends Metric return new BoundValueRecorder( labels, this._disabled, - this._monotonic, this._absolute, this._valueType, this._logger, @@ -187,7 +182,6 @@ export class ObserverMetric extends Metric return new BoundObserver( labels, this._disabled, - this._monotonic, this._valueType, this._logger, this._batcher.aggregatorFor(this._descriptor) diff --git a/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts b/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts new file mode 100644 index 0000000000..03a4b1c277 --- /dev/null +++ b/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts @@ -0,0 +1,55 @@ +/*! + * Copyright 2019, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as api from '@opentelemetry/api'; +import { Resource } from '@opentelemetry/resources'; +import { BoundUpDownCounter } from './BoundInstrument'; +import { MetricOptions } from './types'; +import { MetricKind } from './export/types'; +import { Batcher } from './export/Batcher'; +import { Metric } from './Metric'; + +/** This is a SDK implementation of UpDownCounter Metric. */ +export class UpDownCounterMetric extends Metric + implements api.UpDownCounter { + constructor( + name: string, + options: MetricOptions, + private readonly _batcher: Batcher, + resource: Resource + ) { + super(name, options, MetricKind.UP_DOWN_COUNTER, resource); + } + protected _makeInstrument(labels: api.Labels): BoundUpDownCounter { + return new BoundUpDownCounter( + labels, + this._disabled, + this._valueType, + this._logger, + this._batcher.aggregatorFor(this._descriptor) + ); + } + + /** + * Adds the given value to the current value. Values cannot be negative. + * @param value the value to add. + * @param [labels = {}] key-values pairs that are associated with a specific + * metric that you want to record. + */ + add(value: number, labels: api.Labels = {}) { + this.bind(labels).add(value); + } +} diff --git a/packages/opentelemetry-metrics/src/export/Batcher.ts b/packages/opentelemetry-metrics/src/export/Batcher.ts index 8b3dfa5392..23f2d24fa2 100644 --- a/packages/opentelemetry-metrics/src/export/Batcher.ts +++ b/packages/opentelemetry-metrics/src/export/Batcher.ts @@ -55,6 +55,7 @@ export class UngroupedBatcher extends Batcher { aggregatorFor(metricDescriptor: MetricDescriptor): Aggregator { switch (metricDescriptor.metricKind) { case MetricKind.COUNTER: + case MetricKind.UP_DOWN_COUNTER: return new CounterSumAggregator(); case MetricKind.OBSERVER: return new ObserverAggregator(); diff --git a/packages/opentelemetry-metrics/src/export/types.ts b/packages/opentelemetry-metrics/src/export/types.ts index a07ca8224e..2dacf02a9f 100644 --- a/packages/opentelemetry-metrics/src/export/types.ts +++ b/packages/opentelemetry-metrics/src/export/types.ts @@ -82,7 +82,6 @@ export interface MetricDescriptor { readonly unit: string; readonly metricKind: MetricKind; readonly valueType: ValueType; - readonly monotonic: boolean; } /** diff --git a/packages/opentelemetry-metrics/src/index.ts b/packages/opentelemetry-metrics/src/index.ts index 6cb01ff9a8..bc2cce8475 100644 --- a/packages/opentelemetry-metrics/src/index.ts +++ b/packages/opentelemetry-metrics/src/index.ts @@ -22,3 +22,4 @@ export * from './MetricObservable'; export * from './export/aggregators'; export * from './export/ConsoleMetricExporter'; export * from './export/types'; +export * from './UpDownCounterMetric'; diff --git a/packages/opentelemetry-metrics/src/types.ts b/packages/opentelemetry-metrics/src/types.ts index 6f0fea05e7..d3a89cacb7 100644 --- a/packages/opentelemetry-metrics/src/types.ts +++ b/packages/opentelemetry-metrics/src/types.ts @@ -37,10 +37,7 @@ export interface MetricOptions { /** Indicates the metric is a verbose metric that is disabled by default. */ disabled: boolean; - /** Monotonic metrics may only increase. */ - monotonic: boolean; - - /** (ValueRecorder only) Asserts that this metric will only accept non-negative values. */ + /** (Measure only) Asserts that this metric will only accept non-negative values. */ absolute: boolean; /** User provided logger. */ @@ -79,6 +76,7 @@ export const DEFAULT_CONFIG = { /** The default metric creation options value. */ export const DEFAULT_METRIC_OPTIONS = { disabled: false, + absolute: false, description: '', unit: '1', valueType: ValueType.DOUBLE, diff --git a/packages/opentelemetry-metrics/test/Meter.test.ts b/packages/opentelemetry-metrics/test/Meter.test.ts index a71c82b41f..451ff27487 100644 --- a/packages/opentelemetry-metrics/test/Meter.test.ts +++ b/packages/opentelemetry-metrics/test/Meter.test.ts @@ -29,6 +29,7 @@ import { Aggregator, MetricObservable, MetricDescriptor, + UpDownCounterMetric, } from '../src'; import * as api from '@opentelemetry/api'; import { NoopLogger, hrTime, hrTimeToNanoseconds } from '@opentelemetry/core'; @@ -66,7 +67,6 @@ describe('Meter', () => { description: 'desc', unit: '1', disabled: false, - monotonic: false, }); assert.ok(counter instanceof Metric); }); @@ -97,7 +97,6 @@ describe('Meter', () => { description: 'desc', unit: '1', disabled: false, - monotonic: true, }); counter.add(1); meter.collect(); @@ -136,7 +135,7 @@ describe('Meter', () => { assert.strictEqual(boundCounter.getLabels(), labels); }); - it('should add positive values by default', () => { + it('should add positive values only', () => { const counter = meter.createCounter('name') as CounterMetric; const boundCounter = counter.bind(labels); boundCounter.add(10); @@ -160,17 +159,6 @@ describe('Meter', () => { assert.strictEqual(record1.aggregator.toPoint().value, 0); }); - it('should add negative value when monotonic is set to false', () => { - const counter = meter.createCounter('name', { - monotonic: false, - }) as CounterMetric; - const boundCounter = counter.bind(labels); - boundCounter.add(-10); - meter.collect(); - const [record1] = meter.getBatcher().checkPointSet(); - assert.strictEqual(record1.aggregator.toPoint().value, -10); - }); - it('should return same instrument on same label values', () => { const counter = meter.createCounter('name') as CounterMetric; const boundCounter = counter.bind(labels); @@ -229,7 +217,201 @@ describe('Meter', () => { assert.deepStrictEqual(record[0].descriptor, { description: '', metricKind: MetricKind.COUNTER, - monotonic: true, + name: 'name1', + unit: '1', + valueType: ValueType.DOUBLE, + }); + assert.strictEqual(record[0].aggregator.toPoint().value, 10); + }); + }); + + describe('names', () => { + it('should create counter with valid names', () => { + const counter1 = meter.createCounter('name1'); + const counter2 = meter.createCounter( + 'Name_with-all.valid_CharacterClasses' + ); + assert.ok(counter1 instanceof CounterMetric); + assert.ok(counter2 instanceof CounterMetric); + }); + + it('should return no op metric if name is an empty string', () => { + const counter = meter.createCounter(''); + assert.ok(counter instanceof api.NoopMetric); + }); + + it('should return no op metric if name does not start with a letter', () => { + const counter1 = meter.createCounter('1name'); + const counter_ = meter.createCounter('_name'); + assert.ok(counter1 instanceof api.NoopMetric); + assert.ok(counter_ instanceof api.NoopMetric); + }); + + it('should return no op metric if name is an empty string contain only letters, numbers, ".", "_", and "-"', () => { + const counter = meter.createCounter('name with invalid characters^&*('); + assert.ok(counter instanceof api.NoopMetric); + }); + }); + }); + + describe('#UpDownCounter', () => { + const performanceTimeOrigin = hrTime(); + + it('should create a UpDownCounter', () => { + const upDownCounter = meter.createUpDownCounter('name'); + assert.ok(upDownCounter instanceof Metric); + }); + + it('should create a UpDownCounter with options', () => { + const upDownCounter = meter.createUpDownCounter('name', { + description: 'desc', + unit: '1', + disabled: false, + }); + assert.ok(upDownCounter instanceof Metric); + }); + + it('should be able to call add() directly on UpDownCounter', () => { + const upDownCounter = meter.createUpDownCounter('name'); + upDownCounter.add(10, labels); + meter.collect(); + const [record1] = meter.getBatcher().checkPointSet(); + + assert.strictEqual(record1.aggregator.toPoint().value, 10); + const lastTimestamp = record1.aggregator.toPoint().timestamp; + assert.ok( + hrTimeToNanoseconds(lastTimestamp) > + hrTimeToNanoseconds(performanceTimeOrigin) + ); + upDownCounter.add(10, labels); + assert.strictEqual(record1.aggregator.toPoint().value, 20); + + assert.ok( + hrTimeToNanoseconds(record1.aggregator.toPoint().timestamp) > + hrTimeToNanoseconds(lastTimestamp) + ); + }); + + it('should be able to call add with no labels', () => { + const upDownCounter = meter.createUpDownCounter('name', { + description: 'desc', + unit: '1', + disabled: false, + }); + upDownCounter.add(1); + meter.collect(); + const [record1] = meter.getBatcher().checkPointSet(); + assert.strictEqual(record1.aggregator.toPoint().value, 1); + }); + + it('should pipe through resource', () => { + const upDownCounter = meter.createUpDownCounter( + 'name' + ) as UpDownCounterMetric; + assert.ok(upDownCounter.resource instanceof Resource); + + upDownCounter.add(1, { foo: 'bar' }); + + const [record] = upDownCounter.getMetricRecord(); + assert.ok(record.resource instanceof Resource); + }); + + describe('.bind()', () => { + it('should create a UpDownCounter instrument', () => { + const upDownCounter = meter.createUpDownCounter('name'); + const boundCounter = upDownCounter.bind(labels); + boundCounter.add(10); + meter.collect(); + const [record1] = meter.getBatcher().checkPointSet(); + + assert.strictEqual(record1.aggregator.toPoint().value, 10); + boundCounter.add(-200); + assert.strictEqual(record1.aggregator.toPoint().value, -190); + }); + + it('should return the aggregator', () => { + const upDownCounter = meter.createUpDownCounter( + 'name' + ) as UpDownCounterMetric; + const boundCounter = upDownCounter.bind(labels); + boundCounter.add(20); + assert.ok(boundCounter.getAggregator() instanceof CounterSumAggregator); + assert.strictEqual(boundCounter.getLabels(), labels); + }); + + it('should not add the instrument data when disabled', () => { + const upDownCounter = meter.createUpDownCounter('name', { + disabled: true, + }); + const boundCounter = upDownCounter.bind(labels); + boundCounter.add(10); + meter.collect(); + const [record1] = meter.getBatcher().checkPointSet(); + assert.strictEqual(record1.aggregator.toPoint().value, 0); + }); + + it('should return same instrument on same label values', () => { + const upDownCounter = meter.createUpDownCounter('name'); + const boundCounter = upDownCounter.bind(labels); + boundCounter.add(10); + const boundCounter1 = upDownCounter.bind(labels); + boundCounter1.add(10); + meter.collect(); + const [record1] = meter.getBatcher().checkPointSet(); + + assert.strictEqual(record1.aggregator.toPoint().value, 20); + assert.strictEqual(boundCounter, boundCounter1); + }); + }); + + describe('.unbind()', () => { + it('should remove a UpDownCounter instrument', () => { + const upDownCounter = meter.createUpDownCounter( + 'name' + ) as UpDownCounterMetric; + const boundCounter = upDownCounter.bind(labels); + assert.strictEqual(upDownCounter['_instruments'].size, 1); + upDownCounter.unbind(labels); + assert.strictEqual(upDownCounter['_instruments'].size, 0); + const boundCounter1 = upDownCounter.bind(labels); + assert.strictEqual(upDownCounter['_instruments'].size, 1); + assert.notStrictEqual(boundCounter, boundCounter1); + }); + + it('should not fail when removing non existing instrument', () => { + const upDownCounter = meter.createUpDownCounter('name'); + upDownCounter.unbind({}); + }); + + it('should clear all instruments', () => { + const upDownCounter = meter.createUpDownCounter( + 'name' + ) as CounterMetric; + upDownCounter.bind(labels); + assert.strictEqual(upDownCounter['_instruments'].size, 1); + upDownCounter.clear(); + assert.strictEqual(upDownCounter['_instruments'].size, 0); + }); + }); + + describe('.registerMetric()', () => { + it('skip already registered Metric', () => { + const counter1 = meter.createCounter('name1') as CounterMetric; + counter1.bind(labels).add(10); + + // should skip below metric + const counter2 = meter.createCounter('name1', { + valueType: api.ValueType.INT, + }) as CounterMetric; + counter2.bind(labels).add(500); + + meter.collect(); + const record = meter.getBatcher().checkPointSet(); + + assert.strictEqual(record.length, 1); + assert.deepStrictEqual(record[0].descriptor, { + description: '', + metricKind: MetricKind.COUNTER, name: 'name1', unit: '1', valueType: ValueType.DOUBLE, @@ -557,7 +739,6 @@ describe('Meter', () => { name: 'counter', description: 'test', metricKind: MetricKind.COUNTER, - monotonic: true, unit: '1', valueType: ValueType.DOUBLE, }); @@ -584,7 +765,6 @@ describe('Meter', () => { name: 'counter', description: 'test', metricKind: MetricKind.COUNTER, - monotonic: true, unit: '1', valueType: ValueType.INT, }); @@ -630,5 +810,4 @@ function ensureMetric(metric: MetricRecord) { assert.strictEqual(descriptor.unit, '1'); assert.strictEqual(descriptor.metricKind, MetricKind.OBSERVER); assert.strictEqual(descriptor.valueType, ValueType.DOUBLE); - assert.strictEqual(descriptor.monotonic, false); } diff --git a/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts b/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts index d47bc2981c..987f468212 100644 --- a/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts +++ b/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts @@ -57,7 +57,6 @@ describe('ConsoleMetricExporter', () => { { description: 'a test description', metricKind: MetricKind.COUNTER, - monotonic: true, name: 'counter', unit: '1', valueType: ValueType.DOUBLE, From e9b2cf9aeb1daf5ffbab800681bfe1cafc636576 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Fri, 12 Jun 2020 09:27:21 -0400 Subject: [PATCH 05/22] refactor: remove copyright year from file headers (#1150) --- eslint.config.js | 10 +++++----- karma.base.js | 2 +- karma.webpack.js | 2 +- packages/opentelemetry-api/karma.conf.js | 2 +- packages/opentelemetry-api/src/api/context.ts | 4 ++-- packages/opentelemetry-api/src/api/global-utils.ts | 4 ++-- packages/opentelemetry-api/src/api/metrics.ts | 4 ++-- packages/opentelemetry-api/src/api/propagation.ts | 4 ++-- packages/opentelemetry-api/src/api/trace.ts | 4 ++-- packages/opentelemetry-api/src/common/Logger.ts | 4 ++-- packages/opentelemetry-api/src/common/Time.ts | 6 ++---- .../src/context/propagation/HttpTextPropagator.ts | 4 ++-- .../src/context/propagation/NoopHttpTextPropagator.ts | 4 ++-- .../src/context/propagation/getter.ts | 4 ++-- .../src/context/propagation/setter.ts | 4 ++-- .../src/correlation_context/CorrelationContext.ts | 4 ++-- .../src/correlation_context/EntryValue.ts | 9 ++------- packages/opentelemetry-api/src/index.ts | 4 ++-- .../opentelemetry-api/src/metrics/BoundInstrument.ts | 4 ++-- packages/opentelemetry-api/src/metrics/Meter.ts | 4 ++-- .../opentelemetry-api/src/metrics/MeterProvider.ts | 4 ++-- packages/opentelemetry-api/src/metrics/Metric.ts | 4 ++-- .../opentelemetry-api/src/metrics/MetricObservable.ts | 8 ++------ packages/opentelemetry-api/src/metrics/NoopMeter.ts | 4 ++-- .../src/metrics/NoopMeterProvider.ts | 4 ++-- .../opentelemetry-api/src/metrics/ObserverResult.ts | 4 ++-- .../src/platform/browser/globalThis.ts | 4 ++-- .../opentelemetry-api/src/platform/browser/index.ts | 4 ++-- packages/opentelemetry-api/src/platform/index.ts | 4 ++-- .../opentelemetry-api/src/platform/node/globalThis.ts | 4 ++-- packages/opentelemetry-api/src/platform/node/index.ts | 4 ++-- packages/opentelemetry-api/src/trace/Event.ts | 4 ++-- packages/opentelemetry-api/src/trace/NoopSpan.ts | 4 ++-- packages/opentelemetry-api/src/trace/NoopTracer.ts | 4 ++-- .../opentelemetry-api/src/trace/NoopTracerProvider.ts | 4 ++-- packages/opentelemetry-api/src/trace/Sampler.ts | 4 ++-- .../opentelemetry-api/src/trace/SamplingResult.ts | 4 ++-- packages/opentelemetry-api/src/trace/SpanOptions.ts | 4 ++-- packages/opentelemetry-api/src/trace/TimedEvent.ts | 4 ++-- packages/opentelemetry-api/src/trace/attributes.ts | 9 ++------- .../src/trace/instrumentation/Plugin.ts | 4 ++-- packages/opentelemetry-api/src/trace/link.ts | 4 ++-- packages/opentelemetry-api/src/trace/link_context.ts | 4 ++-- packages/opentelemetry-api/src/trace/span.ts | 4 ++-- packages/opentelemetry-api/src/trace/span_context.ts | 4 ++-- packages/opentelemetry-api/src/trace/span_kind.ts | 9 ++------- packages/opentelemetry-api/src/trace/status.ts | 9 ++------- packages/opentelemetry-api/src/trace/trace_flags.ts | 10 ++-------- packages/opentelemetry-api/src/trace/trace_state.ts | 10 ++-------- packages/opentelemetry-api/src/trace/tracer.ts | 4 ++-- .../opentelemetry-api/src/trace/tracer_provider.ts | 4 ++-- packages/opentelemetry-api/src/version.ts | 2 +- packages/opentelemetry-api/test/api/api.test.ts | 4 ++-- packages/opentelemetry-api/test/api/global.test.ts | 4 ++-- packages/opentelemetry-api/test/index-webpack.ts | 7 ++----- .../test/noop-implementations/noop-meter.test.ts | 4 ++-- .../test/noop-implementations/noop-span.test.ts | 4 ++-- .../test/noop-implementations/noop-tracer.test.ts | 4 ++-- .../src/AsyncHooksContextManager.ts | 4 ++-- .../opentelemetry-context-async-hooks/src/index.ts | 2 +- .../opentelemetry-context-async-hooks/src/version.ts | 2 +- .../test/AsyncHooksContextManager.test.ts | 4 ++-- .../src/NoopContextManager.ts | 4 ++-- packages/opentelemetry-context-base/src/context.ts | 10 ++-------- packages/opentelemetry-context-base/src/index.ts | 2 +- packages/opentelemetry-context-base/src/types.ts | 4 ++-- packages/opentelemetry-context-base/src/version.ts | 2 +- .../test/NoopContextManager.test.ts | 4 ++-- .../opentelemetry-context-zone-peer-dep/karma.conf.js | 2 +- .../src/ZoneContextManager.ts | 4 ++-- .../opentelemetry-context-zone-peer-dep/src/index.ts | 2 +- .../opentelemetry-context-zone-peer-dep/src/types.ts | 4 ++-- .../opentelemetry-context-zone-peer-dep/src/util.ts | 4 ++-- .../src/version.ts | 2 +- .../test/ZoneContextManager.test.ts | 4 ++-- .../test/index-webpack.ts | 7 ++----- .../test/utils.test.ts | 4 ++-- packages/opentelemetry-context-zone/src/index.ts | 2 +- packages/opentelemetry-context-zone/src/version.ts | 2 +- packages/opentelemetry-core/karma.conf.js | 2 +- packages/opentelemetry-core/src/ExportResult.ts | 2 +- .../opentelemetry-core/src/common/ConsoleLogger.ts | 4 ++-- packages/opentelemetry-core/src/common/NoopLogger.ts | 4 ++-- packages/opentelemetry-core/src/common/time.ts | 4 ++-- packages/opentelemetry-core/src/common/types.ts | 6 ++---- packages/opentelemetry-core/src/context/context.ts | 4 ++-- .../src/context/propagation/B3Propagator.ts | 4 ++-- .../src/context/propagation/HttpTraceContext.ts | 4 ++-- .../src/context/propagation/composite.ts | 4 ++-- .../src/context/propagation/types.ts | 4 ++-- .../src/correlation-context/correlation-context.ts | 4 ++-- .../propagation/HttpCorrelationContext.ts | 4 ++-- packages/opentelemetry-core/src/index.ts | 4 ++-- .../opentelemetry-core/src/internal/validators.ts | 4 ++-- .../src/platform/BaseAbstractPlugin.ts | 4 ++-- .../src/platform/browser/BasePlugin.ts | 4 ++-- .../src/platform/browser/hex-to-base64.ts | 9 ++------- .../opentelemetry-core/src/platform/browser/id.ts | 6 ++---- .../opentelemetry-core/src/platform/browser/index.ts | 4 ++-- .../src/platform/browser/performance.ts | 4 ++-- .../src/platform/browser/sdk-info.ts | 4 ++-- .../src/platform/browser/timer-util.ts | 6 ++---- packages/opentelemetry-core/src/platform/index.ts | 8 ++------ .../src/platform/node/BasePlugin.ts | 4 ++-- .../src/platform/node/hex-to-base64.ts | 9 ++------- packages/opentelemetry-core/src/platform/node/id.ts | 4 ++-- .../opentelemetry-core/src/platform/node/index.ts | 4 ++-- .../src/platform/node/performance.ts | 4 ++-- .../opentelemetry-core/src/platform/node/sdk-info.ts | 4 ++-- .../src/platform/node/timer-util.ts | 9 ++------- .../opentelemetry-core/src/trace/NoRecordingSpan.ts | 4 ++-- packages/opentelemetry-core/src/trace/TraceState.ts | 4 ++-- .../src/trace/sampler/ProbabilitySampler.ts | 4 ++-- .../opentelemetry-core/src/trace/spancontext-utils.ts | 4 ++-- packages/opentelemetry-core/src/utils/url.ts | 10 ++-------- packages/opentelemetry-core/src/utils/wrap.ts | 4 ++-- packages/opentelemetry-core/src/version.ts | 2 +- .../test/common/ConsoleLogger.test.ts | 4 ++-- packages/opentelemetry-core/test/common/time.test.ts | 4 ++-- .../test/context/B3Propagator.test.ts | 4 ++-- .../test/context/HttpTraceContext.test.ts | 4 ++-- .../opentelemetry-core/test/context/composite.test.ts | 4 ++-- .../HttpCorrelationContext.test.ts | 4 ++-- packages/opentelemetry-core/test/index-webpack.ts | 7 ++----- .../test/internal/validators.test.ts | 4 ++-- .../test/platform/BasePlugin.test.ts | 4 ++-- .../test/platform/browser/BasePlugin.test.ts | 4 ++-- .../test/platform/hex-to-base64.test.ts | 4 ++-- packages/opentelemetry-core/test/platform/id.test.ts | 4 ++-- .../test/trace/NoRecordingSpan.test.ts | 4 ++-- .../test/trace/ProbabilitySampler.test.ts | 4 ++-- .../trace/fixtures/test-package/foo/bar/internal.d.ts | 2 +- .../test/trace/spancontext-utils.test.ts | 4 ++-- .../opentelemetry-core/test/trace/tracestate.test.ts | 4 ++-- packages/opentelemetry-core/test/utils/url.test.ts | 4 ++-- packages/opentelemetry-core/test/utils/wrap.test.ts | 4 ++-- .../opentelemetry-exporter-collector/karma.conf.js | 2 +- .../src/CollectorExporterBase.ts | 2 +- .../opentelemetry-exporter-collector/src/index.ts | 2 +- .../src/platform/browser/CollectorExporter.ts | 4 ++-- .../src/platform/browser/index.ts | 4 ++-- .../src/platform/index.ts | 4 ++-- .../src/platform/node/CollectorExporter.ts | 4 ++-- .../src/platform/node/index.ts | 4 ++-- .../src/platform/node/types.ts | 4 ++-- .../src/platform/node/util.ts | 10 ++-------- .../opentelemetry-exporter-collector/src/transform.ts | 2 +- .../opentelemetry-exporter-collector/src/types.ts | 4 ++-- .../opentelemetry-exporter-collector/src/version.ts | 2 +- .../test/browser/CollectorExporter.test.ts | 4 ++-- .../test/browser/index-webpack.ts | 7 ++----- .../test/common/CollectorExporter.test.ts | 4 ++-- .../test/common/transform.test.ts | 4 ++-- .../opentelemetry-exporter-collector/test/helper.ts | 4 ++-- .../test/node/CollectorExporter.test.ts | 4 ++-- packages/opentelemetry-exporter-jaeger/src/index.ts | 4 ++-- packages/opentelemetry-exporter-jaeger/src/jaeger.ts | 4 ++-- .../opentelemetry-exporter-jaeger/src/transform.ts | 4 ++-- packages/opentelemetry-exporter-jaeger/src/types.ts | 4 ++-- packages/opentelemetry-exporter-jaeger/src/utils.ts | 4 ++-- packages/opentelemetry-exporter-jaeger/src/version.ts | 2 +- .../opentelemetry-exporter-jaeger/test/jaeger.test.ts | 4 ++-- .../test/transform.test.ts | 4 ++-- .../src/export/types.ts | 4 ++-- .../opentelemetry-exporter-prometheus/src/index.ts | 4 ++-- .../src/prometheus.ts | 4 ++-- .../opentelemetry-exporter-prometheus/src/version.ts | 2 +- .../test/prometheus.test.ts | 4 ++-- packages/opentelemetry-exporter-zipkin/src/index.ts | 4 ++-- .../opentelemetry-exporter-zipkin/src/transform.ts | 4 ++-- packages/opentelemetry-exporter-zipkin/src/types.ts | 4 ++-- packages/opentelemetry-exporter-zipkin/src/utils.ts | 4 ++-- packages/opentelemetry-exporter-zipkin/src/version.ts | 2 +- packages/opentelemetry-exporter-zipkin/src/zipkin.ts | 4 ++-- .../opentelemetry-exporter-zipkin/test/e2e.test.ts | 4 ++-- .../test/transform.test.ts | 4 ++-- .../opentelemetry-exporter-zipkin/test/zipkin.test.ts | 4 ++-- packages/opentelemetry-metrics/src/BoundInstrument.ts | 4 ++-- packages/opentelemetry-metrics/src/Meter.ts | 4 ++-- packages/opentelemetry-metrics/src/MeterProvider.ts | 4 ++-- packages/opentelemetry-metrics/src/Metric.ts | 4 ++-- .../opentelemetry-metrics/src/MetricObservable.ts | 4 ++-- packages/opentelemetry-metrics/src/ObserverResult.ts | 4 ++-- .../opentelemetry-metrics/src/UpDownCounterMetric.ts | 4 ++-- packages/opentelemetry-metrics/src/Utils.ts | 4 ++-- packages/opentelemetry-metrics/src/export/Batcher.ts | 4 ++-- .../src/export/ConsoleMetricExporter.ts | 4 ++-- .../opentelemetry-metrics/src/export/Controller.ts | 4 ++-- .../opentelemetry-metrics/src/export/NoopExporter.ts | 4 ++-- .../src/export/aggregators/ValueRecorderExact.ts | 4 ++-- .../src/export/aggregators/countersum.ts | 4 ++-- .../src/export/aggregators/histogram.ts | 4 ++-- .../src/export/aggregators/index.ts | 4 ++-- .../src/export/aggregators/observer.ts | 4 ++-- packages/opentelemetry-metrics/src/export/types.ts | 4 ++-- packages/opentelemetry-metrics/src/index.ts | 4 ++-- packages/opentelemetry-metrics/src/types.ts | 4 ++-- packages/opentelemetry-metrics/src/version.ts | 2 +- packages/opentelemetry-metrics/test/Batcher.test.ts | 4 ++-- packages/opentelemetry-metrics/test/Meter.test.ts | 4 ++-- .../opentelemetry-metrics/test/MeterProvider.test.ts | 4 ++-- .../test/export/ConsoleMetricExporter.test.ts | 4 ++-- .../test/export/aggregators/histogram.test.ts | 4 ++-- packages/opentelemetry-node/src/NodeTracerProvider.ts | 4 ++-- packages/opentelemetry-node/src/config.ts | 4 ++-- packages/opentelemetry-node/src/index.ts | 4 ++-- .../src/instrumentation/PluginLoader.ts | 4 ++-- .../src/instrumentation/ext-types.d.ts | 4 ++-- .../opentelemetry-node/src/instrumentation/utils.ts | 4 ++-- packages/opentelemetry-node/src/version.ts | 2 +- .../test/NodeTracerProvider.test.ts | 4 ++-- .../test/instrumentation/PluginLoader.test.ts | 4 ++-- .../test/instrumentation/utils.test.ts | 4 ++-- packages/opentelemetry-node/test/registration.test.ts | 4 ++-- .../src/enums/AttributeNames.ts | 4 ++-- packages/opentelemetry-plugin-grpc/src/grpc.ts | 4 ++-- packages/opentelemetry-plugin-grpc/src/index.ts | 4 ++-- packages/opentelemetry-plugin-grpc/src/types.ts | 4 ++-- packages/opentelemetry-plugin-grpc/src/utils.ts | 4 ++-- packages/opentelemetry-plugin-grpc/src/version.ts | 2 +- packages/opentelemetry-plugin-grpc/test/grpc.test.ts | 4 ++-- .../test/utils/assertionUtils.ts | 4 ++-- .../src/enums/AttributeNames.ts | 6 +----- packages/opentelemetry-plugin-http/src/http.ts | 2 +- packages/opentelemetry-plugin-http/src/index.ts | 2 +- packages/opentelemetry-plugin-http/src/types.ts | 2 +- packages/opentelemetry-plugin-http/src/utils.ts | 2 +- packages/opentelemetry-plugin-http/src/version.ts | 2 +- .../test/functionals/http-disable.test.ts | 2 +- .../test/functionals/http-enable.test.ts | 2 +- .../test/functionals/http-package.test.ts | 2 +- .../test/functionals/utils.test.ts | 2 +- .../test/integrations/http-enable.test.ts | 2 +- .../test/utils/DummyPropagation.ts | 2 +- .../test/utils/assertSpan.ts | 2 +- .../test/utils/httpRequest.ts | 2 +- .../opentelemetry-plugin-http/test/utils/utils.ts | 2 +- packages/opentelemetry-plugin-https/src/https.ts | 4 ++-- packages/opentelemetry-plugin-https/src/index.ts | 4 ++-- packages/opentelemetry-plugin-https/src/utils.ts | 4 ++-- packages/opentelemetry-plugin-https/src/version.ts | 2 +- .../test/functionals/https-disable.test.ts | 4 ++-- .../test/functionals/https-enable.test.ts | 4 ++-- .../test/functionals/https-package.test.ts | 4 ++-- .../test/integrations/https-enable.test.ts | 4 ++-- .../test/utils/DummyPropagation.ts | 4 ++-- .../test/utils/assertSpan.ts | 4 ++-- .../test/utils/httpsRequest.ts | 4 ++-- .../opentelemetry-plugin-https/test/utils/utils.ts | 4 ++-- .../karma.conf.js | 2 +- .../src/enums/AttributeNames.ts | 8 ++------ .../src/enums/EventNames.ts | 4 ++-- .../src/index.ts | 4 ++-- .../src/types.ts | 4 ++-- .../src/version.ts | 2 +- .../opentelemetry-plugin-xml-http-request/src/xhr.ts | 4 ++-- .../test/index-webpack.ts | 7 ++----- .../test/xhr.test.ts | 4 ++-- packages/opentelemetry-resources/src/Resource.ts | 4 ++-- packages/opentelemetry-resources/src/constants.ts | 11 ++--------- packages/opentelemetry-resources/src/index.ts | 4 ++-- .../src/platform/browser/detect-resources.ts | 4 ++-- .../src/platform/browser/index.ts | 4 ++-- .../opentelemetry-resources/src/platform/index.ts | 8 ++------ .../src/platform/node/detect-resources.ts | 4 ++-- .../src/platform/node/detectors/AwsEc2Detector.ts | 4 ++-- .../src/platform/node/detectors/EnvDetector.ts | 4 ++-- .../src/platform/node/detectors/GcpDetector.ts | 4 ++-- .../src/platform/node/detectors/index.ts | 4 ++-- .../src/platform/node/index.ts | 4 ++-- packages/opentelemetry-resources/src/types.ts | 4 ++-- packages/opentelemetry-resources/src/version.ts | 2 +- .../opentelemetry-resources/test/Resource.test.ts | 4 ++-- .../test/detect-resources.test.ts | 4 ++-- .../test/detectors/AwsEc2Detector.test.ts | 4 ++-- .../test/detectors/EnvDetector.test.ts | 4 ++-- .../test/detectors/GcpDetector.test.ts | 4 ++-- .../test/resource-assertions.test.ts | 4 ++-- .../test/util/resource-assertions.ts | 4 ++-- packages/opentelemetry-shim-opentracing/src/index.ts | 4 ++-- packages/opentelemetry-shim-opentracing/src/shim.ts | 4 ++-- .../opentelemetry-shim-opentracing/src/version.ts | 2 +- .../opentelemetry-shim-opentracing/test/Shim.test.ts | 4 ++-- packages/opentelemetry-tracing/karma.conf.js | 2 +- .../opentelemetry-tracing/src/BasicTracerProvider.ts | 4 ++-- .../opentelemetry-tracing/src/MultiSpanProcessor.ts | 4 ++-- .../opentelemetry-tracing/src/NoopSpanProcessor.ts | 4 ++-- packages/opentelemetry-tracing/src/Span.ts | 4 ++-- packages/opentelemetry-tracing/src/SpanProcessor.ts | 4 ++-- packages/opentelemetry-tracing/src/Tracer.ts | 4 ++-- packages/opentelemetry-tracing/src/config.ts | 4 ++-- .../src/export/BatchSpanProcessor.ts | 4 ++-- .../src/export/ConsoleSpanExporter.ts | 4 ++-- .../src/export/InMemorySpanExporter.ts | 4 ++-- .../opentelemetry-tracing/src/export/ReadableSpan.ts | 4 ++-- .../src/export/SimpleSpanProcessor.ts | 4 ++-- .../opentelemetry-tracing/src/export/SpanExporter.ts | 4 ++-- packages/opentelemetry-tracing/src/index.ts | 4 ++-- packages/opentelemetry-tracing/src/types.ts | 4 ++-- packages/opentelemetry-tracing/src/utility.ts | 4 ++-- packages/opentelemetry-tracing/src/version.ts | 2 +- .../test/BasicTracerProvider.test.ts | 4 ++-- .../test/MultiSpanProcessor.test.ts | 4 ++-- packages/opentelemetry-tracing/test/Span.test.ts | 4 ++-- packages/opentelemetry-tracing/test/Tracer.test.ts | 4 ++-- .../test/export/BatchSpanProcessor.test.ts | 4 ++-- .../test/export/ConsoleSpanExporter.test.ts | 4 ++-- .../test/export/InMemorySpanExporter.test.ts | 4 ++-- .../test/export/SimpleSpanProcessor.test.ts | 4 ++-- packages/opentelemetry-tracing/test/index-webpack.ts | 7 ++----- packages/opentelemetry-web/karma.conf.js | 2 +- packages/opentelemetry-web/src/StackContextManager.ts | 4 ++-- packages/opentelemetry-web/src/WebTracerProvider.ts | 4 ++-- .../src/enums/PerformanceTimingNames.ts | 4 ++-- packages/opentelemetry-web/src/index.ts | 4 ++-- packages/opentelemetry-web/src/types.ts | 8 ++------ packages/opentelemetry-web/src/utils.ts | 4 ++-- packages/opentelemetry-web/src/version.ts | 2 +- .../test/StackContextManager.test.ts | 4 ++-- .../opentelemetry-web/test/WebTracerProvider.test.ts | 4 ++-- packages/opentelemetry-web/test/index-webpack.ts | 7 ++----- packages/opentelemetry-web/test/registration.test.ts | 4 ++-- packages/opentelemetry-web/test/utils.test.ts | 4 ++-- scripts/version-update.js | 4 ++-- 324 files changed, 599 insertions(+), 724 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 5a83bea117..7c1a2ca886 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -27,10 +27,10 @@ module.exports = { "arrow-parens": ["error", "as-needed"], "prettier/prettier": ["error", { "singleQuote": true, "arrowParens": "avoid" }], "node/no-deprecated-api": ["warn"], - "header/header": [2, "block", [{ - pattern: / \* Copyright \d{4}, OpenTelemetry Authors[\r\n]+ \*[\r\n]+ \* Licensed under the Apache License, Version 2\.0 \(the \"License\"\);[\r\n]+ \* you may not use this file except in compliance with the License\.[\r\n]+ \* You may obtain a copy of the License at[\r\n]+ \*[\r\n]+ \* https:\/\/www\.apache\.org\/licenses\/LICENSE-2\.0[\r\n]+ \*[\r\n]+ \* Unless required by applicable law or agreed to in writing, software[\r\n]+ \* distributed under the License is distributed on an \"AS IS\" BASIS,[\r\n]+ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.[\r\n]+ \* See the License for the specific language governing permissions and[\r\n]+ \* limitations under the License\./gm, - template: - `\n * Copyright ${new Date().getFullYear()}, OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ` + "header/header": [2, "block", [{ + pattern: / \* Copyright The OpenTelemetry Authors[\r\n]+ \*[\r\n]+ \* Licensed under the Apache License, Version 2\.0 \(the \"License\"\);[\r\n]+ \* you may not use this file except in compliance with the License\.[\r\n]+ \* You may obtain a copy of the License at[\r\n]+ \*[\r\n]+ \* https:\/\/www\.apache\.org\/licenses\/LICENSE-2\.0[\r\n]+ \*[\r\n]+ \* Unless required by applicable law or agreed to in writing, software[\r\n]+ \* distributed under the License is distributed on an \"AS IS\" BASIS,[\r\n]+ \* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied\.[\r\n]+ \* See the License for the specific language governing permissions and[\r\n]+ \* limitations under the License\./gm, + template: + `\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the "License");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n ` }]] }, overrides: [ @@ -39,7 +39,7 @@ module.exports = { "rules": { "no-empty": "off", "@typescript-eslint/ban-ts-ignore": "off", - "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-function": "off", "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/no-var-requires": "off" diff --git a/karma.base.js b/karma.base.js index 088ac3f987..70435dda11 100644 --- a/karma.base.js +++ b/karma.base.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/karma.webpack.js b/karma.webpack.js index d62d6292c5..bc8eb3a790 100644 --- a/karma.webpack.js +++ b/karma.webpack.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/karma.conf.js b/packages/opentelemetry-api/karma.conf.js index 7183aab033..3019564a15 100644 --- a/packages/opentelemetry-api/karma.conf.js +++ b/packages/opentelemetry-api/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/api/context.ts b/packages/opentelemetry-api/src/api/context.ts index b127917990..ac5aff2cdd 100644 --- a/packages/opentelemetry-api/src/api/context.ts +++ b/packages/opentelemetry-api/src/api/context.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/api/global-utils.ts b/packages/opentelemetry-api/src/api/global-utils.ts index 00b73f8ce8..a294f345d5 100644 --- a/packages/opentelemetry-api/src/api/global-utils.ts +++ b/packages/opentelemetry-api/src/api/global-utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/api/metrics.ts b/packages/opentelemetry-api/src/api/metrics.ts index dedf58be54..f06b09fa36 100644 --- a/packages/opentelemetry-api/src/api/metrics.ts +++ b/packages/opentelemetry-api/src/api/metrics.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/api/propagation.ts b/packages/opentelemetry-api/src/api/propagation.ts index a8af524244..989e497b66 100644 --- a/packages/opentelemetry-api/src/api/propagation.ts +++ b/packages/opentelemetry-api/src/api/propagation.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/api/trace.ts b/packages/opentelemetry-api/src/api/trace.ts index bae7353e08..0ba58af77a 100644 --- a/packages/opentelemetry-api/src/api/trace.ts +++ b/packages/opentelemetry-api/src/api/trace.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/common/Logger.ts b/packages/opentelemetry-api/src/common/Logger.ts index abb8885a15..f4bccbe9db 100644 --- a/packages/opentelemetry-api/src/common/Logger.ts +++ b/packages/opentelemetry-api/src/common/Logger.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/common/Time.ts b/packages/opentelemetry-api/src/common/Time.ts index 0723d9cc43..5cf0dbb46b 100644 --- a/packages/opentelemetry-api/src/common/Time.ts +++ b/packages/opentelemetry-api/src/common/Time.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** High resolution HrTime: [seconds: number, nanoseconds: number] */ export type HrTime = [number, number]; /** diff --git a/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts b/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts index a95a0a4384..6c6f61d668 100644 --- a/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts +++ b/packages/opentelemetry-api/src/context/propagation/HttpTextPropagator.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/context/propagation/NoopHttpTextPropagator.ts b/packages/opentelemetry-api/src/context/propagation/NoopHttpTextPropagator.ts index f36922d875..7782ba30b9 100644 --- a/packages/opentelemetry-api/src/context/propagation/NoopHttpTextPropagator.ts +++ b/packages/opentelemetry-api/src/context/propagation/NoopHttpTextPropagator.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/context/propagation/getter.ts b/packages/opentelemetry-api/src/context/propagation/getter.ts index 158bd0fdd1..7565010728 100644 --- a/packages/opentelemetry-api/src/context/propagation/getter.ts +++ b/packages/opentelemetry-api/src/context/propagation/getter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/context/propagation/setter.ts b/packages/opentelemetry-api/src/context/propagation/setter.ts index 29c6abed73..2eb56adf46 100644 --- a/packages/opentelemetry-api/src/context/propagation/setter.ts +++ b/packages/opentelemetry-api/src/context/propagation/setter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/correlation_context/CorrelationContext.ts b/packages/opentelemetry-api/src/correlation_context/CorrelationContext.ts index e0de5eca1a..c7bd5668b9 100644 --- a/packages/opentelemetry-api/src/correlation_context/CorrelationContext.ts +++ b/packages/opentelemetry-api/src/correlation_context/CorrelationContext.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/correlation_context/EntryValue.ts b/packages/opentelemetry-api/src/correlation_context/EntryValue.ts index 5db17aff63..59ec73cc2a 100644 --- a/packages/opentelemetry-api/src/correlation_context/EntryValue.ts +++ b/packages/opentelemetry-api/src/correlation_context/EntryValue.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * {@link EntryValue} contains properties associated with a {@link - * CorrelationContext}. - */ export interface EntryValue { /** `String` value of the `EntryValue`. */ value: string; diff --git a/packages/opentelemetry-api/src/index.ts b/packages/opentelemetry-api/src/index.ts index 6b77e9dd15..2f5f81ac99 100644 --- a/packages/opentelemetry-api/src/index.ts +++ b/packages/opentelemetry-api/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/BoundInstrument.ts b/packages/opentelemetry-api/src/metrics/BoundInstrument.ts index 0be696d43a..5b77158356 100644 --- a/packages/opentelemetry-api/src/metrics/BoundInstrument.ts +++ b/packages/opentelemetry-api/src/metrics/BoundInstrument.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/Meter.ts b/packages/opentelemetry-api/src/metrics/Meter.ts index 687dea4603..cf6d15df04 100644 --- a/packages/opentelemetry-api/src/metrics/Meter.ts +++ b/packages/opentelemetry-api/src/metrics/Meter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/MeterProvider.ts b/packages/opentelemetry-api/src/metrics/MeterProvider.ts index 465dff91fe..981218ad59 100644 --- a/packages/opentelemetry-api/src/metrics/MeterProvider.ts +++ b/packages/opentelemetry-api/src/metrics/MeterProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/Metric.ts b/packages/opentelemetry-api/src/metrics/Metric.ts index 6effd30946..24f36cfd05 100644 --- a/packages/opentelemetry-api/src/metrics/Metric.ts +++ b/packages/opentelemetry-api/src/metrics/Metric.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/MetricObservable.ts b/packages/opentelemetry-api/src/metrics/MetricObservable.ts index 4e25dce4e5..161d2919f4 100644 --- a/packages/opentelemetry-api/src/metrics/MetricObservable.ts +++ b/packages/opentelemetry-api/src/metrics/MetricObservable.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Metric Observable class to handle asynchronous metrics - */ export interface MetricObservable { /** * Sets the next value for observable metric diff --git a/packages/opentelemetry-api/src/metrics/NoopMeter.ts b/packages/opentelemetry-api/src/metrics/NoopMeter.ts index 3cd7e42ebd..075a1e544e 100644 --- a/packages/opentelemetry-api/src/metrics/NoopMeter.ts +++ b/packages/opentelemetry-api/src/metrics/NoopMeter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/NoopMeterProvider.ts b/packages/opentelemetry-api/src/metrics/NoopMeterProvider.ts index 182463611c..13e73c0e2f 100644 --- a/packages/opentelemetry-api/src/metrics/NoopMeterProvider.ts +++ b/packages/opentelemetry-api/src/metrics/NoopMeterProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/metrics/ObserverResult.ts b/packages/opentelemetry-api/src/metrics/ObserverResult.ts index 47c3d595c4..0b7286ac38 100644 --- a/packages/opentelemetry-api/src/metrics/ObserverResult.ts +++ b/packages/opentelemetry-api/src/metrics/ObserverResult.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/platform/browser/globalThis.ts b/packages/opentelemetry-api/src/platform/browser/globalThis.ts index df2b5b247f..34a8254b88 100644 --- a/packages/opentelemetry-api/src/platform/browser/globalThis.ts +++ b/packages/opentelemetry-api/src/platform/browser/globalThis.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/platform/browser/index.ts b/packages/opentelemetry-api/src/platform/browser/index.ts index c3608dbed7..e9d6ebed71 100644 --- a/packages/opentelemetry-api/src/platform/browser/index.ts +++ b/packages/opentelemetry-api/src/platform/browser/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/platform/index.ts b/packages/opentelemetry-api/src/platform/index.ts index e4361f1724..cdaf8858ce 100644 --- a/packages/opentelemetry-api/src/platform/index.ts +++ b/packages/opentelemetry-api/src/platform/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/platform/node/globalThis.ts b/packages/opentelemetry-api/src/platform/node/globalThis.ts index 8e24cf207e..36e97e2732 100644 --- a/packages/opentelemetry-api/src/platform/node/globalThis.ts +++ b/packages/opentelemetry-api/src/platform/node/globalThis.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/platform/node/index.ts b/packages/opentelemetry-api/src/platform/node/index.ts index c3608dbed7..e9d6ebed71 100644 --- a/packages/opentelemetry-api/src/platform/node/index.ts +++ b/packages/opentelemetry-api/src/platform/node/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/Event.ts b/packages/opentelemetry-api/src/trace/Event.ts index c3238c5393..5c974ccaa9 100644 --- a/packages/opentelemetry-api/src/trace/Event.ts +++ b/packages/opentelemetry-api/src/trace/Event.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/NoopSpan.ts b/packages/opentelemetry-api/src/trace/NoopSpan.ts index 342a587413..a2a3bcef9f 100644 --- a/packages/opentelemetry-api/src/trace/NoopSpan.ts +++ b/packages/opentelemetry-api/src/trace/NoopSpan.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/NoopTracer.ts b/packages/opentelemetry-api/src/trace/NoopTracer.ts index ed4c63f834..2fdc4dc310 100644 --- a/packages/opentelemetry-api/src/trace/NoopTracer.ts +++ b/packages/opentelemetry-api/src/trace/NoopTracer.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts b/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts index 4eb66c056b..09c86bd7d9 100644 --- a/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts +++ b/packages/opentelemetry-api/src/trace/NoopTracerProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/Sampler.ts b/packages/opentelemetry-api/src/trace/Sampler.ts index 5e8621572f..0d23f51e09 100644 --- a/packages/opentelemetry-api/src/trace/Sampler.ts +++ b/packages/opentelemetry-api/src/trace/Sampler.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/SamplingResult.ts b/packages/opentelemetry-api/src/trace/SamplingResult.ts index 84957f8297..dca3a3952f 100644 --- a/packages/opentelemetry-api/src/trace/SamplingResult.ts +++ b/packages/opentelemetry-api/src/trace/SamplingResult.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/SpanOptions.ts b/packages/opentelemetry-api/src/trace/SpanOptions.ts index 13a2c2f389..e20f243eac 100644 --- a/packages/opentelemetry-api/src/trace/SpanOptions.ts +++ b/packages/opentelemetry-api/src/trace/SpanOptions.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/TimedEvent.ts b/packages/opentelemetry-api/src/trace/TimedEvent.ts index 3218bfa604..632107b260 100644 --- a/packages/opentelemetry-api/src/trace/TimedEvent.ts +++ b/packages/opentelemetry-api/src/trace/TimedEvent.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/attributes.ts b/packages/opentelemetry-api/src/trace/attributes.ts index e0f0e922e3..f5ee8f6188 100644 --- a/packages/opentelemetry-api/src/trace/attributes.ts +++ b/packages/opentelemetry-api/src/trace/attributes.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Defines a attributes interface. - * These attributes provides additional data about the {@link Span}. - */ export interface Attributes { [attributeKey: string]: unknown; } diff --git a/packages/opentelemetry-api/src/trace/instrumentation/Plugin.ts b/packages/opentelemetry-api/src/trace/instrumentation/Plugin.ts index 2206d4b0e0..11d96fed2b 100644 --- a/packages/opentelemetry-api/src/trace/instrumentation/Plugin.ts +++ b/packages/opentelemetry-api/src/trace/instrumentation/Plugin.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/link.ts b/packages/opentelemetry-api/src/trace/link.ts index 4226bf1830..b442555a4e 100644 --- a/packages/opentelemetry-api/src/trace/link.ts +++ b/packages/opentelemetry-api/src/trace/link.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/link_context.ts b/packages/opentelemetry-api/src/trace/link_context.ts index 5493f039a6..c52245975d 100644 --- a/packages/opentelemetry-api/src/trace/link_context.ts +++ b/packages/opentelemetry-api/src/trace/link_context.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/span.ts b/packages/opentelemetry-api/src/trace/span.ts index 8408a48d20..13124fff3c 100644 --- a/packages/opentelemetry-api/src/trace/span.ts +++ b/packages/opentelemetry-api/src/trace/span.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/span_context.ts b/packages/opentelemetry-api/src/trace/span_context.ts index b99be63fc9..82eafe4332 100644 --- a/packages/opentelemetry-api/src/trace/span_context.ts +++ b/packages/opentelemetry-api/src/trace/span_context.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/span_kind.ts b/packages/opentelemetry-api/src/trace/span_kind.ts index a6ca9b522c..d0ed18123e 100644 --- a/packages/opentelemetry-api/src/trace/span_kind.ts +++ b/packages/opentelemetry-api/src/trace/span_kind.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Type of span. Can be used to specify additional relationships between spans - * in addition to a parent/child relationship. - */ export enum SpanKind { /** Default value. Indicates that the span is used internally. */ INTERNAL = 0, diff --git a/packages/opentelemetry-api/src/trace/status.ts b/packages/opentelemetry-api/src/trace/status.ts index e9fa7201d8..12504992f7 100644 --- a/packages/opentelemetry-api/src/trace/status.ts +++ b/packages/opentelemetry-api/src/trace/status.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * The status of a Span by providing a standard CanonicalCode in conjunction - * with an optional descriptive message. - */ export interface Status { /** The canonical code of this message. */ code: CanonicalCode; diff --git a/packages/opentelemetry-api/src/trace/trace_flags.ts b/packages/opentelemetry-api/src/trace/trace_flags.ts index 8a593ec254..fd282010c7 100644 --- a/packages/opentelemetry-api/src/trace/trace_flags.ts +++ b/packages/opentelemetry-api/src/trace/trace_flags.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * An enumeration that represents global trace flags. These flags are - * propagated to all child {@link Span}. These determine features such as - * whether a Span should be traced. It is implemented as a bitmask. - */ export enum TraceFlags { /** Represents no flag set. */ NONE = 0x0, diff --git a/packages/opentelemetry-api/src/trace/trace_state.ts b/packages/opentelemetry-api/src/trace/trace_state.ts index b137eba60b..074633633e 100644 --- a/packages/opentelemetry-api/src/trace/trace_state.ts +++ b/packages/opentelemetry-api/src/trace/trace_state.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Tracestate carries system-specific configuration data, represented as a list - * of key-value pairs. TraceState allows multiple tracing systems to - * participate in the same trace. - */ export interface TraceState { /** * Adds or updates the TraceState that has the given `key` if it is diff --git a/packages/opentelemetry-api/src/trace/tracer.ts b/packages/opentelemetry-api/src/trace/tracer.ts index f7edc856a0..c0657ffed0 100644 --- a/packages/opentelemetry-api/src/trace/tracer.ts +++ b/packages/opentelemetry-api/src/trace/tracer.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/trace/tracer_provider.ts b/packages/opentelemetry-api/src/trace/tracer_provider.ts index df5e576e90..6919cc1e26 100644 --- a/packages/opentelemetry-api/src/trace/tracer_provider.ts +++ b/packages/opentelemetry-api/src/trace/tracer_provider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/src/version.ts b/packages/opentelemetry-api/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-api/src/version.ts +++ b/packages/opentelemetry-api/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/test/api/api.test.ts b/packages/opentelemetry-api/test/api/api.test.ts index d02453d252..77ecf8f70b 100644 --- a/packages/opentelemetry-api/test/api/api.test.ts +++ b/packages/opentelemetry-api/test/api/api.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/test/api/global.test.ts b/packages/opentelemetry-api/test/api/global.test.ts index 5ff4e25a2b..7d9ea5b9ca 100644 --- a/packages/opentelemetry-api/test/api/global.test.ts +++ b/packages/opentelemetry-api/test/api/global.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/test/index-webpack.ts b/packages/opentelemetry-api/test/index-webpack.ts index 7731f09091..061a48ccfa 100644 --- a/packages/opentelemetry-api/test/index-webpack.ts +++ b/packages/opentelemetry-api/test/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContext = require.context('.', true, /test$/); testsContext.keys().forEach(testsContext); diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts index 8738708eba..cbfe044a9f 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-meter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts index 76b9a14621..177d60d7bf 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-span.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts b/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts index e49d0c0388..62ed24bb8e 100644 --- a/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts +++ b/packages/opentelemetry-api/test/noop-implementations/noop-tracer.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts b/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts index adeef82c25..0d22c1fd5e 100644 --- a/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts +++ b/packages/opentelemetry-context-async-hooks/src/AsyncHooksContextManager.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-async-hooks/src/index.ts b/packages/opentelemetry-context-async-hooks/src/index.ts index 8a45a59477..9213cb8ae7 100644 --- a/packages/opentelemetry-context-async-hooks/src/index.ts +++ b/packages/opentelemetry-context-async-hooks/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-async-hooks/src/version.ts b/packages/opentelemetry-context-async-hooks/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-context-async-hooks/src/version.ts +++ b/packages/opentelemetry-context-async-hooks/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts b/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts index 15f403d622..15814dd196 100644 --- a/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts +++ b/packages/opentelemetry-context-async-hooks/test/AsyncHooksContextManager.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-base/src/NoopContextManager.ts b/packages/opentelemetry-context-base/src/NoopContextManager.ts index 62fbb88068..e02816f221 100644 --- a/packages/opentelemetry-context-base/src/NoopContextManager.ts +++ b/packages/opentelemetry-context-base/src/NoopContextManager.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-base/src/context.ts b/packages/opentelemetry-context-base/src/context.ts index 8b42d7e9af..a4486fd3ed 100644 --- a/packages/opentelemetry-context-base/src/context.ts +++ b/packages/opentelemetry-context-base/src/context.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Class which stores and manages current context values. All methods which - * update context such as get and delete do not modify an existing context, - * but create a new one with updated values. - */ export class Context { private _currentContext: Map; diff --git a/packages/opentelemetry-context-base/src/index.ts b/packages/opentelemetry-context-base/src/index.ts index edbc18c622..d9e53ab004 100644 --- a/packages/opentelemetry-context-base/src/index.ts +++ b/packages/opentelemetry-context-base/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-base/src/types.ts b/packages/opentelemetry-context-base/src/types.ts index 9624387ac7..e58a4990cf 100644 --- a/packages/opentelemetry-context-base/src/types.ts +++ b/packages/opentelemetry-context-base/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-base/src/version.ts b/packages/opentelemetry-context-base/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-context-base/src/version.ts +++ b/packages/opentelemetry-context-base/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-base/test/NoopContextManager.test.ts b/packages/opentelemetry-context-base/test/NoopContextManager.test.ts index af0323fedb..b35f979799 100644 --- a/packages/opentelemetry-context-base/test/NoopContextManager.test.ts +++ b/packages/opentelemetry-context-base/test/NoopContextManager.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/karma.conf.js b/packages/opentelemetry-context-zone-peer-dep/karma.conf.js index 7183aab033..3019564a15 100644 --- a/packages/opentelemetry-context-zone-peer-dep/karma.conf.js +++ b/packages/opentelemetry-context-zone-peer-dep/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts b/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts index c985738ff4..16c159dbc6 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/src/index.ts b/packages/opentelemetry-context-zone-peer-dep/src/index.ts index 2c37135209..041e627912 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/index.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/src/types.ts b/packages/opentelemetry-context-zone-peer-dep/src/types.ts index e67614be70..4c073178c1 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/types.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/src/util.ts b/packages/opentelemetry-context-zone-peer-dep/src/util.ts index 98022f9219..2d5e87996f 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/util.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/util.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/src/version.ts b/packages/opentelemetry-context-zone-peer-dep/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/version.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts b/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts index 49571bf4bd..9712a7bf1c 100644 --- a/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts +++ b/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone-peer-dep/test/index-webpack.ts b/packages/opentelemetry-context-zone-peer-dep/test/index-webpack.ts index 7731f09091..061a48ccfa 100644 --- a/packages/opentelemetry-context-zone-peer-dep/test/index-webpack.ts +++ b/packages/opentelemetry-context-zone-peer-dep/test/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContext = require.context('.', true, /test$/); testsContext.keys().forEach(testsContext); diff --git a/packages/opentelemetry-context-zone-peer-dep/test/utils.test.ts b/packages/opentelemetry-context-zone-peer-dep/test/utils.test.ts index 66e649e26d..21d9ef1aaf 100644 --- a/packages/opentelemetry-context-zone-peer-dep/test/utils.test.ts +++ b/packages/opentelemetry-context-zone-peer-dep/test/utils.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone/src/index.ts b/packages/opentelemetry-context-zone/src/index.ts index df2ea15056..ba99ea33bd 100644 --- a/packages/opentelemetry-context-zone/src/index.ts +++ b/packages/opentelemetry-context-zone/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-context-zone/src/version.ts b/packages/opentelemetry-context-zone/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-context-zone/src/version.ts +++ b/packages/opentelemetry-context-zone/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/karma.conf.js b/packages/opentelemetry-core/karma.conf.js index 7b8c9678db..bf2a41b799 100644 --- a/packages/opentelemetry-core/karma.conf.js +++ b/packages/opentelemetry-core/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/ExportResult.ts b/packages/opentelemetry-core/src/ExportResult.ts index 75eddbace3..bc73766e98 100644 --- a/packages/opentelemetry-core/src/ExportResult.ts +++ b/packages/opentelemetry-core/src/ExportResult.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/common/ConsoleLogger.ts b/packages/opentelemetry-core/src/common/ConsoleLogger.ts index 561fa74d95..c2cc8b58f4 100644 --- a/packages/opentelemetry-core/src/common/ConsoleLogger.ts +++ b/packages/opentelemetry-core/src/common/ConsoleLogger.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/common/NoopLogger.ts b/packages/opentelemetry-core/src/common/NoopLogger.ts index f0b1edd1d3..ad8cc8b639 100644 --- a/packages/opentelemetry-core/src/common/NoopLogger.ts +++ b/packages/opentelemetry-core/src/common/NoopLogger.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/common/time.ts b/packages/opentelemetry-core/src/common/time.ts index 13fdec0450..893fa03dc6 100644 --- a/packages/opentelemetry-core/src/common/time.ts +++ b/packages/opentelemetry-core/src/common/time.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/common/types.ts b/packages/opentelemetry-core/src/common/types.ts index eb84ba58b7..a5b2e553d0 100644 --- a/packages/opentelemetry-core/src/common/types.ts +++ b/packages/opentelemetry-core/src/common/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** Defines a log levels. */ export enum LogLevel { ERROR, WARN, diff --git a/packages/opentelemetry-core/src/context/context.ts b/packages/opentelemetry-core/src/context/context.ts index c1890915ce..c3a6dc33f5 100644 --- a/packages/opentelemetry-core/src/context/context.ts +++ b/packages/opentelemetry-core/src/context/context.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts b/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts index 27689c5de9..126be42c17 100644 --- a/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts +++ b/packages/opentelemetry-core/src/context/propagation/B3Propagator.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts b/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts index 4a5d4d698b..6d5513bdf2 100644 --- a/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts +++ b/packages/opentelemetry-core/src/context/propagation/HttpTraceContext.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/context/propagation/composite.ts b/packages/opentelemetry-core/src/context/propagation/composite.ts index c6010b319e..8b5d5d0857 100644 --- a/packages/opentelemetry-core/src/context/propagation/composite.ts +++ b/packages/opentelemetry-core/src/context/propagation/composite.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/context/propagation/types.ts b/packages/opentelemetry-core/src/context/propagation/types.ts index 7e32712b8c..9b7b2213d7 100644 --- a/packages/opentelemetry-core/src/context/propagation/types.ts +++ b/packages/opentelemetry-core/src/context/propagation/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/correlation-context/correlation-context.ts b/packages/opentelemetry-core/src/correlation-context/correlation-context.ts index 08df15bc0a..130bf24142 100644 --- a/packages/opentelemetry-core/src/correlation-context/correlation-context.ts +++ b/packages/opentelemetry-core/src/correlation-context/correlation-context.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/correlation-context/propagation/HttpCorrelationContext.ts b/packages/opentelemetry-core/src/correlation-context/propagation/HttpCorrelationContext.ts index 0415b7a4bf..0101e901f5 100644 --- a/packages/opentelemetry-core/src/correlation-context/propagation/HttpCorrelationContext.ts +++ b/packages/opentelemetry-core/src/correlation-context/propagation/HttpCorrelationContext.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index f9266cd2ce..ddf5fe4a67 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/internal/validators.ts b/packages/opentelemetry-core/src/internal/validators.ts index 5b1c941bed..78fbee8234 100644 --- a/packages/opentelemetry-core/src/internal/validators.ts +++ b/packages/opentelemetry-core/src/internal/validators.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/BaseAbstractPlugin.ts b/packages/opentelemetry-core/src/platform/BaseAbstractPlugin.ts index 57ec582d2d..7a334310fd 100644 --- a/packages/opentelemetry-core/src/platform/BaseAbstractPlugin.ts +++ b/packages/opentelemetry-core/src/platform/BaseAbstractPlugin.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/browser/BasePlugin.ts b/packages/opentelemetry-core/src/platform/browser/BasePlugin.ts index f9b99d05cb..4ace89ab48 100644 --- a/packages/opentelemetry-core/src/platform/browser/BasePlugin.ts +++ b/packages/opentelemetry-core/src/platform/browser/BasePlugin.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/browser/hex-to-base64.ts b/packages/opentelemetry-core/src/platform/browser/hex-to-base64.ts index d0441b7772..baf01bdc36 100644 --- a/packages/opentelemetry-core/src/platform/browser/hex-to-base64.ts +++ b/packages/opentelemetry-core/src/platform/browser/hex-to-base64.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * converts id string into base64 - * @param hexStr - id of span - */ export function hexToBase64(hexStr: string): string { const hexStrLen = hexStr.length; let hexAsciiCharsStr = ''; diff --git a/packages/opentelemetry-core/src/platform/browser/id.ts b/packages/opentelemetry-core/src/platform/browser/id.ts index 02af4b220e..24f33972fd 100644 --- a/packages/opentelemetry-core/src/platform/browser/id.ts +++ b/packages/opentelemetry-core/src/platform/browser/id.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// IE 11 exposes `crypto` as `msCrypto`. declare type WindowWithMsCrypto = Window & { msCrypto?: Crypto; }; diff --git a/packages/opentelemetry-core/src/platform/browser/index.ts b/packages/opentelemetry-core/src/platform/browser/index.ts index 15f8e3412d..d066951cf9 100644 --- a/packages/opentelemetry-core/src/platform/browser/index.ts +++ b/packages/opentelemetry-core/src/platform/browser/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/browser/performance.ts b/packages/opentelemetry-core/src/platform/browser/performance.ts index 2287803e65..e07b4ffb60 100644 --- a/packages/opentelemetry-core/src/platform/browser/performance.ts +++ b/packages/opentelemetry-core/src/platform/browser/performance.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/browser/sdk-info.ts b/packages/opentelemetry-core/src/platform/browser/sdk-info.ts index f37897b468..b07b009dee 100644 --- a/packages/opentelemetry-core/src/platform/browser/sdk-info.ts +++ b/packages/opentelemetry-core/src/platform/browser/sdk-info.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/browser/timer-util.ts b/packages/opentelemetry-core/src/platform/browser/timer-util.ts index 81245de391..2798b6c0dc 100644 --- a/packages/opentelemetry-core/src/platform/browser/timer-util.ts +++ b/packages/opentelemetry-core/src/platform/browser/timer-util.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,6 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** This is Node specific, does nothing in case of browser */ export function unrefTimer(timer: number): void {} diff --git a/packages/opentelemetry-core/src/platform/index.ts b/packages/opentelemetry-core/src/platform/index.ts index ef7a1e50a8..a12506ffa9 100644 --- a/packages/opentelemetry-core/src/platform/index.ts +++ b/packages/opentelemetry-core/src/platform/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// Use the node platform by default. The "browser" field of package.json is used -// to override this file to use `./browser/index.ts` when packaged with -// webpack, Rollup, etc. export * from './node'; diff --git a/packages/opentelemetry-core/src/platform/node/BasePlugin.ts b/packages/opentelemetry-core/src/platform/node/BasePlugin.ts index df79686802..d1ebc622cf 100644 --- a/packages/opentelemetry-core/src/platform/node/BasePlugin.ts +++ b/packages/opentelemetry-core/src/platform/node/BasePlugin.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts b/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts index 1ed62f9cf9..9330aaa91f 100644 --- a/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts +++ b/packages/opentelemetry-core/src/platform/node/hex-to-base64.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * converts id string into base64 - * @param hexStr - id of span - */ export function hexToBase64(hexStr: string): string { const hexStrLen = hexStr.length; let hexAsciiCharsStr = ''; diff --git a/packages/opentelemetry-core/src/platform/node/id.ts b/packages/opentelemetry-core/src/platform/node/id.ts index fa4cd6a916..970025385c 100644 --- a/packages/opentelemetry-core/src/platform/node/id.ts +++ b/packages/opentelemetry-core/src/platform/node/id.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/node/index.ts b/packages/opentelemetry-core/src/platform/node/index.ts index 71f289fdf5..693bef3145 100644 --- a/packages/opentelemetry-core/src/platform/node/index.ts +++ b/packages/opentelemetry-core/src/platform/node/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/node/performance.ts b/packages/opentelemetry-core/src/platform/node/performance.ts index fd94ee83ed..6fbd9b31ff 100644 --- a/packages/opentelemetry-core/src/platform/node/performance.ts +++ b/packages/opentelemetry-core/src/platform/node/performance.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/node/sdk-info.ts b/packages/opentelemetry-core/src/platform/node/sdk-info.ts index 33c475d428..0a59c93d33 100644 --- a/packages/opentelemetry-core/src/platform/node/sdk-info.ts +++ b/packages/opentelemetry-core/src/platform/node/sdk-info.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/platform/node/timer-util.ts b/packages/opentelemetry-core/src/platform/node/timer-util.ts index 132ba860bc..92668d5ba1 100644 --- a/packages/opentelemetry-core/src/platform/node/timer-util.ts +++ b/packages/opentelemetry-core/src/platform/node/timer-util.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,11 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * When called, the active Timeout object will not require the Node.js event - * loop to remain active. - */ export function unrefTimer(timer: NodeJS.Timeout): void { timer.unref(); } diff --git a/packages/opentelemetry-core/src/trace/NoRecordingSpan.ts b/packages/opentelemetry-core/src/trace/NoRecordingSpan.ts index cf2920ab37..57c91f4108 100644 --- a/packages/opentelemetry-core/src/trace/NoRecordingSpan.ts +++ b/packages/opentelemetry-core/src/trace/NoRecordingSpan.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/trace/TraceState.ts b/packages/opentelemetry-core/src/trace/TraceState.ts index 951b04964b..0ef420dbe3 100644 --- a/packages/opentelemetry-core/src/trace/TraceState.ts +++ b/packages/opentelemetry-core/src/trace/TraceState.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts b/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts index 04e455e889..d4c7207f34 100644 --- a/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts +++ b/packages/opentelemetry-core/src/trace/sampler/ProbabilitySampler.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/trace/spancontext-utils.ts b/packages/opentelemetry-core/src/trace/spancontext-utils.ts index 42f91368fd..31719aa6e1 100644 --- a/packages/opentelemetry-core/src/trace/spancontext-utils.ts +++ b/packages/opentelemetry-core/src/trace/spancontext-utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/utils/url.ts b/packages/opentelemetry-core/src/utils/url.ts index 8ed779bca2..a6122ae784 100644 --- a/packages/opentelemetry-core/src/utils/url.ts +++ b/packages/opentelemetry-core/src/utils/url.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Check if {@param url} matches {@param urlToMatch} - * @param url - * @param urlToMatch - */ export function urlMatches(url: string, urlToMatch: string | RegExp): boolean { if (typeof urlToMatch === 'string') { return url === urlToMatch; diff --git a/packages/opentelemetry-core/src/utils/wrap.ts b/packages/opentelemetry-core/src/utils/wrap.ts index ad3ac6b4c3..b566a78bbf 100644 --- a/packages/opentelemetry-core/src/utils/wrap.ts +++ b/packages/opentelemetry-core/src/utils/wrap.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/src/version.ts b/packages/opentelemetry-core/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-core/src/version.ts +++ b/packages/opentelemetry-core/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/common/ConsoleLogger.test.ts b/packages/opentelemetry-core/test/common/ConsoleLogger.test.ts index f35dfe38e4..b00900e39f 100644 --- a/packages/opentelemetry-core/test/common/ConsoleLogger.test.ts +++ b/packages/opentelemetry-core/test/common/ConsoleLogger.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/common/time.test.ts b/packages/opentelemetry-core/test/common/time.test.ts index 07c404c8c9..bfbace2df3 100644 --- a/packages/opentelemetry-core/test/common/time.test.ts +++ b/packages/opentelemetry-core/test/common/time.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/context/B3Propagator.test.ts b/packages/opentelemetry-core/test/context/B3Propagator.test.ts index 7b779c3b94..436033480e 100644 --- a/packages/opentelemetry-core/test/context/B3Propagator.test.ts +++ b/packages/opentelemetry-core/test/context/B3Propagator.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts b/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts index c82e50b636..aa28e5583e 100644 --- a/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts +++ b/packages/opentelemetry-core/test/context/HttpTraceContext.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/context/composite.test.ts b/packages/opentelemetry-core/test/context/composite.test.ts index 080b802154..dce823dfe4 100644 --- a/packages/opentelemetry-core/test/context/composite.test.ts +++ b/packages/opentelemetry-core/test/context/composite.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/correlation-context/HttpCorrelationContext.test.ts b/packages/opentelemetry-core/test/correlation-context/HttpCorrelationContext.test.ts index da903819ac..8d294d8362 100644 --- a/packages/opentelemetry-core/test/correlation-context/HttpCorrelationContext.test.ts +++ b/packages/opentelemetry-core/test/correlation-context/HttpCorrelationContext.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/index-webpack.ts b/packages/opentelemetry-core/test/index-webpack.ts index 503a7b71dd..47db37c3f9 100644 --- a/packages/opentelemetry-core/test/index-webpack.ts +++ b/packages/opentelemetry-core/test/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContextCommon = require.context('.', true, /test$/); testsContextCommon.keys().forEach(key => { if (key.indexOf('./platform/BasePlugin.test') >= 0) { diff --git a/packages/opentelemetry-core/test/internal/validators.test.ts b/packages/opentelemetry-core/test/internal/validators.test.ts index 9324842624..58dc7b596d 100644 --- a/packages/opentelemetry-core/test/internal/validators.test.ts +++ b/packages/opentelemetry-core/test/internal/validators.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/platform/BasePlugin.test.ts b/packages/opentelemetry-core/test/platform/BasePlugin.test.ts index 115c07627c..912d4bc4a1 100644 --- a/packages/opentelemetry-core/test/platform/BasePlugin.test.ts +++ b/packages/opentelemetry-core/test/platform/BasePlugin.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/platform/browser/BasePlugin.test.ts b/packages/opentelemetry-core/test/platform/browser/BasePlugin.test.ts index f9e08413ee..202d74e350 100644 --- a/packages/opentelemetry-core/test/platform/browser/BasePlugin.test.ts +++ b/packages/opentelemetry-core/test/platform/browser/BasePlugin.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts b/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts index 1165ef7b95..7f78ded3ef 100644 --- a/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts +++ b/packages/opentelemetry-core/test/platform/hex-to-base64.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/platform/id.test.ts b/packages/opentelemetry-core/test/platform/id.test.ts index 8c4b7d0dc4..c73e09fb0e 100644 --- a/packages/opentelemetry-core/test/platform/id.test.ts +++ b/packages/opentelemetry-core/test/platform/id.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts b/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts index b5855280ed..87bc315c9e 100644 --- a/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts +++ b/packages/opentelemetry-core/test/trace/NoRecordingSpan.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts index c6d7baed45..b7c90c581c 100644 --- a/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts +++ b/packages/opentelemetry-core/test/trace/ProbabilitySampler.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/trace/fixtures/test-package/foo/bar/internal.d.ts b/packages/opentelemetry-core/test/trace/fixtures/test-package/foo/bar/internal.d.ts index b2944765fa..59d191849c 100644 --- a/packages/opentelemetry-core/test/trace/fixtures/test-package/foo/bar/internal.d.ts +++ b/packages/opentelemetry-core/test/trace/fixtures/test-package/foo/bar/internal.d.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts b/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts index 5ffa807efa..9ac47df565 100644 --- a/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts +++ b/packages/opentelemetry-core/test/trace/spancontext-utils.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/trace/tracestate.test.ts b/packages/opentelemetry-core/test/trace/tracestate.test.ts index e59e8a0dca..2fc2a2a13a 100644 --- a/packages/opentelemetry-core/test/trace/tracestate.test.ts +++ b/packages/opentelemetry-core/test/trace/tracestate.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/utils/url.test.ts b/packages/opentelemetry-core/test/utils/url.test.ts index 205ec9aa07..8c9582989d 100644 --- a/packages/opentelemetry-core/test/utils/url.test.ts +++ b/packages/opentelemetry-core/test/utils/url.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-core/test/utils/wrap.test.ts b/packages/opentelemetry-core/test/utils/wrap.test.ts index eb92e0e799..25ef129718 100644 --- a/packages/opentelemetry-core/test/utils/wrap.test.ts +++ b/packages/opentelemetry-core/test/utils/wrap.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/karma.conf.js b/packages/opentelemetry-exporter-collector/karma.conf.js index 86965a0095..455b1437c8 100644 --- a/packages/opentelemetry-exporter-collector/karma.conf.js +++ b/packages/opentelemetry-exporter-collector/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts b/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts index 1d93318aa4..5de8714912 100644 --- a/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts +++ b/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts @@ -1,5 +1,5 @@ /* - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/index.ts b/packages/opentelemetry-exporter-collector/src/index.ts index 1107c4d288..52ec5f71f5 100644 --- a/packages/opentelemetry-exporter-collector/src/index.ts +++ b/packages/opentelemetry-exporter-collector/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts index 28cabeb5f0..696557098b 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/browser/index.ts b/packages/opentelemetry-exporter-collector/src/platform/browser/index.ts index df00fee615..f38bc0489f 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/browser/index.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/browser/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/index.ts b/packages/opentelemetry-exporter-collector/src/platform/index.ts index 16f6fd9be2..cdaf8858ce 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/index.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts index 639d373685..f135c64d93 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/index.ts b/packages/opentelemetry-exporter-collector/src/platform/node/index.ts index df00fee615..f38bc0489f 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/index.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/types.ts b/packages/opentelemetry-exporter-collector/src/platform/node/types.ts index b36b9a65ad..cdb4da9f07 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/types.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/util.ts b/packages/opentelemetry-exporter-collector/src/platform/node/util.ts index 0aef79ba1c..9ad59d5690 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/util.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/util.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,12 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * It will remove http or https from the link as grpc requires link without - * protocol - * @param url - */ export function removeProtocol(url: string): string { return url.replace(/^https?:\/\//, ''); } diff --git a/packages/opentelemetry-exporter-collector/src/transform.ts b/packages/opentelemetry-exporter-collector/src/transform.ts index 1e60930c38..8fed306770 100644 --- a/packages/opentelemetry-exporter-collector/src/transform.ts +++ b/packages/opentelemetry-exporter-collector/src/transform.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/types.ts b/packages/opentelemetry-exporter-collector/src/types.ts index 96fc2e13c0..ea10b0ca4b 100644 --- a/packages/opentelemetry-exporter-collector/src/types.ts +++ b/packages/opentelemetry-exporter-collector/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/src/version.ts b/packages/opentelemetry-exporter-collector/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-exporter-collector/src/version.ts +++ b/packages/opentelemetry-exporter-collector/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts index 539997b8f2..02a0def5d1 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/test/browser/index-webpack.ts b/packages/opentelemetry-exporter-collector/test/browser/index-webpack.ts index 9fdb7117a2..99100a0f6e 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/index-webpack.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContext = require.context('../browser', true, /test$/); testsContext.keys().forEach(testsContext); diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts index 60d482129b..c384b3f804 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/test/common/transform.test.ts b/packages/opentelemetry-exporter-collector/test/common/transform.test.ts index 266b83aa5c..665ef10391 100644 --- a/packages/opentelemetry-exporter-collector/test/common/transform.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/transform.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/test/helper.ts b/packages/opentelemetry-exporter-collector/test/helper.ts index aed78dfb95..86ac2fc688 100644 --- a/packages/opentelemetry-exporter-collector/test/helper.ts +++ b/packages/opentelemetry-exporter-collector/test/helper.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts index a76e35ea1f..da4802b70b 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/src/index.ts b/packages/opentelemetry-exporter-jaeger/src/index.ts index 0eeb94aad7..ca7eafd1d7 100644 --- a/packages/opentelemetry-exporter-jaeger/src/index.ts +++ b/packages/opentelemetry-exporter-jaeger/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts index a08996ac1d..910bc6d837 100644 --- a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts +++ b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/src/transform.ts b/packages/opentelemetry-exporter-jaeger/src/transform.ts index 668576ce6e..e1ff8d88d2 100644 --- a/packages/opentelemetry-exporter-jaeger/src/transform.ts +++ b/packages/opentelemetry-exporter-jaeger/src/transform.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/src/types.ts b/packages/opentelemetry-exporter-jaeger/src/types.ts index b882848e4c..d721b96028 100644 --- a/packages/opentelemetry-exporter-jaeger/src/types.ts +++ b/packages/opentelemetry-exporter-jaeger/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/src/utils.ts b/packages/opentelemetry-exporter-jaeger/src/utils.ts index 6e61f4e7bb..ff29a5a525 100644 --- a/packages/opentelemetry-exporter-jaeger/src/utils.ts +++ b/packages/opentelemetry-exporter-jaeger/src/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/src/version.ts b/packages/opentelemetry-exporter-jaeger/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-exporter-jaeger/src/version.ts +++ b/packages/opentelemetry-exporter-jaeger/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts index 926baabdea..4b5d6ff7fe 100644 --- a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts index 58477ad0fb..173ac26010 100644 --- a/packages/opentelemetry-exporter-jaeger/test/transform.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/transform.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-prometheus/src/export/types.ts b/packages/opentelemetry-exporter-prometheus/src/export/types.ts index c3a04f5d53..d4e320ecdb 100644 --- a/packages/opentelemetry-exporter-prometheus/src/export/types.ts +++ b/packages/opentelemetry-exporter-prometheus/src/export/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-prometheus/src/index.ts b/packages/opentelemetry-exporter-prometheus/src/index.ts index ff3d57cb44..be7bd5f868 100644 --- a/packages/opentelemetry-exporter-prometheus/src/index.ts +++ b/packages/opentelemetry-exporter-prometheus/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts index 1532717b48..e2b23b33a2 100644 --- a/packages/opentelemetry-exporter-prometheus/src/prometheus.ts +++ b/packages/opentelemetry-exporter-prometheus/src/prometheus.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-prometheus/src/version.ts b/packages/opentelemetry-exporter-prometheus/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-exporter-prometheus/src/version.ts +++ b/packages/opentelemetry-exporter-prometheus/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts index e31c154bae..f0a152e9b2 100644 --- a/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts +++ b/packages/opentelemetry-exporter-prometheus/test/prometheus.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/src/index.ts b/packages/opentelemetry-exporter-zipkin/src/index.ts index 36741d5455..9a35ec9d07 100644 --- a/packages/opentelemetry-exporter-zipkin/src/index.ts +++ b/packages/opentelemetry-exporter-zipkin/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/src/transform.ts b/packages/opentelemetry-exporter-zipkin/src/transform.ts index b92d3e2f23..aebd956a93 100644 --- a/packages/opentelemetry-exporter-zipkin/src/transform.ts +++ b/packages/opentelemetry-exporter-zipkin/src/transform.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/src/types.ts b/packages/opentelemetry-exporter-zipkin/src/types.ts index 7667ef1783..812deed5f2 100644 --- a/packages/opentelemetry-exporter-zipkin/src/types.ts +++ b/packages/opentelemetry-exporter-zipkin/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/src/utils.ts b/packages/opentelemetry-exporter-zipkin/src/utils.ts index dc5c69b08d..ff29a5a525 100644 --- a/packages/opentelemetry-exporter-zipkin/src/utils.ts +++ b/packages/opentelemetry-exporter-zipkin/src/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/src/version.ts b/packages/opentelemetry-exporter-zipkin/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-exporter-zipkin/src/version.ts +++ b/packages/opentelemetry-exporter-zipkin/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts index 5ca0ff7c9d..8d2f72e5f6 100644 --- a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts +++ b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/test/e2e.test.ts b/packages/opentelemetry-exporter-zipkin/test/e2e.test.ts index 643a06a74c..96181daa51 100644 --- a/packages/opentelemetry-exporter-zipkin/test/e2e.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/e2e.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts index 0bb180c180..475f0ed2d8 100644 --- a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts b/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts index c4a7a24bc9..813a0a6185 100644 --- a/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/zipkin.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/BoundInstrument.ts b/packages/opentelemetry-metrics/src/BoundInstrument.ts index fd6966b1b3..dad6ce01ec 100644 --- a/packages/opentelemetry-metrics/src/BoundInstrument.ts +++ b/packages/opentelemetry-metrics/src/BoundInstrument.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/Meter.ts b/packages/opentelemetry-metrics/src/Meter.ts index a8678751df..a632befae6 100644 --- a/packages/opentelemetry-metrics/src/Meter.ts +++ b/packages/opentelemetry-metrics/src/Meter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/MeterProvider.ts b/packages/opentelemetry-metrics/src/MeterProvider.ts index 0315a76e35..ae8ef64539 100644 --- a/packages/opentelemetry-metrics/src/MeterProvider.ts +++ b/packages/opentelemetry-metrics/src/MeterProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/Metric.ts b/packages/opentelemetry-metrics/src/Metric.ts index 194971ba5e..a446e4ddc4 100644 --- a/packages/opentelemetry-metrics/src/Metric.ts +++ b/packages/opentelemetry-metrics/src/Metric.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/MetricObservable.ts b/packages/opentelemetry-metrics/src/MetricObservable.ts index cd52774743..f6c751a1e9 100644 --- a/packages/opentelemetry-metrics/src/MetricObservable.ts +++ b/packages/opentelemetry-metrics/src/MetricObservable.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/ObserverResult.ts b/packages/opentelemetry-metrics/src/ObserverResult.ts index 2ed593351d..32793dcc9c 100644 --- a/packages/opentelemetry-metrics/src/ObserverResult.ts +++ b/packages/opentelemetry-metrics/src/ObserverResult.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts b/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts index 03a4b1c277..3618ec2f50 100644 --- a/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts +++ b/packages/opentelemetry-metrics/src/UpDownCounterMetric.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/Utils.ts b/packages/opentelemetry-metrics/src/Utils.ts index 4b94defa89..de9e9eabfa 100644 --- a/packages/opentelemetry-metrics/src/Utils.ts +++ b/packages/opentelemetry-metrics/src/Utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/Batcher.ts b/packages/opentelemetry-metrics/src/export/Batcher.ts index 23f2d24fa2..de7d32c1fe 100644 --- a/packages/opentelemetry-metrics/src/export/Batcher.ts +++ b/packages/opentelemetry-metrics/src/export/Batcher.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts b/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts index 90f2f6be5d..9f0d83eb39 100644 --- a/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts +++ b/packages/opentelemetry-metrics/src/export/ConsoleMetricExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/Controller.ts b/packages/opentelemetry-metrics/src/export/Controller.ts index 5ce3d0ee68..0b63ba12cf 100644 --- a/packages/opentelemetry-metrics/src/export/Controller.ts +++ b/packages/opentelemetry-metrics/src/export/Controller.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/NoopExporter.ts b/packages/opentelemetry-metrics/src/export/NoopExporter.ts index 05b3694939..ef748753b7 100644 --- a/packages/opentelemetry-metrics/src/export/NoopExporter.ts +++ b/packages/opentelemetry-metrics/src/export/NoopExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts b/packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts index 0e70a5792e..5603ee45e7 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/ValueRecorderExact.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts b/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts index 6b1fdc1ee9..182e61ccb4 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/countersum.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts b/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts index 52755804c9..655afd8ff7 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/histogram.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/aggregators/index.ts b/packages/opentelemetry-metrics/src/export/aggregators/index.ts index 7d1bd01d7d..a46b10a624 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/index.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/aggregators/observer.ts b/packages/opentelemetry-metrics/src/export/aggregators/observer.ts index d1ba176c30..90b193896a 100644 --- a/packages/opentelemetry-metrics/src/export/aggregators/observer.ts +++ b/packages/opentelemetry-metrics/src/export/aggregators/observer.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/export/types.ts b/packages/opentelemetry-metrics/src/export/types.ts index 2dacf02a9f..94e6e57c0a 100644 --- a/packages/opentelemetry-metrics/src/export/types.ts +++ b/packages/opentelemetry-metrics/src/export/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/index.ts b/packages/opentelemetry-metrics/src/index.ts index bc2cce8475..cf3eff3026 100644 --- a/packages/opentelemetry-metrics/src/index.ts +++ b/packages/opentelemetry-metrics/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/types.ts b/packages/opentelemetry-metrics/src/types.ts index d3a89cacb7..ab05a53e83 100644 --- a/packages/opentelemetry-metrics/src/types.ts +++ b/packages/opentelemetry-metrics/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/src/version.ts b/packages/opentelemetry-metrics/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-metrics/src/version.ts +++ b/packages/opentelemetry-metrics/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/test/Batcher.test.ts b/packages/opentelemetry-metrics/test/Batcher.test.ts index a295883cc6..b5daf3b454 100644 --- a/packages/opentelemetry-metrics/test/Batcher.test.ts +++ b/packages/opentelemetry-metrics/test/Batcher.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/test/Meter.test.ts b/packages/opentelemetry-metrics/test/Meter.test.ts index 451ff27487..5efdbb3499 100644 --- a/packages/opentelemetry-metrics/test/Meter.test.ts +++ b/packages/opentelemetry-metrics/test/Meter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/test/MeterProvider.test.ts b/packages/opentelemetry-metrics/test/MeterProvider.test.ts index 45c54db6bb..7156e12e7c 100644 --- a/packages/opentelemetry-metrics/test/MeterProvider.test.ts +++ b/packages/opentelemetry-metrics/test/MeterProvider.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts b/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts index 987f468212..08790ea8c5 100644 --- a/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts +++ b/packages/opentelemetry-metrics/test/export/ConsoleMetricExporter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts b/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts index efb1c6519a..45f6fe80f6 100644 --- a/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts +++ b/packages/opentelemetry-metrics/test/export/aggregators/histogram.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/NodeTracerProvider.ts b/packages/opentelemetry-node/src/NodeTracerProvider.ts index 6d7f51737b..0abe4b9aa2 100644 --- a/packages/opentelemetry-node/src/NodeTracerProvider.ts +++ b/packages/opentelemetry-node/src/NodeTracerProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/config.ts b/packages/opentelemetry-node/src/config.ts index f9cacf7ec0..65b7630761 100644 --- a/packages/opentelemetry-node/src/config.ts +++ b/packages/opentelemetry-node/src/config.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/index.ts b/packages/opentelemetry-node/src/index.ts index 665900aefb..bece472ede 100644 --- a/packages/opentelemetry-node/src/index.ts +++ b/packages/opentelemetry-node/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts index be278696a8..8ed3ebf4ce 100644 --- a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts +++ b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts b/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts index fca4da1a3b..832cb09086 100644 --- a/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts +++ b/packages/opentelemetry-node/src/instrumentation/ext-types.d.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/instrumentation/utils.ts b/packages/opentelemetry-node/src/instrumentation/utils.ts index 062682e3fb..238096cd06 100644 --- a/packages/opentelemetry-node/src/instrumentation/utils.ts +++ b/packages/opentelemetry-node/src/instrumentation/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/src/version.ts b/packages/opentelemetry-node/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-node/src/version.ts +++ b/packages/opentelemetry-node/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts index 9c65719061..72745c535a 100644 --- a/packages/opentelemetry-node/test/NodeTracerProvider.test.ts +++ b/packages/opentelemetry-node/test/NodeTracerProvider.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts index ff977d4ad8..2214e7165d 100644 --- a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts +++ b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/test/instrumentation/utils.test.ts b/packages/opentelemetry-node/test/instrumentation/utils.test.ts index 6d76572b76..0f2eb4f7ac 100644 --- a/packages/opentelemetry-node/test/instrumentation/utils.test.ts +++ b/packages/opentelemetry-node/test/instrumentation/utils.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-node/test/registration.test.ts b/packages/opentelemetry-node/test/registration.test.ts index d305673470..91153e1fdc 100644 --- a/packages/opentelemetry-node/test/registration.test.ts +++ b/packages/opentelemetry-node/test/registration.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts b/packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts index 2e9c2a9244..3fdea85bc7 100644 --- a/packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts +++ b/packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/src/grpc.ts b/packages/opentelemetry-plugin-grpc/src/grpc.ts index 0b7de00518..bbb04c0269 100644 --- a/packages/opentelemetry-plugin-grpc/src/grpc.ts +++ b/packages/opentelemetry-plugin-grpc/src/grpc.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/src/index.ts b/packages/opentelemetry-plugin-grpc/src/index.ts index bf0385539c..4ffcf69671 100644 --- a/packages/opentelemetry-plugin-grpc/src/index.ts +++ b/packages/opentelemetry-plugin-grpc/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/src/types.ts b/packages/opentelemetry-plugin-grpc/src/types.ts index f6198295fd..56ee679c63 100644 --- a/packages/opentelemetry-plugin-grpc/src/types.ts +++ b/packages/opentelemetry-plugin-grpc/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/src/utils.ts b/packages/opentelemetry-plugin-grpc/src/utils.ts index f9d5c6dd79..9c9e5a336b 100644 --- a/packages/opentelemetry-plugin-grpc/src/utils.ts +++ b/packages/opentelemetry-plugin-grpc/src/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/src/version.ts b/packages/opentelemetry-plugin-grpc/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-plugin-grpc/src/version.ts +++ b/packages/opentelemetry-plugin-grpc/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts index 12dd723c89..ac113b0e01 100644 --- a/packages/opentelemetry-plugin-grpc/test/grpc.test.ts +++ b/packages/opentelemetry-plugin-grpc/test/grpc.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts b/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts index b484a1561e..d6a6a7b3e2 100644 --- a/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts +++ b/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts b/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts index 6ea8eb8983..5071f31324 100644 --- a/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts +++ b/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Attributes Names according to [OpenTelemetry attributes specs](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-http.md#common-attributes) - */ export enum AttributeNames { HTTP_HOST = 'http.host', COMPONENT = 'component', diff --git a/packages/opentelemetry-plugin-http/src/http.ts b/packages/opentelemetry-plugin-http/src/http.ts index 9db4f207ab..cc4af12c6d 100644 --- a/packages/opentelemetry-plugin-http/src/http.ts +++ b/packages/opentelemetry-plugin-http/src/http.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/src/index.ts b/packages/opentelemetry-plugin-http/src/index.ts index 4d678a5f65..f96c809586 100644 --- a/packages/opentelemetry-plugin-http/src/index.ts +++ b/packages/opentelemetry-plugin-http/src/index.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/src/types.ts b/packages/opentelemetry-plugin-http/src/types.ts index 4be2114657..9f1149e269 100644 --- a/packages/opentelemetry-plugin-http/src/types.ts +++ b/packages/opentelemetry-plugin-http/src/types.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/src/utils.ts b/packages/opentelemetry-plugin-http/src/utils.ts index baa7adf90a..ef54a59b93 100644 --- a/packages/opentelemetry-plugin-http/src/utils.ts +++ b/packages/opentelemetry-plugin-http/src/utils.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/src/version.ts b/packages/opentelemetry-plugin-http/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-plugin-http/src/version.ts +++ b/packages/opentelemetry-plugin-http/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts index 5a5d0407c7..3b80fe84ba 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-disable.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts index 1c32b3156f..0597ce7d4f 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts index 57cbe57427..bb98825b39 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-package.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts index af89fa51ed..c5e8c4c304 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts index 264eec94a8..beac0ac7f3 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts b/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts index f8ef3ed337..fe7ef01e51 100644 --- a/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts +++ b/packages/opentelemetry-plugin-http/test/utils/DummyPropagation.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts index aaf1f7aedb..c99828ec6f 100644 --- a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/utils/httpRequest.ts b/packages/opentelemetry-plugin-http/test/utils/httpRequest.ts index bf97c3bf91..f507b7f1f1 100644 --- a/packages/opentelemetry-plugin-http/test/utils/httpRequest.ts +++ b/packages/opentelemetry-plugin-http/test/utils/httpRequest.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-http/test/utils/utils.ts b/packages/opentelemetry-plugin-http/test/utils/utils.ts index 256afbfdc5..5d2e5cb3bc 100644 --- a/packages/opentelemetry-plugin-http/test/utils/utils.ts +++ b/packages/opentelemetry-plugin-http/test/utils/utils.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/src/https.ts b/packages/opentelemetry-plugin-https/src/https.ts index cbf5d1b919..396587eaca 100644 --- a/packages/opentelemetry-plugin-https/src/https.ts +++ b/packages/opentelemetry-plugin-https/src/https.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/src/index.ts b/packages/opentelemetry-plugin-https/src/index.ts index 19d7007d09..0c7c3d80af 100644 --- a/packages/opentelemetry-plugin-https/src/index.ts +++ b/packages/opentelemetry-plugin-https/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/src/utils.ts b/packages/opentelemetry-plugin-https/src/utils.ts index eed5c63d33..8d702bdfc0 100644 --- a/packages/opentelemetry-plugin-https/src/utils.ts +++ b/packages/opentelemetry-plugin-https/src/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/src/version.ts b/packages/opentelemetry-plugin-https/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-plugin-https/src/version.ts +++ b/packages/opentelemetry-plugin-https/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts index d323be77ba..9d0e8dece6 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-disable.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts index 21d43c39bd..2c3533973a 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts index e22ec5c246..a4463a4754 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-package.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts index 9da20e1b07..d36ef1274b 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts b/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts index 02c85aa92e..906efe7968 100644 --- a/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts +++ b/packages/opentelemetry-plugin-https/test/utils/DummyPropagation.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts index 91afcab170..1b1860df9f 100644 --- a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/utils/httpsRequest.ts b/packages/opentelemetry-plugin-https/test/utils/httpsRequest.ts index 956c1da2e2..f75cf1e566 100644 --- a/packages/opentelemetry-plugin-https/test/utils/httpsRequest.ts +++ b/packages/opentelemetry-plugin-https/test/utils/httpsRequest.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-https/test/utils/utils.ts b/packages/opentelemetry-plugin-https/test/utils/utils.ts index 57a75516a1..a4e37eabea 100644 --- a/packages/opentelemetry-plugin-https/test/utils/utils.ts +++ b/packages/opentelemetry-plugin-https/test/utils/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/karma.conf.js b/packages/opentelemetry-plugin-xml-http-request/karma.conf.js index 7183aab033..3019564a15 100644 --- a/packages/opentelemetry-plugin-xml-http-request/karma.conf.js +++ b/packages/opentelemetry-plugin-xml-http-request/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts b/packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts index 64112652d5..29adbdff16 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-http.md#common-attributes - */ export enum AttributeNames { COMPONENT = 'component', HTTP_HOST = 'http.host', diff --git a/packages/opentelemetry-plugin-xml-http-request/src/enums/EventNames.ts b/packages/opentelemetry-plugin-xml-http-request/src/enums/EventNames.ts index c3edf96cea..b0e7983fa6 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/enums/EventNames.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/enums/EventNames.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/src/index.ts b/packages/opentelemetry-plugin-xml-http-request/src/index.ts index 41f752b023..80ed3961b0 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/index.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/src/types.ts b/packages/opentelemetry-plugin-xml-http-request/src/types.ts index 0fb63f676a..bc49bcd62b 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/types.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/src/version.ts b/packages/opentelemetry-plugin-xml-http-request/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/version.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts index 13e8e03c0f..65fbab52bc 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-plugin-xml-http-request/test/index-webpack.ts b/packages/opentelemetry-plugin-xml-http-request/test/index-webpack.ts index 7731f09091..061a48ccfa 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/index-webpack.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContext = require.context('.', true, /test$/); testsContext.keys().forEach(testsContext); diff --git a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts index ff2b487941..81ab9778fa 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/Resource.ts b/packages/opentelemetry-resources/src/Resource.ts index bed19ee739..f8dc503c1c 100644 --- a/packages/opentelemetry-resources/src/Resource.ts +++ b/packages/opentelemetry-resources/src/Resource.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/constants.ts b/packages/opentelemetry-resources/src/constants.ts index c6423777b3..d60b604522 100644 --- a/packages/opentelemetry-resources/src/constants.ts +++ b/packages/opentelemetry-resources/src/constants.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,13 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Semantic conventions for Resources - * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/data-resource-semantic-conventions.md - */ - -/** Attributes defining a running environment (e.g. Cloud, Data Center). */ export const CLOUD_RESOURCE = { /** Name of the cloud provider. Example values are aws, azure, gcp. */ PROVIDER: 'cloud.provider', diff --git a/packages/opentelemetry-resources/src/index.ts b/packages/opentelemetry-resources/src/index.ts index 13673409aa..f5a851015a 100644 --- a/packages/opentelemetry-resources/src/index.ts +++ b/packages/opentelemetry-resources/src/index.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts index 43db76639a..7ea78b8d39 100644 --- a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts +++ b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/browser/index.ts b/packages/opentelemetry-resources/src/platform/browser/index.ts index 560cdcf821..f90eb34a5f 100644 --- a/packages/opentelemetry-resources/src/platform/browser/index.ts +++ b/packages/opentelemetry-resources/src/platform/browser/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/index.ts b/packages/opentelemetry-resources/src/platform/index.ts index 6c6d039c91..a12506ffa9 100644 --- a/packages/opentelemetry-resources/src/platform/index.ts +++ b/packages/opentelemetry-resources/src/platform/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,8 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// Use the node platform by default. The "browser" field of package.json is used -// to override this file to use `./browser/index.ts` when packaged with -// webpack, Rollup, etc. export * from './node'; diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts index 2351250582..d226ed4437 100644 --- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts +++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts index 7e68016925..e58c214db0 100644 --- a/packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts +++ b/packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts index a6e4cf31b1..58ba567c36 100644 --- a/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts +++ b/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts index ab1136fe8b..25518ed963 100644 --- a/packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts +++ b/packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/index.ts b/packages/opentelemetry-resources/src/platform/node/detectors/index.ts index 79597f3f1c..c0c3c37b2c 100644 --- a/packages/opentelemetry-resources/src/platform/node/detectors/index.ts +++ b/packages/opentelemetry-resources/src/platform/node/detectors/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/platform/node/index.ts b/packages/opentelemetry-resources/src/platform/node/index.ts index 560cdcf821..f90eb34a5f 100644 --- a/packages/opentelemetry-resources/src/platform/node/index.ts +++ b/packages/opentelemetry-resources/src/platform/node/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/types.ts b/packages/opentelemetry-resources/src/types.ts index a9705350a5..e1aa0d45b0 100644 --- a/packages/opentelemetry-resources/src/types.ts +++ b/packages/opentelemetry-resources/src/types.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/src/version.ts b/packages/opentelemetry-resources/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-resources/src/version.ts +++ b/packages/opentelemetry-resources/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/Resource.test.ts b/packages/opentelemetry-resources/test/Resource.test.ts index 4061932532..0c5d0feb9f 100644 --- a/packages/opentelemetry-resources/test/Resource.test.ts +++ b/packages/opentelemetry-resources/test/Resource.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/detect-resources.test.ts b/packages/opentelemetry-resources/test/detect-resources.test.ts index 4bf5a0d7cc..ca609fb3c4 100644 --- a/packages/opentelemetry-resources/test/detect-resources.test.ts +++ b/packages/opentelemetry-resources/test/detect-resources.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts b/packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts index 4c04897916..b60a6cc7f6 100644 --- a/packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts +++ b/packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts b/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts index b8dfe508eb..20a63e64d5 100644 --- a/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts +++ b/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts b/packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts index 271f8f9c89..75adb78980 100644 --- a/packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts +++ b/packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/resource-assertions.test.ts b/packages/opentelemetry-resources/test/resource-assertions.test.ts index 2ccff2e1b4..20e626daac 100644 --- a/packages/opentelemetry-resources/test/resource-assertions.test.ts +++ b/packages/opentelemetry-resources/test/resource-assertions.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-resources/test/util/resource-assertions.ts b/packages/opentelemetry-resources/test/util/resource-assertions.ts index 01ae1f17c0..a6db54b320 100644 --- a/packages/opentelemetry-resources/test/util/resource-assertions.ts +++ b/packages/opentelemetry-resources/test/util/resource-assertions.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-shim-opentracing/src/index.ts b/packages/opentelemetry-shim-opentracing/src/index.ts index 7f4e715ee0..e47e7bbcdf 100644 --- a/packages/opentelemetry-shim-opentracing/src/index.ts +++ b/packages/opentelemetry-shim-opentracing/src/index.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-shim-opentracing/src/shim.ts b/packages/opentelemetry-shim-opentracing/src/shim.ts index 0fc561bacb..14a49f411f 100644 --- a/packages/opentelemetry-shim-opentracing/src/shim.ts +++ b/packages/opentelemetry-shim-opentracing/src/shim.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-shim-opentracing/src/version.ts b/packages/opentelemetry-shim-opentracing/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-shim-opentracing/src/version.ts +++ b/packages/opentelemetry-shim-opentracing/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts index f7358c9421..9524045d15 100644 --- a/packages/opentelemetry-shim-opentracing/test/Shim.test.ts +++ b/packages/opentelemetry-shim-opentracing/test/Shim.test.ts @@ -1,5 +1,5 @@ -/** - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/karma.conf.js b/packages/opentelemetry-tracing/karma.conf.js index 7183aab033..3019564a15 100644 --- a/packages/opentelemetry-tracing/karma.conf.js +++ b/packages/opentelemetry-tracing/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/BasicTracerProvider.ts b/packages/opentelemetry-tracing/src/BasicTracerProvider.ts index 375f998aa7..43b1474cb4 100644 --- a/packages/opentelemetry-tracing/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-tracing/src/BasicTracerProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts b/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts index 92a04dd530..ccd96d51d7 100644 --- a/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/MultiSpanProcessor.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts b/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts index c00bcb393a..d9291c0436 100644 --- a/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/NoopSpanProcessor.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/Span.ts b/packages/opentelemetry-tracing/src/Span.ts index 7a6c97bda7..d602d64dd6 100644 --- a/packages/opentelemetry-tracing/src/Span.ts +++ b/packages/opentelemetry-tracing/src/Span.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/SpanProcessor.ts b/packages/opentelemetry-tracing/src/SpanProcessor.ts index 7f8deae0a9..ad415fec83 100644 --- a/packages/opentelemetry-tracing/src/SpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/SpanProcessor.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/Tracer.ts b/packages/opentelemetry-tracing/src/Tracer.ts index dbedb8949c..9bc8004eab 100644 --- a/packages/opentelemetry-tracing/src/Tracer.ts +++ b/packages/opentelemetry-tracing/src/Tracer.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/config.ts b/packages/opentelemetry-tracing/src/config.ts index 99eb0d22fd..e06be1c7cc 100644 --- a/packages/opentelemetry-tracing/src/config.ts +++ b/packages/opentelemetry-tracing/src/config.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts b/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts index 381ec393f4..9076dfdf21 100644 --- a/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/export/BatchSpanProcessor.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts b/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts index 42c5875bd6..dfb12a25bf 100644 --- a/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts +++ b/packages/opentelemetry-tracing/src/export/ConsoleSpanExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts b/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts index b3de120411..04eec13318 100644 --- a/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts +++ b/packages/opentelemetry-tracing/src/export/InMemorySpanExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/export/ReadableSpan.ts b/packages/opentelemetry-tracing/src/export/ReadableSpan.ts index 93bf90ea5d..48436444be 100644 --- a/packages/opentelemetry-tracing/src/export/ReadableSpan.ts +++ b/packages/opentelemetry-tracing/src/export/ReadableSpan.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts b/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts index 073ffb3f20..eb35a378f6 100644 --- a/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts +++ b/packages/opentelemetry-tracing/src/export/SimpleSpanProcessor.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/export/SpanExporter.ts b/packages/opentelemetry-tracing/src/export/SpanExporter.ts index 72f7ff2572..e83621e594 100644 --- a/packages/opentelemetry-tracing/src/export/SpanExporter.ts +++ b/packages/opentelemetry-tracing/src/export/SpanExporter.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/index.ts b/packages/opentelemetry-tracing/src/index.ts index 6fdcfce454..720241a310 100644 --- a/packages/opentelemetry-tracing/src/index.ts +++ b/packages/opentelemetry-tracing/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/types.ts b/packages/opentelemetry-tracing/src/types.ts index 7f5dedb031..c6eeae35d0 100644 --- a/packages/opentelemetry-tracing/src/types.ts +++ b/packages/opentelemetry-tracing/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/utility.ts b/packages/opentelemetry-tracing/src/utility.ts index a417c6e74b..3143a8b1de 100644 --- a/packages/opentelemetry-tracing/src/utility.ts +++ b/packages/opentelemetry-tracing/src/utility.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/src/version.ts b/packages/opentelemetry-tracing/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-tracing/src/version.ts +++ b/packages/opentelemetry-tracing/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts index 6de7339798..da06751509 100644 --- a/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts +++ b/packages/opentelemetry-tracing/test/BasicTracerProvider.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts index b83da007a6..ea0a6b8e3e 100644 --- a/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/MultiSpanProcessor.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/Span.test.ts b/packages/opentelemetry-tracing/test/Span.test.ts index db73757371..9c070c4189 100644 --- a/packages/opentelemetry-tracing/test/Span.test.ts +++ b/packages/opentelemetry-tracing/test/Span.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/Tracer.test.ts b/packages/opentelemetry-tracing/test/Tracer.test.ts index 71b6aa569d..1c4922db84 100644 --- a/packages/opentelemetry-tracing/test/Tracer.test.ts +++ b/packages/opentelemetry-tracing/test/Tracer.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts index c4452bb069..05ec6b95ff 100644 --- a/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/export/BatchSpanProcessor.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts b/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts index 6377874195..4a4829ec3a 100644 --- a/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts +++ b/packages/opentelemetry-tracing/test/export/ConsoleSpanExporter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts b/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts index f83f96ce02..47af46580e 100644 --- a/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts +++ b/packages/opentelemetry-tracing/test/export/InMemorySpanExporter.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts b/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts index 572883b115..60f5cf0e8b 100644 --- a/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts +++ b/packages/opentelemetry-tracing/test/export/SimpleSpanProcessor.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-tracing/test/index-webpack.ts b/packages/opentelemetry-tracing/test/index-webpack.ts index 7731f09091..061a48ccfa 100644 --- a/packages/opentelemetry-tracing/test/index-webpack.ts +++ b/packages/opentelemetry-tracing/test/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContext = require.context('.', true, /test$/); testsContext.keys().forEach(testsContext); diff --git a/packages/opentelemetry-web/karma.conf.js b/packages/opentelemetry-web/karma.conf.js index 88c2849684..09cb7c72dd 100644 --- a/packages/opentelemetry-web/karma.conf.js +++ b/packages/opentelemetry-web/karma.conf.js @@ -1,5 +1,5 @@ /*! - * Copyright 2019, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/src/StackContextManager.ts b/packages/opentelemetry-web/src/StackContextManager.ts index e91755fdeb..78d8d34dc3 100644 --- a/packages/opentelemetry-web/src/StackContextManager.ts +++ b/packages/opentelemetry-web/src/StackContextManager.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/src/WebTracerProvider.ts b/packages/opentelemetry-web/src/WebTracerProvider.ts index 41200c455d..79d23d938d 100644 --- a/packages/opentelemetry-web/src/WebTracerProvider.ts +++ b/packages/opentelemetry-web/src/WebTracerProvider.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/src/enums/PerformanceTimingNames.ts b/packages/opentelemetry-web/src/enums/PerformanceTimingNames.ts index 12d5a44fa8..846a9ba967 100644 --- a/packages/opentelemetry-web/src/enums/PerformanceTimingNames.ts +++ b/packages/opentelemetry-web/src/enums/PerformanceTimingNames.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/src/index.ts b/packages/opentelemetry-web/src/index.ts index aafef2114c..a506be00ce 100644 --- a/packages/opentelemetry-web/src/index.ts +++ b/packages/opentelemetry-web/src/index.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/src/types.ts b/packages/opentelemetry-web/src/types.ts index be51c8ad62..45ed1a9e03 100644 --- a/packages/opentelemetry-web/src/types.ts +++ b/packages/opentelemetry-web/src/types.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/** - * Performance metrics - */ import { PerformanceTimingNames } from './enums/PerformanceTimingNames'; export type PerformanceEntries = { diff --git a/packages/opentelemetry-web/src/utils.ts b/packages/opentelemetry-web/src/utils.ts index e5a3cd43fe..1edeb64f0c 100644 --- a/packages/opentelemetry-web/src/utils.ts +++ b/packages/opentelemetry-web/src/utils.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/src/version.ts b/packages/opentelemetry-web/src/version.ts index 90d0ab01d0..9e616149a4 100644 --- a/packages/opentelemetry-web/src/version.ts +++ b/packages/opentelemetry-web/src/version.ts @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/test/StackContextManager.test.ts b/packages/opentelemetry-web/test/StackContextManager.test.ts index 5c0fe26b22..daebd27971 100644 --- a/packages/opentelemetry-web/test/StackContextManager.test.ts +++ b/packages/opentelemetry-web/test/StackContextManager.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/test/WebTracerProvider.test.ts b/packages/opentelemetry-web/test/WebTracerProvider.test.ts index 92f40ccdf0..01b1590d96 100644 --- a/packages/opentelemetry-web/test/WebTracerProvider.test.ts +++ b/packages/opentelemetry-web/test/WebTracerProvider.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/test/index-webpack.ts b/packages/opentelemetry-web/test/index-webpack.ts index 7731f09091..061a48ccfa 100644 --- a/packages/opentelemetry-web/test/index-webpack.ts +++ b/packages/opentelemetry-web/test/index-webpack.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,9 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -// This file is the webpack entry point for the browser Karma tests. It requires -// all modules ending in "test" from the current folder and all its subfolders. const testsContext = require.context('.', true, /test$/); testsContext.keys().forEach(testsContext); diff --git a/packages/opentelemetry-web/test/registration.test.ts b/packages/opentelemetry-web/test/registration.test.ts index adcee3a94e..215dfad19f 100644 --- a/packages/opentelemetry-web/test/registration.test.ts +++ b/packages/opentelemetry-web/test/registration.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2020, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/opentelemetry-web/test/utils.test.ts b/packages/opentelemetry-web/test/utils.test.ts index 96745f5514..52a417ba42 100644 --- a/packages/opentelemetry-web/test/utils.test.ts +++ b/packages/opentelemetry-web/test/utils.test.ts @@ -1,5 +1,5 @@ -/*! - * Copyright 2019, OpenTelemetry Authors +/* + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/scripts/version-update.js b/scripts/version-update.js index 720456fdef..32b05516da 100644 --- a/scripts/version-update.js +++ b/scripts/version-update.js @@ -1,5 +1,5 @@ /* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ const packageJsonUrl = path.resolve(`${appRoot}/package.json`); const pjson = require(packageJsonUrl); const content = `/* - * Copyright 2020, OpenTelemetry Authors + * Copyright The OpenTelemetry Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 8c56442e297776bc4164d1079108b872d741c846 Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Fri, 12 Jun 2020 09:58:38 -0400 Subject: [PATCH 06/22] feat: add OPENTELEMETRY_NO_PATCH_MODULES (#1153) Co-authored-by: Daniel Dyla --- packages/opentelemetry-node/README.md | 8 ++ .../src/instrumentation/PluginLoader.ts | 39 +++++++++ .../test/instrumentation/PluginLoader.test.ts | 85 +++++++++++++++++++ 3 files changed, 132 insertions(+) diff --git a/packages/opentelemetry-node/README.md b/packages/opentelemetry-node/README.md index df932e2ed1..258e95ff80 100644 --- a/packages/opentelemetry-node/README.md +++ b/packages/opentelemetry-node/README.md @@ -102,6 +102,14 @@ const provider = new NodeTracerProvider({ }); ``` +### Disable Plugins with Environment Variables + +Plugins can be disabled without modifying and redeploying code. +`OTEL_NO_PATCH_MODULES` accepts a +comma separated list of module names to disabled specific plugins. +The names should match what you use to `require` the module into your application. +For example, `OTEL_NO_PATCH_MODULES=pg,https` will disable the postgres plugin and the https plugin. To disable **all** plugins, set the environment variable to `*`. + ## Examples See how to automatically instrument [http](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/http) and [gRPC](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/grpc) using node-sdk. diff --git a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts index 8ed3ebf4ce..1c3a2b3d11 100644 --- a/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts +++ b/packages/opentelemetry-node/src/instrumentation/PluginLoader.ts @@ -30,6 +30,17 @@ export enum HookState { DISABLED, } +/** + * Environment variable which will contain list of modules to not load corresponding plugins for + * e.g.OTEL_NO_PATCH_MODULES=pg,https,mongodb + */ +export const ENV_PLUGIN_DISABLED_LIST = 'OTEL_NO_PATCH_MODULES'; + +/** + * Wildcard symbol. If ignore list is set to this, disable all plugins + */ +const DISABLE_ALL_PLUGINS = '*'; + export interface Plugins { [pluginName: string]: PluginConfig; } @@ -46,6 +57,18 @@ function filterPlugins(plugins: Plugins): Plugins { }, {}); } +/** + * Parse process.env[ENV_PLUGIN_DISABLED_LIST] for a list of modules + * not to load corresponding plugins for. + */ +function getIgnoreList(): string[] | typeof DISABLE_ALL_PLUGINS { + const envIgnoreList: string = process.env[ENV_PLUGIN_DISABLED_LIST] || ''; + if (envIgnoreList === DISABLE_ALL_PLUGINS) { + return envIgnoreList; + } + return envIgnoreList.split(',').map(v => v.trim()); +} + /** * The PluginLoader class can load instrumentation plugins that use a patch * mechanism to enable automatic tracing for specific target modules. @@ -74,6 +97,7 @@ export class PluginLoader { if (this._hookState === HookState.UNINITIALIZED) { const pluginsToLoad = filterPlugins(plugins); const modulesToHook = Object.keys(pluginsToLoad); + const modulesToIgnore = getIgnoreList(); // Do not hook require when no module is provided. In this case it is // not necessary. With skipping this step we lower our footprint in // customer applications and require-in-the-middle won't show up in CPU @@ -119,6 +143,21 @@ export class PluginLoader { version = utils.getPackageVersion(this.logger, baseDir); } + // Skip loading of all modules if '*' is provided + if (modulesToIgnore === DISABLE_ALL_PLUGINS) { + this.logger.info( + `PluginLoader#load: skipped patching module ${name} because all plugins are disabled (${ENV_PLUGIN_DISABLED_LIST})` + ); + return exports; + } + + if (modulesToIgnore.includes(name)) { + this.logger.info( + `PluginLoader#load: skipped patching module ${name} because it was on the ignore list (${ENV_PLUGIN_DISABLED_LIST})` + ); + return exports; + } + this.logger.info( `PluginLoader#load: trying to load ${name}@${version}` ); diff --git a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts index 2214e7165d..954cf7f8ed 100644 --- a/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts +++ b/packages/opentelemetry-node/test/instrumentation/PluginLoader.test.ts @@ -23,6 +23,7 @@ import { PluginLoader, Plugins, searchPathForTest, + ENV_PLUGIN_DISABLED_LIST, } from '../../src/instrumentation/PluginLoader'; const INSTALLED_PLUGINS_PATH = path.join(__dirname, 'node_modules'); @@ -135,6 +136,10 @@ describe('PluginLoader', () => { }); describe('.load()', () => { + afterEach(() => { + delete process.env[ENV_PLUGIN_DISABLED_LIST]; + }); + it('sanity check', () => { // Ensure that module fixtures contain values that we expect. const simpleModule = require('simple-module'); @@ -152,6 +157,86 @@ describe('PluginLoader', () => { assert.throws(() => require('nonexistent-module')); }); + it('should not load a plugin on the ignore list environment variable', () => { + // Set ignore list env var + process.env[ENV_PLUGIN_DISABLED_LIST] = 'simple-module'; + const pluginLoader = new PluginLoader(provider, logger); + pluginLoader.load({ ...simplePlugins, ...supportedVersionPlugins }); + + assert.strictEqual(pluginLoader['_plugins'].length, 0); + + const simpleModule = require('simple-module'); + assert.strictEqual(pluginLoader['_plugins'].length, 0); + assert.strictEqual(simpleModule.value(), 0); + assert.strictEqual(simpleModule.name(), 'simple-module'); + + const supportedModule = require('supported-module'); + assert.strictEqual(pluginLoader['_plugins'].length, 1); + assert.strictEqual(supportedModule.value(), 1); + assert.strictEqual(supportedModule.name(), 'patched-supported-module'); + + pluginLoader.unload(); + }); + + it('should not load plugins on the ignore list environment variable', () => { + // Set ignore list env var + process.env[ENV_PLUGIN_DISABLED_LIST] = 'simple-module,http'; + const pluginLoader = new PluginLoader(provider, logger); + pluginLoader.load({ + ...simplePlugins, + ...supportedVersionPlugins, + ...httpPlugins, + }); + + assert.strictEqual(pluginLoader['_plugins'].length, 0); + + const simpleModule = require('simple-module'); + assert.strictEqual(pluginLoader['_plugins'].length, 0); + assert.strictEqual(simpleModule.value(), 0); + assert.strictEqual(simpleModule.name(), 'simple-module'); + + const httpModule = require('http'); + assert.ok(httpModule); + assert.strictEqual(pluginLoader['_plugins'].length, 0); + + const supportedModule = require('supported-module'); + assert.strictEqual(pluginLoader['_plugins'].length, 1); + assert.strictEqual(supportedModule.value(), 1); + assert.strictEqual(supportedModule.name(), 'patched-supported-module'); + + pluginLoader.unload(); + }); + + it('should not load any plugins if ignore list environment variable is set to "*"', () => { + // Set ignore list env var + process.env[ENV_PLUGIN_DISABLED_LIST] = '*'; + const pluginLoader = new PluginLoader(provider, logger); + pluginLoader.load({ + ...simplePlugins, + ...supportedVersionPlugins, + ...httpPlugins, + }); + + assert.strictEqual(pluginLoader['_plugins'].length, 0); + + const simpleModule = require('simple-module'); + const httpModule = require('http'); + const supportedModule = require('supported-module'); + + assert.strictEqual( + pluginLoader['_plugins'].length, + 0, + 'No plugins were loaded' + ); + assert.strictEqual(simpleModule.value(), 0); + assert.strictEqual(simpleModule.name(), 'simple-module'); + assert.ok(httpModule); + assert.strictEqual(supportedModule.value(), 0); + assert.strictEqual(supportedModule.name(), 'supported-module'); + + pluginLoader.unload(); + }); + it('should load a plugin and patch the target modules', () => { const pluginLoader = new PluginLoader(provider, logger); assert.strictEqual(pluginLoader['_plugins'].length, 0); From acb0a2fcad2f1d420e44926b3d20e5bb437f5534 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 12 Jun 2020 18:16:10 +0200 Subject: [PATCH 07/22] chore(deps): update dependency karma to v5.1.0 (#1189) Co-authored-by: Daniel Dyla --- packages/opentelemetry-api/package.json | 2 +- packages/opentelemetry-context-zone-peer-dep/package.json | 2 +- packages/opentelemetry-context-zone/package.json | 2 +- packages/opentelemetry-core/package.json | 2 +- packages/opentelemetry-exporter-collector/package.json | 2 +- packages/opentelemetry-plugin-xml-http-request/package.json | 2 +- packages/opentelemetry-tracing/package.json | 2 +- packages/opentelemetry-web/package.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/opentelemetry-api/package.json b/packages/opentelemetry-api/package.json index 5c538564da..13f820977b 100644 --- a/packages/opentelemetry-api/package.json +++ b/packages/opentelemetry-api/package.json @@ -60,7 +60,7 @@ "codecov": "3.7.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-mocha": "2.0.1", diff --git a/packages/opentelemetry-context-zone-peer-dep/package.json b/packages/opentelemetry-context-zone-peer-dep/package.json index ca61ffed52..7594f35d60 100644 --- a/packages/opentelemetry-context-zone-peer-dep/package.json +++ b/packages/opentelemetry-context-zone-peer-dep/package.json @@ -51,7 +51,7 @@ "codecov": "3.7.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-mocha": "2.0.1", diff --git a/packages/opentelemetry-context-zone/package.json b/packages/opentelemetry-context-zone/package.json index b4dba6cdd4..f9aaebceb2 100644 --- a/packages/opentelemetry-context-zone/package.json +++ b/packages/opentelemetry-context-zone/package.json @@ -46,7 +46,7 @@ "babel-loader": "8.1.0", "codecov": "3.7.0", "gts": "2.0.2", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-mocha": "2.0.1", "karma-spec-reporter": "0.0.32", diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 818eec738d..86c5223fd4 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -59,7 +59,7 @@ "codecov": "3.7.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-mocha": "2.0.1", diff --git a/packages/opentelemetry-exporter-collector/package.json b/packages/opentelemetry-exporter-collector/package.json index 5d25eb5ced..bf9197929f 100644 --- a/packages/opentelemetry-exporter-collector/package.json +++ b/packages/opentelemetry-exporter-collector/package.json @@ -63,7 +63,7 @@ "cpx": "1.5.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-mocha": "2.0.1", diff --git a/packages/opentelemetry-plugin-xml-http-request/package.json b/packages/opentelemetry-plugin-xml-http-request/package.json index b0f878bc09..f3964d3998 100644 --- a/packages/opentelemetry-plugin-xml-http-request/package.json +++ b/packages/opentelemetry-plugin-xml-http-request/package.json @@ -55,7 +55,7 @@ "codecov": "3.7.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-mocha": "2.0.1", diff --git a/packages/opentelemetry-tracing/package.json b/packages/opentelemetry-tracing/package.json index 652e245321..201d18e9b7 100644 --- a/packages/opentelemetry-tracing/package.json +++ b/packages/opentelemetry-tracing/package.json @@ -56,7 +56,7 @@ "codecov": "3.7.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-mocha": "2.0.1", diff --git a/packages/opentelemetry-web/package.json b/packages/opentelemetry-web/package.json index dcf829018d..96f83d1c29 100644 --- a/packages/opentelemetry-web/package.json +++ b/packages/opentelemetry-web/package.json @@ -54,7 +54,7 @@ "codecov": "3.7.0", "gts": "2.0.2", "istanbul-instrumenter-loader": "3.0.1", - "karma": "5.0.9", + "karma": "5.1.0", "karma-chrome-launcher": "3.1.0", "karma-coverage-istanbul-reporter": "3.0.3", "karma-jquery": "0.2.4", From 470621aee06da679b378b03efa4d9b239e5ba77b Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Fri, 12 Jun 2020 16:51:24 -0400 Subject: [PATCH 08/22] chore: add grpc-js skeleton (#1148) Co-authored-by: Mayur Kale --- .../.eslintignore | 1 + .../opentelemetry-plugin-grpc-js/.eslintrc.js | 7 + .../opentelemetry-plugin-grpc-js/.npmignore | 4 + packages/opentelemetry-plugin-grpc-js/LICENSE | 201 ++++++++++++++++++ .../opentelemetry-plugin-grpc-js/README.md | 66 ++++++ .../opentelemetry-plugin-grpc-js/package.json | 72 +++++++ .../src/enums/AttributeNames.ts | 24 +++ .../src/grpcJs.ts | 45 ++++ .../src/version.ts | 18 ++ .../tsconfig.json | 11 + 10 files changed, 449 insertions(+) create mode 100644 packages/opentelemetry-plugin-grpc-js/.eslintignore create mode 100644 packages/opentelemetry-plugin-grpc-js/.eslintrc.js create mode 100644 packages/opentelemetry-plugin-grpc-js/.npmignore create mode 100644 packages/opentelemetry-plugin-grpc-js/LICENSE create mode 100644 packages/opentelemetry-plugin-grpc-js/README.md create mode 100644 packages/opentelemetry-plugin-grpc-js/package.json create mode 100644 packages/opentelemetry-plugin-grpc-js/src/enums/AttributeNames.ts create mode 100644 packages/opentelemetry-plugin-grpc-js/src/grpcJs.ts create mode 100644 packages/opentelemetry-plugin-grpc-js/src/version.ts create mode 100644 packages/opentelemetry-plugin-grpc-js/tsconfig.json diff --git a/packages/opentelemetry-plugin-grpc-js/.eslintignore b/packages/opentelemetry-plugin-grpc-js/.eslintignore new file mode 100644 index 0000000000..378eac25d3 --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/.eslintignore @@ -0,0 +1 @@ +build diff --git a/packages/opentelemetry-plugin-grpc-js/.eslintrc.js b/packages/opentelemetry-plugin-grpc-js/.eslintrc.js new file mode 100644 index 0000000000..f726f3becb --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + "env": { + "mocha": true, + "node": true + }, + ...require('../../eslint.config.js') +} diff --git a/packages/opentelemetry-plugin-grpc-js/.npmignore b/packages/opentelemetry-plugin-grpc-js/.npmignore new file mode 100644 index 0000000000..9505ba9450 --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/.npmignore @@ -0,0 +1,4 @@ +/bin +/coverage +/doc +/test diff --git a/packages/opentelemetry-plugin-grpc-js/LICENSE b/packages/opentelemetry-plugin-grpc-js/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/opentelemetry-plugin-grpc-js/README.md b/packages/opentelemetry-plugin-grpc-js/README.md new file mode 100644 index 0000000000..c46aff6b4e --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/README.md @@ -0,0 +1,66 @@ +# OpenTelemetry @grpc/grpc-js Instrumentation for Node.js +[![Gitter chat][gitter-image]][gitter-url] +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-image] + +This module provides automatic instrumentation for [`@grpc/grpc-js`](https://grpc.io/blog/grpc-js-1.0/). Currently, version [`1.x`](https://www.npmjs.com/package/@grpc/grpc-js?activeTab=versions) of `@grpc/grpc-js` is supported. + +For automatic instrumentation see the +[@opentelemetry/node](https://github.com/open-telemetry/opentelemetry-js/tree/master/packages/opentelemetry-node) package. + +## Installation + +``` +npm install --save @opentelemetry/plugin-grpc-js +``` + +## Usage + +OpenTelemetry gRPC Instrumentation allows the user to automatically collect trace data and export them to the backend of choice, to give observability to distributed systems when working with [gRPC](https://www.npmjs.com/package/@grpc/grpc-js). + +To load a specific plugin (**gRPC** in this case), specify it in the Node Tracer's configuration. +```javascript +const { NodeTracerProvider } = require('@opentelemetry/node'); + +const provider = new NodeTracerProvider({ + plugins: { + '@grpc/grpc-js': { + enabled: true, + // You may use a package name or absolute path to the file. + path: '@opentelemetry/plugin-grpc-js', + } + } +}); +``` + +To load all of the [supported plugins](https://github.com/open-telemetry/opentelemetry-js#plugins), use below approach. Each plugin is only loaded when the module that it patches is loaded; in other words, there is no computational overhead for listing plugins for unused modules. +```javascript +const { NodeTracerProvider } = require('@opentelemetry/node'); + +const provider = new NodeTracerProvider(); +``` + + + + +## Useful links +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us on [gitter][gitter-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg +[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-plugin-grpc-js +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-grpc-js +[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-plugin-grpc-js +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-grpc-js&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/plugin-grpc-js +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fplugin-grpc-js.svg diff --git a/packages/opentelemetry-plugin-grpc-js/package.json b/packages/opentelemetry-plugin-grpc-js/package.json new file mode 100644 index 0000000000..f6026fbe1b --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/package.json @@ -0,0 +1,72 @@ +{ + "name": "@opentelemetry/plugin-grpc-js", + "private": true, + "version": "0.8.3", + "description": "OpenTelemetry @grpc/grpc-js automatic instrumentation package.", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "repository": "open-telemetry/opentelemetry-js", + "scripts": { + "test": "nyc ts-mocha -p tsconfig.json test/**/*.test.ts", + "tdd": "npm run test -- --watch-extensions ts --watch", + "clean": "rimraf build/*", + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "precompile": "tsc --version", + "version:update": "node ../../scripts/version-update.js", + "compile": "npm run version:update && tsc -p .", + "prepare": "npm run compile" + }, + "keywords": [ + "opentelemetry", + "grpc", + "grpc-js", + "nodejs", + "tracing", + "profiling", + "plugin" + ], + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + }, + "files": [ + "build/src/**/*.js", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@grpc/grpc-js": "^1.0.5", + "@opentelemetry/context-async-hooks": "^0.8.3", + "@opentelemetry/context-base": "^0.8.3", + "@opentelemetry/node": "^0.8.3", + "@opentelemetry/tracing": "^0.8.3", + "@types/mocha": "^7.0.0", + "@types/node": "^14.0.5", + "@types/semver": "^7.1.0", + "@types/shimmer": "^1.0.1", + "@types/sinon": "^7.0.13", + "codecov": "^3.6.1", + "gts": "^2.0.0", + "mocha": "^7.1.2", + "nyc": "^15.1.0", + "rimraf": "^3.0.0", + "semver": "7.3.2", + "sinon": "^7.5.0", + "ts-mocha": "^7.0.0", + "ts-node": "^8.6.2", + "typescript": "3.7.2" + }, + "dependencies": { + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "shimmer": "^1.2.1" + } +} diff --git a/packages/opentelemetry-plugin-grpc-js/src/enums/AttributeNames.ts b/packages/opentelemetry-plugin-grpc-js/src/enums/AttributeNames.ts new file mode 100644 index 0000000000..3fdea85bc7 --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/src/enums/AttributeNames.ts @@ -0,0 +1,24 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export enum AttributeNames { + COMPONENT = 'component', + GRPC_KIND = 'grpc.kind', // SERVER or CLIENT + GRPC_METHOD = 'grpc.method', + GRPC_STATUS_CODE = 'grpc.status_code', + GRPC_ERROR_NAME = 'grpc.error_name', + GRPC_ERROR_MESSAGE = 'grpc.error_message', +} diff --git a/packages/opentelemetry-plugin-grpc-js/src/grpcJs.ts b/packages/opentelemetry-plugin-grpc-js/src/grpcJs.ts new file mode 100644 index 0000000000..6a2c6e89f8 --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/src/grpcJs.ts @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BasePlugin } from '@opentelemetry/core'; +import { VERSION } from './version'; +import * as path from 'path'; + +import * as grpcJs from '@grpc/grpc-js'; + +/** + * @grpc/grpc-js gRPC instrumentation plugin for Opentelemetry + * https://www.npmjs.com/package/@grpc/grpc-js + */ +export class GrpcJsPlugin extends BasePlugin { + static readonly component = '@grpc/grpc-js'; + readonly supportedVersions = ['1.*']; + + constructor(readonly moduleName: string, readonly version: string) { + super('@opentelemetry/plugin-grpc-js', VERSION); + } + + protected patch(): typeof grpcJs { + throw new Error('Method not implemented.'); + } + protected unpatch(): void { + throw new Error('Method not implemented.'); + } +} + +const basedir = path.dirname(require.resolve(GrpcJsPlugin.component)); +const version = require(path.join(basedir, 'package.json')).version; +export const plugin = new GrpcJsPlugin(GrpcJsPlugin.component, version); diff --git a/packages/opentelemetry-plugin-grpc-js/src/version.ts b/packages/opentelemetry-plugin-grpc-js/src/version.ts new file mode 100644 index 0000000000..9e616149a4 --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/src/version.ts @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// this is autogenerated file, see scripts/version-update.js +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-grpc-js/tsconfig.json b/packages/opentelemetry-plugin-grpc-js/tsconfig.json new file mode 100644 index 0000000000..a2042cd68b --- /dev/null +++ b/packages/opentelemetry-plugin-grpc-js/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} From 5ae563ed0581cff53d286029920e60283480b728 Mon Sep 17 00:00:00 2001 From: Shivkanya Andhare <62445341+shivkanya9146@users.noreply.github.com> Date: Sat, 13 Jun 2020 04:02:45 +0530 Subject: [PATCH 09/22] Fix_typo (#1192) Co-authored-by: Mayur Kale --- packages/opentelemetry-exporter-zipkin/test/transform.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts index 475f0ed2d8..05cbbbfd0d 100644 --- a/packages/opentelemetry-exporter-zipkin/test/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/transform.test.ts @@ -44,7 +44,7 @@ const spanContext: api.SpanContext = { traceFlags: api.TraceFlags.SAMPLED, }; -const DUMMY_RESOUCE = new Resource({ +const DUMMY_RESOURCE = new Resource({ service: 'ui', version: 1, cost: 112.12, @@ -202,7 +202,7 @@ describe('transform', () => { span.status, statusCodeTagName, statusDescriptionTagName, - DUMMY_RESOUCE + DUMMY_RESOURCE ); assert.deepStrictEqual(tags, { From 9d5822713050f5914fb855d61eed0a2c6db79fee Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Sat, 13 Jun 2020 20:50:19 +0200 Subject: [PATCH 10/22] chore(deps): pin dependencies (#1194) --- .../opentelemetry-plugin-grpc-js/package.json | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/opentelemetry-plugin-grpc-js/package.json b/packages/opentelemetry-plugin-grpc-js/package.json index f6026fbe1b..7440b9211f 100644 --- a/packages/opentelemetry-plugin-grpc-js/package.json +++ b/packages/opentelemetry-plugin-grpc-js/package.json @@ -43,30 +43,30 @@ "access": "public" }, "devDependencies": { - "@grpc/grpc-js": "^1.0.5", + "@grpc/grpc-js": "1.0.5", "@opentelemetry/context-async-hooks": "^0.8.3", "@opentelemetry/context-base": "^0.8.3", "@opentelemetry/node": "^0.8.3", "@opentelemetry/tracing": "^0.8.3", - "@types/mocha": "^7.0.0", - "@types/node": "^14.0.5", - "@types/semver": "^7.1.0", - "@types/shimmer": "^1.0.1", - "@types/sinon": "^7.0.13", - "codecov": "^3.6.1", - "gts": "^2.0.0", - "mocha": "^7.1.2", - "nyc": "^15.1.0", - "rimraf": "^3.0.0", + "@types/mocha": "7.0.2", + "@types/node": "14.0.13", + "@types/semver": "7.2.0", + "@types/shimmer": "1.0.1", + "@types/sinon": "7.5.2", + "codecov": "3.7.0", + "gts": "2.0.2", + "mocha": "7.2.0", + "nyc": "15.1.0", + "rimraf": "3.0.2", "semver": "7.3.2", - "sinon": "^7.5.0", - "ts-mocha": "^7.0.0", - "ts-node": "^8.6.2", + "sinon": "7.5.0", + "ts-mocha": "7.0.0", + "ts-node": "8.10.2", "typescript": "3.7.2" }, "dependencies": { "@opentelemetry/api": "^0.8.3", "@opentelemetry/core": "^0.8.3", - "shimmer": "^1.2.1" + "shimmer": "1.2.1" } } From 0596054d56ef6fca5b8c3bfb46b5ce78f2f677cf Mon Sep 17 00:00:00 2001 From: Mark Wolff Date: Mon, 15 Jun 2020 14:15:27 -0400 Subject: [PATCH 11/22] refactor(attributes): move enums to @opentelemetry/semantic-conventions (#1160) --- .../opentelemetry-plugin-grpc/package.json | 1 + .../opentelemetry-plugin-grpc/src/grpc.ts | 46 ++-- .../test/utils/assertionUtils.ts | 4 +- .../opentelemetry-plugin-http/package.json | 1 + .../src/enums/AttributeNames.ts | 41 ---- .../opentelemetry-plugin-http/src/http.ts | 4 +- .../opentelemetry-plugin-http/src/index.ts | 1 - .../opentelemetry-plugin-http/src/utils.ts | 67 +++--- .../test/functionals/http-enable.test.ts | 26 +-- .../test/functionals/utils.test.ts | 10 +- .../test/integrations/http-enable.test.ts | 11 +- .../test/utils/assertSpan.ts | 36 ++-- .../opentelemetry-plugin-https/package.json | 1 + .../test/functionals/https-enable.test.ts | 26 +-- .../test/integrations/https-enable.test.ts | 16 +- .../test/utils/assertSpan.ts | 43 ++-- .../package.json | 1 + .../src/xhr.ts | 21 +- .../test/xhr.test.ts | 37 ++-- .../.eslintignore | 1 + .../.eslintrc.js | 9 + .../.npmignore | 4 + .../LICENSE | 201 ++++++++++++++++++ .../README.md | 49 +++++ .../package.json | 57 +++++ .../src/index.ts} | 9 +- .../src/trace/database.ts | 30 +++ .../src/trace/general.ts | 37 ++++ .../src/trace/http.ts | 33 +++ .../src/trace/index.ts} | 17 +- .../src/trace/rpc.ts | 25 +++ .../src/version.ts | 18 ++ .../tsconfig.json | 8 + 33 files changed, 668 insertions(+), 223 deletions(-) delete mode 100644 packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts create mode 100644 packages/opentelemetry-semantic-conventions/.eslintignore create mode 100644 packages/opentelemetry-semantic-conventions/.eslintrc.js create mode 100644 packages/opentelemetry-semantic-conventions/.npmignore create mode 100644 packages/opentelemetry-semantic-conventions/LICENSE create mode 100644 packages/opentelemetry-semantic-conventions/README.md create mode 100644 packages/opentelemetry-semantic-conventions/package.json rename packages/{opentelemetry-plugin-grpc/src/enums/AttributeNames.ts => opentelemetry-semantic-conventions/src/index.ts} (69%) create mode 100644 packages/opentelemetry-semantic-conventions/src/trace/database.ts create mode 100644 packages/opentelemetry-semantic-conventions/src/trace/general.ts create mode 100644 packages/opentelemetry-semantic-conventions/src/trace/http.ts rename packages/{opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts => opentelemetry-semantic-conventions/src/trace/index.ts} (63%) create mode 100644 packages/opentelemetry-semantic-conventions/src/trace/rpc.ts create mode 100644 packages/opentelemetry-semantic-conventions/src/version.ts create mode 100644 packages/opentelemetry-semantic-conventions/tsconfig.json diff --git a/packages/opentelemetry-plugin-grpc/package.json b/packages/opentelemetry-plugin-grpc/package.json index 5192ae91ce..564cc4e829 100644 --- a/packages/opentelemetry-plugin-grpc/package.json +++ b/packages/opentelemetry-plugin-grpc/package.json @@ -66,6 +66,7 @@ "dependencies": { "@opentelemetry/api": "^0.8.3", "@opentelemetry/core": "^0.8.3", + "@opentelemetry/semantic-conventions": "^0.8.3", "shimmer": "^1.2.1" } } diff --git a/packages/opentelemetry-plugin-grpc/src/grpc.ts b/packages/opentelemetry-plugin-grpc/src/grpc.ts index bbb04c0269..f0072ea569 100644 --- a/packages/opentelemetry-plugin-grpc/src/grpc.ts +++ b/packages/opentelemetry-plugin-grpc/src/grpc.ts @@ -23,12 +23,15 @@ import { SpanOptions, Status, } from '@opentelemetry/api'; +import { + GeneralAttribute, + RpcAttribute, +} from '@opentelemetry/semantic-conventions'; import { BasePlugin } from '@opentelemetry/core'; import * as events from 'events'; import * as grpcTypes from 'grpc'; import * as path from 'path'; import * as shimmer from 'shimmer'; -import { AttributeNames } from './enums/AttributeNames'; import { grpc, GrpcClientFunc, @@ -173,8 +176,8 @@ export class GrpcPlugin extends BasePlugin { const span = plugin._tracer .startSpan(spanName, spanOptions) .setAttributes({ - [AttributeNames.GRPC_KIND]: spanOptions.kind, - [AttributeNames.COMPONENT]: GrpcPlugin.component, + [RpcAttribute.GRPC_KIND]: spanOptions.kind, + [GeneralAttribute.COMPONENT]: GrpcPlugin.component, }); plugin._tracer.withSpan(span, () => { @@ -235,19 +238,16 @@ export class GrpcPlugin extends BasePlugin { code: _grpcStatusCodeToCanonicalCode(err.code), message: err.message, }); - span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, - err.code.toString() - ); + span.setAttribute(RpcAttribute.GRPC_STATUS_CODE, err.code.toString()); } span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, + [RpcAttribute.GRPC_ERROR_NAME]: err.name, + [RpcAttribute.GRPC_ERROR_MESSAGE]: err.message, }); } else { span.setStatus({ code: CanonicalCode.OK }); span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, + RpcAttribute.GRPC_STATUS_CODE, plugin._moduleExports.status.OK.toString() ); } @@ -281,7 +281,7 @@ export class GrpcPlugin extends BasePlugin { call.on('finish', () => { span.setStatus(_grpcStatusCodeToSpanStatus(call.status.code)); span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, + RpcAttribute.GRPC_STATUS_CODE, call.status.code.toString() ); @@ -299,8 +299,8 @@ export class GrpcPlugin extends BasePlugin { }); span.addEvent('finished with error'); span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, + [RpcAttribute.GRPC_ERROR_NAME]: err.name, + [RpcAttribute.GRPC_ERROR_MESSAGE]: err.message, }); endSpan(); }); @@ -357,7 +357,7 @@ export class GrpcPlugin extends BasePlugin { .startSpan(name, { kind: SpanKind.CLIENT, }) - .setAttribute(AttributeNames.COMPONENT, GrpcPlugin.component); + .setAttribute(GeneralAttribute.COMPONENT, GrpcPlugin.component); return plugin._tracer.withSpan(span, () => plugin._makeGrpcClientRemoteCall(original, args, this, plugin)(span) ); @@ -388,18 +388,18 @@ export class GrpcPlugin extends BasePlugin { if (err.code) { span.setStatus(_grpcStatusCodeToSpanStatus(err.code)); span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, + RpcAttribute.GRPC_STATUS_CODE, err.code.toString() ); } span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, + [RpcAttribute.GRPC_ERROR_NAME]: err.name, + [RpcAttribute.GRPC_ERROR_MESSAGE]: err.message, }); } else { span.setStatus({ code: CanonicalCode.OK }); span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, + RpcAttribute.GRPC_STATUS_CODE, plugin._moduleExports.status.OK.toString() ); } @@ -432,8 +432,8 @@ export class GrpcPlugin extends BasePlugin { span.addEvent('sent'); span.setAttributes({ - [AttributeNames.GRPC_METHOD]: original.path, - [AttributeNames.GRPC_KIND]: SpanKind.CLIENT, + [RpcAttribute.GRPC_METHOD]: original.path, + [RpcAttribute.GRPC_KIND]: SpanKind.CLIENT, }); this._setSpanContext(metadata); @@ -459,8 +459,8 @@ export class GrpcPlugin extends BasePlugin { message: err.message, }); span.setAttributes({ - [AttributeNames.GRPC_ERROR_NAME]: err.name, - [AttributeNames.GRPC_ERROR_MESSAGE]: err.message, + [RpcAttribute.GRPC_ERROR_NAME]: err.name, + [RpcAttribute.GRPC_ERROR_MESSAGE]: err.message, }); endSpan(); } @@ -471,7 +471,7 @@ export class GrpcPlugin extends BasePlugin { (status: Status) => { span.setStatus({ code: CanonicalCode.OK }); span.setAttribute( - AttributeNames.GRPC_STATUS_CODE, + RpcAttribute.GRPC_STATUS_CODE, status.code.toString() ); endSpan(); diff --git a/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts b/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts index d6a6a7b3e2..38b0069d1e 100644 --- a/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts +++ b/packages/opentelemetry-plugin-grpc/test/utils/assertionUtils.ts @@ -16,7 +16,6 @@ import { SpanKind } from '@opentelemetry/api'; import * as assert from 'assert'; -import { AttributeNames } from '../../src/enums/AttributeNames'; import { GrpcPlugin } from '../../src/grpc'; import * as grpc from 'grpc'; import { ReadableSpan } from '@opentelemetry/tracing'; @@ -24,6 +23,7 @@ import { hrTimeToMilliseconds, hrTimeToMicroseconds, } from '@opentelemetry/core'; +import { GeneralAttribute } from '@opentelemetry/semantic-conventions'; export const assertSpan = ( span: ReadableSpan, @@ -35,7 +35,7 @@ export const assertSpan = ( assert.strictEqual(span.kind, kind); assert.strictEqual( - span.attributes[AttributeNames.COMPONENT], + span.attributes[GeneralAttribute.COMPONENT], GrpcPlugin.component ); assert.ok(span.endTime); diff --git a/packages/opentelemetry-plugin-http/package.json b/packages/opentelemetry-plugin-http/package.json index f375d22701..ceab9d8a15 100644 --- a/packages/opentelemetry-plugin-http/package.json +++ b/packages/opentelemetry-plugin-http/package.json @@ -72,6 +72,7 @@ "dependencies": { "@opentelemetry/api": "^0.8.3", "@opentelemetry/core": "^0.8.3", + "@opentelemetry/semantic-conventions": "^0.8.3", "semver": "^7.1.3", "shimmer": "^1.2.1" } diff --git a/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts b/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts deleted file mode 100644 index 5071f31324..0000000000 --- a/packages/opentelemetry-plugin-http/src/enums/AttributeNames.ts +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -export enum AttributeNames { - HTTP_HOST = 'http.host', - COMPONENT = 'component', - HTTP_METHOD = 'http.method', - HTTP_TARGET = 'http.target', - HTTP_ROUTE = 'http.route', - HTTP_URL = 'http.url', - HTTP_STATUS_CODE = 'http.status_code', - HTTP_STATUS_TEXT = 'http.status_text', - HTTP_FLAVOR = 'http.flavor', - NET_PEER_IP = 'net.peer.ip', - NET_PEER_PORT = 'net.peer.port', - NET_PEER_NAME = 'net.peer.name', - NET_HOST_IP = 'net.host.ip', - NET_HOST_PORT = 'net.host.port', - NET_HOST_NAME = 'net.host.name', - NET_TRANSPORT = 'net.transport', - IP_TCP = 'IP.TCP', - IP_UDP = 'IP.UDP', - HTTP_SERVER_NAME = 'http.server_name', - HTTP_CLIENT_IP = 'http.client_ip', - // NOT ON OFFICIAL SPEC - HTTP_ERROR_NAME = 'http.error_name', - HTTP_ERROR_MESSAGE = 'http.error_message', - HTTP_USER_AGENT = 'http.user_agent', -} diff --git a/packages/opentelemetry-plugin-http/src/http.ts b/packages/opentelemetry-plugin-http/src/http.ts index cc4af12c6d..83b2792e9e 100644 --- a/packages/opentelemetry-plugin-http/src/http.ts +++ b/packages/opentelemetry-plugin-http/src/http.ts @@ -29,6 +29,7 @@ import { NoRecordingSpan, getExtractedSpanContext, } from '@opentelemetry/core'; +import { GeneralAttribute } from '@opentelemetry/semantic-conventions'; import { ClientRequest, IncomingMessage, @@ -40,7 +41,6 @@ import { Socket } from 'net'; import * as semver from 'semver'; import * as shimmer from 'shimmer'; import * as url from 'url'; -import { AttributeNames } from './enums/AttributeNames'; import { Err, Func, @@ -463,7 +463,7 @@ export class HttpPlugin extends BasePlugin { } else { span = this._tracer .startSpan(name, options) - .setAttribute(AttributeNames.COMPONENT, this.component); + .setAttribute(GeneralAttribute.COMPONENT, this.component); } this._spanNotEnded.add(span); return span; diff --git a/packages/opentelemetry-plugin-http/src/index.ts b/packages/opentelemetry-plugin-http/src/index.ts index f96c809586..265bc235a7 100644 --- a/packages/opentelemetry-plugin-http/src/index.ts +++ b/packages/opentelemetry-plugin-http/src/index.ts @@ -17,4 +17,3 @@ export * from './http'; export * from './types'; export * from './utils'; -export * from './enums/AttributeNames'; diff --git a/packages/opentelemetry-plugin-http/src/utils.ts b/packages/opentelemetry-plugin-http/src/utils.ts index ef54a59b93..90b4c0fe92 100644 --- a/packages/opentelemetry-plugin-http/src/utils.ts +++ b/packages/opentelemetry-plugin-http/src/utils.ts @@ -14,6 +14,10 @@ * limitations under the License. */ import { Attributes, CanonicalCode, Span, Status } from '@opentelemetry/api'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import { ClientRequest, IncomingHttpHeaders, @@ -24,7 +28,6 @@ import { } from 'http'; import { Socket } from 'net'; import * as url from 'url'; -import { AttributeNames } from './enums/AttributeNames'; import { Err, IgnoreMatcher, @@ -196,8 +199,8 @@ export const setSpanWithError = ( const message = error.message; span.setAttributes({ - [AttributeNames.HTTP_ERROR_NAME]: error.name, - [AttributeNames.HTTP_ERROR_MESSAGE]: message, + [HttpAttribute.HTTP_ERROR_NAME]: error.name, + [HttpAttribute.HTTP_ERROR_MESSAGE]: message, }); if (!obj) { @@ -334,18 +337,18 @@ export const getOutgoingRequestAttributes = ( const headers = requestOptions.headers || {}; const userAgent = headers['user-agent']; const attributes: Attributes = { - [AttributeNames.HTTP_URL]: getAbsoluteUrl( + [HttpAttribute.HTTP_URL]: getAbsoluteUrl( requestOptions, headers, `${options.component}:` ), - [AttributeNames.HTTP_METHOD]: method, - [AttributeNames.HTTP_TARGET]: requestOptions.path || '/', - [AttributeNames.NET_PEER_NAME]: hostname, + [HttpAttribute.HTTP_METHOD]: method, + [HttpAttribute.HTTP_TARGET]: requestOptions.path || '/', + [GeneralAttribute.NET_PEER_NAME]: hostname, }; if (userAgent !== undefined) { - attributes[AttributeNames.HTTP_USER_AGENT] = userAgent; + attributes[HttpAttribute.HTTP_USER_AGENT] = userAgent; } return attributes; }; @@ -357,11 +360,11 @@ export const getOutgoingRequestAttributes = ( export const getAttributesFromHttpKind = (kind?: string): Attributes => { const attributes: Attributes = {}; if (kind) { - attributes[AttributeNames.HTTP_FLAVOR] = kind; + attributes[HttpAttribute.HTTP_FLAVOR] = kind; if (kind.toUpperCase() !== 'QUIC') { - attributes[AttributeNames.NET_TRANSPORT] = AttributeNames.IP_TCP; + attributes[GeneralAttribute.NET_TRANSPORT] = GeneralAttribute.IP_TCP; } else { - attributes[AttributeNames.NET_TRANSPORT] = AttributeNames.IP_UDP; + attributes[GeneralAttribute.NET_TRANSPORT] = GeneralAttribute.IP_UDP; } } return attributes; @@ -379,14 +382,14 @@ export const getOutgoingRequestAttributesOnResponse = ( const { statusCode, statusMessage, httpVersion, socket } = response; const { remoteAddress, remotePort } = socket; const attributes: Attributes = { - [AttributeNames.NET_PEER_IP]: remoteAddress, - [AttributeNames.NET_PEER_PORT]: remotePort, - [AttributeNames.HTTP_HOST]: `${options.hostname}:${remotePort}`, + [GeneralAttribute.NET_PEER_IP]: remoteAddress, + [GeneralAttribute.NET_PEER_PORT]: remotePort, + [HttpAttribute.HTTP_HOST]: `${options.hostname}:${remotePort}`, }; if (statusCode) { - attributes[AttributeNames.HTTP_STATUS_CODE] = statusCode; - attributes[AttributeNames.HTTP_STATUS_TEXT] = ( + attributes[HttpAttribute.HTTP_STATUS_CODE] = statusCode; + attributes[HttpAttribute.HTTP_STATUS_TEXT] = ( statusMessage || '' ).toUpperCase(); } @@ -417,31 +420,31 @@ export const getIncomingRequestAttributes = ( 'localhost'; const serverName = options.serverName; const attributes: Attributes = { - [AttributeNames.HTTP_URL]: getAbsoluteUrl( + [HttpAttribute.HTTP_URL]: getAbsoluteUrl( requestUrl, headers, `${options.component}:` ), - [AttributeNames.HTTP_HOST]: host, - [AttributeNames.NET_HOST_NAME]: hostname, - [AttributeNames.HTTP_METHOD]: method, + [HttpAttribute.HTTP_HOST]: host, + [GeneralAttribute.NET_HOST_NAME]: hostname, + [HttpAttribute.HTTP_METHOD]: method, }; if (typeof ips === 'string') { - attributes[AttributeNames.HTTP_CLIENT_IP] = ips.split(',')[0]; + attributes[HttpAttribute.HTTP_CLIENT_IP] = ips.split(',')[0]; } if (typeof serverName === 'string') { - attributes[AttributeNames.HTTP_SERVER_NAME] = serverName; + attributes[HttpAttribute.HTTP_SERVER_NAME] = serverName; } if (requestUrl) { - attributes[AttributeNames.HTTP_ROUTE] = requestUrl.pathname || '/'; - attributes[AttributeNames.HTTP_TARGET] = requestUrl.pathname || '/'; + attributes[HttpAttribute.HTTP_ROUTE] = requestUrl.pathname || '/'; + attributes[HttpAttribute.HTTP_TARGET] = requestUrl.pathname || '/'; } if (userAgent !== undefined) { - attributes[AttributeNames.HTTP_USER_AGENT] = userAgent; + attributes[HttpAttribute.HTTP_USER_AGENT] = userAgent; } const httpKindAttributes = getAttributesFromHttpKind(httpVersion); @@ -471,16 +474,16 @@ export const getIncomingRequestAttributesOnResponse = ( : undefined; const attributes: Attributes = { - [AttributeNames.NET_HOST_IP]: localAddress, - [AttributeNames.NET_HOST_PORT]: localPort, - [AttributeNames.NET_PEER_IP]: remoteAddress, - [AttributeNames.NET_PEER_PORT]: remotePort, - [AttributeNames.HTTP_STATUS_CODE]: statusCode, - [AttributeNames.HTTP_STATUS_TEXT]: (statusMessage || '').toUpperCase(), + [GeneralAttribute.NET_HOST_IP]: localAddress, + [GeneralAttribute.NET_HOST_PORT]: localPort, + [GeneralAttribute.NET_PEER_IP]: remoteAddress, + [GeneralAttribute.NET_PEER_PORT]: remotePort, + [HttpAttribute.HTTP_STATUS_CODE]: statusCode, + [HttpAttribute.HTTP_STATUS_TEXT]: (statusMessage || '').toUpperCase(), }; if (route !== undefined) { - attributes[AttributeNames.HTTP_ROUTE] = route; + attributes[HttpAttribute.HTTP_ROUTE] = route; } return attributes; }; diff --git a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts index 0597ce7d4f..1cb350bf95 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/http-enable.test.ts @@ -26,11 +26,14 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; import * as nock from 'nock'; import * as path from 'path'; -import { AttributeNames } from '../../src/enums/AttributeNames'; import { HttpPlugin, plugin } from '../../src/http'; import { Http, HttpPluginConfig } from '../../src/types'; import { OT_REQUEST_HEADER } from '../../src/utils'; @@ -174,11 +177,11 @@ describe('HttpPlugin', () => { assertSpan(incomingSpan, SpanKind.SERVER, validations); assertSpan(outgoingSpan, SpanKind.CLIENT, validations); assert.strictEqual( - incomingSpan.attributes[AttributeNames.NET_HOST_PORT], + incomingSpan.attributes[GeneralAttribute.NET_HOST_PORT], serverPort ); assert.strictEqual( - outgoingSpan.attributes[AttributeNames.NET_PEER_PORT], + outgoingSpan.attributes[GeneralAttribute.NET_PEER_PORT], serverPort ); }); @@ -276,28 +279,25 @@ describe('HttpPlugin', () => { assert.strictEqual(spans.length, 2); assert.strictEqual( - incomingSpan.attributes[AttributeNames.HTTP_CLIENT_IP], + incomingSpan.attributes[HttpAttribute.HTTP_CLIENT_IP], '' ); assert.strictEqual( - incomingSpan.attributes[AttributeNames.NET_HOST_PORT], + incomingSpan.attributes[GeneralAttribute.NET_HOST_PORT], serverPort ); assert.strictEqual( - outgoingSpan.attributes[AttributeNames.NET_PEER_PORT], + outgoingSpan.attributes[GeneralAttribute.NET_PEER_PORT], serverPort ); [ { span: incomingSpan, kind: SpanKind.SERVER }, { span: outgoingSpan, kind: SpanKind.CLIENT }, ].forEach(({ span, kind }) => { + assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); assert.strictEqual( - span.attributes[AttributeNames.HTTP_FLAVOR], - '1.1' - ); - assert.strictEqual( - span.attributes[AttributeNames.NET_TRANSPORT], - AttributeNames.IP_TCP + span.attributes[GeneralAttribute.NET_TRANSPORT], + GeneralAttribute.IP_TCP ); assertSpan(span, kind, validations); }); @@ -708,7 +708,7 @@ describe('HttpPlugin', () => { assert.strictEqual(spans.length, 1); assert.ok(Object.keys(span.attributes).length > 6); assert.strictEqual( - span.attributes[AttributeNames.HTTP_STATUS_CODE], + span.attributes[HttpAttribute.HTTP_STATUS_CODE], 404 ); assert.strictEqual(span.status.code, CanonicalCode.NOT_FOUND); diff --git a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts index c5e8c4c304..2ecc280604 100644 --- a/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts +++ b/packages/opentelemetry-plugin-http/test/functionals/utils.test.ts @@ -16,13 +16,13 @@ import { CanonicalCode, SpanKind, TraceFlags } from '@opentelemetry/api'; import { NoopLogger } from '@opentelemetry/core'; import { BasicTracerProvider, Span } from '@opentelemetry/tracing'; +import { HttpAttribute } from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; import { IncomingMessage, ServerResponse } from 'http'; import { Socket } from 'net'; import * as sinon from 'sinon'; import * as url from 'url'; -import { AttributeNames } from '../../src'; import { IgnoreMatcher } from '../../src/types'; import * as utils from '../../src/utils'; @@ -264,10 +264,10 @@ describe('Utility', () => { utils.setSpanWithError(span, new Error(errorMessage), obj as any); const attributes = span.attributes; assert.strictEqual( - attributes[AttributeNames.HTTP_ERROR_MESSAGE], + attributes[HttpAttribute.HTTP_ERROR_MESSAGE], errorMessage ); - assert.ok(attributes[AttributeNames.HTTP_ERROR_NAME]); + assert.ok(attributes[HttpAttribute.HTTP_ERROR_NAME]); } }); }); @@ -325,7 +325,7 @@ describe('Utility', () => { const attributes = utils.getIncomingRequestAttributesOnResponse(request, { socket: {}, } as ServerResponse & { socket: Socket }); - assert.deepEqual(attributes[AttributeNames.HTTP_ROUTE], '/test/toto'); + assert.deepEqual(attributes[HttpAttribute.HTTP_ROUTE], '/test/toto'); }); it('should succesfully process without middleware stack', () => { @@ -333,7 +333,7 @@ describe('Utility', () => { const attributes = utils.getIncomingRequestAttributesOnResponse(request, { socket: {}, } as ServerResponse & { socket: Socket }); - assert.deepEqual(attributes[AttributeNames.HTTP_ROUTE], undefined); + assert.deepEqual(attributes[HttpAttribute.HTTP_ROUTE], undefined); }); }); }); diff --git a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts index beac0ac7f3..9fd14f6ff0 100644 --- a/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts +++ b/packages/opentelemetry-plugin-http/test/integrations/http-enable.test.ts @@ -16,6 +16,10 @@ import { NoopLogger } from '@opentelemetry/core'; import { SpanKind, Span, context } from '@opentelemetry/api'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; import * as url from 'url'; @@ -30,7 +34,6 @@ import { SimpleSpanProcessor, } from '@opentelemetry/tracing'; import { HttpPluginConfig } from '../../src/types'; -import { AttributeNames } from '../../src/enums/AttributeNames'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; const protocol = 'http'; const serverPort = 32345; @@ -176,10 +179,10 @@ describe('HttpPlugin Integration tests', () => { assert.strictEqual(spans.length, 1); assert.ok(span.name.indexOf('GET /') >= 0); assert.strictEqual(result.reqHeaders['x-foo'], 'foo'); - assert.strictEqual(span.attributes[AttributeNames.HTTP_FLAVOR], '1.1'); + assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); assert.strictEqual( - span.attributes[AttributeNames.NET_TRANSPORT], - AttributeNames.IP_TCP + span.attributes[GeneralAttribute.NET_TRANSPORT], + GeneralAttribute.IP_TCP ); assertSpan(span, SpanKind.CLIENT, validations); }); diff --git a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts index c99828ec6f..77fbf04c12 100644 --- a/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-http/test/utils/assertSpan.ts @@ -16,9 +16,12 @@ import { SpanKind, Status } from '@opentelemetry/api'; import { hrTimeToNanoseconds } from '@opentelemetry/core'; import { ReadableSpan } from '@opentelemetry/tracing'; +import { + GeneralAttribute, + HttpAttribute, +} from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; -import { AttributeNames } from '../../src/enums/AttributeNames'; import * as utils from '../../src/utils'; import { DummyPropagation } from './DummyPropagation'; @@ -46,23 +49,23 @@ export const assertSpan = ( `${validations.httpMethod} ${validations.pathname}` ); assert.strictEqual( - span.attributes[AttributeNames.COMPONENT], + span.attributes[GeneralAttribute.COMPONENT], validations.component ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_ERROR_MESSAGE], + span.attributes[HttpAttribute.HTTP_ERROR_MESSAGE], span.status.message ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_METHOD], + span.attributes[HttpAttribute.HTTP_METHOD], validations.httpMethod ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_TARGET], + span.attributes[HttpAttribute.HTTP_TARGET], validations.path || validations.pathname ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_STATUS_CODE], + span.attributes[HttpAttribute.HTTP_STATUS_CODE], validations.httpStatusCode ); @@ -82,25 +85,28 @@ export const assertSpan = ( const userAgent = validations.reqHeaders['user-agent']; if (userAgent) { assert.strictEqual( - span.attributes[AttributeNames.HTTP_USER_AGENT], + span.attributes[HttpAttribute.HTTP_USER_AGENT], userAgent ); } } if (span.kind === SpanKind.CLIENT) { assert.strictEqual( - span.attributes[AttributeNames.NET_PEER_NAME], + span.attributes[GeneralAttribute.NET_PEER_NAME], validations.hostname, 'must be consistent (PEER_NAME and hostname)' ); - assert.ok(span.attributes[AttributeNames.NET_PEER_IP], 'must have PEER_IP'); assert.ok( - span.attributes[AttributeNames.NET_PEER_PORT], + span.attributes[GeneralAttribute.NET_PEER_IP], + 'must have PEER_IP' + ); + assert.ok( + span.attributes[GeneralAttribute.NET_PEER_PORT], 'must have PEER_PORT' ); assert.ok( - (span.attributes[AttributeNames.HTTP_URL] as string).indexOf( - span.attributes[AttributeNames.NET_PEER_NAME] as string + (span.attributes[HttpAttribute.HTTP_URL] as string).indexOf( + span.attributes[GeneralAttribute.NET_PEER_NAME] as string ) > -1, 'must be consistent' ); @@ -108,16 +114,16 @@ export const assertSpan = ( if (span.kind === SpanKind.SERVER) { if (validations.serverName) { assert.strictEqual( - span.attributes[AttributeNames.HTTP_SERVER_NAME], + span.attributes[HttpAttribute.HTTP_SERVER_NAME], validations.serverName, ' must have serverName attribute' ); assert.ok( - span.attributes[AttributeNames.NET_HOST_PORT], + span.attributes[GeneralAttribute.NET_HOST_PORT], 'must have HOST_PORT' ); assert.ok( - span.attributes[AttributeNames.NET_HOST_IP], + span.attributes[GeneralAttribute.NET_HOST_IP], 'must have HOST_IP' ); } diff --git a/packages/opentelemetry-plugin-https/package.json b/packages/opentelemetry-plugin-https/package.json index 52309a2511..fcf9aafe08 100644 --- a/packages/opentelemetry-plugin-https/package.json +++ b/packages/opentelemetry-plugin-https/package.json @@ -73,6 +73,7 @@ "@opentelemetry/api": "^0.8.3", "@opentelemetry/core": "^0.8.3", "@opentelemetry/plugin-http": "^0.8.3", + "@opentelemetry/semantic-conventions": "^0.8.3", "semver": "^7.1.3", "shimmer": "^1.2.1" } diff --git a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts index 2c3533973a..39aa2e5493 100644 --- a/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/functionals/https-enable.test.ts @@ -24,7 +24,6 @@ import { import { NoopLogger } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/node'; import { - AttributeNames, Http, HttpPluginConfig, OT_REQUEST_HEADER, @@ -35,6 +34,10 @@ import { InMemorySpanExporter, SimpleSpanProcessor, } from '@opentelemetry/tracing'; +import { + GeneralAttribute, + HttpAttribute, +} from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as fs from 'fs'; import * as http from 'http'; @@ -175,11 +178,11 @@ describe('HttpsPlugin', () => { assertSpan(incomingSpan, SpanKind.SERVER, validations); assertSpan(outgoingSpan, SpanKind.CLIENT, validations); assert.strictEqual( - incomingSpan.attributes[AttributeNames.NET_HOST_PORT], + incomingSpan.attributes[GeneralAttribute.NET_HOST_PORT], serverPort ); assert.strictEqual( - outgoingSpan.attributes[AttributeNames.NET_PEER_PORT], + outgoingSpan.attributes[GeneralAttribute.NET_PEER_PORT], serverPort ); }); @@ -283,15 +286,15 @@ describe('HttpsPlugin', () => { assert.strictEqual(spans.length, 2); assert.strictEqual( - incomingSpan.attributes[AttributeNames.HTTP_CLIENT_IP], + incomingSpan.attributes[HttpAttribute.HTTP_CLIENT_IP], '' ); assert.strictEqual( - incomingSpan.attributes[AttributeNames.NET_HOST_PORT], + incomingSpan.attributes[GeneralAttribute.NET_HOST_PORT], serverPort ); assert.strictEqual( - outgoingSpan.attributes[AttributeNames.NET_PEER_PORT], + outgoingSpan.attributes[GeneralAttribute.NET_PEER_PORT], serverPort ); @@ -299,13 +302,10 @@ describe('HttpsPlugin', () => { { span: incomingSpan, kind: SpanKind.SERVER }, { span: outgoingSpan, kind: SpanKind.CLIENT }, ].forEach(({ span, kind }) => { + assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); assert.strictEqual( - span.attributes[AttributeNames.HTTP_FLAVOR], - '1.1' - ); - assert.strictEqual( - span.attributes[AttributeNames.NET_TRANSPORT], - AttributeNames.IP_TCP + span.attributes[GeneralAttribute.NET_TRANSPORT], + GeneralAttribute.IP_TCP ); assertSpan(span, kind, validations); }); @@ -686,7 +686,7 @@ describe('HttpsPlugin', () => { assert.strictEqual(spans.length, 1); assert.ok(Object.keys(span.attributes).length > 6); assert.strictEqual( - span.attributes[AttributeNames.HTTP_STATUS_CODE], + span.attributes[HttpAttribute.HTTP_STATUS_CODE], 404 ); assert.strictEqual(span.status.code, CanonicalCode.NOT_FOUND); diff --git a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts index d36ef1274b..a0a128bb0d 100644 --- a/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts +++ b/packages/opentelemetry-plugin-https/test/integrations/https-enable.test.ts @@ -15,12 +15,12 @@ */ import { NoopLogger } from '@opentelemetry/core'; -import { - HttpPluginConfig, - Http, - AttributeNames, -} from '@opentelemetry/plugin-http'; +import { HttpPluginConfig, Http } from '@opentelemetry/plugin-http'; import { SpanKind, Span, context } from '@opentelemetry/api'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; import * as https from 'https'; @@ -184,10 +184,10 @@ describe('HttpsPlugin Integration tests', () => { assert.strictEqual(spans.length, 1); assert.ok(span.name.indexOf('GET /') >= 0); assert.strictEqual(result.reqHeaders['x-foo'], 'foo'); - assert.strictEqual(span.attributes[AttributeNames.HTTP_FLAVOR], '1.1'); + assert.strictEqual(span.attributes[HttpAttribute.HTTP_FLAVOR], '1.1'); assert.strictEqual( - span.attributes[AttributeNames.NET_TRANSPORT], - AttributeNames.IP_TCP + span.attributes[GeneralAttribute.NET_TRANSPORT], + GeneralAttribute.IP_TCP ); assertSpan(span, SpanKind.CLIENT, validations); }); diff --git a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts index 1b1860df9f..019ecbd466 100644 --- a/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts +++ b/packages/opentelemetry-plugin-https/test/utils/assertSpan.ts @@ -16,14 +16,15 @@ import { SpanKind } from '@opentelemetry/api'; import { hrTimeToNanoseconds } from '@opentelemetry/core'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import * as assert from 'assert'; import * as http from 'http'; import { DummyPropagation } from './DummyPropagation'; import { ReadableSpan } from '@opentelemetry/tracing'; -import { - AttributeNames, - parseResponseStatus, -} from '@opentelemetry/plugin-http'; +import { parseResponseStatus } from '@opentelemetry/plugin-http'; export const assertSpan = ( span: ReadableSpan, @@ -48,23 +49,23 @@ export const assertSpan = ( `${validations.httpMethod} ${validations.pathname}` ); assert.strictEqual( - span.attributes[AttributeNames.COMPONENT], + span.attributes[GeneralAttribute.COMPONENT], validations.component ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_ERROR_MESSAGE], + span.attributes[HttpAttribute.HTTP_ERROR_MESSAGE], span.status.message ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_METHOD], + span.attributes[HttpAttribute.HTTP_METHOD], validations.httpMethod ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_TARGET], + span.attributes[HttpAttribute.HTTP_TARGET], validations.path || validations.pathname ); assert.strictEqual( - span.attributes[AttributeNames.HTTP_STATUS_CODE], + span.attributes[HttpAttribute.HTTP_STATUS_CODE], validations.httpStatusCode ); assert.ok(span.endTime); @@ -82,25 +83,28 @@ export const assertSpan = ( const userAgent = validations.reqHeaders['user-agent']; if (userAgent) { assert.strictEqual( - span.attributes[AttributeNames.HTTP_USER_AGENT], + span.attributes[HttpAttribute.HTTP_USER_AGENT], userAgent ); } } if (span.kind === SpanKind.CLIENT) { assert.strictEqual( - span.attributes[AttributeNames.NET_PEER_NAME], + span.attributes[GeneralAttribute.NET_PEER_NAME], validations.hostname, 'must be consistent (PEER_NAME and hostname)' ); - assert.ok(span.attributes[AttributeNames.NET_PEER_IP], 'must have PEER_IP'); assert.ok( - span.attributes[AttributeNames.NET_PEER_PORT], + span.attributes[GeneralAttribute.NET_PEER_IP], + 'must have PEER_IP' + ); + assert.ok( + span.attributes[GeneralAttribute.NET_PEER_PORT], 'must have PEER_PORT' ); assert.ok( - (span.attributes[AttributeNames.HTTP_URL] as string).indexOf( - span.attributes[AttributeNames.NET_PEER_NAME] as string + (span.attributes[HttpAttribute.HTTP_URL] as string).indexOf( + span.attributes[GeneralAttribute.NET_PEER_NAME] as string ) > -1, 'must be consistent' ); @@ -108,16 +112,19 @@ export const assertSpan = ( if (span.kind === SpanKind.SERVER) { if (validations.serverName) { assert.strictEqual( - span.attributes[AttributeNames.HTTP_SERVER_NAME], + span.attributes[HttpAttribute.HTTP_SERVER_NAME], validations.serverName, ' must have serverName attribute' ); } assert.ok( - span.attributes[AttributeNames.NET_HOST_PORT], + span.attributes[GeneralAttribute.NET_HOST_PORT], 'must have HOST_PORT' ); - assert.ok(span.attributes[AttributeNames.NET_HOST_IP], 'must have HOST_IP'); + assert.ok( + span.attributes[GeneralAttribute.NET_HOST_IP], + 'must have HOST_IP' + ); assert.strictEqual(span.parentSpanId, DummyPropagation.SPAN_CONTEXT_KEY); } else if (validations.reqHeaders) { assert.ok(validations.reqHeaders[DummyPropagation.TRACE_CONTEXT_KEY]); diff --git a/packages/opentelemetry-plugin-xml-http-request/package.json b/packages/opentelemetry-plugin-xml-http-request/package.json index f3964d3998..d5f3adc59b 100644 --- a/packages/opentelemetry-plugin-xml-http-request/package.json +++ b/packages/opentelemetry-plugin-xml-http-request/package.json @@ -76,6 +76,7 @@ "dependencies": { "@opentelemetry/api": "^0.8.3", "@opentelemetry/core": "^0.8.3", + "@opentelemetry/semantic-conventions": "^0.8.3", "@opentelemetry/web": "^0.8.3", "shimmer": "^1.2.1" } diff --git a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts index 65fbab52bc..ff18cb02f1 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts @@ -23,6 +23,10 @@ import { otperformance, urlMatches, } from '@opentelemetry/core'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import { addSpanNetworkEvent, getResource, @@ -30,7 +34,6 @@ import { PerformanceTimingNames as PTN, } from '@opentelemetry/web'; import * as shimmer from 'shimmer'; -import { AttributeNames } from './enums/AttributeNames'; import { EventNames } from './enums/EventNames'; import { OpenFunction, @@ -151,17 +154,17 @@ export class XMLHttpRequestPlugin extends BasePlugin { if (typeof spanUrl === 'string') { const parsedUrl = parseUrl(spanUrl); - span.setAttribute(AttributeNames.HTTP_STATUS_CODE, xhrMem.status); - span.setAttribute(AttributeNames.HTTP_STATUS_TEXT, xhrMem.statusText); - span.setAttribute(AttributeNames.HTTP_HOST, parsedUrl.host); + span.setAttribute(HttpAttribute.HTTP_STATUS_CODE, xhrMem.status); + span.setAttribute(HttpAttribute.HTTP_STATUS_TEXT, xhrMem.statusText); + span.setAttribute(HttpAttribute.HTTP_HOST, parsedUrl.host); span.setAttribute( - AttributeNames.HTTP_SCHEME, + HttpAttribute.HTTP_SCHEME, parsedUrl.protocol.replace(':', '') ); // @TODO do we want to collect this or it will be collected earlier once only or // maybe when parent span is not available ? - span.setAttribute(AttributeNames.HTTP_USER_AGENT, navigator.userAgent); + span.setAttribute(HttpAttribute.HTTP_USER_AGENT, navigator.userAgent); } } @@ -319,9 +322,9 @@ export class XMLHttpRequestPlugin extends BasePlugin { const currentSpan = this._tracer.startSpan(url, { kind: api.SpanKind.CLIENT, attributes: { - [AttributeNames.COMPONENT]: this.component, - [AttributeNames.HTTP_METHOD]: method, - [AttributeNames.HTTP_URL]: url, + [GeneralAttribute.COMPONENT]: this.component, + [HttpAttribute.HTTP_METHOD]: method, + [HttpAttribute.HTTP_URL]: url, }, }); diff --git a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts index 81ab9778fa..1a59f5c092 100644 --- a/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts +++ b/packages/opentelemetry-plugin-xml-http-request/test/xhr.test.ts @@ -24,13 +24,16 @@ import { } from '@opentelemetry/core'; import { ZoneContextManager } from '@opentelemetry/context-zone'; import * as tracing from '@opentelemetry/tracing'; +import { + HttpAttribute, + GeneralAttribute, +} from '@opentelemetry/semantic-conventions'; import { PerformanceTimingNames as PTN, WebTracerProvider, } from '@opentelemetry/web'; import * as assert from 'assert'; import * as sinon from 'sinon'; -import { AttributeNames } from '../src/enums/AttributeNames'; import { EventNames } from '../src/enums/EventNames'; import { XMLHttpRequestPlugin } from '../src/xhr'; @@ -238,40 +241,40 @@ describe('xhr', () => { assert.ok( attributes[keys[0]] !== '', - `attributes ${AttributeNames.COMPONENT} is not defined` + `attributes ${GeneralAttribute.COMPONENT} is not defined` ); assert.strictEqual( attributes[keys[1]], 'GET', - `attributes ${AttributeNames.HTTP_METHOD} is wrong` + `attributes ${HttpAttribute.HTTP_METHOD} is wrong` ); assert.strictEqual( attributes[keys[2]], url, - `attributes ${AttributeNames.HTTP_URL} is wrong` + `attributes ${HttpAttribute.HTTP_URL} is wrong` ); assert.strictEqual( attributes[keys[3]], 200, - `attributes ${AttributeNames.HTTP_STATUS_CODE} is wrong` + `attributes ${HttpAttribute.HTTP_STATUS_CODE} is wrong` ); assert.strictEqual( attributes[keys[4]], 'OK', - `attributes ${AttributeNames.HTTP_STATUS_TEXT} is wrong` + `attributes ${HttpAttribute.HTTP_STATUS_TEXT} is wrong` ); assert.strictEqual( attributes[keys[5]], window.location.host, - `attributes ${AttributeNames.HTTP_HOST} is wrong` + `attributes ${HttpAttribute.HTTP_HOST} is wrong` ); assert.ok( attributes[keys[6]] === 'http' || attributes[keys[6]] === 'https', - `attributes ${AttributeNames.HTTP_SCHEME} is wrong` + `attributes ${HttpAttribute.HTTP_SCHEME} is wrong` ); assert.ok( attributes[keys[7]] !== '', - `attributes ${AttributeNames.HTTP_USER_AGENT} is not defined` + `attributes ${HttpAttribute.HTTP_USER_AGENT} is not defined` ); assert.strictEqual(keys.length, 8, 'number of attributes is wrong'); @@ -508,40 +511,40 @@ describe('xhr', () => { assert.ok( attributes[keys[0]] !== '', - `attributes ${AttributeNames.COMPONENT} is not defined` + `attributes ${GeneralAttribute.COMPONENT} is not defined` ); assert.strictEqual( attributes[keys[1]], 'GET', - `attributes ${AttributeNames.HTTP_METHOD} is wrong` + `attributes ${HttpAttribute.HTTP_METHOD} is wrong` ); assert.strictEqual( attributes[keys[2]], url, - `attributes ${AttributeNames.HTTP_URL} is wrong` + `attributes ${HttpAttribute.HTTP_URL} is wrong` ); assert.strictEqual( attributes[keys[3]], 400, - `attributes ${AttributeNames.HTTP_STATUS_CODE} is wrong` + `attributes ${HttpAttribute.HTTP_STATUS_CODE} is wrong` ); assert.strictEqual( attributes[keys[4]], 'Bad Request', - `attributes ${AttributeNames.HTTP_STATUS_TEXT} is wrong` + `attributes ${HttpAttribute.HTTP_STATUS_TEXT} is wrong` ); assert.strictEqual( attributes[keys[5]], 'raw.githubusercontent.com', - `attributes ${AttributeNames.HTTP_HOST} is wrong` + `attributes ${HttpAttribute.HTTP_HOST} is wrong` ); assert.ok( attributes[keys[6]] === 'http' || attributes[keys[6]] === 'https', - `attributes ${AttributeNames.HTTP_SCHEME} is wrong` + `attributes ${HttpAttribute.HTTP_SCHEME} is wrong` ); assert.ok( attributes[keys[7]] !== '', - `attributes ${AttributeNames.HTTP_USER_AGENT} is not defined` + `attributes ${HttpAttribute.HTTP_USER_AGENT} is not defined` ); assert.strictEqual(keys.length, 8, 'number of attributes is wrong'); diff --git a/packages/opentelemetry-semantic-conventions/.eslintignore b/packages/opentelemetry-semantic-conventions/.eslintignore new file mode 100644 index 0000000000..378eac25d3 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/.eslintignore @@ -0,0 +1 @@ +build diff --git a/packages/opentelemetry-semantic-conventions/.eslintrc.js b/packages/opentelemetry-semantic-conventions/.eslintrc.js new file mode 100644 index 0000000000..9dfe62f9b8 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + "env": { + "mocha": true, + "commonjs": true, + "node": true, + "browser": true + }, + ...require('../../eslint.config.js') +} diff --git a/packages/opentelemetry-semantic-conventions/.npmignore b/packages/opentelemetry-semantic-conventions/.npmignore new file mode 100644 index 0000000000..9505ba9450 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/.npmignore @@ -0,0 +1,4 @@ +/bin +/coverage +/doc +/test diff --git a/packages/opentelemetry-semantic-conventions/LICENSE b/packages/opentelemetry-semantic-conventions/LICENSE new file mode 100644 index 0000000000..b0e74c7d15 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2020] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/opentelemetry-semantic-conventions/README.md b/packages/opentelemetry-semantic-conventions/README.md new file mode 100644 index 0000000000..eca85da6fc --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/README.md @@ -0,0 +1,49 @@ +# OpenTelemetry Semantic Conventions + +[![Gitter chat][gitter-image]][gitter-url] +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-image] + +Semantic Convention constants for use with the OpenTelemetry SDK/APIs. [This document][trace-semantic_conventions] defines standard attributes for traces. + +## Installation + +```bash +npm install --save @opentelemetry/semantic-conventions +``` + +## Usage + +```ts +import { GeneralAttribute } from '@opentelemetry/semantic-conventions'; + +const span = tracer.startSpan().startSpan(spanName, spanOptions) + .setAttributes({ + [GeneralAttribute.NET_PEER_HOSTNAME]: 'localhost', + }); +``` + +## Useful links + +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us on [gitter][gitter-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg +[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-semantic-conventions +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-semantic-conventions +[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-semantic-conventions +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-semantic-conventions&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/semantic-conventions +[npm-img]: https://badge.fury.io/js/%40opentelemetry%semantic-conventions.svg + +[trace-semantic_conventions]: https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/trace/semantic_conventions diff --git a/packages/opentelemetry-semantic-conventions/package.json b/packages/opentelemetry-semantic-conventions/package.json new file mode 100644 index 0000000000..f033eb908b --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/package.json @@ -0,0 +1,57 @@ +{ + "name": "@opentelemetry/semantic-conventions", + "version": "0.8.3", + "description": "OpenTelemetry semantic conventions", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "repository": "open-telemetry/opentelemetry-js", + "scripts": { + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "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/*", + "precompile": "tsc --version", + "version:update": "node ../../scripts/version-update.js", + "compile": "npm run version:update && tsc -p .", + "prepare": "npm run compile" + }, + "keywords": [ + "opentelemetry", + "nodejs", + "tracing", + "attributes", + "semantic conventions" + ], + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + }, + "files": [ + "build/src/**/*.js", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@types/mocha": "7.0.2", + "@types/node": "14.0.13", + "@types/sinon": "9.0.4", + "codecov": "3.7.0", + "gts": "2.0.2", + "mocha": "7.2.0", + "nock": "12.0.3", + "nyc": "15.1.0", + "rimraf": "3.0.2", + "sinon": "9.0.2", + "ts-mocha": "7.0.0", + "ts-node": "8.10.2", + "typescript": "3.9.5" + } +} diff --git a/packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts b/packages/opentelemetry-semantic-conventions/src/index.ts similarity index 69% rename from packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts rename to packages/opentelemetry-semantic-conventions/src/index.ts index 3fdea85bc7..ae2998a38c 100644 --- a/packages/opentelemetry-plugin-grpc/src/enums/AttributeNames.ts +++ b/packages/opentelemetry-semantic-conventions/src/index.ts @@ -14,11 +14,4 @@ * limitations under the License. */ -export enum AttributeNames { - COMPONENT = 'component', - GRPC_KIND = 'grpc.kind', // SERVER or CLIENT - GRPC_METHOD = 'grpc.method', - GRPC_STATUS_CODE = 'grpc.status_code', - GRPC_ERROR_NAME = 'grpc.error_name', - GRPC_ERROR_MESSAGE = 'grpc.error_message', -} +export * from './trace'; diff --git a/packages/opentelemetry-semantic-conventions/src/trace/database.ts b/packages/opentelemetry-semantic-conventions/src/trace/database.ts new file mode 100644 index 0000000000..86705c746e --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/src/trace/database.ts @@ -0,0 +1,30 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Database attribute names defined by the Opetelemetry Semantic Conventions specification + * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/database.md + */ +export const DatabaseAttribute = { + // db (required) + DB_TYPE: 'db.type', + DB_INSTANCE: 'db.instance', + DB_STATEMENT: 'db.statement', + DB_URL: 'db.url', + + // db (optional) + DB_USER: 'db.user', +}; diff --git a/packages/opentelemetry-semantic-conventions/src/trace/general.ts b/packages/opentelemetry-semantic-conventions/src/trace/general.ts new file mode 100644 index 0000000000..d52f4ff449 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/src/trace/general.ts @@ -0,0 +1,37 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const GeneralAttribute = { + // Not in spec + COMPONENT: 'component', + + NET_PEER_IP: 'net.peer.ip', + NET_PEER_ADDRESS: 'net.peer.address', + NET_PEER_HOSTNAME: 'net.peer.host', + NET_PEER_PORT: 'net.peer.port', + NET_PEER_NAME: 'net.peer.name', + NET_PEER_IPV4: 'net.peer.ipv4', + NET_PEER_IPV6: 'net.peer.ipv6', + NET_PEER_SERVICE: 'net.peer.service', + NET_HOST_IP: 'net.host.ip', + NET_HOST_PORT: 'net.host.port', + NET_HOST_NAME: 'net.host.name', + NET_TRANSPORT: 'net.transport', + + // These are used as potential values to NET_TRANSPORT + IP_TCP: 'IP.TCP', + IP_UDP: 'IP.UDP', + INPROC: 'inproc', +}; diff --git a/packages/opentelemetry-semantic-conventions/src/trace/http.ts b/packages/opentelemetry-semantic-conventions/src/trace/http.ts new file mode 100644 index 0000000000..d194db6a41 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/src/trace/http.ts @@ -0,0 +1,33 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const HttpAttribute = { + HTTP_HOST: 'http.host', + HTTP_METHOD: 'http.method', + HTTP_TARGET: 'http.target', + HTTP_ROUTE: 'http.route', + HTTP_URL: 'http.url', + HTTP_STATUS_CODE: 'http.status_code', + HTTP_STATUS_TEXT: 'http.status_text', + HTTP_FLAVOR: 'http.flavor', + HTTP_SERVER_NAME: 'http.server_name', + HTTP_CLIENT_IP: 'http.client_ip', + HTTP_SCHEME: 'http.scheme', + + // NOT ON OFFICIAL SPEC + HTTP_ERROR_NAME: 'http.error_name', + HTTP_ERROR_MESSAGE: 'http.error_message', + HTTP_USER_AGENT: 'http.user_agent', +}; diff --git a/packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts b/packages/opentelemetry-semantic-conventions/src/trace/index.ts similarity index 63% rename from packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts rename to packages/opentelemetry-semantic-conventions/src/trace/index.ts index 29adbdff16..a923ac0a36 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/enums/AttributeNames.ts +++ b/packages/opentelemetry-semantic-conventions/src/trace/index.ts @@ -13,15 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export enum AttributeNames { - COMPONENT = 'component', - HTTP_HOST = 'http.host', - HTTP_FLAVOR = 'http.flavor', - HTTP_METHOD = 'http.method', - HTTP_SCHEME = 'http.scheme', - HTTP_STATUS_CODE = 'http.status_code', - HTTP_STATUS_TEXT = 'http.status_text', - HTTP_URL = 'http.url', - // NOT ON OFFICIAL SPEC - HTTP_USER_AGENT = 'http.user_agent', -} + +export * from './general'; +export * from './rpc'; +export * from './http'; +export * from './database'; diff --git a/packages/opentelemetry-semantic-conventions/src/trace/rpc.ts b/packages/opentelemetry-semantic-conventions/src/trace/rpc.ts new file mode 100644 index 0000000000..c2681b3d98 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/src/trace/rpc.ts @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export const RpcAttribute = { + RPC_SERVICE: 'rpc.service', + + // GRPC (no spec) + GRPC_KIND: 'grpc.kind', // SERVER or CLIENT + GRPC_METHOD: 'grpc.method', + GRPC_STATUS_CODE: 'grpc.status_code', + GRPC_ERROR_NAME: 'grpc.error_name', + GRPC_ERROR_MESSAGE: 'grpc.error_message', +}; diff --git a/packages/opentelemetry-semantic-conventions/src/version.ts b/packages/opentelemetry-semantic-conventions/src/version.ts new file mode 100644 index 0000000000..9e616149a4 --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/src/version.ts @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// this is autogenerated file, see scripts/version-update.js +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-semantic-conventions/tsconfig.json b/packages/opentelemetry-semantic-conventions/tsconfig.json new file mode 100644 index 0000000000..e4b3b29e6a --- /dev/null +++ b/packages/opentelemetry-semantic-conventions/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +} From 87882cb5e903feecb4079f4d118482f511c583e1 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 16 Jun 2020 08:54:21 +0200 Subject: [PATCH 12/22] chore(deps): update dependency sinon to v9 (#1196) --- packages/opentelemetry-plugin-grpc-js/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/opentelemetry-plugin-grpc-js/package.json b/packages/opentelemetry-plugin-grpc-js/package.json index 7440b9211f..f16b62bb18 100644 --- a/packages/opentelemetry-plugin-grpc-js/package.json +++ b/packages/opentelemetry-plugin-grpc-js/package.json @@ -52,14 +52,14 @@ "@types/node": "14.0.13", "@types/semver": "7.2.0", "@types/shimmer": "1.0.1", - "@types/sinon": "7.5.2", + "@types/sinon": "9.0.4", "codecov": "3.7.0", "gts": "2.0.2", "mocha": "7.2.0", "nyc": "15.1.0", "rimraf": "3.0.2", "semver": "7.3.2", - "sinon": "7.5.0", + "sinon": "9.0.2", "ts-mocha": "7.0.0", "ts-node": "8.10.2", "typescript": "3.7.2" From 56a2413cfa67d2482994d321f1524f0b731a3f2e Mon Sep 17 00:00:00 2001 From: Mayur Kale Date: Tue, 16 Jun 2020 11:50:45 -0700 Subject: [PATCH 13/22] Add @legendecas to approvers / CODEOWNERS (#1198) Co-authored-by: Daniel Dyla --- .github/CODEOWNERS | 2 +- README.md | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 97b1da014c..00411e7fac 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,4 +12,4 @@ # https://help.github.com/en/articles/about-code-owners # -* @dyladan @mayurkale22 @rochdev @bg451 @OlivierAlbertini @vmarchaud @markwolff @obecny @mwear @naseemkullah +* @dyladan @mayurkale22 @rochdev @bg451 @OlivierAlbertini @vmarchaud @markwolff @obecny @mwear @naseemkullah @legendecas diff --git a/README.md b/README.md index 64722444d5..272461f988 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ Approvers ([@open-telemetry/js-approvers](https://github.com/orgs/open-telemetry - [Bartlomiej Obecny](https://github.com/obecny), LightStep - [Matthew Wear](https://github.com/mwear), LightStep - [Naseem K. Ullah](https://github.com/naseemkullah), Transit +- [Chengzhong Wu](https://github.com/legendecas), Alibaba *Find more about the approver role in [community repository](https://github.com/open-telemetry/community/blob/master/community-membership.md#approver).* From fd5c1429f9f1a635dcef33d0c2a5626a9e8a9a00 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 16 Jun 2020 21:49:57 +0200 Subject: [PATCH 14/22] chore(deps): update typescript-eslint monorepo to v3.3.0 (#1199) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f2da39e7e6..ff88fb72e3 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,8 @@ "eslint-config-airbnb-base": "14.2.0", "eslint-plugin-import": "2.21.2", "eslint-plugin-header": "3.0.0", - "@typescript-eslint/eslint-plugin": "3.2.0", - "@typescript-eslint/parser": "3.2.0", + "@typescript-eslint/eslint-plugin": "3.3.0", + "@typescript-eslint/parser": "3.3.0", "gh-pages": "3.0.0", "gts": "2.0.2", "husky": "4.2.5", From b20bbf933427a6cb07666a89f747904638e05f5a Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 16 Jun 2020 22:08:37 +0200 Subject: [PATCH 15/22] chore(deps): update dependency typescript to v3.9.5 (#1195) --- packages/opentelemetry-plugin-grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/opentelemetry-plugin-grpc-js/package.json b/packages/opentelemetry-plugin-grpc-js/package.json index f16b62bb18..c876699bcf 100644 --- a/packages/opentelemetry-plugin-grpc-js/package.json +++ b/packages/opentelemetry-plugin-grpc-js/package.json @@ -62,7 +62,7 @@ "sinon": "9.0.2", "ts-mocha": "7.0.0", "ts-node": "8.10.2", - "typescript": "3.7.2" + "typescript": "3.9.5" }, "dependencies": { "@opentelemetry/api": "^0.8.3", From deb35707b768537619ecf79225476f177c157df2 Mon Sep 17 00:00:00 2001 From: David W Date: Tue, 16 Jun 2020 20:48:16 -0400 Subject: [PATCH 16/22] fix(exporter-collector): default endpoint for node and browser (#1197) Co-authored-by: Mayur Kale --- .../README.md | 6 ++++-- .../src/CollectorExporterBase.ts | 4 ++-- .../src/platform/browser/CollectorExporter.ts | 6 ++++++ .../src/platform/node/CollectorExporter.ts | 6 ++++++ .../test/browser/CollectorExporter.test.ts | 21 +++++++++++++++++++ .../test/common/CollectorExporter.test.ts | 3 +++ .../test/node/CollectorExporter.test.ts | 18 ++++++++++++++++ 7 files changed, 60 insertions(+), 4 deletions(-) diff --git a/packages/opentelemetry-exporter-collector/README.md b/packages/opentelemetry-exporter-collector/README.md index e046bbddb3..d31f7a7370 100644 --- a/packages/opentelemetry-exporter-collector/README.md +++ b/packages/opentelemetry-exporter-collector/README.md @@ -15,6 +15,7 @@ npm install --save @opentelemetry/exporter-collector ``` ## Usage in Web +The CollectorExporter in Web expects the endpoint to end in `/v1/trace`. ```js import { SimpleSpanProcessor } from '@opentelemetry/tracing'; @@ -34,6 +35,7 @@ provider.register(); ``` ## Usage in Node +The CollectorExporter in Node expects the URL to only be the hostname. It will not work with `/v1/trace`. ```js const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing'); @@ -41,7 +43,7 @@ const { CollectorExporter } = require('@opentelemetry/exporter-collector'); const collectorOptions = { serviceName: 'basic-service', - url: '' // url is optional and can be omitted - default is http://localhost:55678/v1/trace + url: '' // url is optional and can be omitted - default is localhost:55678 }; const provider = new BasicTracerProvider(); @@ -62,7 +64,7 @@ const { CollectorExporter } = require('@opentelemetry/exporter-collector'); const collectorOptions = { serviceName: 'basic-service', - url: '', // url is optional and can be omitted - default is http://localhost:55678/v1/trace + url: '', // url is optional and can be omitted - default is localhost:55678 credentials: grpc.credentials.createSsl( fs.readFileSync('./ca.crt'), fs.readFileSync('./client.key'), diff --git a/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts b/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts index 5de8714912..0e6e052e9d 100644 --- a/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts +++ b/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts @@ -31,7 +31,6 @@ export interface CollectorExporterConfigBase { } const DEFAULT_SERVICE_NAME = 'collector-exporter'; -const DEFAULT_COLLECTOR_URL = 'http://localhost:55678/v1/trace'; /** * Collector Exporter abstract base class @@ -51,7 +50,7 @@ export abstract class CollectorExporterBase< */ constructor(config: T = {} as T) { this.serviceName = config.serviceName || DEFAULT_SERVICE_NAME; - this.url = config.url || DEFAULT_COLLECTOR_URL; + this.url = this.getDefaultUrl(config.url); if (typeof config.hostName === 'string') { this.hostName = config.hostName; } @@ -135,4 +134,5 @@ export abstract class CollectorExporterBase< onSuccess: () => void, onError: (error: CollectorExporterError) => void ): void; + abstract getDefaultUrl(url: string | undefined): string; } diff --git a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts index 696557098b..b6607258e1 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts @@ -24,6 +24,8 @@ import * as collectorTypes from '../../types'; export type CollectorExporterConfig = CollectorExporterConfigBase; +const DEFAULT_COLLECTOR_URL = 'http://localhost:55678/v1/trace'; + /** * Collector Exporter for Web */ @@ -38,6 +40,10 @@ export class CollectorExporter extends CollectorExporterBase< window.removeEventListener('unload', this.shutdown); } + getDefaultUrl(url: string | undefined) { + return url || DEFAULT_COLLECTOR_URL; + } + sendSpans( spans: ReadableSpan[], onSuccess: () => void, diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts index f135c64d93..65968be05b 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts @@ -29,6 +29,8 @@ import { toCollectorExportTraceServiceRequest } from '../../transform'; import { GRPCQueueItem, TraceServiceClient } from './types'; import { removeProtocol } from './util'; +const DEFAULT_COLLECTOR_URL = 'localhost:55678'; + /** * Collector Exporter Config for Node */ @@ -135,4 +137,8 @@ export class CollectorExporter extends CollectorExporterBase< }); } } + + getDefaultUrl(url: string | undefined): string { + return url || DEFAULT_COLLECTOR_URL; + } } diff --git a/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts index 02a0def5d1..d282cc1828 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts @@ -219,3 +219,24 @@ describe('CollectorExporter - web', () => { }); }); }); + +describe('CollectorExporter - browser (getDefaultUrl)', () => { + it('should default to v1/trace', done => { + const collectorExporter = new CollectorExporter({}); + setTimeout(() => { + assert.strictEqual( + collectorExporter['url'], + 'http://localhost:55678/v1/trace' + ); + done(); + }); + }); + it('should keep the URL if included', done => { + const url = 'http://foo.bar.com'; + const collectorExporter = new CollectorExporter({ url }); + setTimeout(() => { + assert.strictEqual(collectorExporter['url'], url); + done(); + }); + }); +}); diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts index c384b3f804..e5d67d67db 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorExporter.test.ts @@ -30,6 +30,9 @@ class CollectorExporter extends CollectorExporterBase { onInit() {} onShutdown() {} sendSpans() {} + getDefaultUrl(url: string | undefined) { + return url || ''; + } } describe('CollectorExporter - common', () => { diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts index da4802b70b..2aa2b881fa 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts @@ -159,5 +159,23 @@ const testCollectorExporter = (params: TestParams) => }); }); +describe('CollectorExporter - node (getDefaultUrl)', () => { + it('should default to localhost', done => { + const collectorExporter = new CollectorExporter({}); + setTimeout(() => { + assert.strictEqual(collectorExporter['url'], 'localhost:55678'); + done(); + }); + }); + it('should keep the URL if included', done => { + const url = 'http://foo.bar.com'; + const collectorExporter = new CollectorExporter({ url }); + setTimeout(() => { + assert.strictEqual(collectorExporter['url'], url); + done(); + }); + }); +}); + testCollectorExporter({ useTLS: true }); testCollectorExporter({ useTLS: false }); From 0d939d2a0e9025ab7569d2521633db7eca124143 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 17 Jun 2020 06:05:50 +0200 Subject: [PATCH 17/22] chore: adding plugin-fetch and example (#1121) * chore: adding plugin-fetch and example * chore: investigating failing test * chore: chore fixing tests with better fetch mocking * chore: addressing comments * chore: lint * chore: addressing comments * chore: updating webpack-env * chore: fixes after update for node types * chore: addressing reviews * chore: fixes after merge * chore: updating version Co-authored-by: Mayur Kale Co-authored-by: Daniel Dyla --- README.md | 2 + examples/tracer-web/README.md | 5 + examples/tracer-web/examples/fetch/index.html | 20 + examples/tracer-web/examples/fetch/index.js | 71 +++ examples/tracer-web/package.json | 1 + examples/tracer-web/webpack.config.js | 1 + karma.base.js | 2 +- .../opentelemetry-plugin-fetch/.eslintignore | 1 + .../opentelemetry-plugin-fetch/.eslintrc.js | 9 + .../opentelemetry-plugin-fetch/.npmignore | 4 + packages/opentelemetry-plugin-fetch/LICENSE | 201 +++++++ packages/opentelemetry-plugin-fetch/README.md | 68 +++ .../images/trace1.png | Bin 0 -> 155186 bytes .../images/trace2.png | Bin 0 -> 130296 bytes .../images/trace3.png | Bin 0 -> 118279 bytes .../opentelemetry-plugin-fetch/karma.conf.js | 24 + .../opentelemetry-plugin-fetch/package.json | 82 +++ .../src/enums/AttributeNames.ts | 31 + .../opentelemetry-plugin-fetch/src/fetch.ts | 351 +++++++++++ .../opentelemetry-plugin-fetch/src/index.ts | 17 + .../opentelemetry-plugin-fetch/src/types.ts | 45 ++ .../opentelemetry-plugin-fetch/src/version.ts | 18 + .../test/fetch.test.ts | 563 ++++++++++++++++++ .../test/index-webpack.ts | 20 + .../opentelemetry-plugin-fetch/tsconfig.json | 12 + .../src/xhr.ts | 65 +- .../src/StackContextManager.ts | 2 +- packages/opentelemetry-web/src/types.ts | 9 + packages/opentelemetry-web/src/utils.ts | 74 ++- packages/opentelemetry-web/test/utils.test.ts | 61 ++ 30 files changed, 1697 insertions(+), 62 deletions(-) create mode 100644 examples/tracer-web/examples/fetch/index.html create mode 100644 examples/tracer-web/examples/fetch/index.js create mode 100644 packages/opentelemetry-plugin-fetch/.eslintignore create mode 100644 packages/opentelemetry-plugin-fetch/.eslintrc.js create mode 100644 packages/opentelemetry-plugin-fetch/.npmignore create mode 100644 packages/opentelemetry-plugin-fetch/LICENSE create mode 100644 packages/opentelemetry-plugin-fetch/README.md create mode 100644 packages/opentelemetry-plugin-fetch/images/trace1.png create mode 100644 packages/opentelemetry-plugin-fetch/images/trace2.png create mode 100644 packages/opentelemetry-plugin-fetch/images/trace3.png create mode 100644 packages/opentelemetry-plugin-fetch/karma.conf.js create mode 100644 packages/opentelemetry-plugin-fetch/package.json create mode 100644 packages/opentelemetry-plugin-fetch/src/enums/AttributeNames.ts create mode 100644 packages/opentelemetry-plugin-fetch/src/fetch.ts create mode 100644 packages/opentelemetry-plugin-fetch/src/index.ts create mode 100644 packages/opentelemetry-plugin-fetch/src/types.ts create mode 100644 packages/opentelemetry-plugin-fetch/src/version.ts create mode 100644 packages/opentelemetry-plugin-fetch/test/fetch.test.ts create mode 100644 packages/opentelemetry-plugin-fetch/test/index-webpack.ts create mode 100644 packages/opentelemetry-plugin-fetch/tsconfig.json diff --git a/README.md b/README.md index 272461f988..6347bef679 100644 --- a/README.md +++ b/README.md @@ -206,6 +206,7 @@ These plugins are hosted at and make sure you have the browser console open. The application is using the `ConsoleSpanExporter` and will post the created spans to the browser console. + ## Useful links - For more information on OpenTelemetry, visit: diff --git a/examples/tracer-web/examples/fetch/index.html b/examples/tracer-web/examples/fetch/index.html new file mode 100644 index 0000000000..c8311c8e05 --- /dev/null +++ b/examples/tracer-web/examples/fetch/index.html @@ -0,0 +1,20 @@ + + + + + + Fetch Plugin Example + + + + + + + Example of using Web Tracer with Fetch plugin with console exporter and collector exporter + +
+ + + + + diff --git a/examples/tracer-web/examples/fetch/index.js b/examples/tracer-web/examples/fetch/index.js new file mode 100644 index 0000000000..5be984bbbe --- /dev/null +++ b/examples/tracer-web/examples/fetch/index.js @@ -0,0 +1,71 @@ +'use strict'; + +import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; +import { CollectorExporter } from '@opentelemetry/exporter-collector'; +import { WebTracerProvider } from '@opentelemetry/web'; +import { FetchPlugin } from '@opentelemetry/plugin-fetch'; +import { ZoneContextManager } from '@opentelemetry/context-zone'; +import { B3Propagator } from '@opentelemetry/core'; + +const provider = new WebTracerProvider({ + plugins: [ + new FetchPlugin({ + ignoreUrls: [/localhost:8090\/sockjs-node/], + propagateTraceHeaderCorsUrls: [ + 'https://cors-test.appspot.com/test', + 'https://httpbin.org/get', + ], + clearTimingResources: true + }), + ], +}); + +provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); +provider.addSpanProcessor(new SimpleSpanProcessor(new CollectorExporter())); +provider.register({ + contextManager: new ZoneContextManager(), + propagator: new B3Propagator(), +}); + +const webTracerWithZone = provider.getTracer('example-tracer-web'); + +const getData = (url) => fetch(url, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, +}); + +// example of keeping track of context between async operations +const prepareClickEvent = () => { + const url1 = 'https://httpbin.org/get'; + + const element = document.getElementById('button1'); + + const onClick = () => { + const span1 = webTracerWithZone.startSpan(`files-series-info`, { + parent: webTracerWithZone.getCurrentSpan(), + }); + webTracerWithZone.withSpan(span1, () => { + getData(url1).then((_data) => { + webTracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed'); + span1.end(); + }); + }); + for (let i = 0, j = 5; i < j; i += 1) { + const span1 = webTracerWithZone.startSpan(`files-series-info-${i}`, { + parent: webTracerWithZone.getCurrentSpan(), + }); + webTracerWithZone.withSpan(span1, () => { + getData(url1).then((_data) => { + webTracerWithZone.getCurrentSpan().addEvent('fetching-span1-completed'); + span1.end(); + }); + }); + } + }; + element.addEventListener('click', onClick); +}; + +window.addEventListener('load', prepareClickEvent); diff --git a/examples/tracer-web/package.json b/examples/tracer-web/package.json index ecf4b1a222..bb8a3e4fe5 100644 --- a/examples/tracer-web/package.json +++ b/examples/tracer-web/package.json @@ -38,6 +38,7 @@ "@opentelemetry/core": "^0.8.3", "@opentelemetry/exporter-collector": "^0.8.3", "@opentelemetry/plugin-document-load": "^0.6.1", + "@opentelemetry/plugin-fetch": "^0.8.3", "@opentelemetry/plugin-user-interaction": "^0.6.1", "@opentelemetry/plugin-xml-http-request": "^0.8.3", "@opentelemetry/tracing": "^0.8.3", diff --git a/examples/tracer-web/webpack.config.js b/examples/tracer-web/webpack.config.js index b23949d731..3e1c14ef2f 100644 --- a/examples/tracer-web/webpack.config.js +++ b/examples/tracer-web/webpack.config.js @@ -8,6 +8,7 @@ const common = { mode: 'development', entry: { 'document-load': 'examples/document-load/index.js', + fetch: 'examples/fetch/index.js', 'xml-http-request': 'examples/xml-http-request/index.js', 'user-interaction': 'examples/user-interaction/index.js', }, diff --git a/karma.base.js b/karma.base.js index 70435dda11..cbae813f7b 100644 --- a/karma.base.js +++ b/karma.base.js @@ -20,7 +20,7 @@ module.exports = { browsers: ['ChromeHeadless'], frameworks: ['mocha'], coverageIstanbulReporter: { - reports: ['json'], + reports: ['html', 'json'], dir: '.nyc_output', fixWebpackSourcePaths: true }, diff --git a/packages/opentelemetry-plugin-fetch/.eslintignore b/packages/opentelemetry-plugin-fetch/.eslintignore new file mode 100644 index 0000000000..378eac25d3 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/.eslintignore @@ -0,0 +1 @@ +build diff --git a/packages/opentelemetry-plugin-fetch/.eslintrc.js b/packages/opentelemetry-plugin-fetch/.eslintrc.js new file mode 100644 index 0000000000..9dfe62f9b8 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + "env": { + "mocha": true, + "commonjs": true, + "node": true, + "browser": true + }, + ...require('../../eslint.config.js') +} diff --git a/packages/opentelemetry-plugin-fetch/.npmignore b/packages/opentelemetry-plugin-fetch/.npmignore new file mode 100644 index 0000000000..9505ba9450 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/.npmignore @@ -0,0 +1,4 @@ +/bin +/coverage +/doc +/test diff --git a/packages/opentelemetry-plugin-fetch/LICENSE b/packages/opentelemetry-plugin-fetch/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/opentelemetry-plugin-fetch/README.md b/packages/opentelemetry-plugin-fetch/README.md new file mode 100644 index 0000000000..cdbbce00e8 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/README.md @@ -0,0 +1,68 @@ +# OpenTelemetry Fetch Instrumentation for web +[![Gitter chat][gitter-image]][gitter-url] +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![devDependencies][devDependencies-image]][devDependencies-url] +[![Apache License][license-image]][license-image] + +This module provides auto instrumentation for web using fetch. + +## Installation + +```bash +npm install --save @opentelemetry/plugin-fetch +``` + +## Usage + +```js +'use strict'; +import { ConsoleSpanExporter, SimpleSpanProcessor } from '@opentelemetry/tracing'; +import { WebTracerProvider } from '@opentelemetry/web'; +import { FetchPlugin } from '@opentelemetry/plugin-fetch'; +import { ZoneContextManager } from '@opentelemetry/context-zone'; + +const provider = new WebTracerProvider({ + plugins: [ + new FetchPlugin(), + ], +}); + +provider.addSpanProcessor(new SimpleSpanProcessor(new ConsoleSpanExporter())); + +provider.register({ + contextManager: new ZoneContextManager(), +}); + +// and some test + +fetch('http://localhost:8090/fetch.js'); + +``` + +## Example Screenshots +![Screenshot of the running example](images/trace1.png) +![Screenshot of the running example](images/trace2.png) +![Screenshot of the running example](images/trace3.png) + +See [examples/tracer-web/fetch](https://github.com/open-telemetry/opentelemetry-js/tree/master/examples/tracer-web) for a short example. + +## Useful links +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us on [gitter][gitter-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg +[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-plugin-fetch +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-fetch +[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-plugin-fetch +[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-plugin-fetch&type=dev +[npm-url]: https://www.npmjs.com/package/@opentelemetry/plugin-fetch +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fplugin-fetch.svg diff --git a/packages/opentelemetry-plugin-fetch/images/trace1.png b/packages/opentelemetry-plugin-fetch/images/trace1.png new file mode 100644 index 0000000000000000000000000000000000000000..f26085537de7a66d1371e4ba41d5e7e3ce34e2db GIT binary patch literal 155186 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

u<~Qj{zLR1UGECA<)vbepxZZH5dZ)aVa^i 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≠;a?K6=Y%EN%IWze<8$hFJ5(KVdK)qyumzr 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 literal 0 HcmV?d00001 diff --git a/packages/opentelemetry-plugin-fetch/images/trace3.png b/packages/opentelemetry-plugin-fetch/images/trace3.png new file mode 100644 index 0000000000000000000000000000000000000000..e2a602f29545348e9d3b8e8e47c6fbb53d6fc0a6 GIT binary patch literal 118279 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

-Yc?+b)bbMNKJh9GQdEH!-jcyMH0;)d1 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 T$LZCa0{?EwtH>3~82SGf(a1Dv literal 0 HcmV?d00001 diff --git a/packages/opentelemetry-plugin-fetch/karma.conf.js b/packages/opentelemetry-plugin-fetch/karma.conf.js new file mode 100644 index 0000000000..edcd9f055f --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/karma.conf.js @@ -0,0 +1,24 @@ +/*! + * Copyright 2020, OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const karmaWebpackConfig = require('../../karma.webpack'); +const karmaBaseConfig = require('../../karma.base'); + +module.exports = (config) => { + config.set(Object.assign({}, karmaBaseConfig, { + webpack: karmaWebpackConfig + })) +}; diff --git a/packages/opentelemetry-plugin-fetch/package.json b/packages/opentelemetry-plugin-fetch/package.json new file mode 100644 index 0000000000..2f1fbae5da --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/package.json @@ -0,0 +1,82 @@ +{ + "name": "@opentelemetry/plugin-fetch", + "version": "0.8.3", + "description": "OpenTelemetry fetch automatic instrumentation package.", + "main": "build/src/index.js", + "types": "build/src/index.d.ts", + "repository": "open-telemetry/opentelemetry-js", + "scripts": { + "lint": "eslint . --ext .ts", + "lint:fix": "eslint . --ext .ts --fix", + "clean": "rimraf build/*", + "codecov:browser": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../", + "precompile": "tsc --version", + "version:update": "node ../../scripts/version-update.js", + "compile": "npm run version:update && tsc -p .", + "prepare": "npm run compile", + "tdd": "karma start", + "test:browser": "nyc karma start --single-run", + "watch": "tsc -w" + }, + "keywords": [ + "fetch", + "opentelemetry", + "browser", + "tracing", + "profiling", + "metrics", + "stats" + ], + "author": "OpenTelemetry Authors", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + }, + "files": [ + "build/src/**/*.js", + "build/src/**/*.d.ts", + "doc", + "LICENSE", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "devDependencies": { + "@babel/core": "^7.6.0", + "@opentelemetry/context-zone": "^0.8.2", + "@opentelemetry/tracing": "^0.8.2", + "@types/mocha": "^7.0.0", + "@types/node": "^14.0.5", + "@types/shimmer": "^1.0.1", + "@types/sinon": "^7.0.13", + "@types/webpack-env": "1.15.2", + "babel-loader": "^8.0.6", + "codecov": "^3.1.0", + "gts": "^2.0.0", + "istanbul-instrumenter-loader": "^3.0.1", + "karma": "^5.0.5", + "karma-chrome-launcher": "^3.1.0", + "karma-coverage-istanbul-reporter": "^3.0.2", + "karma-mocha": "^2.0.1", + "karma-spec-reporter": "^0.0.32", + "karma-webpack": "^4.0.2", + "mocha": "^7.1.2", + "nyc": "^15.0.0", + "rimraf": "^3.0.0", + "sinon": "^7.5.0", + "ts-loader": "^6.0.4", + "ts-mocha": "^7.0.0", + "ts-node": "^8.6.2", + "typescript": "3.6.4", + "webpack": "^4.35.2", + "webpack-cli": "^3.3.9", + "webpack-merge": "^4.2.2" + }, + "dependencies": { + "@opentelemetry/api": "^0.8.3", + "@opentelemetry/core": "^0.8.3", + "@opentelemetry/web": "^0.8.3", + "shimmer": "^1.2.1" + } +} diff --git a/packages/opentelemetry-plugin-fetch/src/enums/AttributeNames.ts b/packages/opentelemetry-plugin-fetch/src/enums/AttributeNames.ts new file mode 100644 index 0000000000..452a1111dd --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/src/enums/AttributeNames.ts @@ -0,0 +1,31 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md + */ +export enum AttributeNames { + COMPONENT = 'component', + HTTP_HOST = 'http.host', + HTTP_FLAVOR = 'http.flavor', + HTTP_METHOD = 'http.method', + HTTP_SCHEME = 'http.scheme', + HTTP_STATUS_CODE = 'http.status_code', + HTTP_STATUS_TEXT = 'http.status_text', + HTTP_URL = 'http.url', + HTTP_TARGET = 'http.target', + HTTP_USER_AGENT = 'http.user_agent', +} diff --git a/packages/opentelemetry-plugin-fetch/src/fetch.ts b/packages/opentelemetry-plugin-fetch/src/fetch.ts new file mode 100644 index 0000000000..cccc7d43f9 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/src/fetch.ts @@ -0,0 +1,351 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as shimmer from 'shimmer'; +import * as api from '@opentelemetry/api'; +import * as core from '@opentelemetry/core'; +import * as web from '@opentelemetry/web'; +import { AttributeNames } from './enums/AttributeNames'; +import { FetchError, FetchResponse, SpanData } from './types'; +import { VERSION } from './version'; + +// how long to wait for observer to collect information about resources +// this is needed as event "load" is called before observer +// hard to say how long it should really wait, seems like 300ms is +// safe enough +const OBSERVER_WAIT_TIME_MS = 300; + +/** + * FetchPlugin Config + */ +export interface FetchPluginConfig extends api.PluginConfig { + // the number of timing resources is limited, after the limit + // (chrome 250, safari 150) the information is not collected anymore + // the only way to prevent that is to regularly clean the resources + // whenever it is possible, this is needed only when PerformanceObserver + // is not available + clearTimingResources?: boolean; + // urls which should include trace headers when origin doesn't match + propagateTraceHeaderCorsUrls?: web.PropagateTraceHeaderCorsUrls; +} + +/** + * This class represents a fetch plugin for auto instrumentation + */ +export class FetchPlugin extends core.BasePlugin> { + moduleName = 'fetch'; + private _usedResources = new WeakSet(); + private _tasksCount = 0; + + constructor(protected _config: FetchPluginConfig = {}) { + super('@opentelemetry/plugin-fetch', VERSION); + } + + /** + * Add cors pre flight child span + * @param span + * @param corsPreFlightRequest + */ + private _addChildSpan( + span: api.Span, + corsPreFlightRequest: PerformanceResourceTiming + ): void { + const childSpan = this._tracer.startSpan('CORS Preflight', { + parent: span, + startTime: corsPreFlightRequest[web.PerformanceTimingNames.FETCH_START], + }); + web.addSpanNetworkEvents(childSpan, corsPreFlightRequest); + childSpan.end( + corsPreFlightRequest[web.PerformanceTimingNames.RESPONSE_END] + ); + } + + /** + * Adds more attributes to span just before ending it + * @param span + * @param response + */ + private _addFinalSpanAttributes( + span: api.Span, + response: FetchResponse + ): void { + const parsedUrl = web.parseUrl(response.url); + span.setAttribute(AttributeNames.HTTP_STATUS_CODE, response.status); + span.setAttribute(AttributeNames.HTTP_STATUS_TEXT, response.statusText); + span.setAttribute(AttributeNames.HTTP_HOST, parsedUrl.host); + span.setAttribute( + AttributeNames.HTTP_SCHEME, + parsedUrl.protocol.replace(':', '') + ); + span.setAttribute(AttributeNames.HTTP_USER_AGENT, navigator.userAgent); + } + + /** + * Add headers + * @param options + * @param spanUrl + */ + private _addHeaders(options: RequestInit, spanUrl: string): void { + if ( + !web.shouldPropagateTraceHeaders( + spanUrl, + this._config.propagateTraceHeaderCorsUrls + ) + ) { + return; + } + const headers: { [key: string]: unknown } = {}; + api.propagation.inject(headers); + options.headers = Object.assign({}, headers, options.headers || {}); + } + + /** + * Clears the resource timings and all resources assigned with spans + * when {@link FetchPluginConfig.clearTimingResources} is + * set to true (default false) + * @private + */ + private _clearResources() { + if (this._tasksCount === 0 && this._config.clearTimingResources) { + performance.clearResourceTimings(); + this._usedResources = new WeakSet(); + } + } + + /** + * Creates a new span + * @param url + * @param options + */ + private _createSpan( + url: string, + options: Partial = {} + ): api.Span | undefined { + if (core.isUrlIgnored(url, this._config.ignoreUrls)) { + this._logger.debug('ignoring span as url matches ignored url'); + return; + } + const method = (options.method || 'GET').toUpperCase(); + const spanName = `HTTP ${method}`; + return this._tracer.startSpan(spanName, { + kind: api.SpanKind.CLIENT, + attributes: { + [AttributeNames.COMPONENT]: this.moduleName, + [AttributeNames.HTTP_METHOD]: method, + [AttributeNames.HTTP_URL]: url, + }, + }); + } + + /** + * Finds appropriate resource and add network events to the span + * @param span + * @param resourcesObserver + * @param endTime + */ + private _findResourceAndAddNetworkEvents( + span: api.Span, + resourcesObserver: SpanData, + endTime: api.HrTime + ): void { + let resources: PerformanceResourceTiming[] = resourcesObserver.entries; + if (!resources.length) { + // fallback - either Observer is not available or it took longer + // then OBSERVER_WAIT_TIME_MS and observer didn't collect enough + // information + resources = performance.getEntriesByType( + 'resource' + ) as PerformanceResourceTiming[]; + } + const resource = web.getResource( + resourcesObserver.spanUrl, + resourcesObserver.startTime, + endTime, + resources, + this._usedResources, + 'fetch' + ); + + if (resource.mainRequest) { + const mainRequest = resource.mainRequest; + this._markResourceAsUsed(mainRequest); + + const corsPreFlightRequest = resource.corsPreFlightRequest; + if (corsPreFlightRequest) { + this._addChildSpan(span, corsPreFlightRequest); + this._markResourceAsUsed(corsPreFlightRequest); + } + web.addSpanNetworkEvents(span, mainRequest); + } + } + + /** + * Marks certain [resource]{@link PerformanceResourceTiming} when information + * from this is used to add events to span. + * This is done to avoid reusing the same resource again for next span + * @param resource + */ + private _markResourceAsUsed(resource: PerformanceResourceTiming): void { + this._usedResources.add(resource); + } + + /** + * Finish span, add attributes, network events etc. + * @param span + * @param spanData + * @param response + */ + private _endSpan( + span: api.Span, + spanData: SpanData, + response: FetchResponse + ) { + const endTime = core.hrTime(); + spanData.observer.disconnect(); + this._addFinalSpanAttributes(span, response); + + setTimeout(() => { + this._findResourceAndAddNetworkEvents(span, spanData, endTime); + this._tasksCount--; + this._clearResources(); + span.end(endTime); + }, OBSERVER_WAIT_TIME_MS); + } + + /** + * Patches the constructor of fetch + */ + private _patchConstructor(): ( + original: (input: RequestInfo, init?: RequestInit) => Promise + ) => (input: RequestInfo, init?: RequestInit) => Promise { + return ( + original: (input: RequestInfo, init?: RequestInit) => Promise + ): ((input: RequestInfo, init?: RequestInit) => Promise) => { + const plugin = this; + + return function patchConstructor( + this: (input: RequestInfo, init?: RequestInit) => Promise, + input: RequestInfo, + init?: RequestInit + ): Promise { + const url = input instanceof Request ? input.url : input; + const options: RequestInit = + input instanceof Request ? input : init || {}; + + const span = plugin._createSpan(url, options); + if (!span) { + return original.apply(this, [url, options]); + } + const spanData = plugin._prepareSpanData(url); + + function onSuccess( + span: api.Span, + resolve: ( + value?: Response | PromiseLike | undefined + ) => void, + response: Response + ) { + try { + if (response.status >= 200 && response.status < 400) { + plugin._endSpan(span, spanData, response); + } else { + plugin._endSpan(span, spanData, { + status: response.status, + statusText: response.statusText, + url, + }); + } + } finally { + resolve(response); + } + } + + function onError( + span: api.Span, + reject: (reason?: unknown) => void, + error: FetchError + ) { + try { + plugin._endSpan(span, spanData, { + status: error.status || 0, + statusText: error.message, + url, + }); + } finally { + reject(error); + } + } + + return new Promise((resolve, reject) => { + return plugin._tracer.withSpan(span, () => { + plugin._addHeaders(options, url); + plugin._tasksCount++; + return original + .apply(this, [url, options]) + .then( + onSuccess.bind(this, span, resolve), + onError.bind(this, span, reject) + ); + }); + }); + }; + }; + } + + /** + * Prepares a span data - needed later for matching appropriate network + * resources + * @param spanUrl + */ + private _prepareSpanData(spanUrl: string): SpanData { + const startTime = core.hrTime(); + const entries: PerformanceResourceTiming[] = []; + const observer: PerformanceObserver = new PerformanceObserver(list => { + const entries = list.getEntries() as PerformanceResourceTiming[]; + entries.forEach(entry => { + if (entry.initiatorType === 'fetch' && entry.name === spanUrl) { + entries.push(entry); + } + }); + }); + observer.observe({ + entryTypes: ['resource'], + }); + return { entries, observer, startTime, spanUrl }; + } + + /** + * implements patch function + */ + patch() { + if (core.isWrapped(window.fetch)) { + shimmer.unwrap(window, 'fetch'); + this._logger.debug('removing previous patch for constructor'); + } + + shimmer.wrap(window, 'fetch', this._patchConstructor()); + + return this._moduleExports; + } + + /** + * implements unpatch function + */ + unpatch() { + shimmer.unwrap(window, 'fetch'); + this._usedResources = new WeakSet(); + } +} diff --git a/packages/opentelemetry-plugin-fetch/src/index.ts b/packages/opentelemetry-plugin-fetch/src/index.ts new file mode 100644 index 0000000000..1d39792560 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export * from './fetch'; diff --git a/packages/opentelemetry-plugin-fetch/src/types.ts b/packages/opentelemetry-plugin-fetch/src/types.ts new file mode 100644 index 0000000000..4144aceaa1 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/src/types.ts @@ -0,0 +1,45 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import * as api from '@opentelemetry/api'; + +/** + * Interface used to provide information to finish span on fetch response + */ +export interface FetchResponse { + status: number; + statusText?: string; + url: string; +} + +/** + * Interface used to provide information to finish span on fetch error + */ +export interface FetchError { + status?: number; + message: string; +} + +/** + * Interface used to keep information about span between creating and + * ending span + */ +export interface SpanData { + entries: PerformanceResourceTiming[]; + observer: PerformanceObserver; + spanUrl: string; + startTime: api.HrTime; +} diff --git a/packages/opentelemetry-plugin-fetch/src/version.ts b/packages/opentelemetry-plugin-fetch/src/version.ts new file mode 100644 index 0000000000..9e616149a4 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/src/version.ts @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// this is autogenerated file, see scripts/version-update.js +export const VERSION = '0.8.3'; diff --git a/packages/opentelemetry-plugin-fetch/test/fetch.test.ts b/packages/opentelemetry-plugin-fetch/test/fetch.test.ts new file mode 100644 index 0000000000..cf27f84f40 --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/test/fetch.test.ts @@ -0,0 +1,563 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as api from '@opentelemetry/api'; +import * as core from '@opentelemetry/core'; +import { ZoneContextManager } from '@opentelemetry/context-zone'; +import * as tracing from '@opentelemetry/tracing'; +import { + PerformanceTimingNames as PTN, + WebTracerProvider, +} from '@opentelemetry/web'; +import * as assert from 'assert'; +import * as sinon from 'sinon'; +import { FetchPlugin, FetchPluginConfig } from '../src'; +import { AttributeNames } from '../src/enums/AttributeNames'; + +class DummySpanExporter implements tracing.SpanExporter { + export(spans: any) {} + + shutdown() {} +} + +const getData = (url: string, method?: string) => + fetch(url, { + method: method || 'GET', + headers: { + foo: 'bar', + Accept: 'application/json', + 'Content-Type': 'application/json', + }, + }); + +const defaultResource = { + connectEnd: 15, + connectStart: 13, + decodedBodySize: 0, + domainLookupEnd: 12, + domainLookupStart: 11, + encodedBodySize: 0, + fetchStart: 10.1, + initiatorType: 'fetch', + nextHopProtocol: '', + redirectEnd: 0, + redirectStart: 0, + requestStart: 16, + responseEnd: 20.5, + responseStart: 17, + secureConnectionStart: 14, + transferSize: 0, + workerStart: 0, + duration: 0, + entryType: '', + name: '', + startTime: 0, +}; + +function createResource(resource = {}): PerformanceResourceTiming { + return Object.assign( + {}, + defaultResource, + resource + ) as PerformanceResourceTiming; +} + +function createMasterResource(resource = {}): PerformanceResourceTiming { + const masterResource: any = createResource(resource); + Object.keys(masterResource).forEach((key: string) => { + if (typeof masterResource[key] === 'number') { + masterResource[key] = masterResource[key] + 30; + } + }); + return masterResource; +} + +describe('fetch', () => { + let sandbox: sinon.SinonSandbox; + let contextManager: ZoneContextManager; + let lastResponse: any | undefined; + let webTracerWithZone: api.Tracer; + let webTracerProviderWithZone: WebTracerProvider; + let dummySpanExporter: DummySpanExporter; + let exportSpy: any; + let clearResourceTimingsSpy: any; + let rootSpan: api.Span; + let fakeNow = 0; + let fetchPlugin: FetchPlugin; + + const url = 'http://localhost:8090/get'; + const badUrl = 'http://foo.bar.com/get'; + + const clearData = () => { + sandbox.restore(); + lastResponse = undefined; + }; + + const prepareData = ( + done: any, + fileUrl: string, + config: FetchPluginConfig, + method?: string + ) => { + sandbox = sinon.createSandbox(); + sandbox.useFakeTimers(); + + sandbox.stub(core.otperformance, 'timeOrigin').value(0); + sandbox.stub(core.otperformance, 'now').callsFake(() => fakeNow); + + function fakeFetch(input: RequestInfo, init: RequestInit = {}) { + return new Promise((resolve, reject) => { + const response: any = { + args: {}, + url: fileUrl, + }; + response.headers = Object.assign({}, init.headers); + + if (init.method === 'DELETE') { + response.status = 405; + response.statusText = 'OK'; + resolve(new window.Response('foo', response)); + } else if (input === url) { + response.status = 200; + response.statusText = 'OK'; + resolve(new window.Response(JSON.stringify(response), response)); + } else { + response.status = 404; + response.statusText = 'Bad request'; + reject(new window.Response(JSON.stringify(response), response)); + } + }); + } + + sandbox.stub(window, 'fetch').callsFake(fakeFetch as any); + + const resources: PerformanceResourceTiming[] = []; + resources.push( + createResource({ + name: fileUrl, + }), + createMasterResource({ + name: fileUrl, + }) + ); + + const spyEntries = sandbox.stub(performance, 'getEntriesByType'); + spyEntries.withArgs('resource').returns(resources); + fetchPlugin = new FetchPlugin(config); + webTracerProviderWithZone = new WebTracerProvider({ + logLevel: core.LogLevel.ERROR, + plugins: [fetchPlugin], + }); + webTracerWithZone = webTracerProviderWithZone.getTracer('fetch-test'); + dummySpanExporter = new DummySpanExporter(); + exportSpy = sandbox.stub(dummySpanExporter, 'export'); + clearResourceTimingsSpy = sandbox.stub(performance, 'clearResourceTimings'); + webTracerProviderWithZone.addSpanProcessor( + new tracing.SimpleSpanProcessor(dummySpanExporter) + ); + + rootSpan = webTracerWithZone.startSpan('root'); + webTracerWithZone.withSpan(rootSpan, () => { + fakeNow = 0; + getData(fileUrl, method).then( + response => { + // this is a bit tricky as the only way to get all request headers from + // fetch is to use json() + response.json().then( + json => { + lastResponse = json; + const headers: { [key: string]: string } = {}; + Object.keys(lastResponse.headers).forEach(key => { + headers[key.toLowerCase()] = lastResponse.headers[key]; + }); + lastResponse.headers = headers; + // OBSERVER_WAIT_TIME_MS + sandbox.clock.tick(300); + done(); + }, + () => { + lastResponse = undefined; + // OBSERVER_WAIT_TIME_MS + sandbox.clock.tick(300); + done(); + } + ); + }, + () => { + lastResponse = undefined; + // OBSERVER_WAIT_TIME_MS + sandbox.clock.tick(300); + done(); + } + ); + fakeNow = 300; + }); + }; + + beforeEach(() => { + contextManager = new ZoneContextManager().enable(); + api.context.setGlobalContextManager(contextManager); + }); + + afterEach(() => { + api.context.disable(); + }); + + before(() => { + api.propagation.setGlobalPropagator(new core.B3Propagator()); + }); + + describe('when request is successful', () => { + beforeEach(done => { + const propagateTraceHeaderCorsUrls = [url]; + prepareData(done, url, { propagateTraceHeaderCorsUrls }); + }); + + afterEach(() => { + clearData(); + }); + + it('should wrap methods', () => { + assert.ok(core.isWrapped(window.fetch)); + fetchPlugin.patch(); + assert.ok(core.isWrapped(window.fetch)); + }); + + it('should unwrap methods', () => { + assert.ok(core.isWrapped(window.fetch)); + fetchPlugin.unpatch(); + assert.ok(!core.isWrapped(window.fetch)); + }); + + it('should create a span with correct root span', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + assert.strictEqual( + span.parentSpanId, + rootSpan.context().spanId, + 'parent span is not root span' + ); + }); + + it('span should have correct name', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + assert.strictEqual(span.name, 'HTTP GET', 'span has wrong name'); + }); + + it('span should have correct kind', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + assert.strictEqual(span.kind, api.SpanKind.CLIENT, 'span has wrong kind'); + }); + + it('span should have correct attributes', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + const attributes = span.attributes; + const keys = Object.keys(attributes); + + assert.ok( + attributes[keys[0]] !== '', + `attributes ${AttributeNames.COMPONENT} is not defined` + ); + assert.strictEqual( + attributes[keys[1]], + 'GET', + `attributes ${AttributeNames.HTTP_METHOD} is wrong` + ); + assert.strictEqual( + attributes[keys[2]], + url, + `attributes ${AttributeNames.HTTP_URL} is wrong` + ); + assert.strictEqual( + attributes[keys[3]], + 200, + `attributes ${AttributeNames.HTTP_STATUS_CODE} is wrong` + ); + assert.ok( + attributes[keys[4]] === 'OK' || attributes[keys[4]] === '', + `attributes ${AttributeNames.HTTP_STATUS_TEXT} is wrong` + ); + assert.ok( + (attributes[keys[5]] as string).indexOf('localhost') === 0, + `attributes ${AttributeNames.HTTP_HOST} is wrong` + ); + assert.ok( + attributes[keys[6]] === 'http' || attributes[keys[6]] === 'https', + `attributes ${AttributeNames.HTTP_SCHEME} is wrong` + ); + assert.ok( + attributes[keys[7]] !== '', + `attributes ${AttributeNames.HTTP_USER_AGENT} is not defined` + ); + + assert.strictEqual(keys.length, 8, 'number of attributes is wrong'); + }); + + it('span should have correct events', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + const events = span.events; + assert.strictEqual(events.length, 9, 'number of events is wrong'); + + assert.strictEqual( + events[0].name, + PTN.FETCH_START, + `event ${PTN.FETCH_START} is not defined` + ); + assert.strictEqual( + events[1].name, + PTN.DOMAIN_LOOKUP_START, + `event ${PTN.DOMAIN_LOOKUP_START} is not defined` + ); + assert.strictEqual( + events[2].name, + PTN.DOMAIN_LOOKUP_END, + `event ${PTN.DOMAIN_LOOKUP_END} is not defined` + ); + assert.strictEqual( + events[3].name, + PTN.CONNECT_START, + `event ${PTN.CONNECT_START} is not defined` + ); + assert.strictEqual( + events[4].name, + PTN.SECURE_CONNECTION_START, + `event ${PTN.SECURE_CONNECTION_START} is not defined` + ); + assert.strictEqual( + events[5].name, + PTN.CONNECT_END, + `event ${PTN.CONNECT_END} is not defined` + ); + assert.strictEqual( + events[6].name, + PTN.REQUEST_START, + `event ${PTN.REQUEST_START} is not defined` + ); + assert.strictEqual( + events[7].name, + PTN.RESPONSE_START, + `event ${PTN.RESPONSE_START} is not defined` + ); + assert.strictEqual( + events[8].name, + PTN.RESPONSE_END, + `event ${PTN.RESPONSE_END} is not defined` + ); + }); + + it('should create a span for preflight request', () => { + const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; + const parentSpan: tracing.ReadableSpan = exportSpy.args[1][0][0]; + assert.strictEqual( + span.parentSpanId, + parentSpan.spanContext.spanId, + 'parent span is not root span' + ); + }); + + it('preflight request span should have correct name', () => { + const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; + assert.strictEqual( + span.name, + 'CORS Preflight', + 'preflight request span has wrong name' + ); + }); + + it('preflight request span should have correct kind', () => { + const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; + assert.strictEqual( + span.kind, + api.SpanKind.INTERNAL, + 'span has wrong kind' + ); + }); + + it('preflight request span should have correct events', () => { + const span: tracing.ReadableSpan = exportSpy.args[0][0][0]; + const events = span.events; + assert.strictEqual(events.length, 9, 'number of events is wrong'); + + assert.strictEqual( + events[0].name, + PTN.FETCH_START, + `event ${PTN.FETCH_START} is not defined` + ); + assert.strictEqual( + events[1].name, + PTN.DOMAIN_LOOKUP_START, + `event ${PTN.DOMAIN_LOOKUP_START} is not defined` + ); + assert.strictEqual( + events[2].name, + PTN.DOMAIN_LOOKUP_END, + `event ${PTN.DOMAIN_LOOKUP_END} is not defined` + ); + assert.strictEqual( + events[3].name, + PTN.CONNECT_START, + `event ${PTN.CONNECT_START} is not defined` + ); + assert.strictEqual( + events[4].name, + PTN.SECURE_CONNECTION_START, + `event ${PTN.SECURE_CONNECTION_START} is not defined` + ); + assert.strictEqual( + events[5].name, + PTN.CONNECT_END, + `event ${PTN.CONNECT_END} is not defined` + ); + assert.strictEqual( + events[6].name, + PTN.REQUEST_START, + `event ${PTN.REQUEST_START} is not defined` + ); + assert.strictEqual( + events[7].name, + PTN.RESPONSE_START, + `event ${PTN.RESPONSE_START} is not defined` + ); + assert.strictEqual( + events[8].name, + PTN.RESPONSE_END, + `event ${PTN.RESPONSE_END} is not defined` + ); + }); + + it('should set trace headers', () => { + const span: api.Span = exportSpy.args[1][0][0]; + assert.strictEqual( + lastResponse.headers[core.X_B3_TRACE_ID], + span.context().traceId, + `trace header '${core.X_B3_TRACE_ID}' not set` + ); + assert.strictEqual( + lastResponse.headers[core.X_B3_SPAN_ID], + span.context().spanId, + `trace header '${core.X_B3_SPAN_ID}' not set` + ); + assert.strictEqual( + lastResponse.headers[core.X_B3_SAMPLED], + String(span.context().traceFlags), + `trace header '${core.X_B3_SAMPLED}' not set` + ); + }); + + it('should NOT clear the resources', () => { + assert.strictEqual( + clearResourceTimingsSpy.args.length, + 0, + 'resources have been cleared' + ); + }); + + describe('when propagateTraceHeaderCorsUrls does NOT MATCH', () => { + beforeEach(done => { + clearData(); + prepareData(done, url, {}); + }); + it('should NOT set trace headers', () => { + assert.strictEqual( + lastResponse.headers[core.X_B3_TRACE_ID], + undefined, + `trace header '${core.X_B3_TRACE_ID}' should not be set` + ); + assert.strictEqual( + lastResponse.headers[core.X_B3_SPAN_ID], + undefined, + `trace header '${core.X_B3_SPAN_ID}' should not be set` + ); + assert.strictEqual( + lastResponse.headers[core.X_B3_SAMPLED], + undefined, + `trace header '${core.X_B3_SAMPLED}' should not be set` + ); + }); + }); + }); + + describe('when url is ignored', () => { + beforeEach(done => { + const propagateTraceHeaderCorsUrls = url; + prepareData(done, url, { + propagateTraceHeaderCorsUrls, + ignoreUrls: [propagateTraceHeaderCorsUrls], + }); + }); + afterEach(() => { + clearData(); + }); + it('should NOT create any span', () => { + assert.strictEqual(exportSpy.args.length, 0, "span shouldn't b exported"); + }); + }); + + describe('when clearTimingResources is TRUE', () => { + beforeEach(done => { + const propagateTraceHeaderCorsUrls = url; + prepareData(done, url, { + propagateTraceHeaderCorsUrls, + clearTimingResources: true, + }); + }); + afterEach(() => { + clearData(); + }); + it('should clear the resources', () => { + assert.strictEqual( + clearResourceTimingsSpy.args.length, + 1, + "resources haven't been cleared" + ); + }); + }); + + describe('when request is NOT successful (wrong url)', () => { + beforeEach(done => { + const propagateTraceHeaderCorsUrls = badUrl; + prepareData(done, badUrl, { propagateTraceHeaderCorsUrls }); + }); + afterEach(() => { + clearData(); + }); + it('should create a span with correct root span', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + assert.strictEqual( + span.parentSpanId, + rootSpan.context().spanId, + 'parent span is not root span' + ); + }); + }); + + describe('when request is NOT successful (405)', () => { + beforeEach(done => { + const propagateTraceHeaderCorsUrls = url; + prepareData(done, url, { propagateTraceHeaderCorsUrls }, 'DELETE'); + }); + afterEach(() => { + clearData(); + }); + + it('should create a span with correct root span', () => { + const span: tracing.ReadableSpan = exportSpy.args[1][0][0]; + assert.strictEqual( + span.parentSpanId, + rootSpan.context().spanId, + 'parent span is not root span' + ); + }); + }); +}); diff --git a/packages/opentelemetry-plugin-fetch/test/index-webpack.ts b/packages/opentelemetry-plugin-fetch/test/index-webpack.ts new file mode 100644 index 0000000000..061a48ccfa --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/test/index-webpack.ts @@ -0,0 +1,20 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const testsContext = require.context('.', true, /test$/); +testsContext.keys().forEach(testsContext); + +const srcContext = require.context('.', true, /src$/); +srcContext.keys().forEach(srcContext); diff --git a/packages/opentelemetry-plugin-fetch/tsconfig.json b/packages/opentelemetry-plugin-fetch/tsconfig.json new file mode 100644 index 0000000000..71661a842e --- /dev/null +++ b/packages/opentelemetry-plugin-fetch/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.base", + "compilerOptions": { + "rootDir": ".", + "outDir": "build", + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts index ff18cb02f1..59b59cc03d 100644 --- a/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts +++ b/packages/opentelemetry-plugin-xml-http-request/src/xhr.ts @@ -21,17 +21,17 @@ import { isUrlIgnored, isWrapped, otperformance, - urlMatches, } from '@opentelemetry/core'; import { HttpAttribute, GeneralAttribute, } from '@opentelemetry/semantic-conventions'; import { - addSpanNetworkEvent, + addSpanNetworkEvents, getResource, parseUrl, PerformanceTimingNames as PTN, + shouldPropagateTraceHeaders, } from '@opentelemetry/web'; import * as shimmer from 'shimmer'; import { EventNames } from './enums/EventNames'; @@ -86,7 +86,12 @@ export class XMLHttpRequestPlugin extends BasePlugin { * @private */ private _addHeaders(xhr: XMLHttpRequest, spanUrl: string) { - if (!this._shouldPropagateTraceHeaders(spanUrl)) { + if ( + !shouldPropagateTraceHeaders( + spanUrl, + this._config.propagateTraceHeaderCorsUrls + ) + ) { return; } const headers: { [key: string]: unknown } = {}; @@ -96,34 +101,6 @@ export class XMLHttpRequestPlugin extends BasePlugin { }); } - /** - * checks if trace headers should be propagated - * @param spanUrl - * @private - */ - _shouldPropagateTraceHeaders(spanUrl: string) { - let propagateTraceHeaderUrls = - this._config.propagateTraceHeaderCorsUrls || []; - if ( - typeof propagateTraceHeaderUrls === 'string' || - propagateTraceHeaderUrls instanceof RegExp - ) { - propagateTraceHeaderUrls = [propagateTraceHeaderUrls]; - } - const parsedSpanUrl = parseUrl(spanUrl); - - if (parsedSpanUrl.origin === window.location.origin) { - return true; - } else { - for (const propagateTraceHeaderUrl of propagateTraceHeaderUrls) { - if (urlMatches(spanUrl, propagateTraceHeaderUrl)) { - return true; - } - } - return false; - } - } - /** * Add cors pre flight child span * @param span @@ -138,7 +115,7 @@ export class XMLHttpRequestPlugin extends BasePlugin { const childSpan = this._tracer.startSpan('CORS Preflight', { startTime: corsPreFlightRequest[PTN.FETCH_START], }); - this._addSpanNetworkEvents(childSpan, corsPreFlightRequest); + addSpanNetworkEvents(childSpan, corsPreFlightRequest); childSpan.end(corsPreFlightRequest[PTN.RESPONSE_END]); }); } @@ -168,27 +145,6 @@ export class XMLHttpRequestPlugin extends BasePlugin { } } - /** - * Adds Network events to the span - * @param span - * @param resource - * @private - */ - private _addSpanNetworkEvents( - span: api.Span, - resource: PerformanceResourceTiming - ) { - addSpanNetworkEvent(span, PTN.FETCH_START, resource); - addSpanNetworkEvent(span, PTN.DOMAIN_LOOKUP_START, resource); - addSpanNetworkEvent(span, PTN.DOMAIN_LOOKUP_END, resource); - addSpanNetworkEvent(span, PTN.CONNECT_START, resource); - addSpanNetworkEvent(span, PTN.SECURE_CONNECTION_START, resource); - addSpanNetworkEvent(span, PTN.CONNECT_END, resource); - addSpanNetworkEvent(span, PTN.REQUEST_START, resource); - addSpanNetworkEvent(span, PTN.RESPONSE_START, resource); - addSpanNetworkEvent(span, PTN.RESPONSE_END, resource); - } - /** * will collect information about all resources created * between "send" and "end" with additional waiting for main resource @@ -260,6 +216,7 @@ export class XMLHttpRequestPlugin extends BasePlugin { // information resources = otperformance.getEntriesByType( // ts thinks this is the perf_hooks module, but it is the browser performance api + // eslint-disable-next-line @typescript-eslint/no-explicit-any 'resource' as any ) as PerformanceResourceTiming[]; } @@ -281,7 +238,7 @@ export class XMLHttpRequestPlugin extends BasePlugin { this._addChildSpan(span, corsPreFlightRequest); this._markResourceAsUsed(corsPreFlightRequest); } - this._addSpanNetworkEvents(span, mainRequest); + addSpanNetworkEvents(span, mainRequest); } } diff --git a/packages/opentelemetry-web/src/StackContextManager.ts b/packages/opentelemetry-web/src/StackContextManager.ts index 78d8d34dc3..718ec88035 100644 --- a/packages/opentelemetry-web/src/StackContextManager.ts +++ b/packages/opentelemetry-web/src/StackContextManager.ts @@ -42,7 +42,7 @@ export class StackContextManager implements ContextManager { context = Context.ROOT_CONTEXT ): T { const manager = this; - const contextWrapper = function (this: any, ...args: any[]) { + const contextWrapper = function (this: unknown, ...args: unknown[]) { return manager.with(context, () => target.apply(this, args)); }; Object.defineProperty(contextWrapper, 'length', { diff --git a/packages/opentelemetry-web/src/types.ts b/packages/opentelemetry-web/src/types.ts index 45ed1a9e03..10ee04f14e 100644 --- a/packages/opentelemetry-web/src/types.ts +++ b/packages/opentelemetry-web/src/types.ts @@ -53,3 +53,12 @@ export interface PerformanceResourceTimingInfo { corsPreFlightRequest?: PerformanceResourceTiming; mainRequest?: PerformanceResourceTiming; } + +type PropagateTraceHeaderCorsUrl = string | RegExp; + +/** + * urls which should include trace headers when origin doesn't match + */ +export type PropagateTraceHeaderCorsUrls = + | PropagateTraceHeaderCorsUrl + | PropagateTraceHeaderCorsUrl[]; diff --git a/packages/opentelemetry-web/src/utils.ts b/packages/opentelemetry-web/src/utils.ts index 1edeb64f0c..aa3dd320b6 100644 --- a/packages/opentelemetry-web/src/utils.ts +++ b/packages/opentelemetry-web/src/utils.ts @@ -14,16 +14,25 @@ * limitations under the License. */ -import { PerformanceEntries, PerformanceResourceTimingInfo } from './types'; +import { + PerformanceEntries, + PerformanceResourceTimingInfo, + PropagateTraceHeaderCorsUrls, +} from './types'; import { PerformanceTimingNames as PTN } from './enums/PerformanceTimingNames'; import * as api from '@opentelemetry/api'; -import { hrTimeToNanoseconds, timeInputToHrTime } from '@opentelemetry/core'; +import { + hrTimeToNanoseconds, + timeInputToHrTime, + urlMatches, +} from '@opentelemetry/core'; /** * Helper function to be able to use enum as typed key in type and in interface when using forEach * @param obj * @param key */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function hasKey(obj: O, key: keyof any): key is keyof O { return key in obj; } @@ -54,6 +63,26 @@ export function addSpanNetworkEvent( return undefined; } +/** + * Helper function for adding network events + * @param span + * @param resource + */ +export function addSpanNetworkEvents( + span: api.Span, + resource: PerformanceEntries +): void { + addSpanNetworkEvent(span, PTN.FETCH_START, resource); + addSpanNetworkEvent(span, PTN.DOMAIN_LOOKUP_START, resource); + addSpanNetworkEvent(span, PTN.DOMAIN_LOOKUP_END, resource); + addSpanNetworkEvent(span, PTN.CONNECT_START, resource); + addSpanNetworkEvent(span, PTN.SECURE_CONNECTION_START, resource); + addSpanNetworkEvent(span, PTN.CONNECT_END, resource); + addSpanNetworkEvent(span, PTN.REQUEST_START, resource); + addSpanNetworkEvent(span, PTN.RESPONSE_START, resource); + addSpanNetworkEvent(span, PTN.RESPONSE_END, resource); +} + /** * sort resources by startTime * @param filteredResources @@ -79,6 +108,7 @@ export function sortResources(filteredResources: PerformanceResourceTiming[]) { * @param endTimeHR * @param resources * @param ignoredResources + * @param initiatorType */ export function getResource( spanUrl: string, @@ -87,14 +117,16 @@ export function getResource( resources: PerformanceResourceTiming[], ignoredResources: WeakSet = new WeakSet< PerformanceResourceTiming - >() + >(), + initiatorType?: string ): PerformanceResourceTimingInfo { const filteredResources = filterResourcesForSpan( spanUrl, startTimeHR, endTimeHR, resources, - ignoredResources + ignoredResources, + initiatorType ); if (filteredResources.length === 0) { @@ -192,7 +224,8 @@ function filterResourcesForSpan( startTimeHR: api.HrTime, endTimeHR: api.HrTime, resources: PerformanceResourceTiming[], - ignoredResources: WeakSet + ignoredResources: WeakSet, + initiatorType?: string ) { const startTime = hrTimeToNanoseconds(startTimeHR); const endTime = hrTimeToNanoseconds(endTimeHR); @@ -205,7 +238,8 @@ function filterResourcesForSpan( ); return ( - resource.initiatorType.toLowerCase() === 'xmlhttprequest' && + resource.initiatorType.toLowerCase() === + (initiatorType || 'xmlhttprequest') && resource.name === spanUrl && resourceStartTime >= startTime && resourceEndTime <= endTime @@ -237,6 +271,7 @@ export function parseUrl(url: string): HTMLAnchorElement { * @param optimised - when id attribute of element is present the xpath can be * simplified to contain id */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function getElementXPath(target: any, optimised?: boolean) { if (target.nodeType === Node.DOCUMENT_NODE) { return '/'; @@ -312,3 +347,30 @@ function getNodeValue(target: HTMLElement, optimised?: boolean): string { } return `/${nodeValue}`; } + +/** + * Checks if trace headers should be propagated + * @param spanUrl + * @private + */ +export function shouldPropagateTraceHeaders( + spanUrl: string, + propagateTraceHeaderCorsUrls?: PropagateTraceHeaderCorsUrls +) { + let propagateTraceHeaderUrls = propagateTraceHeaderCorsUrls || []; + if ( + typeof propagateTraceHeaderUrls === 'string' || + propagateTraceHeaderUrls instanceof RegExp + ) { + propagateTraceHeaderUrls = [propagateTraceHeaderUrls]; + } + const parsedSpanUrl = parseUrl(spanUrl); + + if (parsedSpanUrl.origin === window.location.origin) { + return true; + } else { + return propagateTraceHeaderUrls.some(propagateTraceHeaderUrl => + urlMatches(spanUrl, propagateTraceHeaderUrl) + ); + } +} diff --git a/packages/opentelemetry-web/test/utils.test.ts b/packages/opentelemetry-web/test/utils.test.ts index 52a417ba42..805986de71 100644 --- a/packages/opentelemetry-web/test/utils.test.ts +++ b/packages/opentelemetry-web/test/utils.test.ts @@ -26,9 +26,11 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { addSpanNetworkEvent, + addSpanNetworkEvents, getElementXPath, getResource, PerformanceEntries, + shouldPropagateTraceHeaders, } from '../src'; import { PerformanceTimingNames as PTN } from '../src/enums/PerformanceTimingNames'; @@ -132,6 +134,31 @@ describe('utils', () => { sandbox.restore(); }); + describe('addSpanNetworkEvents', () => { + it('should add all network events to span', () => { + const addEventSpy = sinon.spy(); + const span = ({ + addEvent: addEventSpy, + } as unknown) as tracing.Span; + const entries = { + [PTN.FETCH_START]: 123, + [PTN.DOMAIN_LOOKUP_START]: 123, + [PTN.DOMAIN_LOOKUP_END]: 123, + [PTN.CONNECT_START]: 123, + [PTN.SECURE_CONNECTION_START]: 123, + [PTN.CONNECT_END]: 123, + [PTN.REQUEST_START]: 123, + [PTN.RESPONSE_START]: 123, + [PTN.RESPONSE_END]: 123, + } as PerformanceEntries; + + assert.strictEqual(addEventSpy.callCount, 0); + + addSpanNetworkEvents(span, entries); + + assert.strictEqual(addEventSpy.callCount, 9); + }); + }); describe('addSpanNetworkEvent', () => { describe('when entries contain the performance', () => { it('should add event to span', () => { @@ -508,6 +535,40 @@ describe('utils', () => { assert.strictEqual(node, getElementByXpath(element)); }); }); + + describe('shouldPropagateTraceHeaders', () => { + it('should propagate trace when url is the same as origin', () => { + const result = shouldPropagateTraceHeaders( + `${window.location.origin}/foo/bar` + ); + assert.strictEqual(result, true); + }); + it('should propagate trace when url match', () => { + const result = shouldPropagateTraceHeaders( + 'http://foo.com', + 'http://foo.com' + ); + assert.strictEqual(result, true); + }); + it('should propagate trace when url match regexp', () => { + const result = shouldPropagateTraceHeaders('http://foo.com', /foo.+/); + assert.strictEqual(result, true); + }); + it('should propagate trace when url match array of string', () => { + const result = shouldPropagateTraceHeaders('http://foo.com', [ + 'http://foo.com', + ]); + assert.strictEqual(result, true); + }); + it('should propagate trace when url match array of regexp', () => { + const result = shouldPropagateTraceHeaders('http://foo.com', [/foo.+/]); + assert.strictEqual(result, true); + }); + it("should NOT propagate trace when url doesn't match", () => { + const result = shouldPropagateTraceHeaders('http://foo.com'); + assert.strictEqual(result, false); + }); + }); }); function getElementByXpath(path: string) { From 744c8719305eecc55af10f18551685eeb865fa32 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Wed, 17 Jun 2020 14:55:43 +0200 Subject: [PATCH 18/22] chore(deps): pin dependencies (#1205) --- .../opentelemetry-plugin-fetch/package.json | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/opentelemetry-plugin-fetch/package.json b/packages/opentelemetry-plugin-fetch/package.json index 2f1fbae5da..6a0e3c943a 100644 --- a/packages/opentelemetry-plugin-fetch/package.json +++ b/packages/opentelemetry-plugin-fetch/package.json @@ -43,35 +43,35 @@ "access": "public" }, "devDependencies": { - "@babel/core": "^7.6.0", + "@babel/core": "7.10.2", "@opentelemetry/context-zone": "^0.8.2", "@opentelemetry/tracing": "^0.8.2", - "@types/mocha": "^7.0.0", - "@types/node": "^14.0.5", - "@types/shimmer": "^1.0.1", - "@types/sinon": "^7.0.13", + "@types/mocha": "7.0.2", + "@types/node": "14.0.13", + "@types/shimmer": "1.0.1", + "@types/sinon": "7.5.2", "@types/webpack-env": "1.15.2", - "babel-loader": "^8.0.6", - "codecov": "^3.1.0", - "gts": "^2.0.0", - "istanbul-instrumenter-loader": "^3.0.1", - "karma": "^5.0.5", - "karma-chrome-launcher": "^3.1.0", - "karma-coverage-istanbul-reporter": "^3.0.2", - "karma-mocha": "^2.0.1", - "karma-spec-reporter": "^0.0.32", - "karma-webpack": "^4.0.2", - "mocha": "^7.1.2", - "nyc": "^15.0.0", - "rimraf": "^3.0.0", - "sinon": "^7.5.0", - "ts-loader": "^6.0.4", - "ts-mocha": "^7.0.0", - "ts-node": "^8.6.2", + "babel-loader": "8.1.0", + "codecov": "3.7.0", + "gts": "2.0.2", + "istanbul-instrumenter-loader": "3.0.1", + "karma": "5.1.0", + "karma-chrome-launcher": "3.1.0", + "karma-coverage-istanbul-reporter": "3.0.3", + "karma-mocha": "2.0.1", + "karma-spec-reporter": "0.0.32", + "karma-webpack": "4.0.2", + "mocha": "7.2.0", + "nyc": "15.1.0", + "rimraf": "3.0.2", + "sinon": "7.5.0", + "ts-loader": "6.2.2", + "ts-mocha": "7.0.0", + "ts-node": "8.10.2", "typescript": "3.6.4", - "webpack": "^4.35.2", - "webpack-cli": "^3.3.9", - "webpack-merge": "^4.2.2" + "webpack": "4.43.0", + "webpack-cli": "3.3.11", + "webpack-merge": "4.2.2" }, "dependencies": { "@opentelemetry/api": "^0.8.3", From a2d1964b16018837c009f6f75351a41a00a66650 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Wed, 17 Jun 2020 14:11:24 -0400 Subject: [PATCH 19/22] feat: add node-plugins-all package (#1181) --- metapackages/plugins-node-all/README.md | 51 ++++++++++++++++++++++ metapackages/plugins-node-all/package.json | 28 ++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 metapackages/plugins-node-all/README.md create mode 100644 metapackages/plugins-node-all/package.json diff --git a/metapackages/plugins-node-all/README.md b/metapackages/plugins-node-all/README.md new file mode 100644 index 0000000000..3b63827b5b --- /dev/null +++ b/metapackages/plugins-node-all/README.md @@ -0,0 +1,51 @@ +# OpenTelemetry Plugins Node Core +[![Gitter chat][gitter-image]][gitter-url] +[![NPM Published Version][npm-img]][npm-url] +[![dependencies][dependencies-image]][dependencies-url] +[![Apache License][license-image]][license-image] + +This package depends on all node plugins maintained by OpenTelemetry authors. +Installing it will also install all plugins. + +## Plugins + +In addition to all [node core plugins][otel-plugins-node-core], the following plugins will be installed by this package: + +- [@opentelemetry/plugin-express][otel-plugin-express] +- [@opentelemetry/plugin-ioredis][otel-plugin-ioredis] +- [@opentelemetry/plugin-mongodb][otel-plugin-mongodb] +- [@opentelemetry/plugin-mysql][otel-plugin-mysql] +- [@opentelemetry/plugin-pg-pool][otel-plugin-pg-pool] +- [@opentelemetry/plugin-pg][otel-plugin-pg] +- [@opentelemetry/plugin-redis][otel-plugin-redis] + +Note: [@opentelemetry/plugin-dns][otel-plugin-dns] is excluded by default because it requires some manual configuration to prevent infinite loops with exporters. + +## Useful links +- For more information on OpenTelemetry, visit: +- For more about OpenTelemetry JavaScript: +- For help or feedback on this project, join us on [gitter][gitter-url] + +## License + +Apache 2.0 - See [LICENSE][license-url] for more information. + +[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg +[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge +[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE +[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat +[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=metapackages/plugins-node-core +[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetryplugins-node-core +[npm-url]: https://www.npmjs.com/package/@opentelemetry/plugins-node-core +[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fplugins-node-core.svg + +[otel-plugins-node-core]: https://www.npmjs.com/package/@opentelemetry/plugins-node-core + +[otel-plugin-dns]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-dns +[otel-plugin-express]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-express +[otel-plugin-ioredis]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-ioredis +[otel-plugin-mongodb]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-mongodb +[otel-plugin-mysql]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-mysql +[otel-plugin-pg-pool]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-pg-pool +[otel-plugin-pg]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-pg +[otel-plugin-redis]: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/master/plugins/node/opentelemetry-plugin-redis diff --git a/metapackages/plugins-node-all/package.json b/metapackages/plugins-node-all/package.json new file mode 100644 index 0000000000..e1377a972c --- /dev/null +++ b/metapackages/plugins-node-all/package.json @@ -0,0 +1,28 @@ +{ + "name": "@opentelemetry/plugins-node-all", + "version": "0.8.3", + "description": "Metapackage which bundles opentelemetry node core and contrib plugins", + "author": "OpenTelemetry Authors", + "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", + "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/open-telemetry/opentelemetry-js.git" + }, + "bugs": { + "url": "https://github.com/open-telemetry/opentelemetry-js/issues" + }, + "dependencies": { + "@opentelemetry/plugins-node-core": "^0.8.3", + "@opentelemetry/plugin-express": "^0.8.0", + "@opentelemetry/plugin-ioredis": "^0.8.0", + "@opentelemetry/plugin-mongodb": "^0.8.0", + "@opentelemetry/plugin-mysql": "^0.8.0", + "@opentelemetry/plugin-pg-pool": "^0.8.0", + "@opentelemetry/plugin-pg": "^0.8.0", + "@opentelemetry/plugin-redis": "^0.8.0" + } +} From 7afc4548c51e11b73f07d15c0d131be289f5ea1c Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Thu, 18 Jun 2020 07:21:12 +0200 Subject: [PATCH 20/22] fix(deps): pin dependencies (#1212) --- metapackages/plugins-node-all/package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/metapackages/plugins-node-all/package.json b/metapackages/plugins-node-all/package.json index e1377a972c..427c3f88ab 100644 --- a/metapackages/plugins-node-all/package.json +++ b/metapackages/plugins-node-all/package.json @@ -17,12 +17,12 @@ }, "dependencies": { "@opentelemetry/plugins-node-core": "^0.8.3", - "@opentelemetry/plugin-express": "^0.8.0", - "@opentelemetry/plugin-ioredis": "^0.8.0", - "@opentelemetry/plugin-mongodb": "^0.8.0", - "@opentelemetry/plugin-mysql": "^0.8.0", - "@opentelemetry/plugin-pg-pool": "^0.8.0", - "@opentelemetry/plugin-pg": "^0.8.0", - "@opentelemetry/plugin-redis": "^0.8.0" + "@opentelemetry/plugin-express": "0.8.0", + "@opentelemetry/plugin-ioredis": "0.8.0", + "@opentelemetry/plugin-mongodb": "0.8.0", + "@opentelemetry/plugin-mysql": "0.8.0", + "@opentelemetry/plugin-pg-pool": "0.8.0", + "@opentelemetry/plugin-pg": "0.8.0", + "@opentelemetry/plugin-redis": "0.8.0" } } From 28ad2ceea1e365ed5d9713376ecf8fe31b65fa07 Mon Sep 17 00:00:00 2001 From: Matthew Wear Date: Wed, 17 Jun 2020 23:15:00 -0700 Subject: [PATCH 21/22] feat: collector exporter custom headers and metadata (#1204) Co-authored-by: Mayur Kale --- .../README.md | 30 +++++- .../src/platform/browser/CollectorExporter.ts | 35 +++++-- .../src/platform/node/CollectorExporter.ts | 4 + .../src/platform/node/types.ts | 6 +- .../test/browser/CollectorExporter.test.ts | 96 +++++++++++++++++-- .../test/helper.ts | 24 +++++ .../test/node/CollectorExporter.test.ts | 20 +++- 7 files changed, 194 insertions(+), 21 deletions(-) diff --git a/packages/opentelemetry-exporter-collector/README.md b/packages/opentelemetry-exporter-collector/README.md index d31f7a7370..63fa55d13b 100644 --- a/packages/opentelemetry-exporter-collector/README.md +++ b/packages/opentelemetry-exporter-collector/README.md @@ -15,15 +15,16 @@ npm install --save @opentelemetry/exporter-collector ``` ## Usage in Web -The CollectorExporter in Web expects the endpoint to end in `/v1/trace`. +The CollectorExporter in Web expects the endpoint to end in `/v1/trace`. ```js import { SimpleSpanProcessor } from '@opentelemetry/tracing'; import { WebTracerProvider } from '@opentelemetry/web'; -import { CollectorExporter } from '@opentelemetry/exporter-collector' +import { CollectorExporter } from '@opentelemetry/exporter-collector'; const collectorOptions = { - url: '' // url is optional and can be omitted - default is http://localhost:55678/v1/trace + url: '', // url is optional and can be omitted - default is http://localhost:55678/v1/trace + headers: {}, //an optional object containing custom headers to be sent with each request }; const provider = new WebTracerProvider(); @@ -81,6 +82,29 @@ provider.register(); To see how to generate credentials, you can refer to the script used to generate certificates for tests [here](./test/certs/regenerate.sh) +The exporter can be configured to send custom metadata with each request as in the example below: + +```js +const grpc = require('grpc'); +const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tracing'); +const { CollectorExporter } = require('@opentelemetry/exporter-collector'); + +const metadata = new grpc.Metadata(); +metadata.set('k', 'v'); + +const collectorOptions = { + serviceName: 'basic-service', + url: '', // url is optional and can be omitted - default is localhost:55678 + metadata, // // an optional grpc.Metadata object to be sent with each request +}; + +const provider = new BasicTracerProvider(); +const exporter = new CollectorExporter(collectorOptions); +provider.addSpanProcessor(new SimpleSpanProcessor(exporter)); + +provider.register(); +``` + Note, that this will only work if TLS is also configured on the server. ## Running opentelemetry-collector locally to see the traces diff --git a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts index b6607258e1..5e7f121ac6 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorExporter.ts @@ -22,7 +22,12 @@ import { ReadableSpan } from '@opentelemetry/tracing'; import { toCollectorExportTraceServiceRequest } from '../../transform'; import * as collectorTypes from '../../types'; -export type CollectorExporterConfig = CollectorExporterConfigBase; +/** + * Collector Exporter Config for Web + */ +export interface CollectorExporterConfig extends CollectorExporterConfigBase { + headers?: { [key: string]: string }; +} const DEFAULT_COLLECTOR_URL = 'http://localhost:55678/v1/trace'; @@ -32,6 +37,22 @@ const DEFAULT_COLLECTOR_URL = 'http://localhost:55678/v1/trace'; export class CollectorExporter extends CollectorExporterBase< CollectorExporterConfig > { + DEFAULT_HEADERS: { [key: string]: string } = { + [collectorTypes.OT_REQUEST_HEADER]: '1', + }; + private _headers: { [key: string]: string }; + private _useXHR: boolean = false; + + /** + * @param config + */ + constructor(config: CollectorExporterConfig = {}) { + super(config); + this._headers = config.headers || this.DEFAULT_HEADERS; + this._useXHR = + !!config.headers || typeof navigator.sendBeacon !== 'function'; + } + onInit(): void { window.addEventListener('unload', this.shutdown); } @@ -53,13 +74,12 @@ export class CollectorExporter extends CollectorExporterBase< spans, this ); - const body = JSON.stringify(exportTraceServiceRequest); - if (typeof navigator.sendBeacon === 'function') { - this._sendSpansWithBeacon(body, onSuccess, onError); - } else { + if (this._useXHR) { this._sendSpansWithXhr(body, onSuccess, onError); + } else { + this._sendSpansWithBeacon(body, onSuccess, onError); } } @@ -97,9 +117,12 @@ export class CollectorExporter extends CollectorExporterBase< ) { const xhr = new XMLHttpRequest(); xhr.open('POST', this.url); - xhr.setRequestHeader(collectorTypes.OT_REQUEST_HEADER, '1'); xhr.setRequestHeader('Accept', 'application/json'); xhr.setRequestHeader('Content-Type', 'application/json'); + Object.entries(this._headers).forEach(([k, v]) => { + xhr.setRequestHeader(k, v); + }); + xhr.send(body); xhr.onreadystatechange = () => { diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts index 65968be05b..e5c767ecf3 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorExporter.ts @@ -36,6 +36,7 @@ const DEFAULT_COLLECTOR_URL = 'localhost:55678'; */ export interface CollectorExporterConfig extends CollectorExporterConfigBase { credentials?: grpc.ChannelCredentials; + metadata?: grpc.Metadata; } /** @@ -47,12 +48,14 @@ export class CollectorExporter extends CollectorExporterBase< isShutDown: boolean = false; traceServiceClient?: TraceServiceClient = undefined; grpcSpansQueue: GRPCQueueItem[] = []; + metadata?: grpc.Metadata; /** * @param config */ constructor(config: CollectorExporterConfig = {}) { super(config); + this.metadata = config.metadata; } onShutdown(): void { @@ -115,6 +118,7 @@ export class CollectorExporter extends CollectorExporterBase< this.traceServiceClient.export( exportTraceServiceRequest, + this.metadata, ( err: collectorTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceError ) => { diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/types.ts b/packages/opentelemetry-exporter-collector/src/platform/node/types.ts index cdb4da9f07..4674fadf90 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/types.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/types.ts @@ -32,5 +32,9 @@ export interface GRPCQueueItem { * Trace Service Client for sending spans */ export interface TraceServiceClient extends grpc.Client { - export: (request: any, callback: Function) => {}; + export: ( + request: any, + metadata: grpc.Metadata | undefined, + callback: Function + ) => {}; } diff --git a/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts index d282cc1828..265bf44136 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/CollectorExporter.test.ts @@ -28,6 +28,7 @@ import { ensureSpanIsCorrect, ensureExportTraceServiceRequestIsSet, ensureWebResourceIsCorrect, + ensureHeadersContain, mockedReadableSpan, } from '../helper'; const sendBeacon = navigator.sendBeacon; @@ -44,14 +45,6 @@ describe('CollectorExporter - web', () => { spyOpen = sinon.stub(XMLHttpRequest.prototype, 'open'); spySend = sinon.stub(XMLHttpRequest.prototype, 'send'); spyBeacon = sinon.stub(navigator, 'sendBeacon'); - collectorExporterConfig = { - hostName: 'foo', - logger: new NoopLogger(), - serviceName: 'bar', - attributes: {}, - url: 'http://foo.bar.com', - }; - collectorExporter = new CollectorExporter(collectorExporterConfig); spans = []; spans.push(Object.assign({}, mockedReadableSpan)); }); @@ -64,7 +57,21 @@ describe('CollectorExporter - web', () => { }); describe('export', () => { + beforeEach(() => { + collectorExporterConfig = { + hostName: 'foo', + logger: new NoopLogger(), + serviceName: 'bar', + attributes: {}, + url: 'http://foo.bar.com', + }; + }); + describe('when "sendBeacon" is available', () => { + beforeEach(() => { + collectorExporter = new CollectorExporter(collectorExporterConfig); + }); + it('should successfully send the spans using sendBeacon', done => { collectorExporter.export(spans, () => {}); @@ -139,6 +146,7 @@ describe('CollectorExporter - web', () => { let server: any; beforeEach(() => { (window.navigator as any).sendBeacon = false; + collectorExporter = new CollectorExporter(collectorExporterConfig); server = sinon.fakeServer.create(); }); afterEach(() => { @@ -216,6 +224,78 @@ describe('CollectorExporter - web', () => { done(); }); }); + + it('should send custom headers', done => { + collectorExporter.export(spans, () => {}); + + setTimeout(() => { + const request = server.requests[0]; + request.respond(200); + + assert.strictEqual(spyBeacon.callCount, 0); + done(); + }); + }); + }); + }); + + describe('export with custom headers', () => { + let server: any; + const customHeaders = { + foo: 'bar', + bar: 'baz', + }; + + beforeEach(() => { + collectorExporterConfig = { + logger: new NoopLogger(), + headers: customHeaders, + }; + server = sinon.fakeServer.create(); + }); + + afterEach(() => { + server.restore(); + }); + + describe('when "sendBeacon" is available', () => { + beforeEach(() => { + collectorExporter = new CollectorExporter(collectorExporterConfig); + }); + it('should successfully send custom headers using XMLHTTPRequest', done => { + collectorExporter.export(spans, () => {}); + + setTimeout(() => { + const [{ requestHeaders }] = server.requests; + + ensureHeadersContain(requestHeaders, customHeaders); + assert.strictEqual(spyBeacon.callCount, 0); + assert.strictEqual(spyOpen.callCount, 0); + + done(); + }); + }); + }); + + describe('when "sendBeacon" is NOT available', () => { + beforeEach(() => { + (window.navigator as any).sendBeacon = false; + collectorExporter = new CollectorExporter(collectorExporterConfig); + }); + + it('should successfully send spans using XMLHttpRequest', done => { + collectorExporter.export(spans, () => {}); + + setTimeout(() => { + const [{ requestHeaders }] = server.requests; + + ensureHeadersContain(requestHeaders, customHeaders); + assert.strictEqual(spyBeacon.callCount, 0); + assert.strictEqual(spyOpen.callCount, 0); + + done(); + }); + }); }); }); }); diff --git a/packages/opentelemetry-exporter-collector/test/helper.ts b/packages/opentelemetry-exporter-collector/test/helper.ts index 86ac2fc688..4737c66b96 100644 --- a/packages/opentelemetry-exporter-collector/test/helper.ts +++ b/packages/opentelemetry-exporter-collector/test/helper.ts @@ -20,6 +20,7 @@ import { Resource } from '@opentelemetry/resources'; import * as assert from 'assert'; import { opentelemetryProto } from '../src/types'; import * as collectorTypes from '../src/types'; +import * as grpc from 'grpc'; if (typeof Buffer === 'undefined') { (window as any).Buffer = { @@ -509,3 +510,26 @@ export function ensureExportTraceServiceRequestIsSet( const spans = instrumentationLibrarySpans[0].spans; assert.strictEqual(spans && spans.length, 1, 'spans are missing'); } + +export function ensureMetadataIsCorrect( + actual: grpc.Metadata, + expected: grpc.Metadata +) { + //ignore user agent + expected.remove('user-agent'); + actual.remove('user-agent'); + assert.deepStrictEqual(actual.getMap(), expected.getMap()); +} + +export function ensureHeadersContain( + actual: { [key: string]: string }, + expected: { [key: string]: string } +) { + Object.entries(expected).forEach(([k, v]) => { + assert.strictEqual( + v, + actual[k], + `Expected ${actual} to contain ${k}: ${v}` + ); + }); +} diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts index 2aa2b881fa..13da3284a2 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorExporter.test.ts @@ -31,6 +31,7 @@ import * as collectorTypes from '../../src/types'; import { ensureResourceIsCorrect, ensureExportedSpanIsCorrect, + ensureMetadataIsCorrect, mockedReadableSpan, } from '../helper'; @@ -41,18 +42,23 @@ const includeDirs = [path.resolve(__dirname, '../../src/platform/node/protos')]; const address = 'localhost:1501'; type TestParams = { - useTLS: boolean; + useTLS?: boolean; + metadata?: grpc.Metadata; }; +const metadata = new grpc.Metadata(); +metadata.set('k', 'v'); + const testCollectorExporter = (params: TestParams) => describe(`CollectorExporter - node ${ - params.useTLS ? 'with TLS' : '' - }`, () => { + params.useTLS ? 'with' : 'without' + } TLS, ${params.metadata ? 'with' : 'without'} metadata`, () => { let collectorExporter: CollectorExporter; let server: grpc.Server; let exportedData: | collectorTypes.opentelemetryProto.trace.v1.ResourceSpans | undefined; + let reqMetadata: grpc.Metadata | undefined; before(done => { server = new grpc.Server(); @@ -75,9 +81,11 @@ const testCollectorExporter = (params: TestParams) => { Export: (data: { request: collectorTypes.opentelemetryProto.collector.trace.v1.ExportTraceServiceRequest; + metadata: grpc.Metadata; }) => { try { exportedData = data.request.resourceSpans[0]; + reqMetadata = data.metadata; } catch (e) { exportedData = undefined; } @@ -117,6 +125,7 @@ const testCollectorExporter = (params: TestParams) => serviceName: 'basic-service', url: address, credentials, + metadata: params.metadata, }); const provider = new BasicTracerProvider(); @@ -126,6 +135,7 @@ const testCollectorExporter = (params: TestParams) => afterEach(() => { exportedData = undefined; + reqMetadata = undefined; }); describe('export', () => { @@ -153,6 +163,9 @@ const testCollectorExporter = (params: TestParams) => ensureResourceIsCorrect(resource); } } + if (params.metadata && reqMetadata) { + ensureMetadataIsCorrect(reqMetadata, params.metadata); + } done(); }, 200); }); @@ -179,3 +192,4 @@ describe('CollectorExporter - node (getDefaultUrl)', () => { testCollectorExporter({ useTLS: true }); testCollectorExporter({ useTLS: false }); +testCollectorExporter({ metadata }); From 2486c3dbf18aca6b57ca6591de5f2d9b575da0b8 Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Thu, 18 Jun 2020 20:00:45 +0200 Subject: [PATCH 22/22] chore: fixing zone from which to fork a new zone (#1209) * chore: fixing zone from which to fork a new zone * chore: adding tests for creating zone Co-authored-by: Mayur Kale --- .../src/ZoneContextManager.ts | 2 +- .../test/ZoneContextManager.test.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts b/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts index 16c159dbc6..93ce9e1c6c 100644 --- a/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts +++ b/packages/opentelemetry-context-zone-peer-dep/src/ZoneContextManager.ts @@ -113,7 +113,7 @@ export class ZoneContextManager implements ContextManager { * @param context A context (span) to be bind with Zone */ private _createZone(zoneName: string, context: unknown): Zone { - return Zone.root.fork({ + return Zone.current.fork({ name: zoneName, properties: { [ZONE_CONTEXT_KEY]: context, diff --git a/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts b/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts index 9712a7bf1c..905348005c 100644 --- a/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts +++ b/packages/opentelemetry-context-zone-peer-dep/test/ZoneContextManager.test.ts @@ -199,6 +199,23 @@ describe('ZoneContextManager', () => { }); }); }); + + it('should fork new zone from active one', () => { + const context = Context.ROOT_CONTEXT; + const rootZone = Zone.current; + contextManager.with(context, () => { + const zone1 = Zone.current; + assert.ok(zone1.parent === rootZone); + contextManager.with(context, () => { + const zone2 = Zone.current; + contextManager.with(context, () => { + const zone3 = Zone.current; + assert.ok(zone3.parent === zone2); + }); + assert.ok(zone2.parent === zone1); + }); + }); + }); }); describe('.bind(function)', () => {

ej| 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�n_RtpP6AR~H|PxRDY^ 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 literal 0 HcmV?d00001 diff --git a/packages/opentelemetry-plugin-fetch/images/trace2.png b/packages/opentelemetry-plugin-fetch/images/trace2.png new file mode 100644 index 0000000000000000000000000000000000000000..0f9130ce8a5b21416a746bbf7daf670632275989 GIT binary patch literal 130296 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