diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index f9ead87184..b25c11fb3c 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to experimental packages in this project will be documented ### :rocket: (Enhancement) +* feat(metrics-sdk): Add tracing suppresing for Metrics Export [#3332](https://github.com/open-telemetry/opentelemetry-js/pull/3332) @hectorhdzg * feat(instrumentation): implement `require-in-the-middle` singleton [#3161](https://github.com/open-telemetry/opentelemetry-js/pull/3161) @mhassan1 * feat(sdk-node): configure trace exporter with environment variables [#3143](https://github.com/open-telemetry/opentelemetry-js/pull/3143) @svetlanabrennan * feat: enable tree shaking [#3329](https://github.com/open-telemetry/opentelemetry-js/pull/3329) @pkanal diff --git a/experimental/packages/opentelemetry-sdk-metrics/src/export/PeriodicExportingMetricReader.ts b/experimental/packages/opentelemetry-sdk-metrics/src/export/PeriodicExportingMetricReader.ts index e4f78d1cf0..2a686181cc 100644 --- a/experimental/packages/opentelemetry-sdk-metrics/src/export/PeriodicExportingMetricReader.ts +++ b/experimental/packages/opentelemetry-sdk-metrics/src/export/PeriodicExportingMetricReader.ts @@ -16,6 +16,7 @@ import * as api from '@opentelemetry/api'; import { + internal, ExportResultCode, globalErrorHandler, unrefTimer @@ -85,20 +86,12 @@ export class PeriodicExportingMetricReader extends MetricReader { api.diag.error('PeriodicExportingMetricReader: metrics collection errors', ...errors); } - return new Promise((resolve, reject) => { - this._exporter.export(resourceMetrics, result => { - if (result.code !== ExportResultCode.SUCCESS) { - reject( - result.error ?? - new Error( - `PeriodicExportingMetricReader: metrics export failed (error ${result.error})` - ) - ); - } else { - resolve(); - } - }); - }); + const result = await internal._export(this._exporter, resourceMetrics); + if (result.code !== ExportResultCode.SUCCESS) { + throw new Error( + `PeriodicExportingMetricReader: metrics export failed (error ${result.error})` + ); + } } protected override onInitialized(): void { diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index fd8d3c6778..6c0834fe0f 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -42,3 +42,7 @@ export * from './utils/url'; export * from './utils/wrap'; export * from './utils/callback'; export * from './version'; +import { _export } from './internal/exporter'; +export const internal = { + _export +}; diff --git a/packages/opentelemetry-core/src/internal/exporter.ts b/packages/opentelemetry-core/src/internal/exporter.ts new file mode 100644 index 0000000000..a489b35eac --- /dev/null +++ b/packages/opentelemetry-core/src/internal/exporter.ts @@ -0,0 +1,38 @@ +/* + * Copyright The 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 { context } from '@opentelemetry/api'; +import { ExportResult } from '../ExportResult'; +import { suppressTracing } from '../trace/suppress-tracing'; + +export interface Exporter { + export(arg: T, resultCallback: (result: ExportResult) => void): void; +} + +/** +* @internal +* Shared functionality used by Exporters while exporting data, including suppresion of Traces. +*/ +export function _export(exporter: Exporter, arg: T): Promise { + return new Promise(resolve => { + // prevent downstream exporter calls from generating spans + context.with(suppressTracing(context.active()), () => { + exporter.export(arg, (result: ExportResult) => { + resolve(result); + }); + }); + }); +} diff --git a/packages/opentelemetry-core/test/internal/exporter.test.ts b/packages/opentelemetry-core/test/internal/exporter.test.ts new file mode 100644 index 0000000000..1ca256d659 --- /dev/null +++ b/packages/opentelemetry-core/test/internal/exporter.test.ts @@ -0,0 +1,43 @@ +/* + * Copyright The 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 assert from 'assert'; +import * as sinon from 'sinon'; +import { ExportResult, ExportResultCode } from '../../src'; +import * as suppress from '../../src/trace/suppress-tracing'; +import { _export } from '../../src/internal/exporter'; + +describe('exporter', () => { + const sandbox = sinon.createSandbox(); + + afterEach(() => { + sandbox.restore(); + }); + + class TestExporter { + export(arg: any, resultCallback: (result: ExportResult) => void) { + resultCallback({ code: ExportResultCode.SUCCESS }); + } + } + + it('_export should suppress tracing', async () => { + const suppressSpy = sandbox.spy(suppress, 'suppressTracing'); + const exporter = new TestExporter(); + const result = await _export(exporter, ['Test1']); + assert.strictEqual(result.code, ExportResultCode.SUCCESS); + assert.ok(suppressSpy.calledOnce); + }); +}); diff --git a/packages/opentelemetry-sdk-trace-base/src/export/SimpleSpanProcessor.ts b/packages/opentelemetry-sdk-trace-base/src/export/SimpleSpanProcessor.ts index c775bdf6d4..a510ad02a6 100644 --- a/packages/opentelemetry-sdk-trace-base/src/export/SimpleSpanProcessor.ts +++ b/packages/opentelemetry-sdk-trace-base/src/export/SimpleSpanProcessor.ts @@ -14,12 +14,13 @@ * limitations under the License. */ -import { context, Context, TraceFlags } from '@opentelemetry/api'; +import { Context, TraceFlags } from '@opentelemetry/api'; import { + internal, ExportResultCode, globalErrorHandler, - suppressTracing, BindOnceFuture, + ExportResult } from '@opentelemetry/core'; import { Span } from '../Span'; import { SpanProcessor } from '../SpanProcessor'; @@ -45,7 +46,7 @@ export class SimpleSpanProcessor implements SpanProcessor { } // does nothing. - onStart(_span: Span, _parentContext: Context): void {} + onStart(_span: Span, _parentContext: Context): void { } onEnd(span: ReadableSpan): void { if (this._shutdownOnce.isCalled) { @@ -56,18 +57,17 @@ export class SimpleSpanProcessor implements SpanProcessor { return; } - // prevent downstream exporter calls from generating spans - context.with(suppressTracing(context.active()), () => { - this._exporter.export([span], result => { - if (result.code !== ExportResultCode.SUCCESS) { - globalErrorHandler( - result.error ?? - new Error( - `SimpleSpanProcessor: span export failed (status ${result})` - ) - ); - } - }); + internal._export(this._exporter, [span]).then((result: ExportResult) => { + if (result.code !== ExportResultCode.SUCCESS) { + globalErrorHandler( + result.error ?? + new Error( + `SimpleSpanProcessor: span export failed (status ${result})` + ) + ); + } + }).catch(error => { + globalErrorHandler(error); }); }