From 2da67548ceeb0bc94b927765338cf505de149a1f Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Tue, 15 Feb 2022 19:07:49 +0100 Subject: [PATCH 1/5] chore(deps): update dependency chromedriver to v98 (#2780) --- selenium-tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selenium-tests/package.json b/selenium-tests/package.json index f4efd169591..6a0bc718c61 100644 --- a/selenium-tests/package.json +++ b/selenium-tests/package.json @@ -40,7 +40,7 @@ "babel-loader": "8.2.3", "babel-polyfill": "6.26.0", "browserstack-local": "1.4.8", - "chromedriver": "97.0.4", + "chromedriver": "98.0.0", "dotenv": "16.0.0", "fast-safe-stringify": "2.1.1", "geckodriver": "2.0.4", From eb19f3dc5c42c7902d77fe57147b73718926dbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerhard=20St=C3=B6bich?= Date: Thu, 17 Feb 2022 17:30:12 +0100 Subject: [PATCH 2/5] fix: pass same context to Sampler and SpanProcessor in root span case (#2790) --- .../src/Tracer.ts | 34 ++++------ .../test/common/Tracer.test.ts | 62 ++++++++++++++++++- 2 files changed, 72 insertions(+), 24 deletions(-) diff --git a/packages/opentelemetry-sdk-trace-base/src/Tracer.ts b/packages/opentelemetry-sdk-trace-base/src/Tracer.ts index 9960243cba2..5d85373a461 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Tracer.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Tracer.ts @@ -71,19 +71,24 @@ export class Tracer implements api.Tracer { return api.trace.wrapSpanContext(api.INVALID_SPAN_CONTEXT); } - const parentContext = getParent(options, context); + // remove span from context in case a root span is requested via options + if (options.root) { + context = api.trace.deleteSpan(context); + } + + const parentSpanContext = api.trace.getSpanContext(context); const spanId = this._idGenerator.generateSpanId(); let traceId; let traceState; let parentSpanId; - if (!parentContext || !api.trace.isSpanContextValid(parentContext)) { + if (!parentSpanContext || !api.trace.isSpanContextValid(parentSpanContext)) { // New root span. traceId = this._idGenerator.generateTraceId(); } else { // New child span. - traceId = parentContext.traceId; - traceState = parentContext.traceState; - parentSpanId = parentContext.spanId; + traceId = parentSpanContext.traceId; + traceState = parentSpanContext.traceState; + parentSpanId = parentSpanContext.spanId; } const spanKind = options.kind ?? api.SpanKind.INTERNAL; @@ -91,9 +96,7 @@ export class Tracer implements api.Tracer { const attributes = sanitizeAttributes(options.attributes); // make sampling decision const samplingResult = this._sampler.shouldSample( - options.root - ? api.trace.setSpanContext(context, api.INVALID_SPAN_CONTEXT) - : context, + context, traceId, name, spanKind, @@ -228,18 +231,3 @@ export class Tracer implements api.Tracer { return this._tracerProvider.getActiveSpanProcessor(); } } - -/** - * Get the parent to assign to a started span. If options.parent is null, - * do not assign a parent. - * - * @param options span options - * @param context context to check for parent - */ -function getParent( - options: api.SpanOptions, - context: api.Context -): api.SpanContext | undefined { - if (options.root) return undefined; - return api.trace.getSpanContext(context); -} diff --git a/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts b/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts index 893f5219c66..2962d8d7e6e 100644 --- a/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts +++ b/packages/opentelemetry-sdk-trace-base/test/common/Tracer.test.ts @@ -21,6 +21,7 @@ import { Sampler, SamplingDecision, SpanContext, + SpanKind, trace, TraceFlags } from '@opentelemetry/api'; @@ -32,7 +33,7 @@ import { suppressTracing } from '@opentelemetry/core'; import * as assert from 'assert'; -import { BasicTracerProvider, Span, Tracer } from '../../src'; +import { BasicTracerProvider, Span, SpanProcessor, Tracer } from '../../src'; import { TestStackContextManager } from './export/TestStackContextManager'; import * as sinon from 'sinon'; @@ -53,6 +54,17 @@ describe('Tracer', () => { } } + class DummySpanProcessor implements SpanProcessor { + forceFlush () { + return Promise.resolve(); + } + onStart() {} + onEnd() {} + shutdown() { + return Promise.resolve(); + } + } + beforeEach(() => { const contextManager = new TestStackContextManager().enable(); context.setGlobalContextManager(contextManager); @@ -189,6 +201,54 @@ describe('Tracer', () => { assert.strictEqual((span as Span).parentSpanId, undefined); }); + it('should pass the same context to sampler and spanprocessor', () => { + const parent: SpanContext = { + traceId: '00112233445566778899001122334455', + spanId: '0011223344556677', + traceFlags: TraceFlags.SAMPLED, + }; + const context = trace.setSpanContext(ROOT_CONTEXT, parent); + + const sp: SpanProcessor = new DummySpanProcessor(); + const onStartSpy = sinon.spy(sp, 'onStart'); + const tp = new BasicTracerProvider(); + tp.addSpanProcessor(sp); + + const sampler: Sampler = new AlwaysOnSampler(); + const shouldSampleSpy = sinon.spy(sampler, 'shouldSample'); + const tracer = new Tracer({ name: 'default' }, { sampler }, tp); + const span = tracer.startSpan('a', {}, context) as Span; + assert.strictEqual(span.parentSpanId, parent.spanId); + sinon.assert.calledOnceWithExactly(shouldSampleSpy, context, parent.traceId, 'a', SpanKind.INTERNAL, {}, []); + sinon.assert.calledOnceWithExactly(onStartSpy, span, context); + }); + + it('should pass the same context to sampler and spanprocessor if options.root is true', () => { + const parent: SpanContext = { + traceId: '00112233445566778899001122334455', + spanId: '0011223344556677', + traceFlags: TraceFlags.SAMPLED, + }; + const context = trace.setSpanContext(ROOT_CONTEXT, parent); + + const sp: SpanProcessor = new DummySpanProcessor(); + const onStartSpy = sinon.spy(sp, 'onStart'); + const tp = new BasicTracerProvider(); + tp.addSpanProcessor(sp); + + const sampler: Sampler = new AlwaysOnSampler(); + const shouldSampleSpy = sinon.spy(sampler, 'shouldSample'); + const tracer = new Tracer({ name: 'default' }, { sampler }, tp); + const span = tracer.startSpan('a', { root: true }, context) as Span; + assert.strictEqual(span.parentSpanId, undefined); + sinon.assert.calledOnce(shouldSampleSpy); + sinon.assert.calledOnce(onStartSpy); + const samplerContext = shouldSampleSpy.firstCall.args[0]; + const processorContext = onStartSpy.firstCall.args[1]; + assert.strictEqual(samplerContext, processorContext); + assert.strictEqual(getSpan(samplerContext), undefined); + }); + it('should sample a trace when OTEL_TRACES_SAMPLER_ARG is unset', () => { envSource.OTEL_TRACES_SAMPLER = 'traceidratio'; envSource.OTEL_TRACES_SAMPLER_ARG = ''; From b756b7c36dfb8a3735130a1e02b57084b06a52ae Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 18 Feb 2022 17:30:11 +0100 Subject: [PATCH 3/5] chore(deps): update dependency linkinator to v3 (#2794) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index daf2842f00e..bc184dd967f 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "husky": "4.3.8", "lerna": "3.22.1", "lerna-changelog": "1.0.1", - "linkinator": "2.16.2", + "linkinator": "3.0.3", "markdownlint-cli": "0.29.0", "semver": "7.3.5", "typedoc": "0.22.10", From 630a26182a517788060365b40d37605f0b356282 Mon Sep 17 00:00:00 2001 From: Srikanth Chekuri Date: Tue, 22 Feb 2022 19:16:56 +0530 Subject: [PATCH 4/5] feat(sdk-metrics-base): update metric exporter interfaces (#2707) Co-authored-by: legendecas --- .../src/export/MetricExporter.ts | 44 +++++++++---------- .../export/PeriodicExportingMetricReader.ts | 24 +++++++--- .../PeriodicExportingMetricReader.test.ts | 42 ++++++++++++++++-- .../test/state/MetricCollector.test.ts | 13 ++++-- 4 files changed, 87 insertions(+), 36 deletions(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts index 697f020b285..f86f7d84cde 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/MetricExporter.ts @@ -16,40 +16,34 @@ import { AggregationTemporality } from './AggregationTemporality'; import { MetricData } from './MetricData'; +import { + ExportResult, + ExportResultCode, +} from '@opentelemetry/core'; // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/metrics/sdk.md#metricexporter -// TODO should this just be an interface and exporters can implement their own shutdown? -export abstract class MetricExporter { - protected _shutdown = false; +export interface PushMetricExporter { - abstract export(batch: MetricData[]): Promise; + export(batch: MetricData[], resultCallback: (result: ExportResult) => void): void; - abstract forceFlush(): Promise; + forceFlush(): Promise; - abstract getPreferredAggregationTemporality(): AggregationTemporality; + getPreferredAggregationTemporality(): AggregationTemporality; - async shutdown(): Promise { - if (this._shutdown) { - return; - } + shutdown(): Promise; - // Setting _shutdown before flushing might prevent some exporters from flushing - // Waiting until flushing is complete might allow another flush to occur during shutdown - const flushPromise = this.forceFlush(); - this._shutdown = true; - await flushPromise; - } - - isShutdown() { - return this._shutdown; - } } -export class ConsoleMetricExporter extends MetricExporter { - async export(_batch: MetricData[]) { - throw new Error('Method not implemented'); +export class ConsoleMetricExporter implements PushMetricExporter { + protected _shutdown = true; + + export(_batch: MetricData[], resultCallback: (result: ExportResult) => void) { + return resultCallback({ + code: ExportResultCode.FAILED, + error: new Error('Method not implemented') + }); } getPreferredAggregationTemporality() { @@ -58,4 +52,8 @@ export class ConsoleMetricExporter extends MetricExporter { // nothing to do async forceFlush() {} + + async shutdown() { + this._shutdown = true; + } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts index 0e5861941af..f5595a743da 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/PeriodicExportingMetricReader.ts @@ -15,12 +15,13 @@ */ import * as api from '@opentelemetry/api'; +import { ExportResultCode, globalErrorHandler } from '@opentelemetry/core'; import { MetricReader } from './MetricReader'; -import { MetricExporter } from './MetricExporter'; +import { PushMetricExporter } from './MetricExporter'; import { callWithTimeout, TimeoutError } from '../utils'; export type PeriodicExportingMetricReaderOptions = { - exporter: MetricExporter + exporter: PushMetricExporter exportIntervalMillis?: number, exportTimeoutMillis?: number }; @@ -32,7 +33,7 @@ export type PeriodicExportingMetricReaderOptions = { export class PeriodicExportingMetricReader extends MetricReader { private _interval?: ReturnType; - private _exporter: MetricExporter; + private _exporter: PushMetricExporter; private readonly _exportInterval: number; @@ -62,7 +63,20 @@ export class PeriodicExportingMetricReader extends MetricReader { private async _runOnce(): Promise { const metrics = await this.collect({}); - await this._exporter.export(metrics); + return new Promise((resolve, reject) => { + this._exporter.export(metrics, result => { + if (result.code !== ExportResultCode.SUCCESS) { + reject( + result.error ?? + new Error( + `PeriodicExportingMetricReader: metrics export failed (error ${result.error})` + ) + ); + } else { + resolve(); + } + }); + }); } protected override onInitialized(): void { @@ -76,7 +90,7 @@ export class PeriodicExportingMetricReader extends MetricReader { return; } - api.diag.error('Unexpected error during export: %s', err); + globalErrorHandler(err); } }, this._exportInterval); } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts index 4950f1cadc9..586dd379b75 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/export/PeriodicExportingMetricReader.test.ts @@ -16,29 +16,45 @@ import { PeriodicExportingMetricReader } from '../../src/export/PeriodicExportingMetricReader'; import { AggregationTemporality } from '../../src/export/AggregationTemporality'; -import { MetricExporter } from '../../src'; +import { PushMetricExporter } from '../../src'; import { MetricData } from '../../src/export/MetricData'; import * as assert from 'assert'; import * as sinon from 'sinon'; import { MetricProducer } from '../../src/export/MetricProducer'; import { TimeoutError } from '../../src/utils'; +import { ExportResult, ExportResultCode } from '@opentelemetry/core'; import { assertRejects } from '../test-utils'; const MAX_32_BIT_INT = 2 ** 31 - 1; -class TestMetricExporter extends MetricExporter { +class TestMetricExporter implements PushMetricExporter { public exportTime = 0; public forceFlushTime = 0; public throwException = false; + public failureResult = false; private _batches: MetricData[][] = []; + private _shutdown: boolean = false; - async export(batch: MetricData[]): Promise { + export(batch: MetricData[], resultCallback: (result: ExportResult) => void): void { this._batches.push(batch); if (this.throwException) { throw new Error('Error during export'); } - await new Promise(resolve => setTimeout(resolve, this.exportTime)); + setTimeout(() => { + if (this.failureResult) { + resultCallback({code: ExportResultCode.FAILED, error: new Error('some error') }); + } else { + resultCallback({code: ExportResultCode.SUCCESS }); + } + }, this.exportTime); + } + + async shutdown(): Promise { + if (this._shutdown) return; + const flushPromise = this.forceFlush(); + this._shutdown = true; + await flushPromise; } async forceFlush(): Promise { @@ -176,6 +192,24 @@ describe('PeriodicExportingMetricReader', () => { await reader.shutdown(); }); + it('should keep running on export failure', async () => { + const exporter = new TestMetricExporter(); + exporter.failureResult = true; + const reader = new PeriodicExportingMetricReader({ + exporter: exporter, + exportIntervalMillis: 30, + exportTimeoutMillis: 20 + }); + + reader.setMetricProducer(new TestMetricProducer()); + + const result = await exporter.waitForNumberOfExports(2); + assert.deepStrictEqual(result, [[], []]); + + exporter.failureResult = false; + await reader.shutdown(); + }); + it('should keep exporting on export timeouts', async () => { const exporter = new TestMetricExporter(); // set time longer than timeout. diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts index ea263bdd25a..122bdfd881c 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/state/MetricCollector.test.ts @@ -19,18 +19,22 @@ import * as sinon from 'sinon'; import { MeterProvider } from '../../src'; import { AggregationTemporality } from '../../src/export/AggregationTemporality'; import { MetricData, PointDataType } from '../../src/export/MetricData'; -import { MetricExporter } from '../../src/export/MetricExporter'; +import { PushMetricExporter } from '../../src/export/MetricExporter'; import { MeterProviderSharedState } from '../../src/state/MeterProviderSharedState'; import { MetricCollector } from '../../src/state/MetricCollector'; import { defaultInstrumentationLibrary, defaultResource, assertMetricData, assertPointData } from '../util'; import { TestMetricReader } from '../export/TestMetricReader'; +import { ExportResult, ExportResultCode } from '@opentelemetry/core'; -class TestMetricExporter extends MetricExporter { +class TestMetricExporter implements PushMetricExporter { metricDataList: MetricData[] = []; - async export(batch: MetricData[]): Promise { + async export(batch: MetricData[], resultCallback: (result: ExportResult) => void): Promise { this.metricDataList.push(...batch); + resultCallback({code: ExportResultCode.SUCCESS}); } + async shutdown(): Promise {} + async forceFlush(): Promise {} getPreferredAggregationTemporality(): AggregationTemporality { @@ -63,7 +67,8 @@ describe('MetricCollector', () => { }); describe('collect', () => { - function setupInstruments(exporter: MetricExporter) { + + function setupInstruments(exporter: PushMetricExporter) { const meterProvider = new MeterProvider({ resource: defaultResource }); const reader = new TestMetricReader(exporter.getPreferredAggregationTemporality()); From 144e11ab704f90a15e76c22df13a8ee927a3bc61 Mon Sep 17 00:00:00 2001 From: naseemkullah <24660299+naseemkullah@users.noreply.github.com> Date: Tue, 22 Feb 2022 14:51:54 -0500 Subject: [PATCH 5/5] docs(prom-example): remove deprecated startServer option (#2802) Co-authored-by: Valentin Marchaud --- examples/prometheus/index.js | 17 +++++++-------- .../examples/metrics/metrics/observer.js | 21 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/examples/prometheus/index.js b/examples/prometheus/index.js index ea3f2e6882e..8f638d66a1c 100644 --- a/examples/prometheus/index.js +++ b/examples/prometheus/index.js @@ -3,16 +3,13 @@ const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); -const exporter = new PrometheusExporter( - { - startServer: true, - }, - () => { - console.log( - `prometheus scrape endpoint: http://localhost:${PrometheusExporter.DEFAULT_OPTIONS.port}${PrometheusExporter.DEFAULT_OPTIONS.endpoint}`, - ); - }, -); +const { endpoint, port } = PrometheusExporter.DEFAULT_OPTIONS; + +const exporter = new PrometheusExporter({}, () => { + console.log( + `prometheus scrape endpoint: http://localhost:${port}${endpoint}`, + ); +}); const meter = new MeterProvider({ exporter, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js index 2f3d3f9a533..87d0e3817ce 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js +++ b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js @@ -7,16 +7,13 @@ const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); // Optional and only needed to see the internal diagnostic logging (during development) diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); -const exporter = new PrometheusExporter( - { - startServer: true, - }, - () => { - console.log( - `prometheus scrape endpoint: http://localhost:${PrometheusExporter.DEFAULT_OPTIONS.port}${PrometheusExporter.DEFAULT_OPTIONS.endpoint}`, - ); - }, -); +const { endpoint, port } = PrometheusExporter.DEFAULT_OPTIONS; + +const exporter = new PrometheusExporter({}, () => { + console.log( + `prometheus scrape endpoint: http://localhost:${port}${endpoint}`, + ); +}); const meter = new MeterProvider({ exporter, @@ -34,12 +31,12 @@ meter.createObservableGauge('cpu_core_usage', { function getAsyncValue() { return new Promise((resolve) => { - setTimeout(()=> { + setTimeout(() => { resolve(Math.random()); }, 100); }); } -setInterval(function(){ +setInterval(function () { console.log("simulating an app being kept open") }, 5000);