From 33935e78aa3a44f3f1ddc1c0227c7a1fc27cc014 Mon Sep 17 00:00:00 2001 From: Mustafain Ali Khan Date: Sat, 25 Sep 2021 08:54:45 -0400 Subject: [PATCH 01/29] fix: remove usage of serviceName property in tests for otel collector (#2491) --- .../test/node/CollectorMetricExporter.test.ts | 1 - .../test/node/CollectorTraceExporter.test.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts index 2fd9e04a360..4937ef37370 100644 --- a/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -72,7 +72,6 @@ describe('OTLPMetricExporter - node with json over http', () => { // Need to stub/spy on the underlying logger as the "diag" instance is global const spyLoggerWarn = sinon.stub(diag, 'warn'); collectorExporter = new OTLPMetricExporter({ - serviceName: 'basic-service', url: address, metadata, } as any); diff --git a/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts index 7ccf6a97f13..8988572b67c 100644 --- a/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts @@ -58,7 +58,6 @@ describe('OTLPTraceExporter - node with json over http', () => { // Need to stub/spy on the underlying logger as the "diag" instance is global const spyLoggerWarn = sinon.stub(diag, 'warn'); collectorExporter = new OTLPTraceExporter({ - serviceName: 'basic-service', metadata, url: address, } as any); From d41fa7bdeab017dc4b2a51b631835468dc013f3d Mon Sep 17 00:00:00 2001 From: Siim Kallas Date: Mon, 27 Sep 2021 23:16:01 +0300 Subject: [PATCH 02/29] feat: HTTP instrumentation: add the option to capture headers as span attributes (#2492) --- .../README.md | 1 + .../src/http.ts | 26 ++++++ .../src/types.ts | 5 ++ .../src/utils.ts | 24 ++++++ .../test/functionals/http-enable.test.ts | 83 +++++++++++++++++++ .../test/functionals/utils.test.ts | 61 ++++++++++++++ 6 files changed, 200 insertions(+) diff --git a/experimental/packages/opentelemetry-instrumentation-http/README.md b/experimental/packages/opentelemetry-instrumentation-http/README.md index 139014304f3..6d5fb9a073b 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/README.md +++ b/experimental/packages/opentelemetry-instrumentation-http/README.md @@ -57,6 +57,7 @@ Http instrumentation has few options available to choose from. You can set the f | [`serverName`](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-instrumentation-http/src/types.ts#L101) | `string` | The primary server name of the matched virtual host. | | [`requireParentforOutgoingSpans`](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-instrumentation-http/src/types.ts#L103) | Boolean | Require that is a parent span to create new span for outgoing requests. | | [`requireParentforIncomingSpans`](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-instrumentation-http/src/types.ts#L105) | Boolean | Require that is a parent span to create new span for incoming requests. | +| [`headersToSpanAttributes`](https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-instrumentation-http/src/types.ts#L107) | `object` | List of case insensitive HTTP headers to convert to span attributes. Client (outgoing requests, incoming responses) and server (incoming requests, outgoing responses) headers will be converted to span attributes in the form of `http.{request\|response}.header.header_name`, e.g. `http.response.header.content_length` | ## Useful links diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts index 2229ae92c7e..b6cba079fc0 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts @@ -58,6 +58,7 @@ export class HttpInstrumentation extends InstrumentationBase { /** keep track on spans not ended */ private readonly _spanNotEnded: WeakSet = new WeakSet(); private readonly _version = process.versions.node; + private _headerCapture; constructor(config: HttpInstrumentationConfig & InstrumentationConfig = {}) { super( @@ -65,6 +66,8 @@ export class HttpInstrumentation extends InstrumentationBase { VERSION, Object.assign({}, config) ); + + this._headerCapture = this._createHeaderCapture(); } private _getConfig(): HttpInstrumentationConfig { @@ -73,6 +76,7 @@ export class HttpInstrumentation extends InstrumentationBase { override setConfig(config: HttpInstrumentationConfig & InstrumentationConfig = {}): void { this._config = Object.assign({}, config); + this._headerCapture = this._createHeaderCapture(); } init(): [InstrumentationNodeModuleDefinition, InstrumentationNodeModuleDefinition] { @@ -296,6 +300,9 @@ export class HttpInstrumentation extends InstrumentationBase { this._callResponseHook(span, response); } + this._headerCapture.client.captureRequestHeaders(span, header => request.getHeader(header)); + this._headerCapture.client.captureResponseHeaders(span, header => response.headers[header]); + context.bind(context.active(), response); this._diag.debug('outgoingRequest on response()'); response.on('end', () => { @@ -424,6 +431,8 @@ export class HttpInstrumentation extends InstrumentationBase { instrumentation._callResponseHook(span, response); } + instrumentation._headerCapture.server.captureRequestHeaders(span, header => request.headers[header]); + // Wraps end (inspired by: // https://github.com/GoogleCloudPlatform/cloud-trace-nodejs/blob/master/src/instrumentations/instrumentation-connect.ts#L75) const originalEnd = response.end; @@ -449,6 +458,8 @@ export class HttpInstrumentation extends InstrumentationBase { response ); + instrumentation._headerCapture.server.captureResponseHeaders(span, header => response.getHeader(header)); + span .setAttributes(attributes) .setStatus(utils.parseResponseStatus(response.statusCode)); @@ -662,4 +673,19 @@ export class HttpInstrumentation extends InstrumentationBase { ); } } + + private _createHeaderCapture() { + const config = this._getConfig(); + + return { + client: { + captureRequestHeaders: utils.headerCapture('request', config.headersToSpanAttributes?.client?.requestHeaders ?? []), + captureResponseHeaders: utils.headerCapture('response', config.headersToSpanAttributes?.client?.responseHeaders ?? []) + }, + server: { + captureRequestHeaders: utils.headerCapture('request', config.headersToSpanAttributes?.server?.requestHeaders ?? []), + captureResponseHeaders: utils.headerCapture('response', config.headersToSpanAttributes?.server?.responseHeaders ?? []), + } + } + } } diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/types.ts b/experimental/packages/opentelemetry-instrumentation-http/src/types.ts index 7be9999d8b6..79f4e844cd2 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/types.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/types.ts @@ -103,6 +103,11 @@ export interface HttpInstrumentationConfig extends InstrumentationConfig { requireParentforOutgoingSpans?: boolean; /** Require parent to create span for incoming requests */ requireParentforIncomingSpans?: boolean; + /** Map the following HTTP headers to span attributes. */ + headersToSpanAttributes?: { + client?: { requestHeaders?: string[]; responseHeaders?: string[]; }, + server?: { requestHeaders?: string[]; responseHeaders?: string[]; }, + } } export interface Err extends Error { diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts b/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts index a24ff6f12a9..d7c3ff83763 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts @@ -495,3 +495,27 @@ export const getIncomingRequestAttributesOnResponse = ( } return attributes; }; + +export function headerCapture(type: 'request' | 'response', headers: string[]) { + const normalizedHeaders = new Map(headers.map(header => [header.toLowerCase(), header.toLowerCase().replace(/-/g, '_')])); + + return (span: Span, getHeader: (key: string) => undefined | string | string[] | number) => { + for (const [capturedHeader, normalizedHeader] of normalizedHeaders) { + const value = getHeader(capturedHeader); + + if (value === undefined) { + continue; + } + + const key = `http.${type}.header.${normalizedHeader}`; + + if (typeof value === 'string') { + span.setAttribute(key, [value]); + } else if (Array.isArray(value)) { + span.setAttribute(key, value); + } else { + span.setAttribute(key, [value]); + } + } + }; +} diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts index 9f62d807b1c..7658bfa65b9 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/http-enable.test.ts @@ -908,4 +908,87 @@ describe('HttpInstrumentation', () => { }); }); }); + + describe('capturing headers as span attributes', () => { + beforeEach(() => { + memoryExporter.reset(); + }); + + before(() => { + instrumentation.setConfig({ + headersToSpanAttributes: { + client: { requestHeaders: ['X-Client-Header1'], responseHeaders: ['X-Server-Header1'] }, + server: { requestHeaders: ['X-Client-Header2'], responseHeaders: ['X-Server-Header2'] }, + } + }); + instrumentation.enable(); + server = http.createServer((request, response) => { + response.setHeader('X-ServeR-header1', 'server123'); + response.setHeader('X-Server-header2', '123server'); + response.end('Test Server Response'); + }); + + server.listen(serverPort); + }); + + after(() => { + server.close(); + instrumentation.disable(); + }); + + it('should convert headers to span attributes', async () => { + await httpRequest.get( + `${protocol}://${hostname}:${serverPort}${pathname}`, + { + headers: { + 'X-client-header1': 'client123', + 'X-CLIENT-HEADER2': '123client', + } + } + ); + const spans = memoryExporter.getFinishedSpans(); + const [incomingSpan, outgoingSpan] = spans; + + assert.strictEqual(spans.length, 2); + + assert.deepStrictEqual( + incomingSpan.attributes['http.request.header.x_client_header2'], + ['123client'] + ); + + assert.deepStrictEqual( + incomingSpan.attributes['http.response.header.x_server_header2'], + ['123server'] + ); + + assert.strictEqual( + incomingSpan.attributes['http.request.header.x_client_header1'], + undefined + ); + + assert.strictEqual( + incomingSpan.attributes['http.response.header.x_server_header1'], + undefined + ); + + assert.deepStrictEqual( + outgoingSpan.attributes['http.request.header.x_client_header1'], + ['client123'] + ); + assert.deepStrictEqual( + outgoingSpan.attributes['http.response.header.x_server_header1'], + ['server123'] + ); + + assert.strictEqual( + outgoingSpan.attributes['http.request.header.x_client_header2'], + undefined + ); + + assert.strictEqual( + outgoingSpan.attributes['http.response.header.x_server_header2'], + undefined + ); + }); + }); }); diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts index d530fac61ca..cde1aafdc7d 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts @@ -465,4 +465,65 @@ describe('Utility', () => { verifyValueInAttributes(attributes, undefined, 1200); }); }); + + describe('headers to span attributes capture', () => { + let span: Span; + + beforeEach(() => { + span = new Span( + new BasicTracerProvider().getTracer('default'), + ROOT_CONTEXT, + 'test', + { spanId: '', traceId: '', traceFlags: TraceFlags.SAMPLED }, + SpanKind.INTERNAL + ); + }); + + it('should set attributes for request and response keys', () => { + utils.headerCapture('request', ['Origin'])(span, () => 'localhost'); + utils.headerCapture('response', ['Cookie'])(span, () => 'token=123'); + assert.deepStrictEqual(span.attributes['http.request.header.origin'], ['localhost']); + assert.deepStrictEqual(span.attributes['http.response.header.cookie'], ['token=123']); + }); + + it('should set attributes for multiple values', () => { + utils.headerCapture('request', ['Origin'])(span, () => ['localhost', 'www.example.com']); + assert.deepStrictEqual(span.attributes['http.request.header.origin'], ['localhost', 'www.example.com']); + }); + + it('sets attributes for multiple headers', () => { + utils.headerCapture('request', ['Origin', 'Foo'])(span, header => { + if (header === 'origin') { + return 'localhost'; + } + + if (header === 'foo') { + return 42; + } + + return undefined; + }); + + assert.deepStrictEqual(span.attributes['http.request.header.origin'], ['localhost']); + assert.deepStrictEqual(span.attributes['http.request.header.foo'], [42]); + }); + + it('should normalize header names', () => { + utils.headerCapture('request', ['X-Forwarded-For'])(span, () => 'foo'); + assert.deepStrictEqual(span.attributes['http.request.header.x_forwarded_for'], ['foo']); + }); + + it('ignores non-existent headers', () => { + utils.headerCapture('request', ['Origin', 'Accept'])(span, header => { + if (header === 'origin') { + return 'localhost'; + } + + return undefined; + }); + + assert.deepStrictEqual(span.attributes['http.request.header.origin'], ['localhost']); + assert.deepStrictEqual(span.attributes['http.request.header.accept'], undefined); + }) + }); }); From f0dc893b79ae7268f7fc80b7e133d0cdbb5a294c Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Mon, 27 Sep 2021 16:30:07 -0400 Subject: [PATCH 03/29] chore: mark otlp exporters experimental (#2490) --- .gitmodules | 8 +++---- examples/otlp-exporter-node/README.md | 4 ++-- .../.eslintignore | 0 .../.eslintrc.js | 2 +- .../.npmignore | 0 .../opentelemetry-exporter-otlp-grpc/LICENSE | 0 .../README.md | 0 .../package.json | 2 +- .../opentelemetry-exporter-otlp-grpc/protos | 0 .../src/OTLPExporterNodeBase.ts | 0 .../src/OTLPMetricExporter.ts | 0 .../src/OTLPTraceExporter.ts | 0 .../src/index.ts | 0 .../src/types.ts | 0 .../src/util.ts | 0 .../submodule.md | 0 .../test/OTLPExporterNodeBase.test.ts | 0 .../test/OTLPMetricExporter.test.ts | 0 .../test/OTLPTraceExporter.test.ts | 0 .../test/certs/ca.crt | 0 .../test/certs/ca.key | 0 .../test/certs/client.crt | 0 .../test/certs/client.csr | 0 .../test/certs/client.key | 0 .../test/certs/regenerate.sh | 0 .../test/certs/server.crt | 0 .../test/certs/server.csr | 0 .../test/certs/server.key | 0 .../test/helper.ts | 0 .../test/util.test.ts | 0 .../tsconfig.json | 9 +++----- .../.eslintignore | 0 .../.eslintrc.js | 2 +- .../.npmignore | 0 .../opentelemetry-exporter-otlp-http/LICENSE | 0 .../README.md | 0 .../karma.conf.js | 4 ++-- .../package.json | 2 +- .../src/OTLPExporterBase.ts | 0 .../src/index.ts | 0 .../browser/OTLPExporterBrowserBase.ts | 0 .../platform/browser/OTLPMetricExporter.ts | 0 .../src/platform/browser/OTLPTraceExporter.ts | 0 .../src/platform/browser/index.ts | 0 .../src/platform/browser/util.ts | 0 .../src/platform/index.ts | 0 .../src/platform/node/OTLPExporterNodeBase.ts | 0 .../src/platform/node/OTLPMetricExporter.ts | 0 .../src/platform/node/OTLPTraceExporter.ts | 0 .../src/platform/node/index.ts | 0 .../src/platform/node/types.ts | 0 .../src/platform/node/util.ts | 0 .../src/transform.ts | 0 .../src/transformMetrics.ts | 0 .../src/types.ts | 0 .../src/util.ts | 0 .../browser/CollectorMetricExporter.test.ts | 0 .../browser/CollectorTraceExporter.test.ts | 0 .../test/browser/index-webpack.ts | 0 .../test/browser/util.test.ts | 0 .../test/certs/ca.crt | 0 .../test/certs/ca.key | 0 .../test/certs/client.crt | 0 .../test/certs/client.csr | 0 .../test/certs/client.key | 0 .../test/certs/regenerate.sh | 0 .../test/certs/server.crt | 0 .../test/certs/server.csr | 0 .../test/certs/server.key | 0 .../common/CollectorMetricExporter.test.ts | 0 .../common/CollectorTraceExporter.test.ts | 0 .../test/common/transform.test.ts | 0 .../test/common/transformMetrics.test.ts | 0 .../test/common/utils.test.ts | 0 .../test/helper.ts | 0 .../test/node/CollectorMetricExporter.test.ts | 0 .../test/node/CollectorTraceExporter.test.ts | 0 .../test/node/nodeHelpers.ts | 0 .../tsconfig.esm.json | 19 ++++++++++++++++ .../tsconfig.json | 19 ++++++++++++++++ .../.eslintignore | 0 .../.eslintrc.js | 2 +- .../.npmignore | 0 .../opentelemetry-exporter-otlp-proto/LICENSE | 0 .../README.md | 0 .../package.json | 2 +- .../opentelemetry-exporter-otlp-proto/protos | 0 .../src/OTLPExporterNodeBase.ts | 0 .../src/OTLPMetricExporter.ts | 0 .../src/OTLPTraceExporter.ts | 0 .../src/index.ts | 0 .../src/types.ts | 0 .../src/util.ts | 0 .../submodule.md | 0 .../test/OTLPMetricExporter.test.ts | 0 .../test/OTLPTraceExporter.test.ts | 0 .../test/certs/ca.crt | 0 .../test/certs/ca.key | 0 .../test/certs/client.crt | 0 .../test/certs/client.csr | 0 .../test/certs/client.key | 0 .../test/certs/regenerate.sh | 0 .../test/certs/server.crt | 0 .../test/certs/server.csr | 0 .../test/certs/server.key | 0 .../test/helper.ts | 0 .../tsconfig.json | 9 +++----- .../tsconfig.json | 3 +++ experimental/tsconfig.esm.json | 12 ++++++++++ experimental/tsconfig.json | 12 ++++++++++ .../tsconfig.esm.json | 22 ------------------- .../tsconfig.json | 22 ------------------- tsconfig.esm.json | 9 -------- tsconfig.json | 15 +++---------- 114 files changed, 88 insertions(+), 91 deletions(-) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/.eslintignore (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/.eslintrc.js (71%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/.npmignore (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/LICENSE (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/README.md (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/package.json (97%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/protos (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/src/OTLPExporterNodeBase.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/src/OTLPMetricExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/src/OTLPTraceExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/src/index.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/src/types.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/src/util.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/submodule.md (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/OTLPExporterNodeBase.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/OTLPTraceExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/ca.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/ca.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/client.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/client.csr (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/client.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/regenerate.sh (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/server.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/server.csr (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/certs/server.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/helper.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/test/util.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-grpc/tsconfig.json (57%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/.eslintignore (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/.eslintrc.js (75%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/.npmignore (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/LICENSE (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/README.md (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/karma.conf.js (87%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/package.json (98%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/OTLPExporterBase.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/index.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPExporterBrowserBase.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPMetricExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPTraceExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/browser/index.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/browser/util.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/index.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/node/OTLPExporterNodeBase.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/node/OTLPMetricExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/node/OTLPTraceExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/node/index.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/node/types.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/platform/node/util.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/transform.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/transformMetrics.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/types.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/src/util.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/browser/CollectorTraceExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/browser/index-webpack.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/browser/util.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/ca.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/ca.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/client.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/client.csr (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/client.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/regenerate.sh (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/server.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/server.csr (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/certs/server.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/common/CollectorTraceExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/common/transform.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/common/utils.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/helper.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-http/test/node/nodeHelpers.ts (100%) create mode 100644 experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json create mode 100644 experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.json rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/.eslintignore (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/.eslintrc.js (71%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/.npmignore (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/LICENSE (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/README.md (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/package.json (97%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/protos (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/src/OTLPExporterNodeBase.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/src/OTLPMetricExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/src/OTLPTraceExporter.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/src/index.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/src/types.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/src/util.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/submodule.md (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/OTLPTraceExporter.test.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/ca.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/ca.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/client.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/client.csr (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/client.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/regenerate.sh (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/server.crt (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/server.csr (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/certs/server.key (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/test/helper.ts (100%) rename {packages => experimental/packages}/opentelemetry-exporter-otlp-proto/tsconfig.json (57%) delete mode 100644 packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json delete mode 100644 packages/opentelemetry-exporter-otlp-http/tsconfig.json diff --git a/.gitmodules b/.gitmodules index f66e08a1b88..ac506a776f9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "packages/opentelemetry-exporter-otlp-grpc/protos"] - path = packages/opentelemetry-exporter-otlp-grpc/protos +[submodule "experimental/packages/opentelemetry-exporter-otlp-proto/protos"] + path = experimental/packages/opentelemetry-exporter-otlp-proto/protos url = https://github.com/open-telemetry/opentelemetry-proto.git -[submodule "packages/opentelemetry-exporter-otlp-proto/protos"] - path = packages/opentelemetry-exporter-otlp-proto/protos +[submodule "experimental/packages/opentelemetry-exporter-otlp-grpc/protos"] + path = experimental/packages/opentelemetry-exporter-otlp-grpc/protos url = https://github.com/open-telemetry/opentelemetry-proto.git diff --git a/examples/otlp-exporter-node/README.md b/examples/otlp-exporter-node/README.md index abfa241965c..21fea5422f0 100644 --- a/examples/otlp-exporter-node/README.md +++ b/examples/otlp-exporter-node/README.md @@ -1,8 +1,8 @@ # Overview -This example shows how to use [@opentelemetry/exporter-otlp-http](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-exporter-otlp-http) to instrument a simple Node.js application. +This example shows how to use [@opentelemetry/exporter-otlp-http](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-otlp-http) to instrument a simple Node.js application. -This example will export spans data simultaneously using [Exporter Collector](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-exporter-otlp-http) and grpc. It will use [proto format](https://github.com/open-telemetry/opentelemetry-proto). +This example will export spans data simultaneously using [Exporter Collector](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-otlp-http) and grpc. It will use [proto format](https://github.com/open-telemetry/opentelemetry-proto). ## Installation diff --git a/packages/opentelemetry-exporter-otlp-grpc/.eslintignore b/experimental/packages/opentelemetry-exporter-otlp-grpc/.eslintignore similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/.eslintignore rename to experimental/packages/opentelemetry-exporter-otlp-grpc/.eslintignore diff --git a/packages/opentelemetry-exporter-otlp-grpc/.eslintrc.js b/experimental/packages/opentelemetry-exporter-otlp-grpc/.eslintrc.js similarity index 71% rename from packages/opentelemetry-exporter-otlp-grpc/.eslintrc.js rename to experimental/packages/opentelemetry-exporter-otlp-grpc/.eslintrc.js index fc4d0381204..3ed0fbeba38 100644 --- a/packages/opentelemetry-exporter-otlp-grpc/.eslintrc.js +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/.eslintrc.js @@ -4,5 +4,5 @@ module.exports = { "commonjs": true, "node": true, }, - ...require('../../eslint.config.js') + ...require('../../../eslint.config.js') } diff --git a/packages/opentelemetry-exporter-otlp-grpc/.npmignore b/experimental/packages/opentelemetry-exporter-otlp-grpc/.npmignore similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/.npmignore rename to experimental/packages/opentelemetry-exporter-otlp-grpc/.npmignore diff --git a/packages/opentelemetry-exporter-otlp-grpc/LICENSE b/experimental/packages/opentelemetry-exporter-otlp-grpc/LICENSE similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/LICENSE rename to experimental/packages/opentelemetry-exporter-otlp-grpc/LICENSE diff --git a/packages/opentelemetry-exporter-otlp-grpc/README.md b/experimental/packages/opentelemetry-exporter-otlp-grpc/README.md similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/README.md rename to experimental/packages/opentelemetry-exporter-otlp-grpc/README.md diff --git a/packages/opentelemetry-exporter-otlp-grpc/package.json b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json similarity index 97% rename from packages/opentelemetry-exporter-otlp-grpc/package.json rename to experimental/packages/opentelemetry-exporter-otlp-grpc/package.json index e4a7e9411b6..5a2f4c86fea 100644 --- a/packages/opentelemetry-exporter-otlp-grpc/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json @@ -15,7 +15,7 @@ "submodule": "git submodule sync --recursive && git submodule update --init --recursive", "tdd": "npm run test -- --watch-extensions ts --watch", "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'", - "version": "node ../../scripts/version-update.js", + "version": "node ../../../scripts/version-update.js", "watch": "npm run protos:copy && tsc -w", "precompile": "lerna run version --scope $(npm pkg get name) --include-filtered-dependencies", "prewatch": "npm run precompile" diff --git a/packages/opentelemetry-exporter-otlp-grpc/protos b/experimental/packages/opentelemetry-exporter-otlp-grpc/protos similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/protos rename to experimental/packages/opentelemetry-exporter-otlp-grpc/protos diff --git a/packages/opentelemetry-exporter-otlp-grpc/src/OTLPExporterNodeBase.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/src/OTLPExporterNodeBase.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/src/OTLPExporterNodeBase.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/src/OTLPExporterNodeBase.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/src/OTLPMetricExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/src/OTLPMetricExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/src/OTLPMetricExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/src/OTLPTraceExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/src/OTLPTraceExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/src/OTLPTraceExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/src/OTLPTraceExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/src/index.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/src/index.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/src/index.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/src/index.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/src/types.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/src/types.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/src/types.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/src/types.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/src/util.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/src/util.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/src/util.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/src/util.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/submodule.md b/experimental/packages/opentelemetry-exporter-otlp-grpc/submodule.md similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/submodule.md rename to experimental/packages/opentelemetry-exporter-otlp-grpc/submodule.md diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/OTLPExporterNodeBase.test.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPExporterNodeBase.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/OTLPExporterNodeBase.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPExporterNodeBase.test.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/OTLPTraceExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPTraceExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/OTLPTraceExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPTraceExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.crt b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.crt rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.crt diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.key b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.key rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/ca.key diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.crt b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/client.crt rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.crt diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.csr b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.csr similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/client.csr rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.csr diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.key b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/client.key rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/client.key diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/regenerate.sh b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/regenerate.sh similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/regenerate.sh rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/regenerate.sh diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.crt b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/server.crt rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.crt diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.csr b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.csr similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/server.csr rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.csr diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.key b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/certs/server.key rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/certs/server.key diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/helper.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/test/util.test.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/util.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-grpc/test/util.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-grpc/test/util.test.ts diff --git a/packages/opentelemetry-exporter-otlp-grpc/tsconfig.json b/experimental/packages/opentelemetry-exporter-otlp-grpc/tsconfig.json similarity index 57% rename from packages/opentelemetry-exporter-otlp-grpc/tsconfig.json rename to experimental/packages/opentelemetry-exporter-otlp-grpc/tsconfig.json index cfc7b73a484..caced6b4e8b 100644 --- a/packages/opentelemetry-exporter-otlp-grpc/tsconfig.json +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "rootDir": ".", "outDir": "build" @@ -10,16 +10,13 @@ ], "references": [ { - "path": "../opentelemetry-core" + "path": "../opentelemetry-api-metrics" }, { "path": "../opentelemetry-exporter-otlp-http" }, { - "path": "../opentelemetry-resources" - }, - { - "path": "../opentelemetry-sdk-trace-base" + "path": "../opentelemetry-sdk-metrics-base" } ] } diff --git a/packages/opentelemetry-exporter-otlp-http/.eslintignore b/experimental/packages/opentelemetry-exporter-otlp-http/.eslintignore similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/.eslintignore rename to experimental/packages/opentelemetry-exporter-otlp-http/.eslintignore diff --git a/packages/opentelemetry-exporter-otlp-http/.eslintrc.js b/experimental/packages/opentelemetry-exporter-otlp-http/.eslintrc.js similarity index 75% rename from packages/opentelemetry-exporter-otlp-http/.eslintrc.js rename to experimental/packages/opentelemetry-exporter-otlp-http/.eslintrc.js index 9dfe62f9b8c..e41d9a9299b 100644 --- a/packages/opentelemetry-exporter-otlp-http/.eslintrc.js +++ b/experimental/packages/opentelemetry-exporter-otlp-http/.eslintrc.js @@ -5,5 +5,5 @@ module.exports = { "node": true, "browser": true }, - ...require('../../eslint.config.js') + ...require('../../../eslint.config.js') } diff --git a/packages/opentelemetry-exporter-otlp-http/.npmignore b/experimental/packages/opentelemetry-exporter-otlp-http/.npmignore similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/.npmignore rename to experimental/packages/opentelemetry-exporter-otlp-http/.npmignore diff --git a/packages/opentelemetry-exporter-otlp-http/LICENSE b/experimental/packages/opentelemetry-exporter-otlp-http/LICENSE similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/LICENSE rename to experimental/packages/opentelemetry-exporter-otlp-http/LICENSE diff --git a/packages/opentelemetry-exporter-otlp-http/README.md b/experimental/packages/opentelemetry-exporter-otlp-http/README.md similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/README.md rename to experimental/packages/opentelemetry-exporter-otlp-http/README.md diff --git a/packages/opentelemetry-exporter-otlp-http/karma.conf.js b/experimental/packages/opentelemetry-exporter-otlp-http/karma.conf.js similarity index 87% rename from packages/opentelemetry-exporter-otlp-http/karma.conf.js rename to experimental/packages/opentelemetry-exporter-otlp-http/karma.conf.js index 455b1437c87..4c60b54edba 100644 --- a/packages/opentelemetry-exporter-otlp-http/karma.conf.js +++ b/experimental/packages/opentelemetry-exporter-otlp-http/karma.conf.js @@ -14,8 +14,8 @@ * limitations under the License. */ -const karmaWebpackConfig = require('../../karma.webpack'); -const karmaBaseConfig = require('../../karma.base'); +const karmaWebpackConfig = require('../../../karma.webpack'); +const karmaBaseConfig = require('../../../karma.base'); module.exports = (config) => { config.set(Object.assign({}, karmaBaseConfig, { diff --git a/packages/opentelemetry-exporter-otlp-http/package.json b/experimental/packages/opentelemetry-exporter-otlp-http/package.json similarity index 98% rename from packages/opentelemetry-exporter-otlp-http/package.json rename to experimental/packages/opentelemetry-exporter-otlp-http/package.json index 3a03727c437..00e2bcdf767 100644 --- a/packages/opentelemetry-exporter-otlp-http/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-http/package.json @@ -21,7 +21,7 @@ "tdd:browser": "karma start", "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts' --exclude 'test/browser/**/*.ts'", "test:browser": "nyc karma start --single-run", - "version": "node ../../scripts/version-update.js", + "version": "node ../../../scripts/version-update.js", "watch": "tsc --build --watch tsconfig.json tsconfig.esm.json", "precompile": "lerna run version --scope $(npm pkg get name) --include-filtered-dependencies", "prewatch": "npm run precompile" diff --git a/packages/opentelemetry-exporter-otlp-http/src/OTLPExporterBase.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/OTLPExporterBase.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/OTLPExporterBase.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/OTLPExporterBase.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/index.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/index.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/index.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/index.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPExporterBrowserBase.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPExporterBrowserBase.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPExporterBrowserBase.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPExporterBrowserBase.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPMetricExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPMetricExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPMetricExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPTraceExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPTraceExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPTraceExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/OTLPTraceExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/browser/index.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/index.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/browser/index.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/index.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/browser/util.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/util.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/browser/util.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/browser/util.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/index.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/index.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/index.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/index.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPExporterNodeBase.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPExporterNodeBase.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPExporterNodeBase.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPExporterNodeBase.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPMetricExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPMetricExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPMetricExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPTraceExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPTraceExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPTraceExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/OTLPTraceExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/node/index.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/index.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/node/index.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/index.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/node/types.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/types.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/node/types.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/types.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/platform/node/util.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/util.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/platform/node/util.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/platform/node/util.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/transform.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/transform.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/transform.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/transform.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/types.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/types.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/types.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/types.ts diff --git a/packages/opentelemetry-exporter-otlp-http/src/util.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/util.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/src/util.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/src/util.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorTraceExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorTraceExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/browser/CollectorTraceExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorTraceExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/browser/index-webpack.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/index-webpack.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/browser/index-webpack.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/browser/index-webpack.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/browser/util.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/util.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/browser/util.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/browser/util.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/ca.crt b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/ca.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/ca.crt rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/ca.crt diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/ca.key b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/ca.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/ca.key rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/ca.key diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/client.crt b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/client.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/client.crt rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/client.crt diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/client.csr b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/client.csr similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/client.csr rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/client.csr diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/client.key b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/client.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/client.key rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/client.key diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/regenerate.sh b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/regenerate.sh similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/regenerate.sh rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/regenerate.sh diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/server.crt b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/server.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/server.crt rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/server.crt diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/server.csr b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/server.csr similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/server.csr rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/server.csr diff --git a/packages/opentelemetry-exporter-otlp-http/test/certs/server.key b/experimental/packages/opentelemetry-exporter-otlp-http/test/certs/server.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/certs/server.key rename to experimental/packages/opentelemetry-exporter-otlp-http/test/certs/server.key diff --git a/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/common/CollectorTraceExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorTraceExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/common/CollectorTraceExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorTraceExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/common/transform.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/transform.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/common/transform.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/common/transform.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/common/utils.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/utils.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/common/utils.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/common/utils.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/helper.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/helper.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/helper.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/helper.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorTraceExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-http/test/node/nodeHelpers.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/node/nodeHelpers.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-http/test/node/nodeHelpers.ts rename to experimental/packages/opentelemetry-exporter-otlp-http/test/node/nodeHelpers.ts diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json b/experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json new file mode 100644 index 00000000000..7b09613481b --- /dev/null +++ b/experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.esm.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build/esm", + "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" + }, + "include": [ + "src/**/*.ts" + ], + "references": [ + { + "path": "../opentelemetry-api-metrics/tsconfig.esm.json" + }, + { + "path": "../opentelemetry-sdk-metrics-base/tsconfig.esm.json" + } + ] +} diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.json b/experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.json new file mode 100644 index 00000000000..3c062d3feb2 --- /dev/null +++ b/experimental/packages/opentelemetry-exporter-otlp-http/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ], + "references": [ + { + "path": "../opentelemetry-api-metrics" + }, + { + "path": "../opentelemetry-sdk-metrics-base" + } + ] +} diff --git a/packages/opentelemetry-exporter-otlp-proto/.eslintignore b/experimental/packages/opentelemetry-exporter-otlp-proto/.eslintignore similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/.eslintignore rename to experimental/packages/opentelemetry-exporter-otlp-proto/.eslintignore diff --git a/packages/opentelemetry-exporter-otlp-proto/.eslintrc.js b/experimental/packages/opentelemetry-exporter-otlp-proto/.eslintrc.js similarity index 71% rename from packages/opentelemetry-exporter-otlp-proto/.eslintrc.js rename to experimental/packages/opentelemetry-exporter-otlp-proto/.eslintrc.js index fc4d0381204..3ed0fbeba38 100644 --- a/packages/opentelemetry-exporter-otlp-proto/.eslintrc.js +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/.eslintrc.js @@ -4,5 +4,5 @@ module.exports = { "commonjs": true, "node": true, }, - ...require('../../eslint.config.js') + ...require('../../../eslint.config.js') } diff --git a/packages/opentelemetry-exporter-otlp-proto/.npmignore b/experimental/packages/opentelemetry-exporter-otlp-proto/.npmignore similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/.npmignore rename to experimental/packages/opentelemetry-exporter-otlp-proto/.npmignore diff --git a/packages/opentelemetry-exporter-otlp-proto/LICENSE b/experimental/packages/opentelemetry-exporter-otlp-proto/LICENSE similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/LICENSE rename to experimental/packages/opentelemetry-exporter-otlp-proto/LICENSE diff --git a/packages/opentelemetry-exporter-otlp-proto/README.md b/experimental/packages/opentelemetry-exporter-otlp-proto/README.md similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/README.md rename to experimental/packages/opentelemetry-exporter-otlp-proto/README.md diff --git a/packages/opentelemetry-exporter-otlp-proto/package.json b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json similarity index 97% rename from packages/opentelemetry-exporter-otlp-proto/package.json rename to experimental/packages/opentelemetry-exporter-otlp-proto/package.json index b890fd32d9b..f8fb5c5e078 100644 --- a/packages/opentelemetry-exporter-otlp-proto/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json @@ -15,7 +15,7 @@ "submodule": "git submodule sync --recursive && git submodule update --init --recursive", "tdd": "npm run test -- --watch-extensions ts --watch", "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'", - "version": "node ../../scripts/version-update.js", + "version": "node ../../../scripts/version-update.js", "watch": "npm run protos:copy && tsc -w", "precompile": "lerna run version --scope $(npm pkg get name) --include-filtered-dependencies", "prewatch": "npm run precompile" diff --git a/packages/opentelemetry-exporter-otlp-proto/protos b/experimental/packages/opentelemetry-exporter-otlp-proto/protos similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/protos rename to experimental/packages/opentelemetry-exporter-otlp-proto/protos diff --git a/packages/opentelemetry-exporter-otlp-proto/src/OTLPExporterNodeBase.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/src/OTLPExporterNodeBase.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/src/OTLPExporterNodeBase.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/src/OTLPExporterNodeBase.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/src/OTLPMetricExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/src/OTLPMetricExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/src/OTLPMetricExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/src/OTLPMetricExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/src/OTLPTraceExporter.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/src/OTLPTraceExporter.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/src/OTLPTraceExporter.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/src/OTLPTraceExporter.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/src/index.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/src/index.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/src/index.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/src/index.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/src/types.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/src/types.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/src/types.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/src/types.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/src/util.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/src/util.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/src/util.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/src/util.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/submodule.md b/experimental/packages/opentelemetry-exporter-otlp-proto/submodule.md similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/submodule.md rename to experimental/packages/opentelemetry-exporter-otlp-proto/submodule.md diff --git a/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/test/OTLPTraceExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPTraceExporter.test.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/OTLPTraceExporter.test.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPTraceExporter.test.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/ca.crt b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/ca.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/ca.crt rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/ca.crt diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/ca.key b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/ca.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/ca.key rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/ca.key diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/client.crt b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/client.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/client.crt rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/client.crt diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/client.csr b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/client.csr similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/client.csr rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/client.csr diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/client.key b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/client.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/client.key rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/client.key diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/regenerate.sh b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/regenerate.sh similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/regenerate.sh rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/regenerate.sh diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/server.crt b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/server.crt similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/server.crt rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/server.crt diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/server.csr b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/server.csr similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/server.csr rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/server.csr diff --git a/packages/opentelemetry-exporter-otlp-proto/test/certs/server.key b/experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/server.key similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/certs/server.key rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/certs/server.key diff --git a/packages/opentelemetry-exporter-otlp-proto/test/helper.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/test/helper.ts similarity index 100% rename from packages/opentelemetry-exporter-otlp-proto/test/helper.ts rename to experimental/packages/opentelemetry-exporter-otlp-proto/test/helper.ts diff --git a/packages/opentelemetry-exporter-otlp-proto/tsconfig.json b/experimental/packages/opentelemetry-exporter-otlp-proto/tsconfig.json similarity index 57% rename from packages/opentelemetry-exporter-otlp-proto/tsconfig.json rename to experimental/packages/opentelemetry-exporter-otlp-proto/tsconfig.json index cfc7b73a484..caced6b4e8b 100644 --- a/packages/opentelemetry-exporter-otlp-proto/tsconfig.json +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.base.json", + "extends": "../../../tsconfig.base.json", "compilerOptions": { "rootDir": ".", "outDir": "build" @@ -10,16 +10,13 @@ ], "references": [ { - "path": "../opentelemetry-core" + "path": "../opentelemetry-api-metrics" }, { "path": "../opentelemetry-exporter-otlp-http" }, { - "path": "../opentelemetry-resources" - }, - { - "path": "../opentelemetry-sdk-trace-base" + "path": "../opentelemetry-sdk-metrics-base" } ] } diff --git a/experimental/packages/opentelemetry-exporter-prometheus/tsconfig.json b/experimental/packages/opentelemetry-exporter-prometheus/tsconfig.json index 948abef3ceb..3c062d3feb2 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/tsconfig.json +++ b/experimental/packages/opentelemetry-exporter-prometheus/tsconfig.json @@ -11,6 +11,9 @@ "references": [ { "path": "../opentelemetry-api-metrics" + }, + { + "path": "../opentelemetry-sdk-metrics-base" } ] } diff --git a/experimental/tsconfig.esm.json b/experimental/tsconfig.esm.json index cd3052ad278..c37493f8e74 100644 --- a/experimental/tsconfig.esm.json +++ b/experimental/tsconfig.esm.json @@ -5,6 +5,18 @@ { "path": "packages/opentelemetry-api-metrics/tsconfig.esm.json" }, + { + "path": "packages/opentelemetry-exporter-otlp-grpc" + }, + { + "path": "packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json" + }, + { + "path": "packages/opentelemetry-exporter-otlp-proto" + }, + { + "path": "packages/opentelemetry-exporter-prometheus" + }, { "path": "packages/opentelemetry-instrumentation-fetch/tsconfig.esm.json" }, diff --git a/experimental/tsconfig.json b/experimental/tsconfig.json index a4220672a87..6571f7fa7c9 100644 --- a/experimental/tsconfig.json +++ b/experimental/tsconfig.json @@ -5,6 +5,18 @@ { "path": "packages/opentelemetry-api-metrics" }, + { + "path": "packages/opentelemetry-exporter-otlp-grpc" + }, + { + "path": "packages/opentelemetry-exporter-otlp-http" + }, + { + "path": "packages/opentelemetry-exporter-otlp-proto" + }, + { + "path": "packages/opentelemetry-exporter-prometheus" + }, { "path": "packages/opentelemetry-instrumentation-fetch" }, diff --git a/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json b/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json deleted file mode 100644 index 7a9bb54ea7d..00000000000 --- a/packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfig.base.esm.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "build/esm", - "tsBuildInfoFile": "build/esm/tsconfig.esm.tsbuildinfo" - }, - "include": [ - "src/**/*.ts" - ], - "references": [ - { - "path": "../opentelemetry-core/tsconfig.esm.json" - }, - { - "path": "../opentelemetry-resources/tsconfig.esm.json" - }, - { - "path": "../opentelemetry-sdk-trace-base/tsconfig.esm.json" - } - ] -} diff --git a/packages/opentelemetry-exporter-otlp-http/tsconfig.json b/packages/opentelemetry-exporter-otlp-http/tsconfig.json deleted file mode 100644 index 1d7ba827ac5..00000000000 --- a/packages/opentelemetry-exporter-otlp-http/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "rootDir": ".", - "outDir": "build" - }, - "include": [ - "src/**/*.ts", - "test/**/*.ts" - ], - "references": [ - { - "path": "../opentelemetry-core" - }, - { - "path": "../opentelemetry-resources" - }, - { - "path": "../opentelemetry-sdk-trace-base" - } - ] -} diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 57f33c032a0..528d200ba51 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -26,15 +26,6 @@ { "path": "packages/opentelemetry-exporter-jaeger" }, - { - "path": "packages/opentelemetry-exporter-otlp-grpc" - }, - { - "path": "packages/opentelemetry-exporter-otlp-http/tsconfig.esm.json" - }, - { - "path": "packages/opentelemetry-exporter-otlp-proto" - }, { "path": "packages/opentelemetry-exporter-zipkin/tsconfig.esm.json" }, diff --git a/tsconfig.json b/tsconfig.json index 8c9f7c196ae..be14fd46434 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,9 @@ "typedocOptions": { "packages": [ "experimental/packages/opentelemetry-api-metrics", + "experimental/packages/opentelemetry-exporter-otlp-grpc", + "experimental/packages/opentelemetry-exporter-otlp-http", + "experimental/packages/opentelemetry-exporter-otlp-proto", "experimental/packages/opentelemetry-exporter-prometheus", "experimental/packages/opentelemetry-instrumentation-fetch", "experimental/packages/opentelemetry-instrumentation-grpc", @@ -16,9 +19,6 @@ "packages/opentelemetry-context-zone", "packages/opentelemetry-core", "packages/opentelemetry-exporter-jaeger", - "packages/opentelemetry-exporter-otlp-grpc", - "packages/opentelemetry-exporter-otlp-http", - "packages/opentelemetry-exporter-otlp-proto", "packages/opentelemetry-exporter-zipkin", "packages/opentelemetry-propagator-b3", "packages/opentelemetry-propagator-jaeger", @@ -65,15 +65,6 @@ { "path": "packages/opentelemetry-exporter-jaeger" }, - { - "path": "packages/opentelemetry-exporter-otlp-grpc" - }, - { - "path": "packages/opentelemetry-exporter-otlp-http" - }, - { - "path": "packages/opentelemetry-exporter-otlp-proto" - }, { "path": "packages/opentelemetry-exporter-zipkin" }, From be52259d736d6762f83d89682dc528c2db0ffeaa Mon Sep 17 00:00:00 2001 From: Mustafain Ali Khan Date: Tue, 28 Sep 2021 13:49:47 -0400 Subject: [PATCH 04/29] fix: remove setting http.route in http span attributes (#2494) --- .../src/utils.ts | 1 - .../test/functionals/utils.test.ts | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts b/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts index d7c3ff83763..4f8a03c7af8 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/utils.ts @@ -453,7 +453,6 @@ export const getIncomingRequestAttributes = ( } if (requestUrl) { - attributes[SemanticAttributes.HTTP_ROUTE] = requestUrl.pathname || '/'; attributes[SemanticAttributes.HTTP_TARGET] = requestUrl.pathname || '/'; } diff --git a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts index cde1aafdc7d..7b8a2e8d1ef 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/test/functionals/utils.test.ts @@ -466,6 +466,21 @@ describe('Utility', () => { }); }); + describe('getIncomingRequestAttributes()', () => { + it('should not set http.route in http span attributes', () => { + const request = { + url: 'http://hostname/user/:id', + method: 'GET' + } as IncomingMessage; + request.headers = { + 'user-agent': 'chrome', + 'x-forwarded-for': ', , ' + } + const attributes = utils.getIncomingRequestAttributes(request, { component: 'http'}) + assert.strictEqual(attributes[SemanticAttributes.HTTP_ROUTE], undefined) + }); + }); + describe('headers to span attributes capture', () => { let span: Span; From 7287dcb042ff0af40d9a5d7f06c0efc4c11a9e04 Mon Sep 17 00:00:00 2001 From: Mustafain Ali Khan Date: Wed, 29 Sep 2021 09:07:28 -0400 Subject: [PATCH 05/29] fix: update typescript getting-started tracing example and docs (#2504) --- getting-started/ts-example/README.md | 34 +++++++++---------- .../ts-example/traced-example/tracing.ts | 19 ++++++----- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/getting-started/ts-example/README.md b/getting-started/ts-example/README.md index 49da9bc4a51..a1ccd6a1cb6 100644 --- a/getting-started/ts-example/README.md +++ b/getting-started/ts-example/README.md @@ -54,15 +54,17 @@ This guide uses the example application provided in the [example directory](exam ([link to JavaScript version](../README.md#install-the-required-opentelemetry-libraries)) -To create traces on NodeJS, you will need `@opentelemetry/sdk-trace-node`, `@opentelemetry/core`, and any plugins required by your application such as gRPC, or HTTP. If you are using the example application, you will need to install `@opentelemetry/plugin-http`. +To create traces on NodeJS, you will need `@opentelemetry/sdk-trace-node`, `@opentelemetry/api`, and any plugins required by your application such as gRPC, or HTTP. If you are using the example application, you will need to install `@opentelemetry/instrumentation-http` and `@opentelemetry/instrumentation-express`. ```sh $ npm install \ - @opentelemetry/core \ + @opentelemetry/api \ @opentelemetry/sdk-trace-node \ @opentelemetry/instrumentation \ @opentelemetry/instrumentation-http \ - @opentelemetry/instrumentation-express + @opentelemetry/instrumentation-express \ + @@opentelemetry/resources \ + @opentelemetry/semantic-conventions ``` #### Initialize a global tracer @@ -74,16 +76,16 @@ All tracing initialization should happen before your application’s code runs. Create a file named `tracing.ts` and add the following code: ```typescript -import { LogLevel } from '@opentelemetry/core'; +import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -const provider: NodeTracerProvider = new NodeTracerProvider({ - logLevel: LogLevel.ERROR, -}); +const provider: NodeTracerProvider = new NodeTracerProvider(); + +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); provider.register(); @@ -120,26 +122,26 @@ $ # npm install @opentelemetry/exporter-jaeger After these dependencies are installed, we will need to initialize and register them. Modify `tracing.ts` so that it matches the following code snippet, replacing the service name `"getting-started"` with your own service name if you wish. ```typescript -import { LogLevel } from '@opentelemetry/core'; +import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; - +import { registerInstrumentations } from '@opentelemetry/instrumentation'; +import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; +import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; +import { Resource } from '@opentelemetry/resources' +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; // For Jaeger, use the following line instead: // import { JaegerExporter } from '@opentelemetry/exporter-jaeger'; -import { registerInstrumentations } from '@opentelemetry/instrumentation'; -import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; -import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; - const provider: NodeTracerProvider = new NodeTracerProvider({ - logLevel: LogLevel.ERROR, resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'getting-started', }), }); +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); + provider.addSpanProcessor( new SimpleSpanProcessor( new ZipkinExporter({ @@ -151,7 +153,6 @@ provider.addSpanProcessor( }), ), ); - provider.register(); registerInstrumentations({ @@ -161,7 +162,6 @@ registerInstrumentations({ ], }); - console.log('tracing initialized'); ``` diff --git a/getting-started/ts-example/traced-example/tracing.ts b/getting-started/ts-example/traced-example/tracing.ts index 4426da25f98..8d4628a06e9 100644 --- a/getting-started/ts-example/traced-example/tracing.ts +++ b/getting-started/ts-example/traced-example/tracing.ts @@ -1,22 +1,23 @@ +import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; - +import { registerInstrumentations } from '@opentelemetry/instrumentation'; +import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; +import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; +import { Resource } from '@opentelemetry/resources' +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; - -const { Resource } = require('@opentelemetry/resources'); -const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions'); // For Jaeger, use the following line instead: // import { JaegerExporter } from '@opentelemetry/exporter-jaeger'; -const { registerInstrumentations } = require('@opentelemetry/instrumentation'); -const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express'); -const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); - const provider: NodeTracerProvider = new NodeTracerProvider({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'getting-started', }), }); + +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); + provider.addSpanProcessor( new SimpleSpanProcessor( new ZipkinExporter({ @@ -37,4 +38,4 @@ registerInstrumentations({ ], }); -console.log('tracing initialized'); +console.log('tracing initialized'); \ No newline at end of file From b66c650849ed4da78ab7d9acbbb50df6f8d58e37 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Wed, 29 Sep 2021 10:53:40 -0400 Subject: [PATCH 06/29] chore: move backwards compatibility to experimental (#2508) --- .../backwards-compatability}/node10/index.ts | 0 .../backwards-compatability}/node10/package.json | 0 .../backwards-compatability}/node10/tsconfig.json | 4 ++-- .../backwards-compatability}/node12/index.ts | 0 .../backwards-compatability}/node12/package.json | 0 .../backwards-compatability}/node12/tsconfig.json | 4 ++-- .../backwards-compatability}/node8/index.ts | 0 .../backwards-compatability}/node8/package.json | 0 .../backwards-compatability}/node8/tsconfig.json | 4 ++-- experimental/lerna.json | 3 ++- experimental/tsconfig.esm.json | 9 +++++++++ experimental/tsconfig.json | 9 +++++++++ lerna.json | 1 - tsconfig.esm.json | 9 --------- tsconfig.json | 9 --------- 15 files changed, 26 insertions(+), 26 deletions(-) rename {backwards-compatability => experimental/backwards-compatability}/node10/index.ts (100%) rename {backwards-compatability => experimental/backwards-compatability}/node10/package.json (100%) rename {backwards-compatability => experimental/backwards-compatability}/node10/tsconfig.json (58%) rename {backwards-compatability => experimental/backwards-compatability}/node12/index.ts (100%) rename {backwards-compatability => experimental/backwards-compatability}/node12/package.json (100%) rename {backwards-compatability => experimental/backwards-compatability}/node12/tsconfig.json (58%) rename {backwards-compatability => experimental/backwards-compatability}/node8/index.ts (100%) rename {backwards-compatability => experimental/backwards-compatability}/node8/package.json (100%) rename {backwards-compatability => experimental/backwards-compatability}/node8/tsconfig.json (58%) diff --git a/backwards-compatability/node10/index.ts b/experimental/backwards-compatability/node10/index.ts similarity index 100% rename from backwards-compatability/node10/index.ts rename to experimental/backwards-compatability/node10/index.ts diff --git a/backwards-compatability/node10/package.json b/experimental/backwards-compatability/node10/package.json similarity index 100% rename from backwards-compatability/node10/package.json rename to experimental/backwards-compatability/node10/package.json diff --git a/backwards-compatability/node10/tsconfig.json b/experimental/backwards-compatability/node10/tsconfig.json similarity index 58% rename from backwards-compatability/node10/tsconfig.json rename to experimental/backwards-compatability/node10/tsconfig.json index 557ca620428..049617e92fe 100644 --- a/backwards-compatability/node10/tsconfig.json +++ b/experimental/backwards-compatability/node10/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.es5.json", + "extends": "../../../tsconfig.es5.json", "compilerOptions": { "rootDir": ".", "outDir": "build" @@ -9,7 +9,7 @@ ], "references": [ { - "path": "../../packages/opentelemetry-sdk-trace-base" + "path": "../../packages/opentelemetry-sdk-node" } ] } diff --git a/backwards-compatability/node12/index.ts b/experimental/backwards-compatability/node12/index.ts similarity index 100% rename from backwards-compatability/node12/index.ts rename to experimental/backwards-compatability/node12/index.ts diff --git a/backwards-compatability/node12/package.json b/experimental/backwards-compatability/node12/package.json similarity index 100% rename from backwards-compatability/node12/package.json rename to experimental/backwards-compatability/node12/package.json diff --git a/backwards-compatability/node12/tsconfig.json b/experimental/backwards-compatability/node12/tsconfig.json similarity index 58% rename from backwards-compatability/node12/tsconfig.json rename to experimental/backwards-compatability/node12/tsconfig.json index 557ca620428..049617e92fe 100644 --- a/backwards-compatability/node12/tsconfig.json +++ b/experimental/backwards-compatability/node12/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.es5.json", + "extends": "../../../tsconfig.es5.json", "compilerOptions": { "rootDir": ".", "outDir": "build" @@ -9,7 +9,7 @@ ], "references": [ { - "path": "../../packages/opentelemetry-sdk-trace-base" + "path": "../../packages/opentelemetry-sdk-node" } ] } diff --git a/backwards-compatability/node8/index.ts b/experimental/backwards-compatability/node8/index.ts similarity index 100% rename from backwards-compatability/node8/index.ts rename to experimental/backwards-compatability/node8/index.ts diff --git a/backwards-compatability/node8/package.json b/experimental/backwards-compatability/node8/package.json similarity index 100% rename from backwards-compatability/node8/package.json rename to experimental/backwards-compatability/node8/package.json diff --git a/backwards-compatability/node8/tsconfig.json b/experimental/backwards-compatability/node8/tsconfig.json similarity index 58% rename from backwards-compatability/node8/tsconfig.json rename to experimental/backwards-compatability/node8/tsconfig.json index 557ca620428..049617e92fe 100644 --- a/backwards-compatability/node8/tsconfig.json +++ b/experimental/backwards-compatability/node8/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "../../tsconfig.es5.json", + "extends": "../../../tsconfig.es5.json", "compilerOptions": { "rootDir": ".", "outDir": "build" @@ -9,7 +9,7 @@ ], "references": [ { - "path": "../../packages/opentelemetry-sdk-trace-base" + "path": "../../packages/opentelemetry-sdk-node" } ] } diff --git a/experimental/lerna.json b/experimental/lerna.json index 99276cc155d..c8010cca0c9 100644 --- a/experimental/lerna.json +++ b/experimental/lerna.json @@ -3,6 +3,7 @@ "version": "0.25.0", "npmClient": "npm", "packages": [ - "packages/*" + "packages/*", + "backwards-compatability/*" ] } diff --git a/experimental/tsconfig.esm.json b/experimental/tsconfig.esm.json index c37493f8e74..a233a3b76d1 100644 --- a/experimental/tsconfig.esm.json +++ b/experimental/tsconfig.esm.json @@ -37,6 +37,15 @@ }, { "path": "packages/opentelemetry-sdk-node" + }, + { + "path": "backwards-compatability/node10" + }, + { + "path": "backwards-compatability/node12" + }, + { + "path": "backwards-compatability/node8" } ] } diff --git a/experimental/tsconfig.json b/experimental/tsconfig.json index 6571f7fa7c9..3ae14512e28 100644 --- a/experimental/tsconfig.json +++ b/experimental/tsconfig.json @@ -37,6 +37,15 @@ }, { "path": "packages/opentelemetry-sdk-node" + }, + { + "path": "backwards-compatability/node10" + }, + { + "path": "backwards-compatability/node12" + }, + { + "path": "backwards-compatability/node8" } ] } diff --git a/lerna.json b/lerna.json index 5f3df4e8bd0..deedbc87c7b 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,6 @@ "npmClient": "npm", "packages": [ "benchmark/*", - "backwards-compatability/*", "packages/*", "integration-tests/*" ] diff --git a/tsconfig.esm.json b/tsconfig.esm.json index 528d200ba51..4bbf108bfcf 100644 --- a/tsconfig.esm.json +++ b/tsconfig.esm.json @@ -2,15 +2,6 @@ "extends": "./tsconfig.base.esm.json", "files": [], "references": [ - { - "path": "backwards-compatability/node10" - }, - { - "path": "backwards-compatability/node12" - }, - { - "path": "backwards-compatability/node8" - }, { "path": "packages/opentelemetry-context-async-hooks" }, diff --git a/tsconfig.json b/tsconfig.json index be14fd46434..17cfa102617 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -41,15 +41,6 @@ "excludePrivate": true }, "references": [ - { - "path": "backwards-compatability/node10" - }, - { - "path": "backwards-compatability/node12" - }, - { - "path": "backwards-compatability/node8" - }, { "path": "packages/opentelemetry-context-async-hooks" }, From 25e5ddea8a0d273f70a6ff49b1a07cb9d8e02190 Mon Sep 17 00:00:00 2001 From: Paurush Garg <62579325+PaurushGarg@users.noreply.github.com> Date: Wed, 29 Sep 2021 14:21:29 -0700 Subject: [PATCH 07/29] fix: 2389- replaced logger unformatted strings with template literals (#2499) --- CHANGELOG.md | 2 ++ .../src/grpc-js/index.ts | 2 +- .../opentelemetry-instrumentation-grpc/src/grpc/index.ts | 2 +- .../opentelemetry-instrumentation-http/src/http.ts | 4 ++-- packages/opentelemetry-exporter-jaeger/src/jaeger.ts | 4 ++-- .../src/platform/browser/util.ts | 4 ++-- .../src/platform/node/util.ts | 8 ++------ packages/opentelemetry-sdk-trace-base/src/Span.ts | 6 +----- 8 files changed, 13 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b361fd135b6..cb66b2d0b16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ All notable changes to this project will be documented in this file. ### :bug: (Bug Fix) +* `opentelemetry-instrumentation-grpc`, `opentelemetry-instrumentation-http`, `opentelemetry-instrumentation-jaeger`, `opentelemetry-exporter-zipkin`, `opentelemetry-sdk-trace-base` + * [#2499](https://github.com/open-telemetry/opentelemetry-js/pull/2499) fix: 2389- replaced logger unformatted strings with template literals ([@PaurushGarg](https://github.com/PaurushGarg)) * `opentelemetry-instrumentation-fetch` * [#2411](https://github.com/open-telemetry/opentelemetry-js/pull/2411) fix(instrumentation-fetch): `fetch(string, Request)` silently drops request body ([@t2t2](https://github.com/t2t2)) * `opentelemetry-sdk-trace-base` diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts index 0cf2114891e..ba4f46e3516 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc-js/index.ts @@ -185,7 +185,7 @@ export class GrpcJsInstrumentation extends InstrumentationBase { kind: SpanKind.SERVER, }; - instrumentation._diag.debug('patch func: %s', JSON.stringify(spanOptions)); + instrumentation._diag.debug(`patch func: ${JSON.stringify(spanOptions)}`); context.with( propagation.extract(ROOT_CONTEXT, call.metadata, { diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts index 87486ef157f..18b649b95ca 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/src/grpc/index.ts @@ -190,7 +190,7 @@ export class GrpcNativeInstrumentation extends InstrumentationBase< kind: SpanKind.SERVER, }; - instrumentation._diag.debug('patch func: %s', JSON.stringify(spanOptions)); + instrumentation._diag.debug(`patch func: ${JSON.stringify(spanOptions)}`); context.with( propagation.extract(context.active(), call.metadata, { diff --git a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts index b6cba079fc0..6c889b40664 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/src/http.ts +++ b/experimental/packages/opentelemetry-instrumentation-http/src/http.ts @@ -377,7 +377,7 @@ export class HttpInstrumentation extends InstrumentationBase { : '/'; const method = request.method || 'GET'; - instrumentation._diag.debug('%s instrumentation incomingRequest', component); + instrumentation._diag.debug(`${component} instrumentation incomingRequest`); if ( utils.isIgnored( @@ -591,7 +591,7 @@ export class HttpInstrumentation extends InstrumentationBase { } ); - instrumentation._diag.debug('%s instrumentation outgoingRequest', component); + instrumentation._diag.debug(`${component} instrumentation outgoingRequest`); context.bind(parentContext, request); return instrumentation._traceClientRequest( request, diff --git a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts index 614871d0198..319d99ce377 100644 --- a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts +++ b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts @@ -124,7 +124,7 @@ export class JaegerExporter implements SpanExporter { if (done) return done({ code: ExportResultCode.FAILED, error }); } } - diag.debug('successful append for : %s', thriftSpan.length); + diag.debug(`successful append for : ${thriftSpan.length}`); // Flush all spans on each export. No-op if span buffer is empty await this._flush(); @@ -177,7 +177,7 @@ export class JaegerExporter implements SpanExporter { if (err) { return reject(new Error(err)); } - diag.debug('successful flush for %s spans', _count); + diag.debug(`successful flush for ${_count} spans`); resolve(); }); }); diff --git a/packages/opentelemetry-exporter-zipkin/src/platform/browser/util.ts b/packages/opentelemetry-exporter-zipkin/src/platform/browser/util.ts index 2b0ef76b2e7..222f138d070 100644 --- a/packages/opentelemetry-exporter-zipkin/src/platform/browser/util.ts +++ b/packages/opentelemetry-exporter-zipkin/src/platform/browser/util.ts @@ -103,7 +103,7 @@ function sendWithXhr( xhr.onreadystatechange = () => { if (xhr.readyState === XMLHttpRequest.DONE) { const statusCode = xhr.status || 0; - diag.debug('Zipkin response status code: %d, body: %s', statusCode, data); + diag.debug(`Zipkin response status code: ${statusCode}, body: ${data}`); if (xhr.status >= 200 && xhr.status < 400) { return done({ code: ExportResultCode.SUCCESS }); @@ -124,6 +124,6 @@ function sendWithXhr( }; // Issue request to remote service - diag.debug('Zipkin request payload: %s', data); + diag.debug(`Zipkin request payload: ${data}`); xhr.send(data); } diff --git a/packages/opentelemetry-exporter-zipkin/src/platform/node/util.ts b/packages/opentelemetry-exporter-zipkin/src/platform/node/util.ts index 1d19b8dd3d5..ca0af75886c 100644 --- a/packages/opentelemetry-exporter-zipkin/src/platform/node/util.ts +++ b/packages/opentelemetry-exporter-zipkin/src/platform/node/util.ts @@ -61,11 +61,7 @@ export function prepareSend(urlStr: string, headers?: Record): z }); res.on('end', () => { const statusCode = res.statusCode || 0; - diag.debug( - 'Zipkin response status code: %d, body: %s', - statusCode, - rawData - ); + diag.debug(`Zipkin response status code: ${statusCode}, body: ${rawData}`); // Consider 2xx and 3xx as success. if (statusCode < 400) { @@ -91,7 +87,7 @@ export function prepareSend(urlStr: string, headers?: Record): z // Issue request to remote service const payload = JSON.stringify(zipkinSpans); - diag.debug('Zipkin request payload: %s', payload); + diag.debug(`Zipkin request payload: ${payload}`); req.write(payload, 'utf8'); req.end(); }; diff --git a/packages/opentelemetry-sdk-trace-base/src/Span.ts b/packages/opentelemetry-sdk-trace-base/src/Span.ts index 429bf06e8d5..c4bd66b20cd 100644 --- a/packages/opentelemetry-sdk-trace-base/src/Span.ts +++ b/packages/opentelemetry-sdk-trace-base/src/Span.ts @@ -229,11 +229,7 @@ export class Span implements api.Span, ReadableSpan { private _isSpanEnded(): boolean { if (this._ended) { - api.diag.warn( - 'Can not execute the operation on ended Span {traceId: %s, spanId: %s}', - this._spanContext.traceId, - this._spanContext.spanId - ); + api.diag.warn(`Can not execute the operation on ended Span {traceId: ${this._spanContext.traceId}, spanId: ${this._spanContext.spanId}}`); } return this._ended; } From 9ac1d8ed34e7673cdca4b68326c3bbdbcffe9d77 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 30 Sep 2021 04:41:52 -0400 Subject: [PATCH 08/29] chore: fix cache paths for backcompat tests (#2511) --- .github/workflows/unit-test.yml | 4 ++-- .github/workflows/w3c-integration-test.yml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index e4a4a6d90ee..6352235f8bf 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -103,7 +103,7 @@ jobs: with: path: | experimental/node_modules - experimental/packages/*/node_modules + experimental/*/*/node_modules key: node-tests-experimental-${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('experimental/**/package.json') }} - name: Bootstrap @@ -143,7 +143,7 @@ jobs: with: path: | experimental/node_modules - experimental/packages/*/node_modules + experimental/*/*/node_modules key: browser-tests-experimental-${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('**/package.json') }} - name: Bootstrap diff --git a/.github/workflows/w3c-integration-test.yml b/.github/workflows/w3c-integration-test.yml index 4b514356134..f00cacf0c1e 100644 --- a/.github/workflows/w3c-integration-test.yml +++ b/.github/workflows/w3c-integration-test.yml @@ -22,7 +22,6 @@ jobs: package-lock.json packages/*/package-lock.json benchmark/*/package-lock.json - backwards-compatability/*/package-lock.json metapackages/*/package-lock.json packages/*/package-lock.json integration-tests/*/package-lock.json From a25e30a54105427f5241cfc93d34f5306be5a25f Mon Sep 17 00:00:00 2001 From: legendecas Date: Thu, 30 Sep 2021 19:58:43 +0800 Subject: [PATCH 09/29] test: add esModuleInterop compatibility test (#2506) Co-authored-by: Daniel Dyla --- experimental/backwards-compatability/node10/package.json | 2 +- experimental/backwards-compatability/node12/package.json | 2 +- experimental/backwards-compatability/node8/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/experimental/backwards-compatability/node10/package.json b/experimental/backwards-compatability/node10/package.json index 44969816b7a..140fedf95f9 100644 --- a/experimental/backwards-compatability/node10/package.json +++ b/experimental/backwards-compatability/node10/package.json @@ -5,7 +5,7 @@ "description": "Backwards compatability app for node8 types and the OpenTelemetry Node.js SDK", "main": "index.js", "scripts": { - "test:backcompat": "tsc --noEmit index.ts" + "test:backcompat": "tsc --noEmit index.ts && tsc --noEmit --esModuleInterop index.ts" }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", diff --git a/experimental/backwards-compatability/node12/package.json b/experimental/backwards-compatability/node12/package.json index afbf0d8b4a2..714edd0b402 100644 --- a/experimental/backwards-compatability/node12/package.json +++ b/experimental/backwards-compatability/node12/package.json @@ -5,7 +5,7 @@ "description": "Backwards compatability app for node8 types and the OpenTelemetry Node.js SDK", "main": "index.js", "scripts": { - "test:backcompat": "tsc --noEmit index.ts" + "test:backcompat": "tsc --noEmit index.ts && tsc --noEmit --esModuleInterop index.ts" }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", diff --git a/experimental/backwards-compatability/node8/package.json b/experimental/backwards-compatability/node8/package.json index 37a66f6652a..9e4512f884f 100644 --- a/experimental/backwards-compatability/node8/package.json +++ b/experimental/backwards-compatability/node8/package.json @@ -5,7 +5,7 @@ "description": "Backwards compatability app for node8 types and the OpenTelemetry Node.js SDK", "main": "index.js", "scripts": { - "test:backcompat": "tsc --noEmit index.ts" + "test:backcompat": "tsc --noEmit index.ts && tsc --noEmit --esModuleInterop index.ts" }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", From fa2e897587a2441205fd085772d80a0a225ee78e Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 30 Sep 2021 08:26:34 -0400 Subject: [PATCH 10/29] chore: v0.26.0 proposal (#2505) Co-authored-by: Valentin Marchaud --- CHANGELOG.md | 86 +++++++++++++++++++ .../node10/package.json | 2 +- .../node12/package.json | 2 +- .../node8/package.json | 2 +- .../package.json | 8 +- lerna.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- .../opentelemetry-context-zone/package.json | 4 +- packages/opentelemetry-core/package.json | 4 +- .../package.json | 10 +-- .../package.json | 10 +-- .../opentelemetry-propagator-b3/package.json | 4 +- .../package.json | 4 +- packages/opentelemetry-resources/package.json | 6 +- .../opentelemetry-sdk-trace-base/package.json | 8 +- .../opentelemetry-sdk-trace-node/package.json | 16 ++-- .../opentelemetry-sdk-trace-web/package.json | 14 +-- .../package.json | 2 +- .../package.json | 12 +-- packages/template/package.json | 2 +- 21 files changed, 144 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb66b2d0b16..d667b35ef9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,92 @@ All notable changes to this project will be documented in this file. ## Unreleased +## 0.26.0 + +### :boom: Breaking Change + +* `opentelemetry-exporter-collector-grpc`, `opentelemetry-exporter-otlp-grpc`, `opentelemetry-exporter-otlp-http`, `opentelemetry-exporter-otlp-proto` + * [#2476](https://github.com/open-telemetry/opentelemetry-js/pull/2476) chore!: rename collector exporters ([@dyladan](https://github.com/dyladan)) +* `opentelemetry-core`, `opentelemetry-instrumentation-grpc`, `opentelemetry-sdk-trace-base`, `opentelemetry-shim-opentracing` + * [#2429](https://github.com/open-telemetry/opentelemetry-js/pull/2429) fix!: remove 'Http' from W3C propagator names ([@aabmass](https://github.com/aabmass)) + +### :rocket: (Enhancement) + +* `opentelemetry-core`, `opentelemetry-sdk-trace-base` + * [#2430](https://github.com/open-telemetry/opentelemetry-js/pull/2430) feat(opentelemetry-sdk-trace-base): implemented general limits of attributes ([@banothurameshnaik](https://github.com/banothurameshnaik)) + * [#2418](https://github.com/open-telemetry/opentelemetry-js/pull/2418) feat(opentelemetry-sdk-trace-base): implemented option to limit length of values of attributes ([@banothurameshnaik](https://github.com/banothurameshnaik)) +* `opentelemetry-instrumentation` + * [#2450](https://github.com/open-telemetry/opentelemetry-js/pull/2450) fix: handle missing package.json file when checking for version ([@nozik](https://github.com/nozik)) +* `opentelemetry-semantic-conventions` + * [#2456](https://github.com/open-telemetry/opentelemetry-js/pull/2456) feat: upgrade semantic conventions to the latest 1.6.1 version ([@weyert](https://github.com/weyert)) +* `opentelemetry-exporter-collector-proto`, `opentelemetry-exporter-collector` + * [#2438](https://github.com/open-telemetry/opentelemetry-js/pull/2438) feat: OTEL_EXPORTER_OTLP_ENDPOINT append version and signal ([@longility](https://github.com/longility)) + +### :bug: (Bug Fix) + +* Other + * [#2494](https://github.com/open-telemetry/opentelemetry-js/pull/2494) fix: remove setting http.route in http span attributes ([@mustafain117](https://github.com/mustafain117)) +* `opentelemetry-instrumentation-fetch` + * [#2426](https://github.com/open-telemetry/opentelemetry-js/pull/2426) fix(opentelemetry-instrumentation-fetch): fixed override of headers ([@philipszalla](https://github.com/philipszalla)) +* `opentelemetry-sdk-trace-base` + * [#2434](https://github.com/open-telemetry/opentelemetry-js/pull/2434) fix: ReferenceError when OTEL_TRACES_SAMPLER used without OTEL_TRACES_SAMPLER_ARG ([@hermanbanken](https://github.com/hermanbanken)) + +### :books: (Refine Doc) + +* [#2478](https://github.com/open-telemetry/opentelemetry-js/pull/2478) Update links to packages moved to experimental ([@jessitron](https://github.com/jessitron)) +* [#2463](https://github.com/open-telemetry/opentelemetry-js/pull/2463) docs(README): Fix links in README.md ([@JamesJHPark](https://github.com/JamesJHPark)) +* [#2437](https://github.com/open-telemetry/opentelemetry-js/pull/2437) docs(examples): updated examples readme links ([@banothurameshnaik](https://github.com/banothurameshnaik)) +* [#2421](https://github.com/open-telemetry/opentelemetry-js/pull/2421) docs(website): support GH page links to canonical src ([@chalin](https://github.com/chalin)) +* [#2408](https://github.com/open-telemetry/opentelemetry-js/pull/2408) docs: make link to exporters filter only exporters ([@Rauno56](https://github.com/Rauno56)) +* [#2297](https://github.com/open-telemetry/opentelemetry-js/pull/2297) eslint configuration for getting-started examples ([@alisabzevari](https://github.com/alisabzevari)) + +### :house: (Internal) + +* `opentelemetry-exporter-otlp-http` + * [#2490](https://github.com/open-telemetry/opentelemetry-js/pull/2490) chore: mark otlp exporters experimental ([@dyladan](https://github.com/dyladan)) + * [#2491](https://github.com/open-telemetry/opentelemetry-js/pull/2491) fix: remove usage of serviceName property in tests for otel collector ([@mustafain117](https://github.com/mustafain117)) +* `opentelemetry-sdk-node` + * [#2473](https://github.com/open-telemetry/opentelemetry-js/pull/2473) chore: move sdk-node to experimental ([@dyladan](https://github.com/dyladan)) + * [#2453](https://github.com/open-telemetry/opentelemetry-js/pull/2453) chore(sdk-node): fix lint warnings ([@alisabzevari](https://github.com/alisabzevari)) +* Other + * [#2469](https://github.com/open-telemetry/opentelemetry-js/pull/2469) Drop website_docs folder ([@chalin](https://github.com/chalin)) + * [#2474](https://github.com/open-telemetry/opentelemetry-js/pull/2474) chore: move missed test file to its package ([@dyladan](https://github.com/dyladan)) + * [#2435](https://github.com/open-telemetry/opentelemetry-js/pull/2435) chore: simplify unit test cache ([@dyladan](https://github.com/dyladan)) +* `opentelemetry-context-zone`, `opentelemetry-core`, `opentelemetry-exporter-collector-grpc`, `opentelemetry-exporter-collector-proto`, `opentelemetry-exporter-collector`, `opentelemetry-exporter-prometheus`, `opentelemetry-exporter-zipkin`, `opentelemetry-instrumentation-fetch`, `opentelemetry-instrumentation-grpc`, `opentelemetry-instrumentation-http`, `opentelemetry-instrumentation-xml-http-request`, `opentelemetry-propagator-b3`, `opentelemetry-propagator-jaeger`, `opentelemetry-resources`, `opentelemetry-sdk-metrics-base`, `opentelemetry-sdk-node`, `opentelemetry-sdk-trace-base`, `opentelemetry-sdk-trace-web` + * [#2462](https://github.com/open-telemetry/opentelemetry-js/pull/2462) chore: split stable and experimental packages into groups using directories ([@dyladan](https://github.com/dyladan)) +* `opentelemetry-instrumentation-http` + * [#2126](https://github.com/open-telemetry/opentelemetry-js/pull/2126) feat(instrumentation-http): add diag debug on http request events ([@Asafb26](https://github.com/Asafb26)) + * [#2455](https://github.com/open-telemetry/opentelemetry-js/pull/2455) chore(instrumentation-http): fix lint warnings ([@alisabzevari](https://github.com/alisabzevari)) +* `opentelemetry-instrumentation-fetch` + * [#2454](https://github.com/open-telemetry/opentelemetry-js/pull/2454) chore(instrumentation-fetch): fix lint warnings ([@alisabzevari](https://github.com/alisabzevari)) +* `opentelemetry-exporter-collector` + * [#2452](https://github.com/open-telemetry/opentelemetry-js/pull/2452) chore(exporter-collector): fix lint warnings ([@alisabzevari](https://github.com/alisabzevari)) +* `opentelemetry-sdk-trace-base`, `opentelemetry-sdk-trace-node` + * [#2446](https://github.com/open-telemetry/opentelemetry-js/pull/2446) chore(sdk-trace): fix lint warnings ([@alisabzevari](https://github.com/alisabzevari)) +* `opentelemetry-exporter-prometheus`, `opentelemetry-exporter-zipkin`, `opentelemetry-shim-opentracing` + * [#2447](https://github.com/open-telemetry/opentelemetry-js/pull/2447) chore(exporter): fix lint warnings ([@alisabzevari](https://github.com/alisabzevari)) + +### Committers: 18 + +* Aaron Abbott ([@aabmass](https://github.com/aabmass)) +* Ali Sabzevari ([@alisabzevari](https://github.com/alisabzevari)) +* Asaf Ben Aharon ([@Asafb26](https://github.com/Asafb26)) +* Banothu Ramesh Naik ([@banothurameshnaik](https://github.com/banothurameshnaik)) +* Daniel Dyla ([@dyladan](https://github.com/dyladan)) +* Gerhard Stöbich ([@Flarna](https://github.com/Flarna)) +* Herman ([@hermanbanken](https://github.com/hermanbanken)) +* James ([@JamesJHPark](https://github.com/JamesJHPark)) +* Jessica Kerr ([@jessitron](https://github.com/jessitron)) +* Long Mai ([@longility](https://github.com/longility)) +* Mustafain Ali Khan ([@mustafain117](https://github.com/mustafain117)) +* Patrice Chalin ([@chalin](https://github.com/chalin)) +* Philip Szalla ([@philipszalla](https://github.com/philipszalla)) +* Ran Nozik ([@nozik](https://github.com/nozik)) +* Rauno Viskus ([@Rauno56](https://github.com/Rauno56)) +* Siim Kallas ([@seemk](https://github.com/seemk)) +* Weyert de Boer ([@weyert](https://github.com/weyert)) +* legendecas ([@legendecas](https://github.com/legendecas)) + ## 0.25.0 ### :boom: Breaking Change diff --git a/experimental/backwards-compatability/node10/package.json b/experimental/backwards-compatability/node10/package.json index 140fedf95f9..c4092f2c96a 100644 --- a/experimental/backwards-compatability/node10/package.json +++ b/experimental/backwards-compatability/node10/package.json @@ -1,6 +1,6 @@ { "name": "backcompat-node10", - "version": "0.25.0", + "version": "0.26.0", "private": true, "description": "Backwards compatability app for node8 types and the OpenTelemetry Node.js SDK", "main": "index.js", diff --git a/experimental/backwards-compatability/node12/package.json b/experimental/backwards-compatability/node12/package.json index 714edd0b402..d1b37edadd1 100644 --- a/experimental/backwards-compatability/node12/package.json +++ b/experimental/backwards-compatability/node12/package.json @@ -1,6 +1,6 @@ { "name": "backcompat-node12", - "version": "0.25.0", + "version": "0.26.0", "private": true, "description": "Backwards compatability app for node8 types and the OpenTelemetry Node.js SDK", "main": "index.js", diff --git a/experimental/backwards-compatability/node8/package.json b/experimental/backwards-compatability/node8/package.json index 9e4512f884f..f16ae85c77d 100644 --- a/experimental/backwards-compatability/node8/package.json +++ b/experimental/backwards-compatability/node8/package.json @@ -1,6 +1,6 @@ { "name": "backcompat-node8", - "version": "0.25.0", + "version": "0.26.0", "private": true, "description": "Backwards compatability app for node8 types and the OpenTelemetry Node.js SDK", "main": "index.js", diff --git a/integration-tests/propagation-validation-server/package.json b/integration-tests/propagation-validation-server/package.json index 47e540e6c5e..fbb89875970 100644 --- a/integration-tests/propagation-validation-server/package.json +++ b/integration-tests/propagation-validation-server/package.json @@ -1,6 +1,6 @@ { "name": "propagation-validation-server", - "version": "0.25.0", + "version": "0.26.0", "description": "server for w3c tests", "main": "validation_server.js", "private": true, @@ -12,9 +12,9 @@ }, "dependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.25.0", - "@opentelemetry/core": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/context-async-hooks": "0.26.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", "axios": "0.21.1", "body-parser": "1.19.0", "express": "4.17.1" diff --git a/lerna.json b/lerna.json index deedbc87c7b..1df4276420d 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.13.4", - "version": "0.25.0", + "version": "0.26.0", "npmClient": "npm", "packages": [ "benchmark/*", diff --git a/packages/opentelemetry-context-async-hooks/package.json b/packages/opentelemetry-context-async-hooks/package.json index f276c6dd191..cb065873c34 100644 --- a/packages/opentelemetry-context-async-hooks/package.json +++ b/packages/opentelemetry-context-async-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-async-hooks", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry AsyncHooks-based Context Manager", "main": "build/src/index.js", "types": "build/src/index.d.ts", diff --git a/packages/opentelemetry-context-zone-peer-dep/package.json b/packages/opentelemetry-context-zone-peer-dep/package.json index 49b8f5be455..8444c120081 100644 --- a/packages/opentelemetry-context-zone-peer-dep/package.json +++ b/packages/opentelemetry-context-zone-peer-dep/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-zone-peer-dep", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Context Zone with peer dependency for zone.js", "main": "build/src/index.js", "module": "build/esm/index.js", diff --git a/packages/opentelemetry-context-zone/package.json b/packages/opentelemetry-context-zone/package.json index d1521bc420f..44b11341ea3 100644 --- a/packages/opentelemetry-context-zone/package.json +++ b/packages/opentelemetry-context-zone/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-zone", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Context Zone", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -68,7 +68,7 @@ "webpack-merge": "5.8.0" }, "dependencies": { - "@opentelemetry/context-zone-peer-dep": "0.25.0", + "@opentelemetry/context-zone-peer-dep": "0.26.0", "zone.js": "^0.11.0" }, "sideEffects": true diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 38b843ddd12..d70dc140b58 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/core", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Core provides default and no-op implementations of the OpenTelemetry types for trace and metrics", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -84,7 +84,7 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/semantic-conventions": "0.25.0", + "@opentelemetry/semantic-conventions": "0.26.0", "semver": "^7.3.5" } } diff --git a/packages/opentelemetry-exporter-jaeger/package.json b/packages/opentelemetry-exporter-jaeger/package.json index dd36ce26922..4f69bb4a009 100644 --- a/packages/opentelemetry-exporter-jaeger/package.json +++ b/packages/opentelemetry-exporter-jaeger/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-jaeger", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Exporter Jaeger allows user to send collected traces to Jaeger", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -43,7 +43,7 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/resources": "0.25.0", + "@opentelemetry/resources": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -60,9 +60,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0", "jaeger-client": "^3.15.0" } } diff --git a/packages/opentelemetry-exporter-zipkin/package.json b/packages/opentelemetry-exporter-zipkin/package.json index 12342223f55..6b656862d0d 100644 --- a/packages/opentelemetry-exporter-zipkin/package.json +++ b/packages/opentelemetry-exporter-zipkin/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-zipkin", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Zipkin Exporter allows the user to send collected traces to Zipkin.", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -84,9 +84,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/resources": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0" + "@opentelemetry/core": "0.26.0", + "@opentelemetry/resources": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0" } } diff --git a/packages/opentelemetry-propagator-b3/package.json b/packages/opentelemetry-propagator-b3/package.json index 24fe03b7d75..aa072153478 100644 --- a/packages/opentelemetry-propagator-b3/package.json +++ b/packages/opentelemetry-propagator-b3/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/propagator-b3", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry B3 propagator provides context propagation for systems that are using the B3 header format", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -45,7 +45,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/core": "0.25.0" + "@opentelemetry/core": "0.26.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.2" diff --git a/packages/opentelemetry-propagator-jaeger/package.json b/packages/opentelemetry-propagator-jaeger/package.json index 0d793bc93e1..f4b090a6a01 100644 --- a/packages/opentelemetry-propagator-jaeger/package.json +++ b/packages/opentelemetry-propagator-jaeger/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/propagator-jaeger", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Jaeger propagator provides HTTP header propagation for systems that are using Jaeger HTTP header format.", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -75,6 +75,6 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0" + "@opentelemetry/core": "0.26.0" } } diff --git a/packages/opentelemetry-resources/package.json b/packages/opentelemetry-resources/package.json index 4e71f7f23a5..f8e85b5d02d 100644 --- a/packages/opentelemetry-resources/package.json +++ b/packages/opentelemetry-resources/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/resources", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry SDK resources", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -67,7 +67,7 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0" + "@opentelemetry/core": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0" } } diff --git a/packages/opentelemetry-sdk-trace-base/package.json b/packages/opentelemetry-sdk-trace-base/package.json index 2d7a0102bd1..fd39966f46f 100644 --- a/packages/opentelemetry-sdk-trace-base/package.json +++ b/packages/opentelemetry-sdk-trace-base/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-trace-base", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Tracing", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -82,9 +82,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/resources": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/resources": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0", "lodash.merge": "^4.6.2" } } diff --git a/packages/opentelemetry-sdk-trace-node/package.json b/packages/opentelemetry-sdk-trace-node/package.json index b8ecc09d730..f8fc7669826 100644 --- a/packages/opentelemetry-sdk-trace-node/package.json +++ b/packages/opentelemetry-sdk-trace-node/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-trace-node", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Node SDK provides automatic telemetry (tracing, metrics, etc) for Node.js applications", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -44,8 +44,8 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/resources": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0", + "@opentelemetry/resources": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/semver": "7.3.8", @@ -62,11 +62,11 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/context-async-hooks": "0.25.0", - "@opentelemetry/core": "0.25.0", - "@opentelemetry/propagator-b3": "0.25.0", - "@opentelemetry/propagator-jaeger": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/context-async-hooks": "0.26.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/propagator-b3": "0.26.0", + "@opentelemetry/propagator-jaeger": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", "semver": "^7.3.5" } } diff --git a/packages/opentelemetry-sdk-trace-web/package.json b/packages/opentelemetry-sdk-trace-web/package.json index 8e6c82616d9..d2bc2d3ea93 100644 --- a/packages/opentelemetry-sdk-trace-web/package.json +++ b/packages/opentelemetry-sdk-trace-web/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-trace-web", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Web Tracer", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -49,9 +49,9 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-zone": "0.25.0", - "@opentelemetry/propagator-b3": "0.25.0", - "@opentelemetry/resources": "0.25.0", + "@opentelemetry/context-zone": "0.26.0", + "@opentelemetry/propagator-b3": "0.26.0", + "@opentelemetry/resources": "0.26.0", "@types/jquery": "3.5.6", "@types/mocha": "8.2.3", "@types/node": "14.17.11", @@ -82,8 +82,8 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0" + "@opentelemetry/core": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0" } } diff --git a/packages/opentelemetry-semantic-conventions/package.json b/packages/opentelemetry-semantic-conventions/package.json index fda3f4f4147..29c7d52c5b0 100644 --- a/packages/opentelemetry-semantic-conventions/package.json +++ b/packages/opentelemetry-semantic-conventions/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/semantic-conventions", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry semantic conventions", "main": "build/src/index.js", "module": "build/esm/index.js", diff --git a/packages/opentelemetry-shim-opentracing/package.json b/packages/opentelemetry-shim-opentracing/package.json index 6c1348d80c1..b1dcaf40362 100644 --- a/packages/opentelemetry-shim-opentracing/package.json +++ b/packages/opentelemetry-shim-opentracing/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/shim-opentracing", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTracing to OpenTelemetry shim", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,9 +41,9 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/propagator-b3": "0.25.0", - "@opentelemetry/propagator-jaeger": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/propagator-b3": "0.26.0", + "@opentelemetry/propagator-jaeger": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "codecov": "3.8.3", @@ -57,8 +57,8 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0", "opentracing": "^0.14.4" } } diff --git a/packages/template/package.json b/packages/template/package.json index dea1646f165..9fe48822c1d 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/template", - "version": "0.25.0", + "version": "0.26.0", "private": true, "publishConfig": { "access": "restricted" From 6afe2fc3089c91bf280e158c4397fe515768beff Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 30 Sep 2021 11:40:37 -0400 Subject: [PATCH 11/29] chore(experimental): update stable deps to 26 (#2512) --- .../backwards-compatability/node10/package.json | 2 +- .../backwards-compatability/node12/package.json | 2 +- .../backwards-compatability/node8/package.json | 2 +- .../opentelemetry-exporter-otlp-grpc/package.json | 6 +++--- .../opentelemetry-exporter-otlp-http/package.json | 6 +++--- .../opentelemetry-exporter-otlp-proto/package.json | 6 +++--- .../opentelemetry-exporter-prometheus/package.json | 2 +- .../opentelemetry-instrumentation-fetch/package.json | 12 ++++++------ .../opentelemetry-instrumentation-grpc/package.json | 10 +++++----- .../test/helper.ts | 4 ++-- .../opentelemetry-instrumentation-http/package.json | 10 +++++----- .../package.json | 12 ++++++------ .../opentelemetry-sdk-metrics-base/package.json | 4 ++-- .../packages/opentelemetry-sdk-node/package.json | 10 +++++----- 14 files changed, 44 insertions(+), 44 deletions(-) diff --git a/experimental/backwards-compatability/node10/package.json b/experimental/backwards-compatability/node10/package.json index c4092f2c96a..73fdf3da6f7 100644 --- a/experimental/backwards-compatability/node10/package.json +++ b/experimental/backwards-compatability/node10/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0" + "@opentelemetry/sdk-trace-base": "0.26.0" }, "devDependencies": { "@types/node": "10.17.60", diff --git a/experimental/backwards-compatability/node12/package.json b/experimental/backwards-compatability/node12/package.json index d1b37edadd1..023b7904f0b 100644 --- a/experimental/backwards-compatability/node12/package.json +++ b/experimental/backwards-compatability/node12/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0" + "@opentelemetry/sdk-trace-base": "0.26.0" }, "devDependencies": { "@types/node": "12.20.20", diff --git a/experimental/backwards-compatability/node8/package.json b/experimental/backwards-compatability/node8/package.json index f16ae85c77d..ef00fada8a6 100644 --- a/experimental/backwards-compatability/node8/package.json +++ b/experimental/backwards-compatability/node8/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0" + "@opentelemetry/sdk-trace-base": "0.26.0" }, "devDependencies": { "@types/node": "8.10.66", diff --git a/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json index 5a2f4c86fea..ad56fe7a1dc 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json @@ -69,10 +69,10 @@ "dependencies": { "@grpc/grpc-js": "^1.3.7", "@grpc/proto-loader": "^0.6.4", - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/exporter-otlp-http": "0.25.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/resources": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0" + "@opentelemetry/resources": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0" } } diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/package.json b/experimental/packages/opentelemetry-exporter-otlp-http/package.json index 00e2bcdf767..ff5104ecc29 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-http/package.json @@ -87,9 +87,9 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.25.0", - "@opentelemetry/resources": "0.25.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/resources": "0.26.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0" + "@opentelemetry/sdk-trace-base": "0.26.0" } } diff --git a/experimental/packages/opentelemetry-exporter-otlp-proto/package.json b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json index f8fb5c5e078..fa1f6b99e0d 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-proto/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json @@ -68,11 +68,11 @@ }, "dependencies": { "@grpc/proto-loader": "^0.6.4", - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/exporter-otlp-http": "0.25.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/resources": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/resources": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", "protobufjs": "^6.9.0" } } diff --git a/experimental/packages/opentelemetry-exporter-prometheus/package.json b/experimental/packages/opentelemetry-exporter-prometheus/package.json index ec6fbb75711..fa56a5da0dc 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/package.json +++ b/experimental/packages/opentelemetry-exporter-prometheus/package.json @@ -58,7 +58,7 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/sdk-metrics-base": "0.25.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/package.json b/experimental/packages/opentelemetry-instrumentation-fetch/package.json index 97a2f00eade..3e605e8dd94 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/package.json +++ b/experimental/packages/opentelemetry-instrumentation-fetch/package.json @@ -50,9 +50,9 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-zone": "0.25.0", - "@opentelemetry/propagator-b3": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/context-zone": "0.26.0", + "@opentelemetry/propagator-b3": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -81,9 +81,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/sdk-trace-web": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0" + "@opentelemetry/sdk-trace-web": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json index f415b0db58b..3a063a6689c 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json +++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json @@ -46,10 +46,10 @@ "@grpc/grpc-js": "1.3.7", "@grpc/proto-loader": "0.6.4", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.25.0", - "@opentelemetry/core": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", - "@opentelemetry/sdk-trace-node": "0.25.0", + "@opentelemetry/context-async-hooks": "0.26.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/sdk-trace-node": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/semver": "7.3.8", @@ -71,6 +71,6 @@ "dependencies": { "@opentelemetry/api-metrics": "0.25.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0" + "@opentelemetry/semantic-conventions": "0.26.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts index 559b9acf062..5a39f3fd68c 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts +++ b/experimental/packages/opentelemetry-instrumentation-grpc/test/helper.ts @@ -19,7 +19,7 @@ import { SpanKind, propagation, trace, } from '@opentelemetry/api'; -import { HttpTraceContextPropagator } from '@opentelemetry/core'; +import { W3CTraceContextPropagator } from '@opentelemetry/core'; import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { AsyncHooksContextManager } from '@opentelemetry/context-async-hooks'; import { ContextManager } from '@opentelemetry/api'; @@ -386,7 +386,7 @@ export const runTests = ( let contextManager: ContextManager; before(() => { - propagation.setGlobalPropagator(new HttpTraceContextPropagator()); + propagation.setGlobalPropagator(new W3CTraceContextPropagator()); }); beforeEach(() => { diff --git a/experimental/packages/opentelemetry-instrumentation-http/package.json b/experimental/packages/opentelemetry-instrumentation-http/package.json index 4b2e4280671..905df05fb82 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/package.json +++ b/experimental/packages/opentelemetry-instrumentation-http/package.json @@ -44,9 +44,9 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", - "@opentelemetry/sdk-trace-node": "0.25.0", + "@opentelemetry/context-async-hooks": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/sdk-trace-node": "0.26.0", "@types/got": "9.6.12", "@types/mocha": "8.2.3", "@types/node": "14.17.11", @@ -72,9 +72,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0", + "@opentelemetry/semantic-conventions": "0.26.0", "semver": "^7.3.5" } } diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json index 29fdfbb9f63..2c7b1443541 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json @@ -50,9 +50,9 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-zone": "0.25.0", - "@opentelemetry/propagator-b3": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/context-zone": "0.26.0", + "@opentelemetry/propagator-b3": "0.26.0", + "@opentelemetry/sdk-trace-base": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -81,9 +81,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/sdk-trace-web": "0.25.0", - "@opentelemetry/semantic-conventions": "0.25.0" + "@opentelemetry/sdk-trace-web": "0.26.0", + "@opentelemetry/semantic-conventions": "0.26.0" } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/package.json b/experimental/packages/opentelemetry-sdk-metrics-base/package.json index 773ff1e9f3c..c7d7ad3114e 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/package.json +++ b/experimental/packages/opentelemetry-sdk-metrics-base/package.json @@ -64,8 +64,8 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.25.0", - "@opentelemetry/resources": "0.25.0", + "@opentelemetry/core": "0.26.0", + "@opentelemetry/resources": "0.26.0", "lodash.merge": "^4.6.2" } } diff --git a/experimental/packages/opentelemetry-sdk-node/package.json b/experimental/packages/opentelemetry-sdk-node/package.json index c4a18e84ac2..a7d25637953 100644 --- a/experimental/packages/opentelemetry-sdk-node/package.json +++ b/experimental/packages/opentelemetry-sdk-node/package.json @@ -43,21 +43,21 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.25.0", + "@opentelemetry/core": "0.26.0", "@opentelemetry/instrumentation": "0.25.0", "@opentelemetry/resource-detector-aws": "0.24.0", "@opentelemetry/resource-detector-gcp": "0.24.0", - "@opentelemetry/resources": "0.25.0", + "@opentelemetry/resources": "0.26.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", - "@opentelemetry/sdk-trace-node": "0.25.0" + "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/sdk-trace-node": "0.26.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.2" }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.25.0", + "@opentelemetry/context-async-hooks": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/semver": "7.3.8", From 69b925d142a4405c7c6bec7deadd8b4e96c7d5d6 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Thu, 30 Sep 2021 16:40:20 -0400 Subject: [PATCH 12/29] chore: v1.0.0 proposal (#2468) --- CHANGELOG.md | 4 ++++ .../propagation-validation-server/package.json | 8 ++++---- lerna.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/opentelemetry-context-zone/package.json | 4 ++-- packages/opentelemetry-core/package.json | 6 +++--- .../opentelemetry-exporter-jaeger/package.json | 10 +++++----- .../opentelemetry-exporter-zipkin/package.json | 10 +++++----- .../opentelemetry-propagator-b3/package.json | 4 ++-- .../opentelemetry-propagator-jaeger/package.json | 4 ++-- packages/opentelemetry-resources/package.json | 6 +++--- .../opentelemetry-sdk-trace-base/package.json | 8 ++++---- .../opentelemetry-sdk-trace-node/package.json | 16 ++++++++-------- .../opentelemetry-sdk-trace-web/package.json | 14 +++++++------- .../package.json | 2 +- .../opentelemetry-shim-opentracing/package.json | 12 ++++++------ packages/template/package.json | 2 +- 18 files changed, 60 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d667b35ef9e..48c1bb849f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## Unreleased +## 1.0.0 + +No changes + ## 0.26.0 ### :boom: Breaking Change diff --git a/integration-tests/propagation-validation-server/package.json b/integration-tests/propagation-validation-server/package.json index fbb89875970..7c11eb10b11 100644 --- a/integration-tests/propagation-validation-server/package.json +++ b/integration-tests/propagation-validation-server/package.json @@ -1,6 +1,6 @@ { "name": "propagation-validation-server", - "version": "0.26.0", + "version": "1.0.0", "description": "server for w3c tests", "main": "validation_server.js", "private": true, @@ -12,9 +12,9 @@ }, "dependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.26.0", - "@opentelemetry/core": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/context-async-hooks": "1.0.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "axios": "0.21.1", "body-parser": "1.19.0", "express": "4.17.1" diff --git a/lerna.json b/lerna.json index 1df4276420d..b530144ffcd 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.13.4", - "version": "0.26.0", + "version": "1.0.0", "npmClient": "npm", "packages": [ "benchmark/*", diff --git a/packages/opentelemetry-context-async-hooks/package.json b/packages/opentelemetry-context-async-hooks/package.json index cb065873c34..67b4751d957 100644 --- a/packages/opentelemetry-context-async-hooks/package.json +++ b/packages/opentelemetry-context-async-hooks/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-async-hooks", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry AsyncHooks-based Context Manager", "main": "build/src/index.js", "types": "build/src/index.d.ts", diff --git a/packages/opentelemetry-context-zone-peer-dep/package.json b/packages/opentelemetry-context-zone-peer-dep/package.json index 8444c120081..94c21e2a089 100644 --- a/packages/opentelemetry-context-zone-peer-dep/package.json +++ b/packages/opentelemetry-context-zone-peer-dep/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-zone-peer-dep", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Context Zone with peer dependency for zone.js", "main": "build/src/index.js", "module": "build/esm/index.js", diff --git a/packages/opentelemetry-context-zone/package.json b/packages/opentelemetry-context-zone/package.json index 44b11341ea3..f844a972d53 100644 --- a/packages/opentelemetry-context-zone/package.json +++ b/packages/opentelemetry-context-zone/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/context-zone", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Context Zone", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -68,7 +68,7 @@ "webpack-merge": "5.8.0" }, "dependencies": { - "@opentelemetry/context-zone-peer-dep": "0.26.0", + "@opentelemetry/context-zone-peer-dep": "1.0.0", "zone.js": "^0.11.0" }, "sideEffects": true diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index d70dc140b58..6e48dd47ec6 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -1,7 +1,7 @@ { "name": "@opentelemetry/core", - "version": "0.26.0", - "description": "OpenTelemetry Core provides default and no-op implementations of the OpenTelemetry types for trace and metrics", + "version": "1.0.0", + "description": "OpenTelemetry Core provides constants and utilities shared by all OpenTelemetry SDK packages.", "main": "build/src/index.js", "module": "build/esm/index.js", "browser": { @@ -84,7 +84,7 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/semantic-conventions": "0.26.0", + "@opentelemetry/semantic-conventions": "1.0.0", "semver": "^7.3.5" } } diff --git a/packages/opentelemetry-exporter-jaeger/package.json b/packages/opentelemetry-exporter-jaeger/package.json index 4f69bb4a009..e2988c1869a 100644 --- a/packages/opentelemetry-exporter-jaeger/package.json +++ b/packages/opentelemetry-exporter-jaeger/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-jaeger", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Exporter Jaeger allows user to send collected traces to Jaeger", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -43,7 +43,7 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/resources": "0.26.0", + "@opentelemetry/resources": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -60,9 +60,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0", "jaeger-client": "^3.15.0" } } diff --git a/packages/opentelemetry-exporter-zipkin/package.json b/packages/opentelemetry-exporter-zipkin/package.json index 6b656862d0d..653dc8a3215 100644 --- a/packages/opentelemetry-exporter-zipkin/package.json +++ b/packages/opentelemetry-exporter-zipkin/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-zipkin", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Zipkin Exporter allows the user to send collected traces to Zipkin.", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -84,9 +84,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", - "@opentelemetry/resources": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0" + "@opentelemetry/core": "1.0.0", + "@opentelemetry/resources": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/packages/opentelemetry-propagator-b3/package.json b/packages/opentelemetry-propagator-b3/package.json index aa072153478..5015c0a74bb 100644 --- a/packages/opentelemetry-propagator-b3/package.json +++ b/packages/opentelemetry-propagator-b3/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/propagator-b3", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry B3 propagator provides context propagation for systems that are using the B3 header format", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -45,7 +45,7 @@ "access": "public" }, "dependencies": { - "@opentelemetry/core": "0.26.0" + "@opentelemetry/core": "1.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.2" diff --git a/packages/opentelemetry-propagator-jaeger/package.json b/packages/opentelemetry-propagator-jaeger/package.json index f4b090a6a01..16fe0436903 100644 --- a/packages/opentelemetry-propagator-jaeger/package.json +++ b/packages/opentelemetry-propagator-jaeger/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/propagator-jaeger", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Jaeger propagator provides HTTP header propagation for systems that are using Jaeger HTTP header format.", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -75,6 +75,6 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0" + "@opentelemetry/core": "1.0.0" } } diff --git a/packages/opentelemetry-resources/package.json b/packages/opentelemetry-resources/package.json index f8e85b5d02d..2eb290aa59e 100644 --- a/packages/opentelemetry-resources/package.json +++ b/packages/opentelemetry-resources/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/resources", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry SDK resources", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -67,7 +67,7 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0" + "@opentelemetry/core": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/packages/opentelemetry-sdk-trace-base/package.json b/packages/opentelemetry-sdk-trace-base/package.json index fd39966f46f..2926cd3a6ab 100644 --- a/packages/opentelemetry-sdk-trace-base/package.json +++ b/packages/opentelemetry-sdk-trace-base/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-trace-base", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Tracing", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -82,9 +82,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", - "@opentelemetry/resources": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/resources": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0", "lodash.merge": "^4.6.2" } } diff --git a/packages/opentelemetry-sdk-trace-node/package.json b/packages/opentelemetry-sdk-trace-node/package.json index f8fc7669826..69d5195d6d1 100644 --- a/packages/opentelemetry-sdk-trace-node/package.json +++ b/packages/opentelemetry-sdk-trace-node/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-trace-node", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Node SDK provides automatic telemetry (tracing, metrics, etc) for Node.js applications", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -44,8 +44,8 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/resources": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0", + "@opentelemetry/resources": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/semver": "7.3.8", @@ -62,11 +62,11 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/context-async-hooks": "0.26.0", - "@opentelemetry/core": "0.26.0", - "@opentelemetry/propagator-b3": "0.26.0", - "@opentelemetry/propagator-jaeger": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/context-async-hooks": "1.0.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/propagator-b3": "1.0.0", + "@opentelemetry/propagator-jaeger": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "semver": "^7.3.5" } } diff --git a/packages/opentelemetry-sdk-trace-web/package.json b/packages/opentelemetry-sdk-trace-web/package.json index d2bc2d3ea93..ca9cb926434 100644 --- a/packages/opentelemetry-sdk-trace-web/package.json +++ b/packages/opentelemetry-sdk-trace-web/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-trace-web", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry Web Tracer", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -49,9 +49,9 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-zone": "0.26.0", - "@opentelemetry/propagator-b3": "0.26.0", - "@opentelemetry/resources": "0.26.0", + "@opentelemetry/context-zone": "1.0.0", + "@opentelemetry/propagator-b3": "1.0.0", + "@opentelemetry/resources": "1.0.0", "@types/jquery": "3.5.6", "@types/mocha": "8.2.3", "@types/node": "14.17.11", @@ -82,8 +82,8 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0" + "@opentelemetry/core": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/packages/opentelemetry-semantic-conventions/package.json b/packages/opentelemetry-semantic-conventions/package.json index 29c7d52c5b0..54114b923c7 100644 --- a/packages/opentelemetry-semantic-conventions/package.json +++ b/packages/opentelemetry-semantic-conventions/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/semantic-conventions", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTelemetry semantic conventions", "main": "build/src/index.js", "module": "build/esm/index.js", diff --git a/packages/opentelemetry-shim-opentracing/package.json b/packages/opentelemetry-shim-opentracing/package.json index b1dcaf40362..496657c20ab 100644 --- a/packages/opentelemetry-shim-opentracing/package.json +++ b/packages/opentelemetry-shim-opentracing/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/shim-opentracing", - "version": "0.26.0", + "version": "1.0.0", "description": "OpenTracing to OpenTelemetry shim", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -41,9 +41,9 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/propagator-b3": "0.26.0", - "@opentelemetry/propagator-jaeger": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/propagator-b3": "1.0.0", + "@opentelemetry/propagator-jaeger": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "codecov": "3.8.3", @@ -57,8 +57,8 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0", "opentracing": "^0.14.4" } } diff --git a/packages/template/package.json b/packages/template/package.json index 9fe48822c1d..861fb6c69d0 100644 --- a/packages/template/package.json +++ b/packages/template/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/template", - "version": "0.26.0", + "version": "1.0.0", "private": true, "publishConfig": { "access": "restricted" From d15127c95121615e7926aa86ffde1539fc78aba1 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Fri, 1 Oct 2021 11:05:19 -0400 Subject: [PATCH 13/29] chore: update stable dependencies to 1.0 (#2514) --- .../backwards-compatability/node10/package.json | 2 +- .../backwards-compatability/node12/package.json | 2 +- .../backwards-compatability/node8/package.json | 2 +- .../opentelemetry-exporter-otlp-grpc/package.json | 6 +++--- .../opentelemetry-exporter-otlp-http/package.json | 6 +++--- .../opentelemetry-exporter-otlp-proto/package.json | 6 +++--- .../opentelemetry-exporter-prometheus/package.json | 2 +- .../opentelemetry-instrumentation-fetch/package.json | 12 ++++++------ .../opentelemetry-instrumentation-grpc/package.json | 10 +++++----- .../opentelemetry-instrumentation-http/package.json | 10 +++++----- .../package.json | 12 ++++++------ .../opentelemetry-sdk-metrics-base/package.json | 4 ++-- .../packages/opentelemetry-sdk-node/package.json | 10 +++++----- 13 files changed, 42 insertions(+), 42 deletions(-) diff --git a/experimental/backwards-compatability/node10/package.json b/experimental/backwards-compatability/node10/package.json index 73fdf3da6f7..6d64e17467f 100644 --- a/experimental/backwards-compatability/node10/package.json +++ b/experimental/backwards-compatability/node10/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.26.0" + "@opentelemetry/sdk-trace-base": "1.0.0" }, "devDependencies": { "@types/node": "10.17.60", diff --git a/experimental/backwards-compatability/node12/package.json b/experimental/backwards-compatability/node12/package.json index 023b7904f0b..2d85338a9a1 100644 --- a/experimental/backwards-compatability/node12/package.json +++ b/experimental/backwards-compatability/node12/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.26.0" + "@opentelemetry/sdk-trace-base": "1.0.0" }, "devDependencies": { "@types/node": "12.20.20", diff --git a/experimental/backwards-compatability/node8/package.json b/experimental/backwards-compatability/node8/package.json index ef00fada8a6..61a831de63c 100644 --- a/experimental/backwards-compatability/node8/package.json +++ b/experimental/backwards-compatability/node8/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@opentelemetry/sdk-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.26.0" + "@opentelemetry/sdk-trace-base": "1.0.0" }, "devDependencies": { "@types/node": "8.10.66", diff --git a/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json index ad56fe7a1dc..880f00f2071 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json @@ -69,10 +69,10 @@ "dependencies": { "@grpc/grpc-js": "^1.3.7", "@grpc/proto-loader": "^0.6.4", - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/exporter-otlp-http": "0.25.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/resources": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0" + "@opentelemetry/resources": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/package.json b/experimental/packages/opentelemetry-exporter-otlp-http/package.json index ff5104ecc29..6cfeb26df2f 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-http/package.json @@ -87,9 +87,9 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.26.0", - "@opentelemetry/resources": "0.26.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/resources": "1.0.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.26.0" + "@opentelemetry/sdk-trace-base": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-exporter-otlp-proto/package.json b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json index fa1f6b99e0d..106142e27cf 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-proto/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json @@ -68,11 +68,11 @@ }, "dependencies": { "@grpc/proto-loader": "^0.6.4", - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/exporter-otlp-http": "0.25.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/resources": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/resources": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "protobufjs": "^6.9.0" } } diff --git a/experimental/packages/opentelemetry-exporter-prometheus/package.json b/experimental/packages/opentelemetry-exporter-prometheus/package.json index fa56a5da0dc..55e02c2cc04 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/package.json +++ b/experimental/packages/opentelemetry-exporter-prometheus/package.json @@ -58,7 +58,7 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/sdk-metrics-base": "0.25.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/package.json b/experimental/packages/opentelemetry-instrumentation-fetch/package.json index 3e605e8dd94..1fdd8290e1c 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/package.json +++ b/experimental/packages/opentelemetry-instrumentation-fetch/package.json @@ -50,9 +50,9 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-zone": "0.26.0", - "@opentelemetry/propagator-b3": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/context-zone": "1.0.0", + "@opentelemetry/propagator-b3": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -81,9 +81,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/sdk-trace-web": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0" + "@opentelemetry/sdk-trace-web": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json index 3a063a6689c..fdc2f3b04b0 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json +++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json @@ -46,10 +46,10 @@ "@grpc/grpc-js": "1.3.7", "@grpc/proto-loader": "0.6.4", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.26.0", - "@opentelemetry/core": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", - "@opentelemetry/sdk-trace-node": "0.26.0", + "@opentelemetry/context-async-hooks": "1.0.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", + "@opentelemetry/sdk-trace-node": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/semver": "7.3.8", @@ -71,6 +71,6 @@ "dependencies": { "@opentelemetry/api-metrics": "0.25.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/semantic-conventions": "0.26.0" + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-http/package.json b/experimental/packages/opentelemetry-instrumentation-http/package.json index 905df05fb82..4bd25b04b19 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/package.json +++ b/experimental/packages/opentelemetry-instrumentation-http/package.json @@ -44,9 +44,9 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", - "@opentelemetry/sdk-trace-node": "0.26.0", + "@opentelemetry/context-async-hooks": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", + "@opentelemetry/sdk-trace-node": "1.0.0", "@types/got": "9.6.12", "@types/mocha": "8.2.3", "@types/node": "14.17.11", @@ -72,9 +72,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/semantic-conventions": "0.26.0", + "@opentelemetry/semantic-conventions": "1.0.0", "semver": "^7.3.5" } } diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json index 2c7b1443541..2d130b599e2 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json @@ -50,9 +50,9 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-zone": "0.26.0", - "@opentelemetry/propagator-b3": "0.26.0", - "@opentelemetry/sdk-trace-base": "0.26.0", + "@opentelemetry/context-zone": "1.0.0", + "@opentelemetry/propagator-b3": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -81,9 +81,9 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/sdk-trace-web": "0.26.0", - "@opentelemetry/semantic-conventions": "0.26.0" + "@opentelemetry/sdk-trace-web": "1.0.0", + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/package.json b/experimental/packages/opentelemetry-sdk-metrics-base/package.json index c7d7ad3114e..b7d3a5f578b 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/package.json +++ b/experimental/packages/opentelemetry-sdk-metrics-base/package.json @@ -64,8 +64,8 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.26.0", - "@opentelemetry/resources": "0.26.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/resources": "1.0.0", "lodash.merge": "^4.6.2" } } diff --git a/experimental/packages/opentelemetry-sdk-node/package.json b/experimental/packages/opentelemetry-sdk-node/package.json index a7d25637953..b706f72648d 100644 --- a/experimental/packages/opentelemetry-sdk-node/package.json +++ b/experimental/packages/opentelemetry-sdk-node/package.json @@ -43,21 +43,21 @@ }, "dependencies": { "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/core": "0.26.0", + "@opentelemetry/core": "1.0.0", "@opentelemetry/instrumentation": "0.25.0", "@opentelemetry/resource-detector-aws": "0.24.0", "@opentelemetry/resource-detector-gcp": "0.24.0", - "@opentelemetry/resources": "0.26.0", + "@opentelemetry/resources": "1.0.0", "@opentelemetry/sdk-metrics-base": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.26.0", - "@opentelemetry/sdk-trace-node": "0.26.0" + "@opentelemetry/sdk-trace-base": "1.0.0", + "@opentelemetry/sdk-trace-node": "1.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.2" }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/context-async-hooks": "0.26.0", + "@opentelemetry/context-async-hooks": "1.0.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/semver": "7.3.8", From f29434b0a3304bce5b92953a16e489cc24ada2e2 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Fri, 1 Oct 2021 13:55:55 -0400 Subject: [PATCH 14/29] chore: inline sources in source maps (#2488) * chore: inline sources in source maps * chore: sort tsconfig options Co-authored-by: Nev <54870357+MSNev@users.noreply.github.com> Co-authored-by: Valentin Marchaud --- tsconfig.base.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tsconfig.base.json b/tsconfig.base.json index b2d1a3bd96f..2d628cad8de 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -6,19 +6,20 @@ "declaration": true, "declarationMap": true, "forceConsistentCasingInFileNames": true, + "incremental": true, + "inlineSources": true, "module": "commonjs", + "newLine": "LF", "noEmitOnError": true, "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, "noImplicitReturns": true, "noUnusedLocals": true, - "noImplicitOverride": true, "pretty": true, "sourceMap": true, "strict": true, "strictNullChecks": true, - "target": "es2017", - "incremental": true, - "newLine": "LF" + "target": "es2017" }, "exclude": [ "node_modules" From 52d3f9b20e48f25e1283b634c08dfd0aba156de9 Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Mon, 4 Oct 2021 09:58:59 +0200 Subject: [PATCH 15/29] fix(deps): update opentelemetry-js monorepo to v1 (major) (#2516) --- getting-started/traced-example/package.json | 8 ++++---- getting-started/ts-example/traced-example/package.json | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/getting-started/traced-example/package.json b/getting-started/traced-example/package.json index b51de03f72c..8268cd9ddc8 100644 --- a/getting-started/traced-example/package.json +++ b/getting-started/traced-example/package.json @@ -9,13 +9,13 @@ "author": "OpenTelemetry Authors", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/exporter-zipkin": "0.25.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/exporter-zipkin": "1.0.0", "@opentelemetry/instrumentation-express": "^0.24.0", "@opentelemetry/instrumentation-http": "0.25.0", "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/sdk-trace-node": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/sdk-trace-node": "1.0.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "axios": "^0.21.0", "express": "^4.17.1" } diff --git a/getting-started/ts-example/traced-example/package.json b/getting-started/ts-example/traced-example/package.json index 3739e79b062..f157176404f 100644 --- a/getting-started/ts-example/traced-example/package.json +++ b/getting-started/ts-example/traced-example/package.json @@ -14,13 +14,13 @@ "ts-node": "10.2.1" }, "dependencies": { - "@opentelemetry/core": "0.25.0", - "@opentelemetry/exporter-zipkin": "0.25.0", + "@opentelemetry/core": "1.0.0", + "@opentelemetry/exporter-zipkin": "1.0.0", "@opentelemetry/instrumentation": "0.25.0", "@opentelemetry/instrumentation-express": "^0.24.0", - "@opentelemetry/sdk-trace-node": "0.25.0", + "@opentelemetry/sdk-trace-node": "1.0.0", "@opentelemetry/instrumentation-http": "0.25.0", - "@opentelemetry/sdk-trace-base": "0.25.0", + "@opentelemetry/sdk-trace-base": "1.0.0", "axios": "^0.21.0", "express": "^4.17.1" } From 0f5a5bc906a2166c30a4344e460b7206c0b20bac Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 5 Oct 2021 13:15:49 -0400 Subject: [PATCH 16/29] chore(experimental): v0.26.0 proposal (#2513) --- README.md | 36 ++++++++++--------- .../node10/package.json | 2 +- .../node12/package.json | 2 +- .../node8/package.json | 2 +- experimental/lerna.json | 2 +- .../opentelemetry-api-metrics/package.json | 2 +- .../package.json | 8 ++--- .../package.json | 6 ++-- .../package.json | 8 ++--- .../package.json | 6 ++-- .../package.json | 4 +-- .../package.json | 6 ++-- .../package.json | 4 +-- .../package.json | 4 +-- .../package.json | 4 +-- .../package.json | 4 +-- .../opentelemetry-sdk-node/package.json | 8 ++--- 17 files changed, 55 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index d0e06cc564e..d5e2f0d9173 100644 --- a/README.md +++ b/README.md @@ -47,23 +47,25 @@ This is the JavaScript version of [OpenTelemetry](https://opentelemetry.io/), a ## Compatibility Matrix -| API Version | Core version | Contrib Version | -| ----------- |--------------|-------------------------| -| 1.0.x | 0.25.x | ------ | -| 1.0.x | 0.24.x | 0.24.x | -| 1.0.x | 0.23.x | 0.23.x | -| 1.0.x | 0.22.x | 0.22.x | -| 0.21.x | 0.21.x | 0.21.x | -| 0.20.x | 0.20.x | 0.20.x | -| v1.0.0-rc.3 | 0.19.x | 0.16.x | -| 0.18.x | 0.18.x | 0.14.x | -| | 0.17.x | ------ | -| | 0.16.x | ------ | -| | 0.15.x | 0.13.x | -| | 0.14.x | 0.12.x | -| | 0.13.x | ------ | -| | 0.12.x | 0.11.x | -| | 0.11.x | 0.10.x | +| API Version | Core version | Experimental Packages | Contrib Version | +| ----------- |--------------| --------------------- |-------------------------| +| 1.0.x | 1.x | 0.26.x | ------ | +| 1.0.x | 0.26.x | ----- | ------ | +| 1.0.x | 0.25.x | ----- | ------ | +| 1.0.x | 0.24.x | ----- | 0.24.x | +| 1.0.x | 0.23.x | ----- | 0.23.x | +| 1.0.x | 0.22.x | ----- | 0.22.x | +| 0.21.x | 0.21.x | ----- | 0.21.x | +| 0.20.x | 0.20.x | ----- | 0.20.x | +| v1.0.0-rc.3 | 0.19.x | ----- | 0.16.x | +| 0.18.x | 0.18.x | ----- | 0.14.x | +| | 0.17.x | ----- | ------ | +| | 0.16.x | ----- | ------ | +| | 0.15.x | ----- | 0.13.x | +| | 0.14.x | ----- | 0.12.x | +| | 0.13.x | ----- | ------ | +| | 0.12.x | ----- | 0.11.x | +| | 0.11.x | ----- | 0.10.x | ## Versioning diff --git a/experimental/backwards-compatability/node10/package.json b/experimental/backwards-compatability/node10/package.json index 6d64e17467f..6f1fbd01829 100644 --- a/experimental/backwards-compatability/node10/package.json +++ b/experimental/backwards-compatability/node10/package.json @@ -8,7 +8,7 @@ "test:backcompat": "tsc --noEmit index.ts && tsc --noEmit --esModuleInterop index.ts" }, "dependencies": { - "@opentelemetry/sdk-node": "0.25.0", + "@opentelemetry/sdk-node": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0" }, "devDependencies": { diff --git a/experimental/backwards-compatability/node12/package.json b/experimental/backwards-compatability/node12/package.json index 2d85338a9a1..ca9bc34ae72 100644 --- a/experimental/backwards-compatability/node12/package.json +++ b/experimental/backwards-compatability/node12/package.json @@ -8,7 +8,7 @@ "test:backcompat": "tsc --noEmit index.ts && tsc --noEmit --esModuleInterop index.ts" }, "dependencies": { - "@opentelemetry/sdk-node": "0.25.0", + "@opentelemetry/sdk-node": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0" }, "devDependencies": { diff --git a/experimental/backwards-compatability/node8/package.json b/experimental/backwards-compatability/node8/package.json index 61a831de63c..e5607fcf77d 100644 --- a/experimental/backwards-compatability/node8/package.json +++ b/experimental/backwards-compatability/node8/package.json @@ -8,7 +8,7 @@ "test:backcompat": "tsc --noEmit index.ts && tsc --noEmit --esModuleInterop index.ts" }, "dependencies": { - "@opentelemetry/sdk-node": "0.25.0", + "@opentelemetry/sdk-node": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0" }, "devDependencies": { diff --git a/experimental/lerna.json b/experimental/lerna.json index c8010cca0c9..dd8377ce722 100644 --- a/experimental/lerna.json +++ b/experimental/lerna.json @@ -1,6 +1,6 @@ { "lerna": "3.13.4", - "version": "0.25.0", + "version": "0.26.0", "npmClient": "npm", "packages": [ "packages/*", diff --git a/experimental/packages/opentelemetry-api-metrics/package.json b/experimental/packages/opentelemetry-api-metrics/package.json index 83950b2687b..5cb9e1503b4 100644 --- a/experimental/packages/opentelemetry-api-metrics/package.json +++ b/experimental/packages/opentelemetry-api-metrics/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/api-metrics", - "version": "0.25.0", + "version": "0.26.0", "description": "Public metrics API for OpenTelemetry", "main": "build/src/index.js", "module": "build/esm/index.js", diff --git a/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json index 880f00f2071..0e169d818b4 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-otlp-grpc", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -49,7 +49,7 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -70,9 +70,9 @@ "@grpc/grpc-js": "^1.3.7", "@grpc/proto-loader": "^0.6.4", "@opentelemetry/core": "1.0.0", - "@opentelemetry/exporter-otlp-http": "0.25.0", - "@opentelemetry/sdk-metrics-base": "0.25.0", + "@opentelemetry/exporter-otlp-http": "0.26.0", "@opentelemetry/resources": "1.0.0", + "@opentelemetry/sdk-metrics-base": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/package.json b/experimental/packages/opentelemetry-exporter-otlp-http/package.json index 6cfeb26df2f..91399c51a8d 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-http/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-otlp-http", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -86,10 +86,10 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "@opentelemetry/core": "1.0.0", "@opentelemetry/resources": "1.0.0", - "@opentelemetry/sdk-metrics-base": "0.25.0", + "@opentelemetry/sdk-metrics-base": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-exporter-otlp-proto/package.json b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json index 106142e27cf..a8f7ff5afa7 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-proto/package.json +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-otlp-proto", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Collector Exporter allows user to send collected traces to the OpenTelemetry Collector using protobuf over HTTP", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -49,7 +49,7 @@ "devDependencies": { "@babel/core": "7.15.0", "@opentelemetry/api": "^1.0.2", - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -69,9 +69,9 @@ "dependencies": { "@grpc/proto-loader": "^0.6.4", "@opentelemetry/core": "1.0.0", - "@opentelemetry/exporter-otlp-http": "0.25.0", - "@opentelemetry/sdk-metrics-base": "0.25.0", + "@opentelemetry/exporter-otlp-http": "0.26.0", "@opentelemetry/resources": "1.0.0", + "@opentelemetry/sdk-metrics-base": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0", "protobufjs": "^6.9.0" } diff --git a/experimental/packages/opentelemetry-exporter-prometheus/package.json b/experimental/packages/opentelemetry-exporter-prometheus/package.json index 55e02c2cc04..a8af029d50e 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/package.json +++ b/experimental/packages/opentelemetry-exporter-prometheus/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/exporter-prometheus", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry Exporter Prometheus provides a metrics endpoint for Prometheus", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -57,8 +57,8 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "@opentelemetry/core": "1.0.0", - "@opentelemetry/sdk-metrics-base": "0.25.0" + "@opentelemetry/sdk-metrics-base": "0.26.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/package.json b/experimental/packages/opentelemetry-instrumentation-fetch/package.json index 1fdd8290e1c..40b652afb5d 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/package.json +++ b/experimental/packages/opentelemetry-instrumentation-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation-fetch", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry fetch automatic instrumentation package.", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -82,7 +82,7 @@ }, "dependencies": { "@opentelemetry/core": "1.0.0", - "@opentelemetry/instrumentation": "0.25.0", + "@opentelemetry/instrumentation": "0.26.0", "@opentelemetry/sdk-trace-web": "1.0.0", "@opentelemetry/semantic-conventions": "1.0.0" } diff --git a/experimental/packages/opentelemetry-instrumentation-grpc/package.json b/experimental/packages/opentelemetry-instrumentation-grpc/package.json index fdc2f3b04b0..158588b7fbc 100644 --- a/experimental/packages/opentelemetry-instrumentation-grpc/package.json +++ b/experimental/packages/opentelemetry-instrumentation-grpc/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation-grpc", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry grpc automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -69,8 +69,8 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/api-metrics": "0.25.0", - "@opentelemetry/instrumentation": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", + "@opentelemetry/instrumentation": "0.26.0", "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/experimental/packages/opentelemetry-instrumentation-http/package.json b/experimental/packages/opentelemetry-instrumentation-http/package.json index 4bd25b04b19..41abcbab84b 100644 --- a/experimental/packages/opentelemetry-instrumentation-http/package.json +++ b/experimental/packages/opentelemetry-instrumentation-http/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation-http", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry http/https automatic instrumentation package.", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -73,7 +73,7 @@ }, "dependencies": { "@opentelemetry/core": "1.0.0", - "@opentelemetry/instrumentation": "0.25.0", + "@opentelemetry/instrumentation": "0.26.0", "@opentelemetry/semantic-conventions": "1.0.0", "semver": "^7.3.5" } diff --git a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json index 2d130b599e2..66d3c85f331 100644 --- a/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json +++ b/experimental/packages/opentelemetry-instrumentation-xml-http-request/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation-xml-http-request", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry XMLHttpRequest automatic instrumentation package.", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -82,7 +82,7 @@ }, "dependencies": { "@opentelemetry/core": "1.0.0", - "@opentelemetry/instrumentation": "0.25.0", + "@opentelemetry/instrumentation": "0.26.0", "@opentelemetry/sdk-trace-web": "1.0.0", "@opentelemetry/semantic-conventions": "1.0.0" } diff --git a/experimental/packages/opentelemetry-instrumentation/package.json b/experimental/packages/opentelemetry-instrumentation/package.json index a4b21cc46f1..7204d0e3911 100644 --- a/experimental/packages/opentelemetry-instrumentation/package.json +++ b/experimental/packages/opentelemetry-instrumentation/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/instrumentation", - "version": "0.25.0", + "version": "0.26.0", "description": "Base class for node which OpenTelemetry instrumentation modules extend", "author": "OpenTelemetry Authors", "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme", @@ -61,7 +61,7 @@ "url": "https://github.com/open-telemetry/opentelemetry-js/issues" }, "dependencies": { - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "require-in-the-middle": "^5.0.3", "semver": "^7.3.2", "shimmer": "^1.2.1" diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/package.json b/experimental/packages/opentelemetry-sdk-metrics-base/package.json index b7d3a5f578b..862e167d1d7 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/package.json +++ b/experimental/packages/opentelemetry-sdk-metrics-base/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-metrics-base", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry metrics SDK", "main": "build/src/index.js", "module": "build/esm/index.js", @@ -63,7 +63,7 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "@opentelemetry/core": "1.0.0", "@opentelemetry/resources": "1.0.0", "lodash.merge": "^4.6.2" diff --git a/experimental/packages/opentelemetry-sdk-node/package.json b/experimental/packages/opentelemetry-sdk-node/package.json index b706f72648d..dddf6d0845f 100644 --- a/experimental/packages/opentelemetry-sdk-node/package.json +++ b/experimental/packages/opentelemetry-sdk-node/package.json @@ -1,6 +1,6 @@ { "name": "@opentelemetry/sdk-node", - "version": "0.25.0", + "version": "0.26.0", "description": "OpenTelemetry SDK for Node.js", "main": "build/src/index.js", "types": "build/src/index.d.ts", @@ -42,13 +42,13 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api-metrics": "0.25.0", + "@opentelemetry/api-metrics": "0.26.0", "@opentelemetry/core": "1.0.0", - "@opentelemetry/instrumentation": "0.25.0", + "@opentelemetry/instrumentation": "0.26.0", "@opentelemetry/resource-detector-aws": "0.24.0", "@opentelemetry/resource-detector-gcp": "0.24.0", "@opentelemetry/resources": "1.0.0", - "@opentelemetry/sdk-metrics-base": "0.25.0", + "@opentelemetry/sdk-metrics-base": "0.26.0", "@opentelemetry/sdk-trace-base": "1.0.0", "@opentelemetry/sdk-trace-node": "1.0.0" }, From 0c7f1c3ae9b8fcc0b7943c074319ef6c0265cb12 Mon Sep 17 00:00:00 2001 From: Weyert de Boer Date: Sat, 9 Oct 2021 14:45:43 +0100 Subject: [PATCH 17/29] feat: upgrade semantic-conventions to latest v1.7.0 spec (#2528) Co-authored-by: Weyert de Boer --- .../src/trace/SemanticAttributes.ts | 53 ++++++++++++++++++- scripts/semconv/generate.sh | 4 +- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts b/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts index eb7260c0738..48fecf29bed 100644 --- a/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts +++ b/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts @@ -372,7 +372,9 @@ clear whether the exception will escape. HTTP_TARGET: 'http.target', /** - * The value of the [HTTP host header](https://tools.ietf.org/html/rfc7230#section-5.4). When the header is empty or not present, this attribute should be the same. + * The value of the [HTTP host header](https://tools.ietf.org/html/rfc7230#section-5.4). An empty Host header should also be reported, see note. + * + * Note: When the header is present but empty the attribute SHOULD be set to the empty string. Note that this is a valid situation that is expected in certain cases, according the aforementioned [section of RFC 7230](https://tools.ietf.org/html/rfc7230#section-5.4). When the header is not set the attribute MUST NOT be set. */ HTTP_HOST: 'http.host', @@ -433,7 +435,17 @@ clear whether the exception will escape. /** * The IP address of the original client behind all proxies, if known (e.g. from [X-Forwarded-For](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)). * - * Note: This is not necessarily the same as `net.peer.ip`, which would identify the network-level peer, which may be a proxy. + * Note: This is not necessarily the same as `net.peer.ip`, which would +identify the network-level peer, which may be a proxy. + +This attribute should be set when a source of information different +from the one used for `net.peer.ip`, is available even if that other +source just confirms the same value as `net.peer.ip`. +Rationale: For `net.peer.ip`, one typically does not know if it +comes from a proxy, reverse proxy, or the actual client. Setting +`http.client_ip` when it's the same as `net.peer.ip` means that +one is at least somewhat confident that the address is not that of +the closest proxy. */ HTTP_CLIENT_IP: 'http.client_ip', @@ -607,6 +619,11 @@ clear whether the exception will escape. */ MESSAGING_OPERATION: 'messaging.operation', + /** + * The identifier for the consumer receiving a message. For Kafka, set it to `{messaging.kafka.consumer_group} - {messaging.kafka.client_id}`, if both are present, or only `messaging.kafka.consumer_group`. For brokers, such as RabbitMQ and Artemis, set it to the `client_id` of the client consuming the message. + */ + MESSAGING_CONSUMER_ID: 'messaging.consumer_id', + /** * RabbitMQ message routing key. */ @@ -682,6 +699,28 @@ clear whether the exception will escape. * `error.message` property of response if it is an error response. */ RPC_JSONRPC_ERROR_MESSAGE: 'rpc.jsonrpc.error_message', + + /** + * Whether this is a received or sent message. + */ + MESSAGE_TYPE: 'message.type', + + /** + * MUST be calculated as two different counters starting from `1` one for sent messages and one for received message. + * + * Note: This way we guarantee that the values will be consistent between different implementations. + */ + MESSAGE_ID: 'message.id', + + /** + * Compressed size of the message in bytes. + */ + MESSAGE_COMPRESSED_SIZE: 'message.compressed_size', + + /** + * Uncompressed size of the message in bytes. + */ + MESSAGE_UNCOMPRESSED_SIZE: 'message.uncompressed_size', } // Enum definitions @@ -1014,3 +1053,13 @@ export enum RpcGrpcStatusCodeValues { UNAUTHENTICATED = 16, } + + + +export enum MessageTypeValues { + /** sent. */ + SENT = 'SENT', + /** received. */ + RECEIVED = 'RECEIVED', +} + diff --git a/scripts/semconv/generate.sh b/scripts/semconv/generate.sh index 89718f52e1b..dbd99464eac 100755 --- a/scripts/semconv/generate.sh +++ b/scripts/semconv/generate.sh @@ -4,8 +4,8 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" ROOT_DIR="${SCRIPT_DIR}/../../" # freeze the spec version to make SpanAttributess generation reproducible -SPEC_VERSION=v1.6.1 -GENERATOR_VERSION=0.5.0 +SPEC_VERSION=v1.7.0 +GENERATOR_VERSION=0.7.0 cd ${SCRIPT_DIR} From 8d433248711804f2e06e32e7b0cbe9957494978f Mon Sep 17 00:00:00 2001 From: t2t2 Date: Sat, 9 Oct 2021 16:57:36 +0300 Subject: [PATCH 18/29] fix(exporter-zipkin): correct status tags names (#2519) Co-authored-by: Valentin Marchaud --- .../src/transform.ts | 18 +++++++++-------- .../src/zipkin.ts | 4 ++-- .../test/common/transform.test.ts | 20 ++++++++----------- .../test/helper.ts | 2 +- .../test/node/zipkin.test.ts | 4 ++-- 5 files changed, 23 insertions(+), 25 deletions(-) diff --git a/packages/opentelemetry-exporter-zipkin/src/transform.ts b/packages/opentelemetry-exporter-zipkin/src/transform.ts index 64e4b48bbf6..9ffd48ecce7 100644 --- a/packages/opentelemetry-exporter-zipkin/src/transform.ts +++ b/packages/opentelemetry-exporter-zipkin/src/transform.ts @@ -29,8 +29,8 @@ const ZIPKIN_SPAN_KIND_MAPPING = { [api.SpanKind.INTERNAL]: undefined, }; -export const defaultStatusCodeTagName = 'ot.status_code'; -export const defaultStatusDescriptionTagName = 'ot.status_description'; +export const defaultStatusCodeTagName = 'otel.status_code'; +export const defaultStatusErrorTagName = 'error'; /** * Translate OpenTelemetry ReadableSpan to ZipkinSpan format @@ -40,7 +40,7 @@ export function toZipkinSpan( span: ReadableSpan, serviceName: string, statusCodeTagName: string, - statusDescriptionTagName: string + statusErrorTagName: string ): zipkinTypes.Span { const zipkinSpan: zipkinTypes.Span = { traceId: span.spanContext().traceId, @@ -55,7 +55,7 @@ export function toZipkinSpan( span.attributes, span.status, statusCodeTagName, - statusDescriptionTagName, + statusErrorTagName, span.resource ), annotations: span.events.length @@ -71,16 +71,18 @@ export function _toZipkinTags( attributes: api.SpanAttributes, status: api.SpanStatus, statusCodeTagName: string, - statusDescriptionTagName: string, + statusErrorTagName: string, resource: Resource ): zipkinTypes.Tags { const tags: { [key: string]: string } = {}; for (const key of Object.keys(attributes)) { tags[key] = String(attributes[key]); } - tags[statusCodeTagName] = String(api.SpanStatusCode[status.code]); - if (status.message) { - tags[statusDescriptionTagName] = status.message; + if (status.code !== api.SpanStatusCode.UNSET) { + tags[statusCodeTagName] = String(api.SpanStatusCode[status.code]); + } + if (status.code === api.SpanStatusCode.ERROR && status.message) { + tags[statusErrorTagName] = status.message; } Object.keys(resource.attributes).forEach( diff --git a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts index ef43cff0f89..614d728cb5b 100644 --- a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts +++ b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts @@ -22,7 +22,7 @@ import * as zipkinTypes from './types'; import { toZipkinSpan, defaultStatusCodeTagName, - defaultStatusDescriptionTagName, + defaultStatusErrorTagName, } from './transform'; import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { prepareGetHeaders } from './utils'; @@ -47,7 +47,7 @@ export class ZipkinExporter implements SpanExporter { this._serviceName = config.serviceName; this._statusCodeTagName = config.statusCodeTagName || defaultStatusCodeTagName; this._statusDescriptionTagName = - config.statusDescriptionTagName || defaultStatusDescriptionTagName; + config.statusDescriptionTagName || defaultStatusErrorTagName; this._isShutdown = false; if (typeof config.getExportRequestHeaders === 'function') { this._getHeaders = prepareGetHeaders(config.getExportRequestHeaders); diff --git a/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts index ca8d37aa752..3c7b5a5ddb2 100644 --- a/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts @@ -26,7 +26,7 @@ import * as assert from 'assert'; import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { defaultStatusCodeTagName, - defaultStatusDescriptionTagName, + defaultStatusErrorTagName, toZipkinSpan, _toZipkinAnnotations, _toZipkinTags, @@ -79,7 +79,7 @@ describe('transform', () => { span, 'my-service', defaultStatusCodeTagName, - defaultStatusDescriptionTagName + defaultStatusErrorTagName ); assert.deepStrictEqual(zipkinSpan, { kind: 'SERVER', @@ -101,7 +101,6 @@ describe('transform', () => { tags: { key1: 'value1', key2: 'value2', - [defaultStatusCodeTagName]: 'UNSET', [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', @@ -125,7 +124,7 @@ describe('transform', () => { span, 'my-service', defaultStatusCodeTagName, - defaultStatusDescriptionTagName + defaultStatusErrorTagName ); assert.deepStrictEqual(zipkinSpan, { kind: 'SERVER', @@ -140,7 +139,6 @@ describe('transform', () => { name: span.name, parentId: undefined, tags: { - [defaultStatusCodeTagName]: 'UNSET', [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', @@ -174,7 +172,7 @@ describe('transform', () => { span, 'my-service', defaultStatusCodeTagName, - defaultStatusDescriptionTagName + defaultStatusErrorTagName ); assert.deepStrictEqual(zipkinSpan, { kind: item.zipkin, @@ -189,7 +187,6 @@ describe('transform', () => { name: span.name, parentId: undefined, tags: { - [defaultStatusCodeTagName]: 'UNSET', [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', @@ -220,14 +217,13 @@ describe('transform', () => { span.attributes, span.status, defaultStatusCodeTagName, - defaultStatusDescriptionTagName, + defaultStatusErrorTagName, DUMMY_RESOURCE ); assert.deepStrictEqual(tags, { key1: 'value1', key2: 'value2', - [defaultStatusCodeTagName]: 'UNSET', cost: '112.12', service: 'ui', version: '1', @@ -255,7 +251,7 @@ describe('transform', () => { span.attributes, span.status, defaultStatusCodeTagName, - defaultStatusDescriptionTagName, + defaultStatusErrorTagName, Resource.empty().merge( new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', @@ -292,7 +288,7 @@ describe('transform', () => { span.attributes, span.status, defaultStatusCodeTagName, - defaultStatusDescriptionTagName, + defaultStatusErrorTagName, Resource.empty().merge( new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', @@ -304,7 +300,7 @@ describe('transform', () => { key1: 'value1', key2: 'value2', [defaultStatusCodeTagName]: 'ERROR', - [defaultStatusDescriptionTagName]: status.message, + [defaultStatusErrorTagName]: status.message, [SemanticResourceAttributes.SERVICE_NAME]: 'zipkin-test', }); }); diff --git a/packages/opentelemetry-exporter-zipkin/test/helper.ts b/packages/opentelemetry-exporter-zipkin/test/helper.ts index b6896313296..c2e13dcdd8d 100644 --- a/packages/opentelemetry-exporter-zipkin/test/helper.ts +++ b/packages/opentelemetry-exporter-zipkin/test/helper.ts @@ -71,7 +71,7 @@ export function ensureSpanIsCorrect(span: Span) { localEndpoint: { serviceName: 'OpenTelemetry Service' }, tags: { component: 'foo', - 'ot.status_code': 'OK', + 'otel.status_code': 'OK', service: 'ui', version: '1', cost: '112.12', diff --git a/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts b/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts index 8749917fe91..d78b46159c7 100644 --- a/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts @@ -215,7 +215,7 @@ describe('Zipkin Exporter - node', () => { tags: { key1: 'value1', key2: 'value2', - 'ot.status_code': 'OK', + 'otel.status_code': 'OK', }, timestamp: startTime * MICROS_PER_SECS, traceId: span1.spanContext().traceId, @@ -230,7 +230,7 @@ describe('Zipkin Exporter - node', () => { }, name: span2.name, tags: { - 'ot.status_code': 'OK', + 'otel.status_code': 'OK', }, timestamp: hrTimeToMicroseconds([startTime, 0]), traceId: span2.spanContext().traceId, From d3f51632678192a0ffa2aa7b7fbd47bb77d8fc16 Mon Sep 17 00:00:00 2001 From: MartenH <72463136+mhennoch@users.noreply.github.com> Date: Sat, 9 Oct 2021 17:01:36 +0300 Subject: [PATCH 19/29] chore(deps): remove unused semver (#2520) Co-authored-by: Valentin Marchaud --- packages/opentelemetry-core/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 6e48dd47ec6..9eecc139df7 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -60,7 +60,6 @@ "@opentelemetry/api": "^1.0.2", "@types/mocha": "8.2.3", "@types/node": "14.17.11", - "@types/semver": "7.3.8", "@types/sinon": "10.0.2", "@types/webpack-env": "1.16.2", "codecov": "3.8.3", @@ -84,7 +83,6 @@ "@opentelemetry/api": "^1.0.2" }, "dependencies": { - "@opentelemetry/semantic-conventions": "1.0.0", - "semver": "^7.3.5" + "@opentelemetry/semantic-conventions": "1.0.0" } } From faca317da12a3d4e2c5f66210cbbf257c4b4c8e9 Mon Sep 17 00:00:00 2001 From: echoontheway <1152760298@qq.com> Date: Sat, 9 Oct 2021 22:10:46 +0800 Subject: [PATCH 20/29] feat(@opentelemetry-instrumentation-fetch): support reading response body from the hook applyCustomAttributesOnSpan (#2497) Co-authored-by: Valentin Marchaud --- .../src/fetch.ts | 3 ++- .../test/fetch.test.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts b/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts index 29d52b09430..a564b76f5a4 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts +++ b/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts @@ -331,6 +331,7 @@ export class FetchInstrumentation extends InstrumentationBase< ): void { try { const resClone = response.clone(); + const resClone4Hook = response.clone(); const body = resClone.body; if (body) { const reader = body.getReader(); @@ -338,7 +339,7 @@ export class FetchInstrumentation extends InstrumentationBase< reader.read().then( ({ done }) => { if (done) { - endSpanOnSuccess(span, response); + endSpanOnSuccess(span, resClone4Hook); } else { read(); } diff --git a/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts b/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts index 1de5b795d0a..a38dbd8b67f 100644 --- a/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts +++ b/experimental/packages/opentelemetry-instrumentation-fetch/test/fetch.test.ts @@ -683,6 +683,22 @@ describe('fetch', () => { prepare(url, applyCustomAttributes); }); + + it('get response body from callback arguments response', done => { + const applyCustomAttributes: FetchCustomAttributeFunction = async ( + span, + request, + response + ) => { + if(response instanceof Response ){ + const rsp = await response.json(); + assert.deepStrictEqual(rsp.args, {}); + done(); + } + }; + + prepare(url, applyCustomAttributes); + }); }); describe('when url is ignored', () => { From ed0ba063aead52cf8d14ac68440eb8277dac3644 Mon Sep 17 00:00:00 2001 From: legendecas Date: Mon, 11 Oct 2021 02:59:43 +0800 Subject: [PATCH 21/29] fix(sdk-metrics-base): metrics name should be in the max length of 63 (#2495) Co-authored-by: Bartlomiej Obecny Co-authored-by: Valentin Marchaud --- .../packages/opentelemetry-sdk-metrics-base/src/Meter.ts | 2 +- .../opentelemetry-sdk-metrics-base/test/Meter.test.ts | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts index 32f295694c6..2ca48dfbf61 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts @@ -350,6 +350,6 @@ export class Meter implements api.Meter { * @param name Name of metric to be created */ private _isValidName(name: string): boolean { - return Boolean(name.match(/^[a-z][a-z0-9_.-]*$/i)); + return Boolean(name.match(/^[a-z][a-z0-9_.-]{0,62}$/i)); } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts index b1e6389b5d3..0fcc05ede30 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts @@ -295,6 +295,13 @@ describe('Meter', () => { const counter = meter.createCounter('name with invalid characters^&*('); assert.ok(counter instanceof api.NoopMetric); }); + + it('should return no op metric if name exceeded length of 63', () => { + const counter = meter.createCounter('a'.repeat(63)); + assert.ok(counter instanceof CounterMetric); + const counter2 = meter.createCounter('a'.repeat(64)); + assert.ok(counter2 instanceof api.NoopMetric); + }); }); }); From df12218cc4c97ad951c5f8c59f1a9f14987c00fe Mon Sep 17 00:00:00 2001 From: Bartlomiej Obecny Date: Wed, 13 Oct 2021 01:33:24 +0200 Subject: [PATCH 22/29] feat: new merge function (#2484) * feat: new merge function * chore: updating info about lodash.merge util --- .../src/Meter.ts | 2 + .../src/MeterProvider.ts | 3 + packages/opentelemetry-core/package.json | 1 + packages/opentelemetry-core/src/index.ts | 1 + .../src/utils/lodash.merge.ts | 174 ++++++++ .../opentelemetry-core/src/utils/merge.ts | 189 +++++++++ .../test/utils/merge.test.ts | 387 ++++++++++++++++++ .../opentelemetry-sdk-trace-base/package.json | 4 +- .../src/BasicTracerProvider.ts | 3 +- 9 files changed, 759 insertions(+), 5 deletions(-) create mode 100644 packages/opentelemetry-core/src/utils/lodash.merge.ts create mode 100644 packages/opentelemetry-core/src/utils/merge.ts create mode 100644 packages/opentelemetry-core/test/utils/merge.test.ts diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts index 2ca48dfbf61..9a77e865bb8 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts @@ -33,6 +33,8 @@ import { ValueObserverMetric } from './ValueObserverMetric'; import { ValueRecorderMetric } from './ValueRecorderMetric'; // eslint-disable-next-line @typescript-eslint/no-var-requires const merge = require('lodash.merge'); +// @TODO - replace once the core is released +// import { merge } from '@opentelemetry/core'; /** * Meter is an implementation of the {@link Meter} interface. diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts index 226ff63aa64..c7edefd0d7f 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/MeterProvider.ts @@ -20,6 +20,9 @@ import { Meter } from '.'; import { DEFAULT_CONFIG, MeterConfig } from './types'; // eslint-disable-next-line @typescript-eslint/no-var-requires const merge = require('lodash.merge'); +// @TODO - replace once the core is released +// import { merge } from '@opentelemetry/core'; + /** * This class represents a meter provider which platform libraries can extend diff --git a/packages/opentelemetry-core/package.json b/packages/opentelemetry-core/package.json index 9eecc139df7..573ea927be4 100644 --- a/packages/opentelemetry-core/package.json +++ b/packages/opentelemetry-core/package.json @@ -70,6 +70,7 @@ "karma-mocha": "2.0.1", "karma-spec-reporter": "0.0.32", "karma-webpack": "4.0.2", + "lerna": "3.22.1", "mocha": "7.2.0", "nyc": "15.1.0", "rimraf": "3.0.2", diff --git a/packages/opentelemetry-core/src/index.ts b/packages/opentelemetry-core/src/index.ts index 44c95f2fe96..ea9e2d2a379 100644 --- a/packages/opentelemetry-core/src/index.ts +++ b/packages/opentelemetry-core/src/index.ts @@ -35,6 +35,7 @@ export * from './trace/sampler/TraceIdRatioBasedSampler'; export * from './trace/suppress-tracing'; export * from './trace/TraceState'; export * from './utils/environment'; +export * from './utils/merge'; export * from './utils/sampling'; export * from './utils/url'; export * from './utils/wrap'; diff --git a/packages/opentelemetry-core/src/utils/lodash.merge.ts b/packages/opentelemetry-core/src/utils/lodash.merge.ts new file mode 100644 index 00000000000..0c55c7aa479 --- /dev/null +++ b/packages/opentelemetry-core/src/utils/lodash.merge.ts @@ -0,0 +1,174 @@ +/* + * Copyright The 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. + */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +/** + * based on lodash in order to support esm builds without esModuleInterop. + * lodash is using MIT License. + **/ + +const objectTag = '[object Object]'; +const nullTag = '[object Null]'; +const undefinedTag = '[object Undefined]'; +const funcProto = Function.prototype; +const funcToString = funcProto.toString; +const objectCtorString = funcToString.call(Object); +const getPrototype = overArg(Object.getPrototypeOf, Object); +const objectProto = Object.prototype; +const hasOwnProperty = objectProto.hasOwnProperty; +const symToStringTag = Symbol ? Symbol.toStringTag : undefined; +const nativeObjectToString = objectProto.toString; + +/** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ +function overArg(func: Function, transform: any): any { + return function(arg: any) { + return func(transform(arg)); + }; +} + +/** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ +export function isPlainObject(value: any) { + if (!isObjectLike(value) || baseGetTag(value) !== objectTag) { + return false; + } + const proto = getPrototype(value); + if (proto === null) { + return true; + } + const Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) === objectCtorString; +} + +/** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ +function isObjectLike(value: any) { + return value != null && typeof value == 'object'; +} + +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value: any) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); +} + +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value: any) { + const isOwn = hasOwnProperty.call(value, symToStringTag as any), + tag = value[symToStringTag as any]; + let unmasked = false; + + try { + value[symToStringTag as any] = undefined; + unmasked = true; + } catch (e) { + // silence + } + + const result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag as any] = tag; + } else { + delete value[symToStringTag as any]; + } + } + return result; +} + +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value: any) { + return nativeObjectToString.call(value); +} diff --git a/packages/opentelemetry-core/src/utils/merge.ts b/packages/opentelemetry-core/src/utils/merge.ts new file mode 100644 index 00000000000..ae01a953a82 --- /dev/null +++ b/packages/opentelemetry-core/src/utils/merge.ts @@ -0,0 +1,189 @@ +/* + * Copyright The 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. + */ + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { isPlainObject } from './lodash.merge'; + +const MAX_LEVEL = 20; + +interface ObjectInto { + obj: any; + key: string; +} + +/** + * Merges objects together + * @param args - objects / values to be merged + */ +export function merge(...args: any[]): any { + let result: any = args.shift(); + const objects: WeakMap | undefined = new WeakMap(); + while (args.length > 0) { + result = mergeTwoObjects(result, args.shift(), 0, objects); + } + + return result; +} + +function takeValue(value: any): any { + if (isArray(value)) { + return value.slice(); + } + return value; +} + +/** + * Merges two objects + * @param one - first object + * @param two - second object + * @param level - current deep level + * @param objects - objects holder that has been already referenced - to prevent + * cyclic dependency + */ +function mergeTwoObjects( + one: any, + two: any, + level = 0, + objects: WeakMap, +): any { + let result: any; + if (level > MAX_LEVEL) { + return undefined; + } + level++; + if (isPrimitive(one) || isPrimitive(two) || isFunction(two)) { + result = takeValue(two); + } else if (isArray(one)) { + result = one.slice(); + if (isArray(two)) { + for (let i = 0, j = two.length; i < j; i++) { + result.push(takeValue(two[i])); + } + } else if (isObject(two)) { + const keys = Object.keys(two); + for (let i = 0, j = keys.length; i < j; i++) { + const key = keys[i]; + result[key] = takeValue(two[key]); + } + } + } else if (isObject(one)) { + if (isObject(two)) { + if (!shouldMerge(one, two)) { + return two; + } + result = Object.assign({}, one); + const keys = Object.keys(two); + + for (let i = 0, j = keys.length; i < j; i++) { + const key = keys[i]; + const twoValue = two[key]; + + if (isPrimitive(twoValue)) { + if (typeof twoValue === 'undefined') { + delete result[key]; + } else { + // result[key] = takeValue(twoValue); + result[key] = twoValue; + } + } else { + const obj1 = result[key]; + const obj2 = twoValue; + + if ( + wasObjectReferenced(one, key, objects) || + wasObjectReferenced(two, key, objects) + ) { + delete result[key]; + } else { + + if (isObject(obj1) && isObject(obj2)) { + const arr1 = objects.get(obj1) || []; + const arr2 = objects.get(obj2) || []; + arr1.push({ obj: one, key }); + arr2.push({ obj: two, key }); + objects.set(obj1, arr1); + objects.set(obj2, arr2); + } + + result[key] = mergeTwoObjects( + result[key], + twoValue, + level, + objects + ); + } + } + } + } else { + result = two; + } + } + + return result; +} + +/** + * Function to check if object has been already reference + * @param obj + * @param key + * @param objects + */ +function wasObjectReferenced( + obj: any, + key: string, + objects: WeakMap, +): boolean { + const arr = objects.get(obj[key]) || []; + for (let i = 0, j = arr.length; i < j; i++) { + const info = arr[i]; + if (info.key === key && info.obj === obj) { + return true; + } + } + return false; +} + +function isArray(value: any): boolean { + return Array.isArray(value); +} + +function isFunction(value: any): boolean { + return typeof value === 'function'; +} + +function isObject(value: any): boolean { + return !isPrimitive(value) && !isArray(value) && !isFunction(value) && typeof value === 'object'; +} + +function isPrimitive(value: any): boolean { + return typeof value === 'string' || + typeof value === 'number' || + typeof value === 'boolean' || + typeof value === 'undefined' || + value instanceof Date || + value instanceof RegExp || + value === null; +} + +function shouldMerge(one: any, two: any): boolean { + if (!isPlainObject(one) || !isPlainObject(two)) { + return false; + } + + return true; +} + diff --git a/packages/opentelemetry-core/test/utils/merge.test.ts b/packages/opentelemetry-core/test/utils/merge.test.ts new file mode 100644 index 00000000000..d008ce2b218 --- /dev/null +++ b/packages/opentelemetry-core/test/utils/merge.test.ts @@ -0,0 +1,387 @@ +/* + * Copyright The 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 { merge } from '../../src/utils/merge'; + +const tests: TestResult[] = []; + +tests.push({ + inputs: ['1', '2'], + result: '2', + desc: 'two strings' +}); +tests.push({ + inputs: [1, 2], + result: 2, + desc: 'two numbers' +}); +tests.push({ + inputs: [true, false], + result: false, + desc: 'two booleans' +}); +tests.push({ + inputs: [false, true], + result: true, + desc: 'two booleans case 2' +}); +tests.push({ + inputs: [undefined, undefined], + result: undefined, + desc: 'two undefined' +}); +tests.push({ + inputs: [null, null], + result: null, + desc: 'two nulls' +}); +tests.push({ + inputs: ['1', 1], + result: 1, + desc: 'string & number' +}); +tests.push({ + inputs: ['1', false], + result: false, + desc: 'string & boolean' +}); +tests.push({ + inputs: ['1', undefined], + result: undefined, + desc: 'string & undefined' +}); +tests.push({ + inputs: ['1', null], + result: null, + desc: 'string & null' +}); +tests.push({ + inputs: [3, '1'], + result: '1', + desc: 'number & string' +}); +tests.push({ + inputs: [3, false], + result: false, + desc: 'number & boolean' +}); +tests.push({ + inputs: [3, undefined], + result: undefined, + desc: 'number & undefined' +}); +tests.push({ + inputs: [3, null], + result: null, + desc: 'number & null' +}); +tests.push({ + inputs: [false, '3'], + result: '3', + desc: 'boolean & string' +}); +tests.push({ + inputs: [false, 3], + result: 3, + desc: 'boolean & number' +}); +tests.push({ + inputs: [false, undefined], + result: undefined, + desc: 'boolean & undefined' +}); +tests.push({ + inputs: [false, null], + result: null, + desc: 'boolean & null' +}); +tests.push({ + inputs: [undefined, '1'], + result: '1', + desc: 'undefined & string' +}); +tests.push({ + inputs: [undefined, 1], + result: 1, + desc: 'undefined & number' +}); +tests.push({ + inputs: [undefined, false], + result: false, + desc: 'undefined & boolean' +}); +tests.push({ + inputs: [undefined, null], + result: null, + desc: 'undefined & null' +}); +tests.push({ + inputs: [null, '1'], + result: '1', + desc: 'null & string' +}); +tests.push({ + inputs: [null, 1], + result: 1, + desc: 'null & number' +}); +tests.push({ + inputs: [null, false], + result: false, + desc: 'null & boolean' +}); +tests.push({ + inputs: [null, undefined], + result: undefined, + desc: 'null & undefined' +}); + +const date1 = new Date(327164400000); +const date2 = new Date(358700400000); +tests.push({ + inputs: [date1, date2], + result: date2, + desc: 'two dates' +}); + +tests.push({ + inputs: [/.+/g, /.a+/g], + result: /.a+/g, + desc: 'two regexp' +}); + +tests.push({ + inputs: [1, { a: 1 }], + result: { a: 1 }, + desc: 'primitive with object' +}); + +tests.push({ + inputs: [{ a: 1 }, 1], + result: 1, + desc: 'object with primitive' +}); + +const arrResult1: any = [1, 2, 3]; +arrResult1['foo'] = 1; +tests.push({ + inputs: [[1, 2, 3], { foo: 1 }], + result: arrResult1, + desc: 'array with object' +}); + +tests.push({ + inputs: [{ foo: 1 }, [1, 2, 3]], + result: [1, 2, 3], + desc: 'object with array' +}); + +tests.push({ + inputs: [{ a: 1, c: 1 }, { a: 2, b: 3 }], + result: { a: 2, b: 3, c: 1 }, + desc: 'two objects' +}); + +tests.push({ + inputs: [{ a: 1, c: 1 }, { a: 2, b: 3, c: { foo: 1 } }], + result: { a: 2, b: 3, c: { foo: 1 } }, + desc: 'two objects 2nd with nested' +}); + +tests.push({ + inputs: [ + { a: 1, c: { bar: 1, d: { bla: 2 } } }, + { a: 2, b: 3, c: { foo: 1 } } + ], + result: { a: 2, b: 3, c: { bar: 1, d: { bla: 2 }, foo: 1 } }, + desc: 'two objects with nested objects' +}); + +tests.push({ + inputs: [[1, 2, 3], [4, 5]], + result: [1, 2, 3, 4, 5], + desc: 'two arrays with numbers' +}); + +tests.push({ + inputs: [[1, 2, 3, { foo: 1 }], [4, 5, { foo: 2 }]], + result: [1, 2, 3, { foo: 1 }, 4, 5, { foo: 2 }], + desc: 'two arrays, with number and objects' +}); + +tests.push({ + inputs: [{ a: 1, c: 1 }, { a: 2, b: 3 }, { a: 3, c: 2, d: 1 }], + result: { a: 3, b: 3, c: 2, d: 1 }, + desc: 'three objects' +}); + +tests.push({ + inputs: [ + { a: 1, c: 1, foo: { bar1: 1 } }, + { a: 2, b: 3, foo: { bar1: 2 } }, + { a: 3, c: 2, d: 1, foo: { bar2: 1 } } + ], + result: { a: 3, b: 3, c: 2, d: 1, foo: { bar1: 2, bar2: 1 } }, + desc: 'three nested objects' +}); + +tests.push({ + inputs: [ + { a: 1, c: { bar: 1, d: { bla: 2 } } }, + { a: 2, b: 3, c: { foo: 1, bar: undefined } } + ], + result: { a: 2, b: 3, c: { d: { bla: 2 }, foo: 1 } }, + desc: 'two objects with nested objects and undefined' +}); + +class A { + constructor(private _name: string = 'foo') { + } + + getName() { + return this._name; + } +} + +class B extends A { + constructor(name = 'foo', private _ver = 1) { + super(name); + } + getVer(){ + return this._ver; + } +} + +const a = new A('foo'); +const b = new B('bar'); + +tests.push({ + inputs: [ + { a: 1, c: 1, foo: a, foo2: { a: 1 } }, + { a: 2, b: 3, foo: b, foo2: { b: 1, a: a } }, + ], + result: { a: 2, b: 3, c: 1, foo: b, foo2: {a: a, b: 1} }, + desc: 'two objects with nested objects and objects created from classes' +}); + +describe('merge', () => { + tests.forEach((test, index) => { + it(`should merge ${ test.desc }`, () => { + const result = merge(...test.inputs); + + assert.deepStrictEqual( + result, + test.result, + `test ${ index + 1 } '${ test.desc }' failed` + ); + }); + }); + + it('should create a shallow copy when merging plain objects', () => { + const a = { a: 1, c: 1, foo: { bar1: 1 } }; + const b = { b: 1, c: 2, foo: { bar2: 2 }, arr: [1, 2, 3] }; + + const result = merge(a, b); + a.a = 5; + b.b = 9; + b.arr.push(5); + + assert.deepStrictEqual( + result, + { a: 1, c: 2, foo: { bar1: 1, bar2: 2 }, b: 1, arr: [1, 2, 3] } + ); + }); + + it('should ignore cyclic reference', () => { + const a: any = { a: 1, c: 1, foo: { bar1: 1 } }; + a.f = a; + const b: any = { b: 1, c: 2, foo: { bar2: 2 }, arr: [1, 2, 3] }; + b.f = b; + + const result = merge(a, b); + assert.deepStrictEqual( + result, + { + a: 1, + c: 2, + foo: { bar1: 1, bar2: 2 }, + f: { a: 1, c: 2, b: 1, arr: [1, 2, 3] }, + b: 1, + arr: [1, 2, 3] + } + ); + }); + + it('should not fail for 1 argument', () => { + const result = merge(1); + assert.deepStrictEqual(result, 1); + }); + + it('should not fail for 0 arguments', () => { + const result = merge(); + assert.deepStrictEqual(result, undefined); + }); + + it('should merge function', () => { + const a = { + a: 1, b: 2 + }; + const b = { + a: 2, + c: function() { + return 'foo'; + }, + }; + const result = merge(a, b); + assert.deepStrictEqual(result, { + a: 2, b: 2, c: b.c + }); + }); + + it('should allow maximum of 20 levels deep', () => { + const a = {}; + const b = {}; + + function add(obj: any, added: any) { + obj.foo = added; + return obj.foo; + } + + let x = a; + let y = b; + for (let i = 0, j = 25; i < j; i++) { + const foo = { c: i + 1 }; + x = add(x, foo); + y = add(y, foo); + } + + const result = merge(a, b); + let check = result.foo; + let count = 0; + while (check.foo) { + count++; + check = check.foo; + } + assert.deepStrictEqual(count, 19); + }); + +}); + +interface TestResult { + desc: string; + inputs: any[]; + result: any; +} diff --git a/packages/opentelemetry-sdk-trace-base/package.json b/packages/opentelemetry-sdk-trace-base/package.json index 2926cd3a6ab..9f52b0efa04 100644 --- a/packages/opentelemetry-sdk-trace-base/package.json +++ b/packages/opentelemetry-sdk-trace-base/package.json @@ -56,7 +56,6 @@ }, "devDependencies": { "@opentelemetry/api": "^1.0.2", - "@types/lodash.merge": "4.6.6", "@types/mocha": "8.2.3", "@types/node": "14.17.11", "@types/sinon": "10.0.2", @@ -84,7 +83,6 @@ "dependencies": { "@opentelemetry/core": "1.0.0", "@opentelemetry/resources": "1.0.0", - "@opentelemetry/semantic-conventions": "1.0.0", - "lodash.merge": "^4.6.2" + "@opentelemetry/semantic-conventions": "1.0.0" } } diff --git a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts index 4c028448b41..ac6b3445ee5 100644 --- a/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-sdk-trace-base/src/BasicTracerProvider.ts @@ -27,6 +27,7 @@ import { W3CBaggagePropagator, W3CTraceContextPropagator, getEnv, + merge, } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; import { SpanProcessor, Tracer } from '.'; @@ -34,8 +35,6 @@ import { DEFAULT_CONFIG } from './config'; import { MultiSpanProcessor } from './MultiSpanProcessor'; import { NoopSpanProcessor } from './export/NoopSpanProcessor'; import { SDKRegistrationConfig, TracerConfig } from './types'; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const merge = require('lodash.merge'); import { SpanExporter } from './export/SpanExporter'; import { BatchSpanProcessor } from './platform'; From 96dab9fc120b0151a954f22c0226a9aff4d53f4d Mon Sep 17 00:00:00 2001 From: WhiteSource Renovate Date: Fri, 15 Oct 2021 21:28:30 +0200 Subject: [PATCH 23/29] chore(deps): update typescript-eslint monorepo to v5 (#2537) --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 56a145db98c..03f45c704f3 100644 --- a/package.json +++ b/package.json @@ -52,8 +52,8 @@ "devDependencies": { "@commitlint/cli": "13.1.0", "@commitlint/config-conventional": "13.1.0", - "@typescript-eslint/eslint-plugin": "4.29.3", - "@typescript-eslint/parser": "4.29.3", + "@typescript-eslint/eslint-plugin": "5.0.0", + "@typescript-eslint/parser": "5.0.0", "beautify-benchmark": "0.2.4", "benchmark": "2.1.4", "eslint": "7.32.0", From f9f43e565af505377ca5c83790f782fb7270e06e Mon Sep 17 00:00:00 2001 From: legendecas Date: Sat, 16 Oct 2021 03:35:18 +0800 Subject: [PATCH 24/29] feat(api-metrics): rename metric instruments to match feature-freeze API specification (#2496) * feat: rename metric instruments to match feature-freeze API specification * fixup! rename observables * fixup! * fixup! * fixup! * fixup! observable naming * fixup! remove unnecessary spaces * fixup! add upgrade guidelines --- README.md | 23 + doc/processor-api.md | 2 +- examples/metrics/metrics/observer.js | 26 +- examples/otlp-exporter-node/metrics.js | 6 +- .../src/NoopMeter.ts | 95 ++--- .../src/api/global-utils.ts | 2 +- .../opentelemetry-api-metrics/src/index.ts | 2 +- .../src/types/BatchObserverResult.ts | 3 +- .../src/types/BoundInstrument.ts | 10 +- .../src/types/Meter.ts | 46 +- .../src/types/Metric.ts | 32 +- ...{ObserverResult.ts => ObservableResult.ts} | 4 +- .../src/types/Observation.ts | 6 +- .../noop-implementations/noop-meter.test.ts | 16 +- .../test/OTLPMetricExporter.test.ts | 48 +-- .../test/helper.ts | 40 +- .../src/transformMetrics.ts | 8 +- .../browser/CollectorMetricExporter.test.ts | 50 +-- .../common/CollectorMetricExporter.test.ts | 18 +- .../test/common/transformMetrics.test.ts | 114 ++--- .../test/helper.ts | 88 ++-- .../test/node/CollectorMetricExporter.test.ts | 44 +- .../test/OTLPMetricExporter.test.ts | 38 +- .../test/helper.ts | 40 +- .../src/PrometheusSerializer.ts | 4 +- .../test/PrometheusExporter.test.ts | 66 +-- .../test/PrometheusSerializer.test.ts | 72 ++-- .../opentelemetry-sdk-metrics-base/README.md | 74 ++-- .../src/BatchObserver.ts | 16 +- .../src/BatchObserverResult.ts | 4 +- .../src/BoundInstrument.ts | 10 +- ...ueRecorderMetric.ts => HistogramMetric.ts} | 16 +- .../src/Meter.ts | 74 ++-- ...erverMetric.ts => ObservableBaseMetric.ts} | 32 +- ...erMetric.ts => ObservableCounterMetric.ts} | 22 +- ...rverMetric.ts => ObservableGaugeMetric.ts} | 14 +- ...{ObserverResult.ts => ObservableResult.ts} | 6 +- ...ic.ts => ObservableUpDownCounterMetric.ts} | 14 +- .../src/export/Processor.ts | 8 +- .../src/export/types.ts | 8 +- .../src/index.ts | 4 +- .../test/Meter.test.ts | 398 +++++++++--------- 42 files changed, 813 insertions(+), 790 deletions(-) rename experimental/packages/opentelemetry-api-metrics/src/types/{ObserverResult.ts => ObservableResult.ts} (86%) rename experimental/packages/opentelemetry-sdk-metrics-base/src/{ValueRecorderMetric.ts => HistogramMetric.ts} (79%) rename experimental/packages/opentelemetry-sdk-metrics-base/src/{BaseObserverMetric.ts => ObservableBaseMetric.ts} (68%) rename experimental/packages/opentelemetry-sdk-metrics-base/src/{SumObserverMetric.ts => ObservableCounterMetric.ts} (72%) rename experimental/packages/opentelemetry-sdk-metrics-base/src/{ValueObserverMetric.ts => ObservableGaugeMetric.ts} (78%) rename experimental/packages/opentelemetry-sdk-metrics-base/src/{ObserverResult.ts => ObservableResult.ts} (83%) rename experimental/packages/opentelemetry-sdk-metrics-base/src/{UpDownSumObserverMetric.ts => ObservableUpDownCounterMetric.ts} (76%) diff --git a/README.md b/README.md index d5e2f0d9173..ae4eb6f4839 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,29 @@ To request automatic tracing support for a module not on this list, please [file ## Upgrade guidelines +### 0.26.x to 0.27.x + +Metric types are renamed: + +- `@openetelemetry/api-metrics` + - `Meter` + - `createValueRecorder` => `createHistogram` + - `createValueObserver` => `createObservableGauge` + - `createSumObserver` => `createObservableCounter` + - `createUpDownSumObserver` => `createObservableUpDownCounter` + - `ValueRecorder` => `Histogram` + - `ValueObserver` => `ObservableGauge` + - `SumObserver` => `ObservableCounter` + - `UpDownSumObserver` => `ObservableUpDownCounter` + - `ObserverResult` => `ObservableResult` + - `Observation.observer` => `Observation.observable` +- `@opentelemetry/sdk-metrics-base` + - `MetricKind` + - `VALUE_RECORDER` => `HISTOGRAM` + - `SUM_OBSERVER` => `OBSERVABLE_COUNTER` + - `UP_DOWN_SUM_OBSERVER` => `OBSERVABLE_UP_DOWN_COUNTER` + - `VALUE_OBSERVER` => `OBSERVABLE_GAUGE` + ### 0.25.x to 1.x.y Collector exporter packages and types are renamed: diff --git a/doc/processor-api.md b/doc/processor-api.md index b3abbcdecc5..944834b038e 100644 --- a/doc/processor-api.md +++ b/doc/processor-api.md @@ -138,7 +138,7 @@ const meter = new MeterProvider({ interval: 1000, }).getMeter('example-custom-processor'); -const requestsLatency = meter.createValueRecorder('requests', { +const requestsLatency = meter.createHistogram('requests', { monotonic: true, description: 'Average latency' }); diff --git a/examples/metrics/metrics/observer.js b/examples/metrics/metrics/observer.js index def56d872b7..a31345f2a50 100644 --- a/examples/metrics/metrics/observer.js +++ b/examples/metrics/metrics/observer.js @@ -21,29 +21,29 @@ const exporter = new PrometheusExporter( const meter = new MeterProvider({ exporter, interval: 2000, -}).getMeter('example-observer'); +}).getMeter('example-meter'); -meter.createValueObserver('cpu_core_usage', { - description: 'Example of a sync value observer with callback', -}, async (observerResult) => { // this callback is called once per each interval +meter.createObservableGauge('cpu_core_usage', { + description: 'Example of a sync observable gauge with callback', +}, async (observableResult) => { // this callback is called once per each interval await new Promise((resolve) => { setTimeout(()=> {resolve()}, 50); }); - observerResult.observe(getRandomValue(), { core: '1' }); - observerResult.observe(getRandomValue(), { core: '2' }); + observableResult.observe(getRandomValue(), { core: '1' }); + observableResult.observe(getRandomValue(), { core: '2' }); }); // no callback as they will be updated in batch observer -const tempMetric = meter.createValueObserver('cpu_temp_per_app', { - description: 'Example of sync value observer used with async batch observer', +const tempMetric = meter.createObservableGauge('cpu_temp_per_app', { + description: 'Example of sync observable gauge used with async batch observer', }); // no callback as they will be updated in batch observer -const cpuUsageMetric = meter.createValueObserver('cpu_usage_per_app', { - description: 'Example of sync value observer used with async batch observer', +const cpuUsageMetric = meter.createObservableGauge('cpu_usage_per_app', { + description: 'Example of sync observable gauge used with async batch observer', }); -meter.createBatchObserver((observerBatchResult) => { +meter.createBatchObserver((batchObserverResult) => { Promise.all([ someAsyncMetrics(), // simulate waiting @@ -52,11 +52,11 @@ meter.createBatchObserver((observerBatchResult) => { }), ]).then(([apps, waiting]) => { apps.forEach(app => { - observerBatchResult.observe({ app: app.name, core: '1' }, [ + batchObserverResult.observe({ app: app.name, core: '1' }, [ tempMetric.observation(app.core1.temp), cpuUsageMetric.observation(app.core1.usage), ]); - observerBatchResult.observe({ app: app.name, core: '2' }, [ + batchObserverResult.observe({ app: app.name, core: '2' }, [ tempMetric.observation(app.core2.temp), cpuUsageMetric.observation(app.core2.usage), ]); diff --git a/examples/otlp-exporter-node/metrics.js b/examples/otlp-exporter-node/metrics.js index e0065aa6972..3a2294f43f0 100644 --- a/examples/otlp-exporter-node/metrics.js +++ b/examples/otlp-exporter-node/metrics.js @@ -31,8 +31,8 @@ const upDownCounter = meter.createUpDownCounter('test_up_down_counter', { description: 'Example of a UpDownCounter', }); -const recorder = meter.createValueRecorder('test_value_recorder', { - description: 'Example of a ValueRecorder', +const histogram = meter.createHistogram('test_histogram', { + description: 'Example of a Histogram', }); const labels = { pid: process.pid, environment: 'staging' }; @@ -40,5 +40,5 @@ const labels = { pid: process.pid, environment: 'staging' }; setInterval(() => { requestCounter.bind(labels).add(1); upDownCounter.bind(labels).add(Math.random() > 0.5 ? 1 : -1); - recorder.bind(labels).record(Math.random()); + histogram.bind(labels).record(Math.random()); }, 1000); diff --git a/experimental/packages/opentelemetry-api-metrics/src/NoopMeter.ts b/experimental/packages/opentelemetry-api-metrics/src/NoopMeter.ts index 6e0fd5bd207..775ad78f008 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/NoopMeter.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/NoopMeter.ts @@ -21,18 +21,19 @@ import { UnboundMetric, Labels, Counter, - ValueRecorder, - ValueObserver, + Histogram, + ObservableGauge, UpDownCounter, - BaseObserver, - UpDownSumObserver, + ObservableBase, + ObservableCounter, + ObservableUpDownCounter, } from './types/Metric'; import { - BoundValueRecorder, + BoundHistogram, BoundCounter, - BoundBaseObserver, + BoundObservableBase, } from './types/BoundInstrument'; -import { ObserverResult } from './types/ObserverResult'; +import { ObservableResult } from './types/ObservableResult'; import { Observation } from './types/Observation'; /** @@ -43,12 +44,12 @@ export class NoopMeter implements Meter { constructor() {} /** - * Returns constant noop value recorder. + * Returns a constant noop histogram. * @param name the name of the metric. * @param [options] the metric options. */ - createValueRecorder(_name: string, _options?: MetricOptions): ValueRecorder { - return NOOP_VALUE_RECORDER_METRIC; + createHistogram(_name: string, _options?: MetricOptions): Histogram { + return NOOP_HISTOGRAM_METRIC; } /** @@ -70,45 +71,45 @@ export class NoopMeter implements Meter { } /** - * Returns constant noop value observer. + * Returns a constant noop observable gauge. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the value observer callback + * @param [callback] the observable gauge callback */ - createValueObserver( + createObservableGauge( _name: string, _options?: MetricOptions, - _callback?: (observerResult: ObserverResult) => void - ): ValueObserver { - return NOOP_VALUE_OBSERVER_METRIC; + _callback?: (observableResult: ObservableResult) => void + ): ObservableGauge { + return NOOP_OBSERVABLE_GAUGE_METRIC; } /** - * Returns constant noop sum observer. + * Returns a constant noop observable counter. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the sum observer callback + * @param [callback] the observable counter callback */ - createSumObserver( + createObservableCounter( _name: string, _options?: MetricOptions, - _callback?: (observerResult: ObserverResult) => void - ): ValueObserver { - return NOOP_SUM_OBSERVER_METRIC; + _callback?: (observableResult: ObservableResult) => void + ): ObservableCounter { + return NOOP_OBSERVABLE_COUNTER_METRIC; } /** - * Returns constant noop up down sum observer. + * Returns a constant noop up down observable counter. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the up down sum observer callback + * @param [callback] the up down observable counter callback */ - createUpDownSumObserver( + createObservableUpDownCounter( _name: string, _options?: MetricOptions, - _callback?: (observerResult: ObserverResult) => void - ): UpDownSumObserver { - return NOOP_UP_DOWN_SUM_OBSERVER_METRIC; + _callback?: (observableResult: ObservableResult) => void + ): ObservableUpDownCounter { + return NOOP_OBSERVABLE_UP_DOWN_COUNTER_METRIC; } /** @@ -165,20 +166,20 @@ export class NoopCounterMetric } } -export class NoopValueRecorderMetric - extends NoopMetric - implements ValueRecorder { +export class NoopHistogramMetric + extends NoopMetric + implements Histogram { record(value: number, labels: Labels): void { this.bind(labels).record(value); } } -export class NoopBaseObserverMetric - extends NoopMetric - implements BaseObserver { +export class NoopObservableBaseMetric + extends NoopMetric + implements ObservableBase { observation(): Observation { return { - observer: this as BaseObserver, + observable: this as ObservableBase, value: 0, }; } @@ -192,13 +193,13 @@ export class NoopBoundCounter implements BoundCounter { } } -export class NoopBoundValueRecorder implements BoundValueRecorder { +export class NoopBoundHistogram implements BoundHistogram { record(_value: number, _baggage?: unknown, _spanContext?: unknown): void { return; } } -export class NoopBoundBaseObserver implements BoundBaseObserver { +export class NoopBoundObservableBase implements BoundObservableBase { update(_value: number): void {} } @@ -206,22 +207,22 @@ export const NOOP_METER = new NoopMeter(); export const NOOP_BOUND_COUNTER = new NoopBoundCounter(); export const NOOP_COUNTER_METRIC = new NoopCounterMetric(NOOP_BOUND_COUNTER); -export const NOOP_BOUND_VALUE_RECORDER = new NoopBoundValueRecorder(); -export const NOOP_VALUE_RECORDER_METRIC = new NoopValueRecorderMetric( - NOOP_BOUND_VALUE_RECORDER +export const NOOP_BOUND_HISTOGRAM = new NoopBoundHistogram(); +export const NOOP_HISTOGRAM_METRIC = new NoopHistogramMetric( + NOOP_BOUND_HISTOGRAM ); -export const NOOP_BOUND_BASE_OBSERVER = new NoopBoundBaseObserver(); -export const NOOP_VALUE_OBSERVER_METRIC = new NoopBaseObserverMetric( - NOOP_BOUND_BASE_OBSERVER +export const NOOP_BOUND_OBSERVABLE_BASE = new NoopBoundObservableBase(); +export const NOOP_OBSERVABLE_GAUGE_METRIC = new NoopObservableBaseMetric( + NOOP_BOUND_OBSERVABLE_BASE ); -export const NOOP_UP_DOWN_SUM_OBSERVER_METRIC = new NoopBaseObserverMetric( - NOOP_BOUND_BASE_OBSERVER +export const NOOP_OBSERVABLE_UP_DOWN_COUNTER_METRIC = new NoopObservableBaseMetric( + NOOP_BOUND_OBSERVABLE_BASE ); -export const NOOP_SUM_OBSERVER_METRIC = new NoopBaseObserverMetric( - NOOP_BOUND_BASE_OBSERVER +export const NOOP_OBSERVABLE_COUNTER_METRIC = new NoopObservableBaseMetric( + NOOP_BOUND_OBSERVABLE_BASE ); export const NOOP_BATCH_OBSERVER = new NoopBatchObserver(); diff --git a/experimental/packages/opentelemetry-api-metrics/src/api/global-utils.ts b/experimental/packages/opentelemetry-api-metrics/src/api/global-utils.ts index a23f76396d7..e371d5165d7 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/api/global-utils.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/api/global-utils.ts @@ -52,4 +52,4 @@ export function makeGetter( * version. If the global API is not compatible with the API package * attempting to get it, a NOOP API implementation will be returned. */ -export const API_BACKWARDS_COMPATIBILITY_VERSION = 3; +export const API_BACKWARDS_COMPATIBILITY_VERSION = 4; diff --git a/experimental/packages/opentelemetry-api-metrics/src/index.ts b/experimental/packages/opentelemetry-api-metrics/src/index.ts index de39eb08215..2a7a0dd2551 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/index.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/index.ts @@ -22,7 +22,7 @@ export * from './types/Meter'; export * from './types/MeterProvider'; export * from './types/Metric'; export * from './types/Observation'; -export * from './types/ObserverResult'; +export * from './types/ObservableResult'; import { MetricsAPI } from './api/metrics'; /** Entrypoint for metrics API */ diff --git a/experimental/packages/opentelemetry-api-metrics/src/types/BatchObserverResult.ts b/experimental/packages/opentelemetry-api-metrics/src/types/BatchObserverResult.ts index bae99eb8664..971156a774c 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/types/BatchObserverResult.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/types/BatchObserverResult.ts @@ -18,8 +18,7 @@ import { Labels } from './Metric'; import { Observation } from './Observation'; /** - * Interface that is being used in callback function for Observer Metric - * for batch + * Interface that is being used in callback function for BatchObserver */ export interface BatchObserverResult { /** diff --git a/experimental/packages/opentelemetry-api-metrics/src/types/BoundInstrument.ts b/experimental/packages/opentelemetry-api-metrics/src/types/BoundInstrument.ts index 0d5554771e6..378c9349884 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/types/BoundInstrument.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/types/BoundInstrument.ts @@ -23,16 +23,16 @@ export interface BoundCounter { add(value: number): void; } -/** ValueRecorder to report instantaneous measurement of a value. */ -export interface BoundValueRecorder { +/** Histogram to report instantaneous measurement of a value. */ +export interface BoundHistogram { /** - * Records the given value to this value recorder. + * Records the given value to this histogram. * @param value to record. */ record(value: number): void; } -/** An Instrument for Base Observer */ -export interface BoundBaseObserver { +/** An Instrument for Base Observable */ +export interface BoundObservableBase { update(value: number): void; } diff --git a/experimental/packages/opentelemetry-api-metrics/src/types/Meter.ts b/experimental/packages/opentelemetry-api-metrics/src/types/Meter.ts index 27428f2554d..a522840ec50 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/types/Meter.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/types/Meter.ts @@ -18,29 +18,29 @@ import { BatchObserverResult } from './BatchObserverResult'; import { MetricOptions, Counter, - ValueRecorder, - ValueObserver, + Histogram, + ObservableGauge, BatchObserverOptions, UpDownCounter, - SumObserver, - UpDownSumObserver, + ObservableCounter, + ObservableUpDownCounter, } from './Metric'; -import { ObserverResult } from './ObserverResult'; +import { ObservableResult } from './ObservableResult'; /** * An interface to allow the recording metrics. * * {@link Metric}s are used for recording pre-defined aggregation (`Counter`), - * or raw values (`ValueRecorder`) in which the aggregation and labels + * or raw values (`Histogram`) in which the aggregation and labels * for the exported metric are deferred. */ export interface Meter { /** - * Creates and returns a new `ValueRecorder`. + * Creates and returns a new `Histogram`. * @param name the name of the metric. * @param [options] the metric options. */ - createValueRecorder(name: string, options?: MetricOptions): ValueRecorder; + createHistogram(name: string, options?: MetricOptions): Histogram; /** * Creates a new `Counter` metric. Generally, this kind of metric when the @@ -71,40 +71,40 @@ export interface Meter { createUpDownCounter(name: string, options?: MetricOptions): UpDownCounter; /** - * Creates a new `ValueObserver` metric. + * Creates a new `ObservableGauge` metric. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the observer callback + * @param [callback] the observable callback */ - createValueObserver( + createObservableGauge( name: string, options?: MetricOptions, - callback?: (observerResult: ObserverResult) => void - ): ValueObserver; + callback?: (observableResult: ObservableResult) => void + ): ObservableGauge; /** - * Creates a new `SumObserver` metric. + * Creates a new `ObservableCounter` metric. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the observer callback + * @param [callback] the observable callback */ - createSumObserver( + createObservableCounter( name: string, options?: MetricOptions, - callback?: (observerResult: ObserverResult) => void - ): SumObserver; + callback?: (observableResult: ObservableResult) => void + ): ObservableCounter; /** - * Creates a new `UpDownSumObserver` metric. + * Creates a new `ObservableUpDownCounter` metric. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the observer callback + * @param [callback] the observable callback */ - createUpDownSumObserver( + createObservableUpDownCounter( name: string, options?: MetricOptions, - callback?: (observerResult: ObserverResult) => void - ): UpDownSumObserver; + callback?: (observableResult: ObservableResult) => void + ): ObservableUpDownCounter; /** * Creates a new `BatchObserver`, can be used to update many metrics diff --git a/experimental/packages/opentelemetry-api-metrics/src/types/Metric.ts b/experimental/packages/opentelemetry-api-metrics/src/types/Metric.ts index aebbc462460..55b51218f85 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/types/Metric.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/types/Metric.ts @@ -15,10 +15,13 @@ */ import { - BoundBaseObserver, + BoundObservableBase, BoundCounter, - BoundValueRecorder, + BoundHistogram, } from './BoundInstrument'; +import { + Observation, +} from './Observation'; /** * Options needed for metric creation @@ -146,31 +149,28 @@ export interface UpDownCounter extends UnboundMetric { add(value: number, labels?: Labels): void; } -export interface ValueRecorder extends UnboundMetric { +export interface Histogram extends UnboundMetric { /** - * Records the given value to this value recorder. + * Records the given value to this histogram. */ record(value: number, labels?: Labels): void; } -/** Base interface for the Observer metrics. */ -export interface BaseObserver extends UnboundMetric { +/** Base interface for the Observable metrics. */ +export interface ObservableBase extends UnboundMetric { observation: ( value: number - ) => { - value: number; - observer: BaseObserver; - }; + ) => Observation; } -/** Base interface for the ValueObserver metrics. */ -export type ValueObserver = BaseObserver; +/** Base interface for the ObservableGauge metrics. */ +export type ObservableGauge = ObservableBase; -/** Base interface for the UpDownSumObserver metrics. */ -export type UpDownSumObserver = BaseObserver; +/** Base interface for the ObservableUpDownCounter metrics. */ +export type ObservableUpDownCounter = ObservableBase; -/** Base interface for the SumObserver metrics. */ -export type SumObserver = BaseObserver; +/** Base interface for the ObservableCounter metrics. */ +export type ObservableCounter = ObservableBase; /** * key-value pairs passed by the user. diff --git a/experimental/packages/opentelemetry-api-metrics/src/types/ObserverResult.ts b/experimental/packages/opentelemetry-api-metrics/src/types/ObservableResult.ts similarity index 86% rename from experimental/packages/opentelemetry-api-metrics/src/types/ObserverResult.ts rename to experimental/packages/opentelemetry-api-metrics/src/types/ObservableResult.ts index 7792483ad1a..c909833ab9c 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/types/ObserverResult.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/types/ObservableResult.ts @@ -17,8 +17,8 @@ import { Labels } from './Metric'; /** - * Interface that is being used in callback function for Observer Metric + * Interface that is being used in callback function for Observable Metric */ -export interface ObserverResult { +export interface ObservableResult { observe(value: number, labels: Labels): void; } diff --git a/experimental/packages/opentelemetry-api-metrics/src/types/Observation.ts b/experimental/packages/opentelemetry-api-metrics/src/types/Observation.ts index d36f48fb717..1e805f3689f 100644 --- a/experimental/packages/opentelemetry-api-metrics/src/types/Observation.ts +++ b/experimental/packages/opentelemetry-api-metrics/src/types/Observation.ts @@ -14,12 +14,12 @@ * limitations under the License. */ -import { BaseObserver } from './Metric'; +import { ObservableBase } from './Metric'; /** - * Interface for updating value of certain value observer + * Interface for updating value of certain observable */ export interface Observation { - observer: BaseObserver; + observable: ObservableBase; value: number; } diff --git a/experimental/packages/opentelemetry-api-metrics/test/noop-implementations/noop-meter.test.ts b/experimental/packages/opentelemetry-api-metrics/test/noop-implementations/noop-meter.test.ts index cbfe044a9f7..07b2e7b4020 100644 --- a/experimental/packages/opentelemetry-api-metrics/test/noop-implementations/noop-meter.test.ts +++ b/experimental/packages/opentelemetry-api-metrics/test/noop-implementations/noop-meter.test.ts @@ -18,9 +18,9 @@ import * as assert from 'assert'; import { NoopMeterProvider, NOOP_BOUND_COUNTER, - NOOP_BOUND_VALUE_RECORDER, + NOOP_BOUND_HISTOGRAM, NOOP_COUNTER_METRIC, - NOOP_VALUE_RECORDER_METRIC, + NOOP_HISTOGRAM_METRIC, } from '../../src'; describe('NoopMeter', () => { @@ -38,23 +38,23 @@ describe('NoopMeter', () => { assert.strictEqual(counter.bind(labels), NOOP_BOUND_COUNTER); counter.clear(); - const valueRecorder = meter.createValueRecorder('some-name'); - valueRecorder.bind(labels).record(1); + const histogram = meter.createHistogram('some-name'); + histogram.bind(labels).record(1); // ensure the correct noop const is returned - assert.strictEqual(valueRecorder, NOOP_VALUE_RECORDER_METRIC); - assert.strictEqual(valueRecorder.bind(labels), NOOP_BOUND_VALUE_RECORDER); + assert.strictEqual(histogram, NOOP_HISTOGRAM_METRIC); + assert.strictEqual(histogram.bind(labels), NOOP_BOUND_HISTOGRAM); const options = { component: 'tests', description: 'the testing package', }; - const valueRecorderWithOptions = meter.createValueRecorder( + const histogramWithOptions = meter.createHistogram( 'some-name', options ); - assert.strictEqual(valueRecorderWithOptions, NOOP_VALUE_RECORDER_METRIC); + assert.strictEqual(histogramWithOptions, NOOP_HISTOGRAM_METRIC); const counterWithOptions = meter.createCounter('some-name', options); assert.strictEqual(counterWithOptions, NOOP_COUNTER_METRIC); }); diff --git a/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts index 86b8e1cef33..83d8723d4f9 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/OTLPMetricExporter.test.ts @@ -17,8 +17,8 @@ import * as protoLoader from '@grpc/proto-loader'; import { Counter, - ValueObserver, - ValueRecorder, + ObservableGauge, + Histogram, } from '@opentelemetry/api-metrics'; import { diag } from '@opentelemetry/api'; import { otlpTypes } from '@opentelemetry/exporter-otlp-http'; @@ -31,13 +31,13 @@ import * as sinon from 'sinon'; import { OTLPMetricExporter } from '../src'; import { ensureExportedCounterIsCorrect, - ensureExportedObserverIsCorrect, - ensureExportedValueRecorderIsCorrect, + ensureExportedObservableGaugeIsCorrect, + ensureExportedHistogramIsCorrect, ensureMetadataIsCorrect, ensureResourceIsCorrect, mockCounter, - mockObserver, - mockValueRecorder, + mockObservableGauge, + mockHistogram, } from './helper'; const metricsServiceProtoPath = @@ -140,21 +140,21 @@ const testOTLPMetricExporter = (params: TestParams) => metrics = []; const counter: metrics.Metric & Counter = mockCounter(); - const observer: metrics.Metric & - ValueObserver = mockObserver(observerResult => { - observerResult.observe(3, {}); - observerResult.observe(6, {}); + const observableGauge: metrics.Metric & + ObservableGauge = mockObservableGauge(observableResult => { + observableResult.observe(3, {}); + observableResult.observe(6, {}); }); - const recorder: metrics.Metric & - ValueRecorder = mockValueRecorder(); + const histogram: metrics.Metric & + Histogram = mockHistogram(); counter.add(1); - recorder.record(7); - recorder.record(14); + histogram.record(7); + histogram.record(14); metrics.push((await counter.getMetricRecord())[0]); - metrics.push((await observer.getMetricRecord())[0]); - metrics.push((await recorder.getMetricRecord())[0]); + metrics.push((await observableGauge.getMetricRecord())[0]); + metrics.push((await histogram.getMetricRecord())[0]); }); afterEach(() => { @@ -203,21 +203,21 @@ const testOTLPMetricExporter = (params: TestParams) => resource = exportedData[0].resource; const counter = exportedData[0].instrumentationLibraryMetrics[0].metrics[0]; - const observer = + const observableGauge = exportedData[0].instrumentationLibraryMetrics[0].metrics[1]; - const recorder = + const histogram = exportedData[0].instrumentationLibraryMetrics[0].metrics[2]; ensureExportedCounterIsCorrect( counter, counter.intSum?.dataPoints[0].timeUnixNano ); - ensureExportedObserverIsCorrect( - observer, - observer.doubleGauge?.dataPoints[0].timeUnixNano + ensureExportedObservableGaugeIsCorrect( + observableGauge, + observableGauge.doubleGauge?.dataPoints[0].timeUnixNano ); - ensureExportedValueRecorderIsCorrect( - recorder, - recorder.intHistogram?.dataPoints[0].timeUnixNano, + ensureExportedHistogramIsCorrect( + histogram, + histogram.intHistogram?.dataPoints[0].timeUnixNano, [0, 100], ['0', '2', '0'] ); diff --git a/experimental/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts index e77f0f1742e..48325a12d4f 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-grpc/test/helper.ts @@ -17,9 +17,9 @@ import { SpanStatusCode, TraceFlags } from '@opentelemetry/api'; import { Counter, - ObserverResult, - ValueObserver, - ValueRecorder, + ObservableResult, + ObservableGauge, + Histogram, ValueType, } from '@opentelemetry/api-metrics'; import { otlpTypes } from '@opentelemetry/exporter-otlp-http'; @@ -75,16 +75,16 @@ export function mockCounter(): metrics.Metric & Counter { return metric; } -export function mockObserver( - callback: (observerResult: ObserverResult) => void -): metrics.Metric & ValueObserver { - const name = 'double-observer'; +export function mockObservableGauge( + callback: (observableResult: ObservableResult) => void +): metrics.Metric & ObservableGauge { + const name = 'double-observable-gauge'; const metric = meter['_metrics'].get(name) || - meter.createValueObserver( + meter.createObservableGauge( name, { - description: 'sample observer description', + description: 'sample observable gauge description', valueType: ValueType.DOUBLE, }, callback @@ -94,13 +94,13 @@ export function mockObserver( return metric; } -export function mockValueRecorder(): metrics.Metric & - ValueRecorder { - const name = 'int-recorder'; +export function mockHistogram(): metrics.Metric & + Histogram { + const name = 'int-histogram'; const metric = meter['_metrics'].get(name) || - meter.createValueRecorder(name, { - description: 'sample recorder description', + meter.createHistogram(name, { + description: 'sample histogram description', valueType: ValueType.INT, boundaries: [0, 100], }); @@ -352,13 +352,13 @@ export function ensureExportedCounterIsCorrect( }); } -export function ensureExportedObserverIsCorrect( +export function ensureExportedObservableGaugeIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time?: number ) { assert.deepStrictEqual(metric, { - name: 'double-observer', - description: 'sample observer description', + name: 'double-observable-gauge', + description: 'sample observable gauge description', unit: '1', data: 'doubleGauge', doubleGauge: { @@ -375,15 +375,15 @@ export function ensureExportedObserverIsCorrect( }); } -export function ensureExportedValueRecorderIsCorrect( +export function ensureExportedHistogramIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time?: number, explicitBounds: number[] = [Infinity], bucketCounts: string[] = ['2', '0'] ) { assert.deepStrictEqual(metric, { - name: 'int-recorder', - description: 'sample recorder description', + name: 'int-histogram', + description: 'sample histogram description', unit: '1', data: 'intHistogram', intHistogram: { diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts b/experimental/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts index cc0f580883c..97a0e1ec3e4 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-http/src/transformMetrics.ts @@ -47,7 +47,7 @@ export function toCollectorLabels( export function toAggregationTemporality( metric: MetricRecord ): opentelemetryProto.metrics.v1.AggregationTemporality { - if (metric.descriptor.metricKind === MetricKind.VALUE_OBSERVER) { + if (metric.descriptor.metricKind === MetricKind.OBSERVABLE_GAUGE) { return opentelemetryProto.metrics.v1.AggregationTemporality .AGGREGATION_TEMPORALITY_UNSPECIFIED; } @@ -115,14 +115,14 @@ export function toCollectorMetric( if ( metric.aggregator.kind === AggregatorKind.SUM || - metric.descriptor.metricKind === MetricKind.SUM_OBSERVER || - metric.descriptor.metricKind === MetricKind.UP_DOWN_SUM_OBSERVER + metric.descriptor.metricKind === MetricKind.OBSERVABLE_COUNTER || + metric.descriptor.metricKind === MetricKind.OBSERVABLE_UP_DOWN_COUNTER ) { const result = { dataPoints: [toDataPoint(metric, startTime)], isMonotonic: metric.descriptor.metricKind === MetricKind.COUNTER || - metric.descriptor.metricKind === MetricKind.SUM_OBSERVER, + metric.descriptor.metricKind === MetricKind.OBSERVABLE_COUNTER, aggregationTemporality: toAggregationTemporality(metric), }; if (metric.descriptor.valueType === ValueType.INT) { diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts index 34463695c86..a2d289a7fe9 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-http/test/browser/CollectorMetricExporter.test.ts @@ -17,14 +17,14 @@ import { diag } from '@opentelemetry/api'; import { Counter, - ValueObserver, - ValueRecorder, + ObservableGauge, + Histogram, } from '@opentelemetry/api-metrics'; import { ExportResultCode, hrTimeToNanoseconds } from '@opentelemetry/core'; import { BoundCounter, - BoundObserver, - BoundValueRecorder, + BoundObservable, + BoundHistogram, Metric, MetricRecord, } from '@opentelemetry/sdk-metrics-base'; @@ -37,12 +37,12 @@ import { ensureCounterIsCorrect, ensureExportMetricsServiceRequestIsSet, ensureHeadersContain, - ensureObserverIsCorrect, - ensureValueRecorderIsCorrect, + ensureObservableGaugeIsCorrect, + ensureHistogramIsCorrect, ensureWebResourceIsCorrect, mockCounter, - mockObserver, - mockValueRecorder, + mockObservableGauge, + mockHistogram, } from '../helper'; describe('OTLPMetricExporter - web', () => { @@ -57,22 +57,22 @@ describe('OTLPMetricExporter - web', () => { stubBeacon = sinon.stub(navigator, 'sendBeacon'); metrics = []; const counter: Metric & Counter = mockCounter(); - const observer: Metric & ValueObserver = mockObserver( - observerResult => { - observerResult.observe(3, {}); - observerResult.observe(6, {}); + const observableGauge: Metric & ObservableGauge = mockObservableGauge( + observableResult => { + observableResult.observe(3, {}); + observableResult.observe(6, {}); }, - 'double-observer2' + 'double-observable-gauge2' ); - const recorder: Metric & - ValueRecorder = mockValueRecorder(); + const histogram: Metric & + Histogram = mockHistogram(); counter.add(1); - recorder.record(7); - recorder.record(14); + histogram.record(7); + histogram.record(14); metrics.push((await counter.getMetricRecord())[0]); - metrics.push((await observer.getMetricRecord())[0]); - metrics.push((await recorder.getMetricRecord())[0]); + metrics.push((await observableGauge.getMetricRecord())[0]); + metrics.push((await histogram.getMetricRecord())[0]); }); afterEach(() => { @@ -121,11 +121,11 @@ describe('OTLPMetricExporter - web', () => { "second metric doesn't exist" ); if (metric2) { - ensureObserverIsCorrect( + ensureObservableGaugeIsCorrect( metric2, hrTimeToNanoseconds(metrics[1].aggregator.toPoint().timestamp), 6, - 'double-observer2' + 'double-observable-gauge2' ); } @@ -134,7 +134,7 @@ describe('OTLPMetricExporter - web', () => { "third metric doesn't exist" ); if (metric3) { - ensureValueRecorderIsCorrect( + ensureHistogramIsCorrect( metric3, hrTimeToNanoseconds(metrics[2].aggregator.toPoint().timestamp), [0, 100], @@ -234,11 +234,11 @@ describe('OTLPMetricExporter - web', () => { "second metric doesn't exist" ); if (metric2) { - ensureObserverIsCorrect( + ensureObservableGaugeIsCorrect( metric2, hrTimeToNanoseconds(metrics[1].aggregator.toPoint().timestamp), 6, - 'double-observer2' + 'double-observable-gauge2' ); } @@ -247,7 +247,7 @@ describe('OTLPMetricExporter - web', () => { "third metric doesn't exist" ); if (metric3) { - ensureValueRecorderIsCorrect( + ensureHistogramIsCorrect( metric3, hrTimeToNanoseconds(metrics[2].aggregator.toPoint().timestamp), [0, 100], diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts index 119702c6836..7282f538c0e 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/CollectorMetricExporter.test.ts @@ -14,11 +14,11 @@ * limitations under the License. */ -import { Counter, ValueObserver } from '@opentelemetry/api-metrics'; +import { Counter, ObservableGauge } from '@opentelemetry/api-metrics'; import { ExportResultCode } from '@opentelemetry/core'; import { BoundCounter, - BoundObserver, + BoundObservable, Metric, MetricRecord, } from '@opentelemetry/sdk-metrics-base'; @@ -27,7 +27,7 @@ import * as sinon from 'sinon'; import { OTLPExporterBase } from '../../src/OTLPExporterBase'; import * as otlpTypes from '../../src/types'; import { OTLPExporterConfigBase } from '../../src/types'; -import { mockCounter, mockObserver } from '../helper'; +import { mockCounter, mockObservableGauge } from '../helper'; type CollectorExporterConfig = OTLPExporterConfigBase; class OTLPMetricExporter extends OTLPExporterBase< @@ -70,17 +70,17 @@ describe('OTLPMetricExporter - common', () => { collectorExporter = new OTLPMetricExporter(collectorExporterConfig); metrics = []; const counter: Metric & Counter = mockCounter(); - const observer: Metric & ValueObserver = mockObserver( - observerResult => { - observerResult.observe(3, {}); - observerResult.observe(6, {}); + const observableGauge: Metric & ObservableGauge = mockObservableGauge( + observableResult => { + observableResult.observe(3, {}); + observableResult.observe(6, {}); }, - 'double-observer3' + 'double-observable-gauge3' ); counter.add(1); metrics.push((await counter.getMetricRecord())[0]); - metrics.push((await observer.getMetricRecord())[0]); + metrics.push((await observableGauge.getMetricRecord())[0]); }); it('should create an instance', () => { diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts index e94a6cf71df..71ce5ab274e 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-http/test/common/transformMetrics.test.ts @@ -15,16 +15,16 @@ */ import { Counter, - SumObserver, - UpDownSumObserver, - ValueObserver, - ValueRecorder, + ObservableCounter, + ObservableUpDownCounter, + ObservableGauge, + Histogram, } from '@opentelemetry/api-metrics'; import { hrTimeToNanoseconds } from '@opentelemetry/core'; import { BoundCounter, - BoundObserver, - BoundValueRecorder, + BoundObservable, + BoundHistogram, Metric, SumAggregator, } from '@opentelemetry/sdk-metrics-base'; @@ -34,18 +34,18 @@ import * as transform from '../../src/transformMetrics'; import { ensureCounterIsCorrect, ensureDoubleCounterIsCorrect, - ensureObserverIsCorrect, - ensureSumObserverIsCorrect, - ensureUpDownSumObserverIsCorrect, - ensureValueRecorderIsCorrect, + ensureObservableGaugeIsCorrect, + ensureObservableCounterIsCorrect, + ensureObservableUpDownCounterIsCorrect, + ensureHistogramIsCorrect, mockCounter, mockDoubleCounter, mockedInstrumentationLibraries, mockedResources, - mockObserver, - mockSumObserver, - mockUpDownSumObserver, - mockValueRecorder, + mockObservableGauge, + mockObservableCounter, + mockObservableUpDownCounter, + mockHistogram, multiInstrumentationLibraryMetricsGet, multiResourceMetricsGet, } from '../helper'; @@ -54,10 +54,10 @@ describe('transformMetrics', () => { describe('toCollectorMetric', async () => { let counter: Metric & Counter; let doubleCounter: Metric & Counter; - let observer: Metric & ValueObserver; - let sumObserver: Metric & SumObserver; - let upDownSumObserver: Metric & UpDownSumObserver; - let recorder: Metric & ValueRecorder; + let observableGauge: Metric & ObservableGauge; + let observableCounter: Metric & ObservableCounter; + let observableUpDownCounter: Metric & ObservableUpDownCounter; + let histogram: Metric & Histogram; beforeEach(() => { counter = mockCounter(); doubleCounter = mockDoubleCounter(); @@ -72,22 +72,22 @@ describe('transformMetrics', () => { return -1; } - observer = mockObserver(observerResult => { + observableGauge = mockObservableGauge(observableResult => { count1++; - observerResult.observe(getValue(count1), {}); + observableResult.observe(getValue(count1), {}); }); - sumObserver = mockSumObserver(observerResult => { + observableCounter = mockObservableCounter(observableResult => { count2++; - observerResult.observe(getValue(count2), {}); + observableResult.observe(getValue(count2), {}); }); - upDownSumObserver = mockUpDownSumObserver(observerResult => { + observableUpDownCounter = mockObservableUpDownCounter(observableResult => { count3++; - observerResult.observe(getValue(count3), {}); + observableResult.observe(getValue(count3), {}); }); - recorder = mockValueRecorder(); + histogram = mockHistogram(); // Counter counter.add(1); @@ -95,9 +95,9 @@ describe('transformMetrics', () => { // Double Counter doubleCounter.add(8); - // ValueRecorder - recorder.record(7); - recorder.record(14); + // Histogram + histogram.record(7); + histogram.record(14); }); it('should convert metric', async () => { @@ -113,46 +113,46 @@ describe('transformMetrics', () => { hrTimeToNanoseconds(doubleCounterMetric.aggregator.toPoint().timestamp) ); - await observer.getMetricRecord(); - await observer.getMetricRecord(); - const observerMetric = (await observer.getMetricRecord())[0]; - ensureObserverIsCorrect( - transform.toCollectorMetric(observerMetric, 1592602232694000000), - hrTimeToNanoseconds(observerMetric.aggregator.toPoint().timestamp), + await observableGauge.getMetricRecord(); + await observableGauge.getMetricRecord(); + const observableGaugeMetric = (await observableGauge.getMetricRecord())[0]; + ensureObservableGaugeIsCorrect( + transform.toCollectorMetric(observableGaugeMetric, 1592602232694000000), + hrTimeToNanoseconds(observableGaugeMetric.aggregator.toPoint().timestamp), -1 ); // collect 3 times - await sumObserver.getMetricRecord(); - await sumObserver.getMetricRecord(); - const sumObserverMetric = (await sumObserver.getMetricRecord())[0]; - ensureSumObserverIsCorrect( - transform.toCollectorMetric(sumObserverMetric, 1592602232694000000), - hrTimeToNanoseconds(sumObserverMetric.aggregator.toPoint().timestamp), + await observableCounter.getMetricRecord(); + await observableCounter.getMetricRecord(); + const observableCounterMetric = (await observableCounter.getMetricRecord())[0]; + ensureObservableCounterIsCorrect( + transform.toCollectorMetric(observableCounterMetric, 1592602232694000000), + hrTimeToNanoseconds(observableCounterMetric.aggregator.toPoint().timestamp), 3 ); // collect 3 times - await upDownSumObserver.getMetricRecord(); - await upDownSumObserver.getMetricRecord(); - const upDownSumObserverMetric = ( - await upDownSumObserver.getMetricRecord() + await observableUpDownCounter.getMetricRecord(); + await observableUpDownCounter.getMetricRecord(); + const observableUpDownCounterMetric = ( + await observableUpDownCounter.getMetricRecord() )[0]; - ensureUpDownSumObserverIsCorrect( + ensureObservableUpDownCounterIsCorrect( transform.toCollectorMetric( - upDownSumObserverMetric, + observableUpDownCounterMetric, 1592602232694000000 ), hrTimeToNanoseconds( - upDownSumObserverMetric.aggregator.toPoint().timestamp + observableUpDownCounterMetric.aggregator.toPoint().timestamp ), -1 ); - const recorderMetric = (await recorder.getMetricRecord())[0]; - ensureValueRecorderIsCorrect( - transform.toCollectorMetric(recorderMetric, 1592602232694000000), - hrTimeToNanoseconds(recorderMetric.aggregator.toPoint().timestamp), + const histogramMetric = (await histogram.getMetricRecord())[0]; + ensureHistogramIsCorrect( + transform.toCollectorMetric(histogramMetric, 1592602232694000000), + hrTimeToNanoseconds(histogramMetric.aggregator.toPoint().timestamp), [0, 100], [0, 2, 0] ); @@ -186,8 +186,8 @@ describe('transformMetrics', () => { const [resource1, resource2] = mockedResources; const [library] = mockedInstrumentationLibraries; const [metric1, metric2, metric3] = multiResourceMetricsGet( - observerResult => { - observerResult.observe(1, {}); + observableResult => { + observableResult.observe(1, {}); } ); @@ -197,8 +197,8 @@ describe('transformMetrics', () => { ]); const result = transform.groupMetricsByResourceAndLibrary( - multiResourceMetricsGet(observerResult => { - observerResult.observe(1, {}); + multiResourceMetricsGet(observableResult => { + observableResult.observe(1, {}); }) ); @@ -212,7 +212,7 @@ describe('transformMetrics', () => { metric1, metric2, metric3, - ] = multiInstrumentationLibraryMetricsGet(observerResult => {}); + ] = multiInstrumentationLibraryMetricsGet(observableResult => {}); const expected = new Map([ [ resource, @@ -224,7 +224,7 @@ describe('transformMetrics', () => { ]); const result = transform.groupMetricsByResourceAndLibrary( - multiInstrumentationLibraryMetricsGet(observerResult => {}) + multiInstrumentationLibraryMetricsGet(observableResult => {}) ); assert.deepStrictEqual(result, expected); diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/test/helper.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/helper.ts index 87839060349..5befa3515f7 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/test/helper.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-http/test/helper.ts @@ -17,11 +17,11 @@ import { SpanStatusCode, TraceFlags } from '@opentelemetry/api'; import { Counter, - ObserverResult, - SumObserver, - UpDownSumObserver, - ValueObserver, - ValueRecorder, + ObservableResult, + ObservableCounter, + ObservableUpDownCounter, + ObservableGauge, + Histogram, ValueType, } from '@opentelemetry/api-metrics'; import { hexToBase64, InstrumentationLibrary, VERSION } from '@opentelemetry/core'; @@ -78,16 +78,16 @@ export function mockDoubleCounter(): metrics.Metric & return metric; } -export function mockObserver( - callback: (observerResult: ObserverResult) => unknown, - name = 'double-observer' -): metrics.Metric & ValueObserver { +export function mockObservableGauge( + callback: (observableResult: ObservableResult) => unknown, + name = 'double-observable-gauge' +): metrics.Metric & ObservableGauge { const metric = meter['_metrics'].get(name) || - meter.createValueObserver( + meter.createObservableGauge( name, { - description: 'sample observer description', + description: 'sample observable gauge description', valueType: ValueType.DOUBLE, }, callback @@ -97,16 +97,16 @@ export function mockObserver( return metric; } -export function mockSumObserver( - callback: (observerResult: ObserverResult) => unknown, - name = 'double-sum-observer' -): metrics.Metric & SumObserver { +export function mockObservableCounter( + callback: (observableResult: ObservableResult) => unknown, + name = 'double-observable-counter' +): metrics.Metric & ObservableCounter { const metric = meter['_metrics'].get(name) || - meter.createSumObserver( + meter.createObservableCounter( name, { - description: 'sample sum observer description', + description: 'sample observable counter description', valueType: ValueType.DOUBLE, }, callback @@ -116,16 +116,16 @@ export function mockSumObserver( return metric; } -export function mockUpDownSumObserver( - callback: (observerResult: ObserverResult) => unknown, - name = 'double-up-down-sum-observer' -): metrics.Metric & UpDownSumObserver { +export function mockObservableUpDownCounter( + callback: (observableResult: ObservableResult) => unknown, + name = 'double-up-down-observable-counter' +): metrics.Metric & ObservableUpDownCounter { const metric = meter['_metrics'].get(name) || - meter.createUpDownSumObserver( + meter.createObservableUpDownCounter( name, { - description: 'sample up down sum observer description', + description: 'sample observable up down counter description', valueType: ValueType.DOUBLE, }, callback @@ -135,13 +135,13 @@ export function mockUpDownSumObserver( return metric; } -export function mockValueRecorder(): metrics.Metric & - ValueRecorder { - const name = 'int-recorder'; +export function mockHistogram(): metrics.Metric & + Histogram { + const name = 'int-histogram'; const metric = meter['_metrics'].get(name) || - meter.createValueRecorder(name, { - description: 'sample recorder description', + meter.createHistogram(name, { + description: 'sample histogram description', valueType: ValueType.INT, boundaries: [0, 100], }); @@ -313,7 +313,7 @@ export const multiResourceTrace: ReadableSpan[] = [ ]; export const multiResourceMetricsGet = function ( - callback: (observerResult: ObserverResult) => unknown + callback: (observableResult: ObservableResult) => unknown ): any[] { return [ { @@ -322,7 +322,7 @@ export const multiResourceMetricsGet = function ( instrumentationLibrary: mockedInstrumentationLibraries[0], }, { - ...mockObserver(callback), + ...mockObservableGauge(callback), resource: mockedResources[1], instrumentationLibrary: mockedInstrumentationLibraries[0], }, @@ -335,7 +335,7 @@ export const multiResourceMetricsGet = function ( }; export const multiInstrumentationLibraryMetricsGet = function ( - callback: (observerResult: ObserverResult) => unknown + callback: (observableResult: ObservableResult) => unknown ): any[] { return [ { @@ -344,7 +344,7 @@ export const multiInstrumentationLibraryMetricsGet = function ( instrumentationLibrary: mockedInstrumentationLibraries[0], }, { - ...mockObserver(callback), + ...mockObservableGauge(callback), resource: mockedResources[0], instrumentationLibrary: mockedInstrumentationLibraries[1], }, @@ -601,15 +601,15 @@ export function ensureDoubleCounterIsCorrect( }); } -export function ensureObserverIsCorrect( +export function ensureObservableGaugeIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time: number, value: number, - name = 'double-observer' + name = 'double-observable-gauge' ) { assert.deepStrictEqual(metric, { name, - description: 'sample observer description', + description: 'sample observable gauge description', unit: '1', doubleGauge: { dataPoints: [ @@ -624,15 +624,15 @@ export function ensureObserverIsCorrect( }); } -export function ensureSumObserverIsCorrect( +export function ensureObservableCounterIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time: number, value: number, - name = 'double-sum-observer' + name = 'double-observable-counter' ) { assert.deepStrictEqual(metric, { name, - description: 'sample sum observer description', + description: 'sample observable counter description', unit: '1', doubleSum: { isMonotonic: true, @@ -651,15 +651,15 @@ export function ensureSumObserverIsCorrect( }); } -export function ensureUpDownSumObserverIsCorrect( +export function ensureObservableUpDownCounterIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time: number, value: number, - name = 'double-up-down-sum-observer' + name = 'double-up-down-observable-counter' ) { assert.deepStrictEqual(metric, { name, - description: 'sample up down sum observer description', + description: 'sample observable up down counter description', unit: '1', doubleSum: { isMonotonic: false, @@ -678,15 +678,15 @@ export function ensureUpDownSumObserverIsCorrect( }); } -export function ensureValueRecorderIsCorrect( +export function ensureHistogramIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time: number, explicitBounds: (number | null)[] = [Infinity], bucketCounts: number[] = [2, 0] ) { assert.deepStrictEqual(metric, { - name: 'int-recorder', - description: 'sample recorder description', + name: 'int-histogram', + description: 'sample histogram description', unit: '1', intHistogram: { dataPoints: [ diff --git a/experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts index 4937ef37370..11308aeef2d 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-http/test/node/CollectorMetricExporter.test.ts @@ -17,14 +17,14 @@ import { diag } from '@opentelemetry/api'; import { Counter, - ValueObserver, - ValueRecorder, + ObservableGauge, + Histogram, } from '@opentelemetry/api-metrics'; import * as core from '@opentelemetry/core'; import { BoundCounter, - BoundObserver, - BoundValueRecorder, + BoundObservable, + BoundHistogram, Metric, MetricRecord, } from '@opentelemetry/sdk-metrics-base'; @@ -39,11 +39,11 @@ import * as otlpTypes from '../../src/types'; import { ensureCounterIsCorrect, ensureExportMetricsServiceRequestIsSet, - ensureObserverIsCorrect, - ensureValueRecorderIsCorrect, + ensureObservableGaugeIsCorrect, + ensureHistogramIsCorrect, mockCounter, - mockObserver, - mockValueRecorder, + mockObservableGauge, + mockHistogram, } from '../helper'; import { MockedResponse } from './nodeHelpers'; @@ -149,21 +149,21 @@ describe('OTLPMetricExporter - node with json over http', () => { }); metrics = []; const counter: Metric & Counter = mockCounter(); - const observer: Metric & ValueObserver = mockObserver( - observerResult => { - observerResult.observe(6, {}); + const observableGauge: Metric & ObservableGauge = mockObservableGauge( + observableResult => { + observableResult.observe(6, {}); }, - 'double-observer2' + 'double-observable-gauge2' ); - const recorder: Metric & - ValueRecorder = mockValueRecorder(); + const histogram: Metric & + Histogram = mockHistogram(); counter.add(1); - recorder.record(7); - recorder.record(14); + histogram.record(7); + histogram.record(14); metrics.push((await counter.getMetricRecord())[0]); - metrics.push((await observer.getMetricRecord())[0]); - metrics.push((await recorder.getMetricRecord())[0]); + metrics.push((await observableGauge.getMetricRecord())[0]); + metrics.push((await histogram.getMetricRecord())[0]); }); it('should open the connection', done => { @@ -224,15 +224,15 @@ describe('OTLPMetricExporter - node with json over http', () => { metric1, core.hrTimeToNanoseconds(metrics[0].aggregator.toPoint().timestamp) ); - assert.ok(typeof metric2 !== 'undefined', "observer doesn't exist"); - ensureObserverIsCorrect( + assert.ok(typeof metric2 !== 'undefined', "observable gauge doesn't exist"); + ensureObservableGaugeIsCorrect( metric2, core.hrTimeToNanoseconds(metrics[1].aggregator.toPoint().timestamp), 6, - 'double-observer2' + 'double-observable-gauge2' ); assert.ok(typeof metric3 !== 'undefined', "histogram doesn't exist"); - ensureValueRecorderIsCorrect( + ensureHistogramIsCorrect( metric3, core.hrTimeToNanoseconds(metrics[2].aggregator.toPoint().timestamp), [0, 100], diff --git a/experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts index 17716f0887f..b623d2d8191 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/test/OTLPMetricExporter.test.ts @@ -17,8 +17,8 @@ import { diag } from '@opentelemetry/api'; import { Counter, - ValueObserver, - ValueRecorder, + ObservableGauge, + Histogram, } from '@opentelemetry/api-metrics'; import { ExportResultCode } from '@opentelemetry/core'; import { @@ -33,13 +33,13 @@ import { OTLPMetricExporter } from '../src'; import { getExportRequestProto } from '../src/util'; import { ensureExportedCounterIsCorrect, - ensureExportedObserverIsCorrect, - ensureExportedValueRecorderIsCorrect, + ensureExportedObservableGaugeIsCorrect, + ensureExportedHistogramIsCorrect, ensureExportMetricsServiceRequestIsSet, mockCounter, MockedResponse, - mockObserver, - mockValueRecorder, + mockObservableGauge, + mockHistogram, } from './helper'; const fakeRequest = { @@ -121,21 +121,21 @@ describe('OTLPMetricExporter - node with proto over http', () => { metrics = []; const counter: metrics.Metric & Counter = mockCounter(); - const observer: metrics.Metric & - ValueObserver = mockObserver(observerResult => { - observerResult.observe(3, {}); - observerResult.observe(6, {}); + const observableGauge: metrics.Metric & + ObservableGauge = mockObservableGauge(observableResult => { + observableResult.observe(3, {}); + observableResult.observe(6, {}); }); - const recorder: metrics.Metric & - ValueRecorder = mockValueRecorder(); + const histogram: metrics.Metric & + Histogram = mockHistogram(); counter.add(1); - recorder.record(7); - recorder.record(14); + histogram.record(7); + histogram.record(14); metrics.push((await counter.getMetricRecord())[0]); - metrics.push((await observer.getMetricRecord())[0]); - metrics.push((await recorder.getMetricRecord())[0]); + metrics.push((await observableGauge.getMetricRecord())[0]); + metrics.push((await histogram.getMetricRecord())[0]); }); afterEach(() => { sinon.restore(); @@ -197,8 +197,8 @@ describe('OTLPMetricExporter - node with proto over http', () => { metric1, metric1.intSum?.dataPoints[0].timeUnixNano ); - assert.ok(typeof metric2 !== 'undefined', "observer doesn't exist"); - ensureExportedObserverIsCorrect( + assert.ok(typeof metric2 !== 'undefined', "observable gauge doesn't exist"); + ensureExportedObservableGaugeIsCorrect( metric2, metric2.doubleGauge?.dataPoints[0].timeUnixNano ); @@ -206,7 +206,7 @@ describe('OTLPMetricExporter - node with proto over http', () => { typeof metric3 !== 'undefined', "value recorder doesn't exist" ); - ensureExportedValueRecorderIsCorrect( + ensureExportedHistogramIsCorrect( metric3, metric3.intHistogram?.dataPoints[0].timeUnixNano, [0, 100], diff --git a/experimental/packages/opentelemetry-exporter-otlp-proto/test/helper.ts b/experimental/packages/opentelemetry-exporter-otlp-proto/test/helper.ts index f8b90b9feff..f76b8619b07 100644 --- a/experimental/packages/opentelemetry-exporter-otlp-proto/test/helper.ts +++ b/experimental/packages/opentelemetry-exporter-otlp-proto/test/helper.ts @@ -17,9 +17,9 @@ import { SpanStatusCode, TraceFlags } from '@opentelemetry/api'; import { Counter, - ObserverResult, - ValueObserver, - ValueRecorder, + ObservableResult, + ObservableGauge, + Histogram, ValueType, } from '@opentelemetry/api-metrics'; import { hexToBase64 } from '@opentelemetry/core'; @@ -54,16 +54,16 @@ export function mockCounter(): metrics.Metric & Counter { return metric; } -export function mockObserver( - callback: (observerResult: ObserverResult) => void -): metrics.Metric & ValueObserver { - const name = 'double-observer'; +export function mockObservableGauge( + callback: (observableResult: ObservableResult) => void +): metrics.Metric & ObservableGauge { + const name = 'double-observable-gauge'; const metric = meter['_metrics'].get(name) || - meter.createValueObserver( + meter.createObservableGauge( name, { - description: 'sample observer description', + description: 'sample observable gauge description', valueType: ValueType.DOUBLE, }, callback @@ -73,13 +73,13 @@ export function mockObserver( return metric; } -export function mockValueRecorder(): metrics.Metric & - ValueRecorder { - const name = 'int-recorder'; +export function mockHistogram(): metrics.Metric & + Histogram { + const name = 'int-histogram'; const metric = meter['_metrics'].get(name) || - meter.createValueRecorder(name, { - description: 'sample recorder description', + meter.createHistogram(name, { + description: 'sample histogram description', valueType: ValueType.INT, boundaries: [0, 100], }); @@ -316,13 +316,13 @@ export function ensureExportedCounterIsCorrect( }); } -export function ensureExportedObserverIsCorrect( +export function ensureExportedObservableGaugeIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time?: number ) { assert.deepStrictEqual(metric, { - name: 'double-observer', - description: 'sample observer description', + name: 'double-observable-gauge', + description: 'sample observable gauge description', unit: '1', doubleGauge: { dataPoints: [ @@ -336,15 +336,15 @@ export function ensureExportedObserverIsCorrect( }); } -export function ensureExportedValueRecorderIsCorrect( +export function ensureExportedHistogramIsCorrect( metric: otlpTypes.opentelemetryProto.metrics.v1.Metric, time?: number, explicitBounds: number[] = [Infinity], bucketCounts: string[] = ['2', '0'] ) { assert.deepStrictEqual(metric, { - name: 'int-recorder', - description: 'sample recorder description', + name: 'int-histogram', + description: 'sample histogram description', unit: '1', intHistogram: { dataPoints: [ diff --git a/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusSerializer.ts b/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusSerializer.ts index e62ba0478ac..35473b14a3d 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusSerializer.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/src/PrometheusSerializer.ts @@ -106,11 +106,11 @@ function toPrometheusType( case AggregatorKind.SUM: if ( metricKind === MetricKind.COUNTER || - metricKind === MetricKind.SUM_OBSERVER + metricKind === MetricKind.OBSERVABLE_COUNTER ) { return 'counter'; } - /** MetricKind.UP_DOWN_COUNTER and MetricKind.UP_DOWN_SUM_OBSERVER */ + /** MetricKind.UP_DOWN_COUNTER and MetricKind.OBSERVABLE_UP_DOWN_COUNTER */ return 'gauge'; case AggregatorKind.LAST_VALUE: return 'gauge'; diff --git a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusExporter.test.ts b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusExporter.test.ts index 11d0090861e..3b5f044be3c 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusExporter.test.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusExporter.test.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { ObserverResult } from '@opentelemetry/api-metrics'; +import { ObservableResult } from '@opentelemetry/api-metrics'; import { CounterMetric, SumAggregator, @@ -270,18 +270,18 @@ describe('PrometheusExporter', () => { }); }); - it('should export an observer aggregation', done => { + it('should export an observable gauge aggregation', done => { function getCpuUsage() { return 0.999; } - meter.createValueObserver( - 'metric_observer', + meter.createObservableGauge( + 'metric_observable_gauge', { description: 'a test description', }, - (observerResult: ObserverResult) => { - observerResult.observe(getCpuUsage(), { + (observableResult: ObservableResult) => { + observableResult.observe(getCpuUsage(), { pid: String(123), core: '1', }); @@ -298,9 +298,9 @@ describe('PrometheusExporter', () => { const lines = body.split('\n'); assert.deepStrictEqual(lines, [ - '# HELP metric_observer a test description', - '# TYPE metric_observer gauge', - `metric_observer{pid="123",core="1"} 0.999 ${mockedHrTimeMs}`, + '# HELP metric_observable_gauge a test description', + '# TYPE metric_observable_gauge gauge', + `metric_observable_gauge{pid="123",core="1"} 0.999 ${mockedHrTimeMs}`, '', ]); done(); @@ -472,18 +472,18 @@ describe('PrometheusExporter', () => { }); }); - it('should export a SumObserver as a counter', done => { + it('should export an ObservableCounter as a counter', done => { function getValue() { return 20; } - meter.createSumObserver( - 'sum_observer', + meter.createObservableCounter( + 'metric_observable_counter', { description: 'a test description', }, - (observerResult: ObserverResult) => { - observerResult.observe(getValue(), { + (observableResult: ObservableResult) => { + observableResult.observe(getValue(), { key1: 'labelValue1', }); } @@ -498,9 +498,9 @@ describe('PrometheusExporter', () => { const lines = body.split('\n'); assert.deepStrictEqual(lines, [ - '# HELP sum_observer a test description', - '# TYPE sum_observer gauge', - `sum_observer{key1="labelValue1"} 20 ${mockedHrTimeMs}`, + '# HELP metric_observable_counter a test description', + '# TYPE metric_observable_counter gauge', + `metric_observable_counter{key1="labelValue1"} 20 ${mockedHrTimeMs}`, '', ]); }); @@ -512,18 +512,18 @@ describe('PrometheusExporter', () => { }); }); - it('should export a UpDownSumObserver as a gauge', done => { + it('should export an ObservableUpDownCounter as a gauge', done => { function getValue() { return 20; } - meter.createUpDownSumObserver( - 'updown_observer', + meter.createObservableUpDownCounter( + 'metric_observable_up_down_counter', { description: 'a test description', }, - (observerResult: ObserverResult) => { - observerResult.observe(getValue(), { + (observableResult: ObservableResult) => { + observableResult.observe(getValue(), { key1: 'labelValue1', }); } @@ -538,9 +538,9 @@ describe('PrometheusExporter', () => { const lines = body.split('\n'); assert.deepStrictEqual(lines, [ - '# HELP updown_observer a test description', - '# TYPE updown_observer gauge', - `updown_observer{key1="labelValue1"} 20 ${mockedHrTimeMs}`, + '# HELP metric_observable_up_down_counter a test description', + '# TYPE metric_observable_up_down_counter gauge', + `metric_observable_up_down_counter{key1="labelValue1"} 20 ${mockedHrTimeMs}`, '', ]); }); @@ -552,12 +552,12 @@ describe('PrometheusExporter', () => { }); }); - it('should export a ValueRecorder as a summary', done => { - const valueRecorder = meter.createValueRecorder('value_recorder', { + it('should export a Histogram as a summary', done => { + const histogram = meter.createHistogram('test_histogram', { description: 'a test description', }); - valueRecorder.bind({ key1: 'labelValue1' }).record(20); + histogram.bind({ key1: 'labelValue1' }).record(20); meter.collect().then(() => { exporter.export(meter.getProcessor().checkPointSet(), () => { @@ -568,11 +568,11 @@ describe('PrometheusExporter', () => { const lines = body.split('\n'); assert.deepStrictEqual(lines, [ - '# HELP value_recorder a test description', - '# TYPE value_recorder histogram', - `value_recorder_count{key1="labelValue1"} 1 ${mockedHrTimeMs}`, - `value_recorder_sum{key1="labelValue1"} 20 ${mockedHrTimeMs}`, - `value_recorder_bucket{key1="labelValue1",le="+Inf"} 1 ${mockedHrTimeMs}`, + '# HELP test_histogram a test description', + '# TYPE test_histogram histogram', + `test_histogram_count{key1="labelValue1"} 1 ${mockedHrTimeMs}`, + `test_histogram_sum{key1="labelValue1"} 20 ${mockedHrTimeMs}`, + `test_histogram_bucket{key1="labelValue1",le="+Inf"} 1 ${mockedHrTimeMs}`, '', ]); diff --git a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts index 4934ebb7889..7c3582f07bd 100644 --- a/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts +++ b/experimental/packages/opentelemetry-exporter-prometheus/test/PrometheusSerializer.test.ts @@ -19,9 +19,9 @@ import { LastValueAggregator, MeterProvider, CounterMetric, - ValueRecorderMetric, + HistogramMetric, UpDownCounterMetric, - ValueObserverMetric, + ObservableGaugeMetric, } from '@opentelemetry/sdk-metrics-base'; import { diag, DiagLogLevel } from '@opentelemetry/api'; import * as assert from 'assert'; @@ -99,15 +99,15 @@ describe('PrometheusSerializer', () => { const meter = new MeterProvider({ processor: new ExactProcessor(LastValueAggregator), }).getMeter('test'); - const observer = meter.createValueObserver( + const observableGauge = meter.createObservableGauge( 'test', {}, - observerResult => { - observerResult.observe(1, labels); + observableResult => { + observableResult.observe(1, labels); } - ) as ValueObserverMetric; + ) as ObservableGaugeMetric; await meter.collect(); - const records = await observer.getMetricRecord(); + const records = await observableGauge.getMetricRecord(); const record = records[0]; const result = serializer.serializeRecord( @@ -126,15 +126,15 @@ describe('PrometheusSerializer', () => { const meter = new MeterProvider({ processor: new ExactProcessor(LastValueAggregator), }).getMeter('test'); - const observer = meter.createValueObserver( + const observableGauge = meter.createObservableGauge( 'test', {}, - observerResult => { - observerResult.observe(1, labels); + observableResult => { + observableResult.observe(1, labels); } - ) as ValueObserverMetric; + ) as ObservableGaugeMetric; await meter.collect(); - const records = await observer.getMetricRecord(); + const records = await observableGauge.getMetricRecord(); const record = records[0]; const result = serializer.serializeRecord( @@ -153,13 +153,13 @@ describe('PrometheusSerializer', () => { const processor = new ExactProcessor(HistogramAggregator, [1, 10, 100]); const meter = new MeterProvider({ processor }).getMeter('test'); - const recorder = meter.createValueRecorder('test', { + const histogram = meter.createHistogram('test', { description: 'foobar', - }) as ValueRecorderMetric; + }) as HistogramMetric; - recorder.bind(labels).record(5); + histogram.bind(labels).record(5); - const records = await recorder.getMetricRecord(); + const records = await histogram.getMetricRecord(); const record = records[0]; const result = serializer.serializeRecord( @@ -181,13 +181,13 @@ describe('PrometheusSerializer', () => { const serializer = new PrometheusSerializer(); const meter = new MeterProvider().getMeter('test'); - const recorder = meter.createValueRecorder('test', { + const histogram = meter.createHistogram('test', { description: 'foobar', boundaries: [1, 10, 100], - }) as ValueRecorderMetric; - recorder.bind(labels).record(5); + }) as HistogramMetric; + histogram.bind(labels).record(5); - const records = await recorder.getMetricRecord(); + const records = await histogram.getMetricRecord(); const record = records[0]; const result = serializer.serializeRecord( @@ -210,12 +210,12 @@ describe('PrometheusSerializer', () => { const processor = new ExactProcessor(HistogramAggregator, [1, 10, 100]); const meter = new MeterProvider({ processor }).getMeter('test'); - const recorder = meter.createValueRecorder('test', { + const histogram = meter.createHistogram('test', { description: 'foobar', - }) as ValueRecorderMetric; - recorder.bind(labels).record(5); + }) as HistogramMetric; + histogram.bind(labels).record(5); - const records = await recorder.getMetricRecord(); + const records = await histogram.getMetricRecord(); const record = records[0]; const result = serializer.serializeRecord( @@ -304,17 +304,17 @@ describe('PrometheusSerializer', () => { processor: new ExactProcessor(LastValueAggregator), }).getMeter('test'); const processor = new PrometheusLabelsBatcher(); - const observer = meter.createValueObserver( + const observableGauge = meter.createObservableGauge( 'test', { description: 'foobar', }, - observerResult => { - observerResult.observe(1, labels); + observableResult => { + observableResult.observe(1, labels); } - ) as ValueObserverMetric; + ) as ObservableGaugeMetric; await meter.collect(); - const records = await observer.getMetricRecord(); + const records = await observableGauge.getMetricRecord(); records.forEach(it => processor.process(it)); const checkPointSet = processor.checkPointSet(); @@ -336,16 +336,16 @@ describe('PrometheusSerializer', () => { const processor = new ExactProcessor(HistogramAggregator, [1, 10, 100]); const meter = new MeterProvider({ processor }).getMeter('test'); - const recorder = meter.createValueRecorder('test', { + const histogram = meter.createHistogram('test', { description: 'foobar', - }) as ValueRecorderMetric; - recorder.bind({ val: '1' }).record(5); - recorder.bind({ val: '1' }).record(50); - recorder.bind({ val: '1' }).record(120); + }) as HistogramMetric; + histogram.bind({ val: '1' }).record(5); + histogram.bind({ val: '1' }).record(50); + histogram.bind({ val: '1' }).record(120); - recorder.bind({ val: '2' }).record(5); + histogram.bind({ val: '2' }).record(5); - const records = await recorder.getMetricRecord(); + const records = await histogram.getMetricRecord(); const labelBatcher = new PrometheusLabelsBatcher(); records.forEach(it => labelBatcher.process(it)); const checkPointSet = labelBatcher.checkPointSet(); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/README.md b/experimental/packages/opentelemetry-sdk-metrics-base/README.md index 1761164b0f5..b760ecc3369 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/README.md +++ b/experimental/packages/opentelemetry-sdk-metrics-base/README.md @@ -73,7 +73,7 @@ boundCounter.add(Math.random() > 0.5 ? 1 : -1); ``` -### Value Observer +### Observable Gauge Choose this kind of metric when only last value is important without worry about aggregation. The callback can be sync or async. @@ -85,11 +85,11 @@ const meter = new MeterProvider().getMeter('your-meter-name'); // async callback - for operation that needs to wait for value -meter.createValueObserver('your_metric_name', { - description: 'Example of an async observer with callback', -}, async (observerResult) => { +meter.createObservableGauge('your_metric_name', { + description: 'Example of an async observable gauge with callback', +}, async (observableResult) => { const value = await getAsyncValue(); - observerResult.observe(value, { label: '1' }); + observableResult.observe(value, { label: '1' }); }); function getAsyncValue() { @@ -101,11 +101,11 @@ function getAsyncValue() { } // sync callback in case you don't need to wait for value -meter.createValueObserver('your_metric_name', { - description: 'Example of a sync observer with callback', -}, (observerResult) => { - observerResult.observe(getRandomValue(), { label: '1' }); - observerResult.observe(getRandomValue(), { label: '2' }); +meter.createObservableGauge('your_metric_name', { + description: 'Example of a sync observable gauge with callback', +}, (observableResult) => { + observableResult.observe(getRandomValue(), { label: '1' }); + observableResult.observe(getRandomValue(), { label: '2' }); }); function getRandomValue() { @@ -113,7 +113,7 @@ function getRandomValue() { } ``` -### UpDownSumObserver +### ObservableUpDownCounter Choose this kind of metric when sum is important and you want to capture any value that starts at zero and rises or falls throughout the process lifetime. The callback can be sync or async. @@ -124,11 +124,11 @@ const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); const meter = new MeterProvider().getMeter('your-meter-name'); // async callback - for operation that needs to wait for value -meter.createUpDownSumObserver('your_metric_name', { - description: 'Example of an async observer with callback', -}, async (observerResult) => { +meter.createObservableUpDownCounter('your_metric_name', { + description: 'Example of an async observable up down counter with callback', +}, async (observableResult) => { const value = await getAsyncValue(); - observerResult.observe(value, { label: '1' }); + observableResult.observe(value, { label: '1' }); }); function getAsyncValue() { @@ -140,10 +140,10 @@ function getAsyncValue() { } // sync callback in case you don't need to wait for value -meter.createUpDownSumObserver('your_metric_name', { - description: 'Example of a sync observer with callback', -}, (observerResult) => { - observerResult.observe(getRandomValue(), { label: '1' }); +meter.createObservableUpDownCounter('your_metric_name', { + description: 'Example of a sync observable up down counter with callback', +}, (observableResult) => { + observableResult.observe(getRandomValue(), { label: '1' }); }); function getRandomValue() { @@ -152,7 +152,7 @@ function getRandomValue() { ``` -### Sum Observer +### Observable Counter Choose this kind of metric when collecting a sum that never decreases. The callback can be sync or async. @@ -163,11 +163,11 @@ const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); const meter = new MeterProvider().getMeter('your-meter-name'); // async callback in case you need to wait for values -meter.createSumObserver('example_metric', { - description: 'Example of an async sum observer with callback', -}, async (observerResult) => { +meter.createObservableCounter('example_metric', { + description: 'Example of an async observable counter with callback', +}, async (observableResult) => { const value = await getAsyncValue(); - observerResult.observe(value, { label: '1' }); + observableResult.observe(value, { label: '1' }); }); function getAsyncValue() { @@ -179,11 +179,11 @@ function getAsyncValue() { } // sync callback in case you don't need to wait for values -meter.createSumObserver('example_metric', { - description: 'Example of a sync sum observer with callback', -}, (observerResult) => { +meter.createObservableCounter('example_metric', { + description: 'Example of a sync observable counter with callback', +}, (observableResult) => { const value = getRandomValue(); - observerResult.observe(value, { label: '1' }); + observableResult.observe(value, { label: '1' }); }); function getRandomValue() { @@ -193,7 +193,7 @@ function getRandomValue() { ### Batch Observer -Choose this kind of metric when you need to update multiple observers with the results of a single async calculation. +Choose this kind of metric when you need to update multiple observables with the results of a single async calculation. ```js const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); @@ -213,17 +213,17 @@ const meter = new MeterProvider({ interval: 3000, }).getMeter('example-observer'); -const cpuUsageMetric = meter.createValueObserver('cpu_usage_per_app', { +const cpuUsageMetric = meter.createObservableGauge('cpu_usage_per_app', { description: 'CPU', }); -const MemUsageMetric = meter.createValueObserver('mem_usage_per_app', { +const MemUsageMetric = meter.createObservableGauge('mem_usage_per_app', { description: 'Memory', }); -meter.createBatchObserver((observerBatchResult) => { +meter.createBatchObserver((batchObserverResult) => { getSomeAsyncMetrics().then(metrics => { - observerBatchResult.observe({ app: 'myApp' }, [ + batchObserverResult.observe({ app: 'myApp' }, [ cpuUsageMetric.observation(metrics.value1), MemUsageMetric.observation(metrics.value2) ]); @@ -245,11 +245,11 @@ function getSomeAsyncMetrics() { See [examples/prometheus](https://github.com/open-telemetry/opentelemetry-js/tree/main/examples/prometheus) for a short example. -### Value Recorder +### Histogram -`ValueRecorder` is a non-additive synchronous instrument useful for recording any non-additive number, positive or negative. -Values captured by `ValueRecorder.record(value)` are treated as individual events belonging to a distribution that is being summarized. -`ValueRecorder` should be chosen either when capturing measurements that do not contribute meaningfully to a sum, or when capturing numbers that are additive in nature, but where the distribution of individual increments is considered interesting. +`Histogram` is a non-additive synchronous instrument useful for recording any non-additive number, positive or negative. +Values captured by `Histogram.record(value)` are treated as individual events belonging to a distribution that is being summarized. +`Histogram` should be chosen either when capturing measurements that do not contribute meaningfully to a sum, or when capturing numbers that are additive in nature, but where the distribution of individual increments is considered interesting. ## Useful links diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserver.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserver.ts index 90c53844658..576102cb46c 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserver.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserver.ts @@ -23,12 +23,12 @@ const MAX_TIMEOUT_UPDATE_MS = 500; /** This is a SDK implementation of Batch Observer. */ export class BatchObserver { - private _callback: (observerResult: api.BatchObserverResult) => void; + private _callback: (observableResult: api.BatchObserverResult) => void; private _maxTimeoutUpdateMS: number; constructor( options: api.BatchObserverOptions, - callback?: (observerResult: api.BatchObserverResult) => void + callback?: (observableResult: api.BatchObserverResult) => void ) { this._maxTimeoutUpdateMS = options.maxTimeoutUpdateMS ?? MAX_TIMEOUT_UPDATE_MS; @@ -38,27 +38,27 @@ export class BatchObserver { collect(): Promise { diag.debug('getMetricRecord - start'); return new Promise(resolve => { - const observerResult = new BatchObserverResult(); + const batchObserverResult = new BatchObserverResult(); // cancels after MAX_TIMEOUT_MS - no more waiting for results const timer = setTimeout(() => { - observerResult.cancelled = true; + batchObserverResult.cancelled = true; // remove callback to prevent user from updating the values later if - // for any reason the observerBatchResult will be referenced - observerResult.onObserveCalled(); + // for any reason the batchObserverResult will be referenced + batchObserverResult.onObserveCalled(); resolve(); diag.debug('getMetricRecord - timeout'); }, this._maxTimeoutUpdateMS); // sets callback for each "observe" method - observerResult.onObserveCalled(() => { + batchObserverResult.onObserveCalled(() => { clearTimeout(timer); resolve(); diag.debug('getMetricRecord - end'); }); // calls the BatchObserverResult callback - this._callback(observerResult); + this._callback(batchObserverResult); }); } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserverResult.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserverResult.ts index 4e2c0c8b281..f882774ad0b 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserverResult.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/BatchObserverResult.ts @@ -44,14 +44,14 @@ export class BatchObserverResult implements api.BatchObserverResult { return; } observations.forEach(observation => { - observation.observer.bind(labels).update(observation.value); + observation.observable.bind(labels).update(observation.value); }); if (!this._immediate) { this._immediate = setImmediate(() => { if (typeof this._callback === 'function') { this._callback(); // prevent user from updating the values later if for any reason - // the observerBatchResult will be referenced and then try to use + // the batchObserverResult will be referenced and then try to use this._callback = undefined; } }); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/BoundInstrument.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/BoundInstrument.ts index 296bf72909e..67a66b204c9 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/BoundInstrument.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/BoundInstrument.ts @@ -117,9 +117,9 @@ export class BoundUpDownCounter /** * BoundMeasure is an implementation of the {@link BoundMeasure} interface. */ -export class BoundValueRecorder +export class BoundHistogram extends BaseBoundInstrument - implements api.BoundValueRecorder { + implements api.BoundHistogram { constructor( labels: api.Labels, disabled: boolean, @@ -135,11 +135,11 @@ export class BoundValueRecorder } /** - * BoundObserver is an implementation of the {@link BoundObserver} interface. + * BoundObservable is an implementation of the {@link BoundObservable} interface. */ -export class BoundObserver +export class BoundObservable extends BaseBoundInstrument - implements api.BoundBaseObserver { + implements api.BoundObservableBase { constructor( labels: api.Labels, disabled: boolean, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/ValueRecorderMetric.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/HistogramMetric.ts similarity index 79% rename from experimental/packages/opentelemetry-sdk-metrics-base/src/ValueRecorderMetric.ts rename to experimental/packages/opentelemetry-sdk-metrics-base/src/HistogramMetric.ts index 28e9d7e1b2c..20a7ade3a77 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/ValueRecorderMetric.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/HistogramMetric.ts @@ -17,15 +17,15 @@ import * as api from '@opentelemetry/api-metrics'; import { InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { BoundValueRecorder } from './BoundInstrument'; +import { BoundHistogram } from './BoundInstrument'; import { Processor } from './export/Processor'; import { MetricKind } from './export/types'; import { Metric } from './Metric'; -/** This is a SDK implementation of Value Recorder Metric. */ -export class ValueRecorderMetric - extends Metric - implements api.ValueRecorder { +/** This is a SDK implementation of Histogram Metric. */ +export class HistogramMetric + extends Metric + implements api.Histogram { constructor( name: string, options: api.MetricOptions, @@ -36,14 +36,14 @@ export class ValueRecorderMetric super( name, options, - MetricKind.VALUE_RECORDER, + MetricKind.HISTOGRAM, resource, instrumentationLibrary ); } - protected _makeInstrument(labels: api.Labels): BoundValueRecorder { - return new BoundValueRecorder( + protected _makeInstrument(labels: api.Labels): BoundHistogram { + return new BoundHistogram( labels, this._disabled, this._valueType, diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts index 9a77e865bb8..143d50692a1 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/Meter.ts @@ -25,12 +25,12 @@ import { PushController } from './export/Controller'; import { NoopExporter } from './export/NoopExporter'; import { Processor, UngroupedProcessor } from './export/Processor'; import { Metric } from './Metric'; -import { SumObserverMetric } from './SumObserverMetric'; +import { ObservableCounterMetric } from './ObservableCounterMetric'; import { DEFAULT_CONFIG, DEFAULT_METRIC_OPTIONS, MeterConfig } from './types'; import { UpDownCounterMetric } from './UpDownCounterMetric'; -import { UpDownSumObserverMetric } from './UpDownSumObserverMetric'; -import { ValueObserverMetric } from './ValueObserverMetric'; -import { ValueRecorderMetric } from './ValueRecorderMetric'; +import { ObservableUpDownCounterMetric } from './ObservableUpDownCounterMetric'; +import { ObservableGaugeMetric } from './ObservableGaugeMetric'; +import { HistogramMetric } from './HistogramMetric'; // eslint-disable-next-line @typescript-eslint/no-var-requires const merge = require('lodash.merge'); // @TODO - replace once the core is released @@ -68,34 +68,34 @@ export class Meter implements api.Meter { } /** - * Creates and returns a new {@link ValueRecorder}. + * Creates and returns a new {@link Histogram}. * @param name the name of the metric. * @param [options] the metric options. */ - createValueRecorder( + createHistogram( name: string, options?: api.MetricOptions - ): api.ValueRecorder { + ): api.Histogram { if (!this._isValidName(name)) { diag.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return api.NOOP_VALUE_RECORDER_METRIC; + return api.NOOP_HISTOGRAM_METRIC; } const opt: api.MetricOptions = { ...DEFAULT_METRIC_OPTIONS, ...options, }; - const valueRecorder = new ValueRecorderMetric( + const histogram = new HistogramMetric( name, opt, this._processor, this._resource, this._instrumentationLibrary ); - this._registerMetric(name, valueRecorder); - return valueRecorder; + this._registerMetric(name, histogram); + return histogram; } /** @@ -163,27 +163,27 @@ export class Meter implements api.Meter { } /** - * Creates a new `ValueObserver` metric. + * Creates a new `ObservableGauge` metric. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the value observer callback + * @param [callback] the observable gauge callback */ - createValueObserver( + createObservableGauge( name: string, options: api.MetricOptions = {}, - callback?: (observerResult: api.ObserverResult) => unknown - ): api.ValueObserver { + callback?: (observableResult: api.ObservableResult) => unknown + ): api.ObservableGauge { if (!this._isValidName(name)) { diag.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return api.NOOP_VALUE_OBSERVER_METRIC; + return api.NOOP_OBSERVABLE_GAUGE_METRIC; } const opt: api.MetricOptions = { ...DEFAULT_METRIC_OPTIONS, ...options, }; - const valueObserver = new ValueObserverMetric( + const observableGauge = new ObservableGaugeMetric( name, opt, this._processor, @@ -191,26 +191,26 @@ export class Meter implements api.Meter { this._instrumentationLibrary, callback ); - this._registerMetric(name, valueObserver); - return valueObserver; + this._registerMetric(name, observableGauge); + return observableGauge; } - createSumObserver( + createObservableCounter( name: string, options: api.MetricOptions = {}, - callback?: (observerResult: api.ObserverResult) => unknown - ): api.SumObserver { + callback?: (observableResult: api.ObservableResult) => unknown + ): api.ObservableCounter { if (!this._isValidName(name)) { diag.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return api.NOOP_SUM_OBSERVER_METRIC; + return api.NOOP_OBSERVABLE_COUNTER_METRIC; } const opt: api.MetricOptions = { ...DEFAULT_METRIC_OPTIONS, ...options, }; - const sumObserver = new SumObserverMetric( + const observableCounter = new ObservableCounterMetric( name, opt, this._processor, @@ -218,32 +218,32 @@ export class Meter implements api.Meter { this._instrumentationLibrary, callback ); - this._registerMetric(name, sumObserver); - return sumObserver; + this._registerMetric(name, observableCounter); + return observableCounter; } /** - * Creates a new `UpDownSumObserver` metric. + * Creates a new `ObservableUpDownCounter` metric. * @param name the name of the metric. * @param [options] the metric options. - * @param [callback] the value observer callback + * @param [callback] the observable gauge callback */ - createUpDownSumObserver( + createObservableUpDownCounter( name: string, options: api.MetricOptions = {}, - callback?: (observerResult: api.ObserverResult) => unknown - ): api.UpDownSumObserver { + callback?: (observableResult: api.ObservableResult) => unknown + ): api.ObservableUpDownCounter { if (!this._isValidName(name)) { diag.warn( `Invalid metric name ${name}. Defaulting to noop metric implementation.` ); - return api.NOOP_UP_DOWN_SUM_OBSERVER_METRIC; + return api.NOOP_OBSERVABLE_UP_DOWN_COUNTER_METRIC; } const opt: api.MetricOptions = { ...DEFAULT_METRIC_OPTIONS, ...options, }; - const upDownSumObserver = new UpDownSumObserverMetric( + const observableUpDownCounter = new ObservableUpDownCounterMetric( name, opt, this._processor, @@ -251,8 +251,8 @@ export class Meter implements api.Meter { this._instrumentationLibrary, callback ); - this._registerMetric(name, upDownSumObserver); - return upDownSumObserver; + this._registerMetric(name, observableUpDownCounter); + return observableUpDownCounter; } /** @@ -261,7 +261,7 @@ export class Meter implements api.Meter { * @param [options] the batch options. */ createBatchObserver( - callback: (observerResult: api.BatchObserverResult) => void, + callback: (observableResult: api.BatchObserverResult) => void, options: api.BatchObserverOptions = {} ): BatchObserver { const opt: api.BatchObserverOptions = { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/BaseObserverMetric.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableBaseMetric.ts similarity index 68% rename from experimental/packages/opentelemetry-sdk-metrics-base/src/BaseObserverMetric.ts rename to experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableBaseMetric.ts index 6f48df49bf0..60626680a57 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/BaseObserverMetric.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableBaseMetric.ts @@ -17,22 +17,22 @@ import * as api from '@opentelemetry/api-metrics'; import { Observation } from '@opentelemetry/api-metrics'; import { InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { BoundObserver } from './BoundInstrument'; +import { BoundObservable } from './BoundInstrument'; import { Processor } from './export/Processor'; import { MetricKind, MetricRecord } from './export/types'; import { Metric } from './Metric'; -import { ObserverResult } from './ObserverResult'; +import { ObservableResult } from './ObservableResult'; const NOOP_CALLBACK = () => {}; /** * This is a SDK implementation of Base Observer Metric. - * All observers should extend this class + * All observables should extend this class */ -export abstract class BaseObserverMetric - extends Metric - implements api.BaseObserver { - protected _callback: (observerResult: api.ObserverResult) => unknown; +export abstract class ObservableBaseMetric + extends Metric + implements api.ObservableBase { + protected _callback: (observableResult: api.ObservableResult) => unknown; constructor( name: string, @@ -41,14 +41,14 @@ export abstract class BaseObserverMetric resource: Resource, metricKind: MetricKind, instrumentationLibrary: InstrumentationLibrary, - callback?: (observerResult: api.ObserverResult) => unknown + callback?: (observableResult: api.ObservableResult) => unknown ) { super(name, options, metricKind, resource, instrumentationLibrary); this._callback = callback || NOOP_CALLBACK; } - protected _makeInstrument(labels: api.Labels): BoundObserver { - return new BoundObserver( + protected _makeInstrument(labels: api.Labels): BoundObservable { + return new BoundObservable( labels, this._disabled, this._valueType, @@ -57,16 +57,16 @@ export abstract class BaseObserverMetric } override async getMetricRecord(): Promise { - const observerResult = new ObserverResult(); - await this._callback(observerResult); + const observableResult = new ObservableResult(); + await this._callback(observableResult); - this._processResults(observerResult); + this._processResults(observableResult); return super.getMetricRecord(); } - protected _processResults(observerResult: ObserverResult): void { - observerResult.values.forEach((value, labels) => { + protected _processResults(observableResult: ObservableResult): void { + observableResult.values.forEach((value, labels) => { const instrument = this.bind(labels); instrument.update(value); }); @@ -75,7 +75,7 @@ export abstract class BaseObserverMetric observation(value: number): Observation { return { value, - observer: this as BaseObserverMetric, + observable: this as ObservableBaseMetric, }; } } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/SumObserverMetric.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableCounterMetric.ts similarity index 72% rename from experimental/packages/opentelemetry-sdk-metrics-base/src/SumObserverMetric.ts rename to experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableCounterMetric.ts index 8f58727cebd..5465f14eff8 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/SumObserverMetric.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableCounterMetric.ts @@ -17,38 +17,38 @@ import * as api from '@opentelemetry/api-metrics'; import { InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { BaseObserverMetric } from './BaseObserverMetric'; +import { ObservableBaseMetric } from './ObservableBaseMetric'; import { Processor } from './export/Processor'; import { LastValue, MetricKind } from './export/types'; -import { ObserverResult } from './ObserverResult'; +import { ObservableResult } from './ObservableResult'; -/** This is a SDK implementation of SumObserver Metric. */ -export class SumObserverMetric - extends BaseObserverMetric - implements api.SumObserver { +/** This is a SDK implementation of ObservableCounter Metric. */ +export class ObservableCounterMetric + extends ObservableBaseMetric + implements api.ObservableCounter { constructor( name: string, options: api.MetricOptions, processor: Processor, resource: Resource, instrumentationLibrary: InstrumentationLibrary, - callback?: (observerResult: api.ObserverResult) => unknown + callback?: (observableResult: api.ObservableResult) => unknown ) { super( name, options, processor, resource, - MetricKind.SUM_OBSERVER, + MetricKind.OBSERVABLE_COUNTER, instrumentationLibrary, callback ); } - protected override _processResults(observerResult: ObserverResult): void { - observerResult.values.forEach((value, labels) => { + protected override _processResults(observableResult: ObservableResult): void { + observableResult.values.forEach((value, labels) => { const instrument = this.bind(labels); - // SumObserver is monotonic which means it should only accept values + // ObservableCounter is monotonic which means it should only accept values // greater or equal then previous value const previous = instrument.getAggregator().toPoint(); let previousValue = -Infinity; diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/ValueObserverMetric.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableGaugeMetric.ts similarity index 78% rename from experimental/packages/opentelemetry-sdk-metrics-base/src/ValueObserverMetric.ts rename to experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableGaugeMetric.ts index a7ac5c5ff59..2d59e78f952 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/ValueObserverMetric.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableGaugeMetric.ts @@ -16,28 +16,28 @@ import * as api from '@opentelemetry/api-metrics'; import { InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { BaseObserverMetric } from './BaseObserverMetric'; +import { ObservableBaseMetric } from './ObservableBaseMetric'; import { Processor } from './export/Processor'; import { MetricKind } from './export/types'; -/** This is a SDK implementation of Value Observer Metric. */ -export class ValueObserverMetric - extends BaseObserverMetric - implements api.ValueObserver { +/** This is a SDK implementation of ObservableGauge Metric. */ +export class ObservableGaugeMetric + extends ObservableBaseMetric + implements api.ObservableGauge { constructor( name: string, options: api.MetricOptions, processor: Processor, resource: Resource, instrumentationLibrary: InstrumentationLibrary, - callback?: (observerResult: api.ObserverResult) => unknown + callback?: (observableResult: api.ObservableResult) => unknown ) { super( name, options, processor, resource, - MetricKind.VALUE_OBSERVER, + MetricKind.OBSERVABLE_GAUGE, instrumentationLibrary, callback ); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/ObserverResult.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableResult.ts similarity index 83% rename from experimental/packages/opentelemetry-sdk-metrics-base/src/ObserverResult.ts rename to experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableResult.ts index 60dcc044493..51fc07899ec 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/ObserverResult.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableResult.ts @@ -15,14 +15,14 @@ */ import { - ObserverResult as TypeObserverResult, + ObservableResult as TypeObservableResult, Labels, } from '@opentelemetry/api-metrics'; /** - * Implementation of {@link TypeObserverResult} + * Implementation of {@link TypeObservableResult} */ -export class ObserverResult implements TypeObserverResult { +export class ObservableResult implements TypeObservableResult { values: Map = new Map(); observe(value: number, labels: Labels): void { diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/UpDownSumObserverMetric.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableUpDownCounterMetric.ts similarity index 76% rename from experimental/packages/opentelemetry-sdk-metrics-base/src/UpDownSumObserverMetric.ts rename to experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableUpDownCounterMetric.ts index 31cec8af7a5..d9a767044ab 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/UpDownSumObserverMetric.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/ObservableUpDownCounterMetric.ts @@ -17,28 +17,28 @@ import * as api from '@opentelemetry/api-metrics'; import { InstrumentationLibrary } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { BaseObserverMetric } from './BaseObserverMetric'; +import { ObservableBaseMetric } from './ObservableBaseMetric'; import { Processor } from './export/Processor'; import { MetricKind } from './export/types'; -/** This is a SDK implementation of UpDownSumObserver Metric. */ -export class UpDownSumObserverMetric - extends BaseObserverMetric - implements api.UpDownSumObserver { +/** This is a SDK implementation of ObservableUpDownCounter Metric. */ +export class ObservableUpDownCounterMetric + extends ObservableBaseMetric + implements api.ObservableUpDownCounter { constructor( name: string, options: api.MetricOptions, processor: Processor, resource: Resource, instrumentationLibrary: InstrumentationLibrary, - callback?: (observerResult: api.ObserverResult) => unknown + callback?: (observableResult: api.ObservableResult) => unknown ) { super( name, options, processor, resource, - MetricKind.UP_DOWN_SUM_OBSERVER, + MetricKind.OBSERVABLE_UP_DOWN_COUNTER, instrumentationLibrary, callback ); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Processor.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Processor.ts index 03d2cbcf52d..3cc23c70f00 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Processor.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/Processor.ts @@ -54,12 +54,12 @@ export class UngroupedProcessor extends Processor { case MetricKind.UP_DOWN_COUNTER: return new aggregators.SumAggregator(); - case MetricKind.SUM_OBSERVER: - case MetricKind.UP_DOWN_SUM_OBSERVER: - case MetricKind.VALUE_OBSERVER: + case MetricKind.OBSERVABLE_COUNTER: + case MetricKind.OBSERVABLE_UP_DOWN_COUNTER: + case MetricKind.OBSERVABLE_GAUGE: return new aggregators.LastValueAggregator(); - case MetricKind.VALUE_RECORDER: + case MetricKind.HISTOGRAM: return new aggregators.HistogramAggregator( metricDescriptor.boundaries || [Infinity] ); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts index 889e96598d7..33206ea9363 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts @@ -27,10 +27,10 @@ import { Resource } from '@opentelemetry/resources'; export enum MetricKind { COUNTER, UP_DOWN_COUNTER, - VALUE_RECORDER, - SUM_OBSERVER, - UP_DOWN_SUM_OBSERVER, - VALUE_OBSERVER, + HISTOGRAM, + OBSERVABLE_COUNTER, + OBSERVABLE_UP_DOWN_COUNTER, + OBSERVABLE_GAUGE, BATCH_OBSERVER, } diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts index afcdeea5b13..a3d74d5352c 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/index.ts @@ -16,11 +16,11 @@ export * from './BoundInstrument'; export * from './CounterMetric'; -export * from './ValueRecorderMetric'; +export * from './HistogramMetric'; export * from './Meter'; export * from './MeterProvider'; export * from './Metric'; -export * from './ValueObserverMetric'; +export * from './ObservableGaugeMetric'; export * from './export/aggregators'; export * from './export/ConsoleMetricExporter'; export * from './export/Processor'; diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts b/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts index 0fcc05ede30..e89545f7adf 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/test/Meter.test.ts @@ -34,15 +34,15 @@ import { MetricRecord, Sum, UpDownCounterMetric, - ValueObserverMetric, - ValueRecorderMetric, + ObservableGaugeMetric, + HistogramMetric, } from '../src'; import { BatchObserver } from '../src/BatchObserver'; import { BatchObserverResult } from '../src/BatchObserverResult'; import { SumAggregator } from '../src/export/aggregators'; import { Processor } from '../src/export/Processor'; -import { SumObserverMetric } from '../src/SumObserverMetric'; -import { UpDownSumObserverMetric } from '../src/UpDownSumObserverMetric'; +import { ObservableCounterMetric } from '../src/ObservableCounterMetric'; +import { ObservableUpDownCounterMetric } from '../src/ObservableUpDownCounterMetric'; import { hashLabels } from '../src/Utils'; const nonNumberValues = [ @@ -550,33 +550,33 @@ describe('Meter', () => { }); }); - describe('#ValueRecorder', () => { - it('should create a valueRecorder', () => { - const valueRecorder = meter.createValueRecorder('name'); - assert.ok(valueRecorder instanceof Metric); + describe('#Histogram', () => { + it('should create a histogram', () => { + const histogram = meter.createHistogram('name'); + assert.ok(histogram instanceof Metric); }); - it('should create a valueRecorder with options', () => { - const valueRecorder = meter.createValueRecorder('name', { + it('should create a histogram with options', () => { + const histogram = meter.createHistogram('name', { description: 'desc', unit: '1', disabled: false, }); - assert.ok(valueRecorder instanceof Metric); + assert.ok(histogram instanceof Metric); }); - it('should set histogram boundaries for value recorder', async () => { - const valueRecorder = meter.createValueRecorder('name', { + it('should set histogram boundaries for histogram', async () => { + const histogram = meter.createHistogram('name', { description: 'desc', unit: '1', disabled: false, boundaries: [10, 20, 30, 100], - }) as ValueRecorderMetric; + }) as HistogramMetric; - valueRecorder.record(10); - valueRecorder.record(30); - valueRecorder.record(50); - valueRecorder.record(200); + histogram.record(10); + histogram.record(30); + histogram.record(50); + histogram.record(200); await meter.collect(); const [record] = meter.getProcessor().checkPointSet(); @@ -589,30 +589,30 @@ describe('Meter', () => { sum: 290, }); - assert.ok(valueRecorder instanceof Metric); + assert.ok(histogram instanceof Metric); }); it('should pipe through resource', async () => { - const valueRecorder = meter.createValueRecorder( + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - assert.ok(valueRecorder.resource instanceof Resource); + ) as HistogramMetric; + assert.ok(histogram.resource instanceof Resource); - valueRecorder.record(1, { foo: 'bar' }); + histogram.record(1, { foo: 'bar' }); - const [record] = await valueRecorder.getMetricRecord(); + const [record] = await histogram.getMetricRecord(); assert.ok(record.resource instanceof Resource); }); it('should pipe through instrumentation library', async () => { - const valueRecorder = meter.createValueRecorder( + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - assert.ok(valueRecorder.instrumentationLibrary); + ) as HistogramMetric; + assert.ok(histogram.instrumentationLibrary); - valueRecorder.record(1, { foo: 'bar' }); + histogram.record(1, { foo: 'bar' }); - const [record] = await valueRecorder.getMetricRecord(); + const [record] = await histogram.getMetricRecord(); const { name, version } = record.instrumentationLibrary; assert.strictEqual(name, 'test-meter'); assert.strictEqual(version, undefined); @@ -620,42 +620,42 @@ describe('Meter', () => { describe('names', () => { it('should return no op metric if name is an empty string', () => { - const valueRecorder = meter.createValueRecorder(''); - assert.ok(valueRecorder instanceof api.NoopMetric); + const histogram = meter.createHistogram(''); + assert.ok(histogram instanceof api.NoopMetric); }); it('should return no op metric if name does not start with a letter', () => { - const valueRecorder1 = meter.createValueRecorder('1name'); - const valueRecorder_ = meter.createValueRecorder('_name'); - assert.ok(valueRecorder1 instanceof api.NoopMetric); - assert.ok(valueRecorder_ instanceof api.NoopMetric); + const histogram1 = meter.createHistogram('1name'); + const histogram_ = meter.createHistogram('_name'); + assert.ok(histogram1 instanceof api.NoopMetric); + assert.ok(histogram_ instanceof api.NoopMetric); }); it('should return no op metric if name is an empty string contain only letters, numbers, ".", "_", and "-"', () => { - const valueRecorder = meter.createValueRecorder( + const histogram = meter.createHistogram( 'name with invalid characters^&*(' ); - assert.ok(valueRecorder instanceof api.NoopMetric); + assert.ok(histogram instanceof api.NoopMetric); }); }); describe('.bind()', () => { const performanceTimeOrigin = hrTime(); - it('should create a valueRecorder instrument', () => { - const valueRecorder = meter.createValueRecorder( + it('should create a histogram instrument', () => { + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - const boundValueRecorder = valueRecorder.bind(labels); - assert.doesNotThrow(() => boundValueRecorder.record(10)); + ) as HistogramMetric; + const boundHistogram = histogram.bind(labels); + assert.doesNotThrow(() => boundHistogram.record(10)); }); it('should not set the instrument data when disabled', async () => { - const valueRecorder = meter.createValueRecorder('name', { + const histogram = meter.createHistogram('name', { disabled: true, - }) as ValueRecorderMetric; - const boundValueRecorder = valueRecorder.bind(labels); - boundValueRecorder.record(10); + }) as HistogramMetric; + const boundHistogram = histogram.bind(labels); + boundHistogram.record(10); await meter.collect(); const [record1] = meter.getProcessor().checkPointSet(); @@ -673,10 +673,10 @@ describe('Meter', () => { }); it('should accept negative (and positive) values', async () => { - const valueRecorder = meter.createValueRecorder('name'); - const boundValueRecorder = valueRecorder.bind(labels); - boundValueRecorder.record(-10); - boundValueRecorder.record(50); + const histogram = meter.createHistogram('name'); + const boundHistogram = histogram.bind(labels); + boundHistogram.record(-10); + boundHistogram.record(50); await meter.collect(); const [record1] = meter.getProcessor().checkPointSet(); @@ -698,13 +698,13 @@ describe('Meter', () => { }); it('should return same instrument on same label values', async () => { - const valueRecorder = meter.createValueRecorder( + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - const boundValueRecorder1 = valueRecorder.bind(labels); - boundValueRecorder1.record(10); - const boundValueRecorder2 = valueRecorder.bind(labels); - boundValueRecorder2.record(100); + ) as HistogramMetric; + const boundHistogram1 = histogram.bind(labels); + boundHistogram1.record(10); + const boundHistogram2 = histogram.bind(labels); + boundHistogram2.record(100); await meter.collect(); const [record1] = meter.getProcessor().checkPointSet(); assert.deepStrictEqual( @@ -718,19 +718,19 @@ describe('Meter', () => { sum: 110, } ); - assert.strictEqual(boundValueRecorder1, boundValueRecorder2); + assert.strictEqual(boundHistogram1, boundHistogram2); }); it('should ignore non-number values', async () => { - const valueRecorder = meter.createValueRecorder( + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - const boundValueRecorder = valueRecorder.bind(labels); + ) as HistogramMetric; + const boundHistogram = histogram.bind(labels); await Promise.all( nonNumberValues.map(async val => { // @ts-expect-error verify non number types - boundValueRecorder.record(val); + boundHistogram.record(val); await meter.collect(); const [record1] = meter.getProcessor().checkPointSet(); assert.deepStrictEqual( @@ -750,47 +750,47 @@ describe('Meter', () => { }); describe('.unbind()', () => { - it('should remove the valueRecorder instrument', () => { - const valueRecorder = meter.createValueRecorder( + it('should remove the histogram instrument', () => { + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - const boundValueRecorder = valueRecorder.bind(labels); - assert.strictEqual(valueRecorder['_instruments'].size, 1); - valueRecorder.unbind(labels); - assert.strictEqual(valueRecorder['_instruments'].size, 0); - const boundValueRecorder2 = valueRecorder.bind(labels); - assert.strictEqual(valueRecorder['_instruments'].size, 1); - assert.notStrictEqual(boundValueRecorder, boundValueRecorder2); + ) as HistogramMetric; + const boundHistogram = histogram.bind(labels); + assert.strictEqual(histogram['_instruments'].size, 1); + histogram.unbind(labels); + assert.strictEqual(histogram['_instruments'].size, 0); + const boundHistogram2 = histogram.bind(labels); + assert.strictEqual(histogram['_instruments'].size, 1); + assert.notStrictEqual(boundHistogram, boundHistogram2); }); it('should not fail when removing non existing instrument', () => { - const valueRecorder = meter.createValueRecorder('name'); - valueRecorder.unbind({}); + const histogram = meter.createHistogram('name'); + histogram.unbind({}); }); it('should clear all instruments', () => { - const valueRecorder = meter.createValueRecorder( + const histogram = meter.createHistogram( 'name' - ) as ValueRecorderMetric; - valueRecorder.bind(labels); - assert.strictEqual(valueRecorder['_instruments'].size, 1); - valueRecorder.clear(); - assert.strictEqual(valueRecorder['_instruments'].size, 0); + ) as HistogramMetric; + histogram.bind(labels); + assert.strictEqual(histogram['_instruments'].size, 1); + histogram.clear(); + assert.strictEqual(histogram['_instruments'].size, 0); }); }); }); - describe('#SumObserverMetric', () => { - it('should create an Sum observer', () => { - const sumObserver = meter.createSumObserver('name') as SumObserverMetric; - assert.ok(sumObserver instanceof Metric); + describe('#ObservableCounterMetric', () => { + it('should create an ObservableCounter', () => { + const observableCounter = meter.createObservableCounter('name') as ObservableCounterMetric; + assert.ok(observableCounter instanceof Metric); }); - it('should return noop observer when name is invalid', () => { + it('should return noop observable counter when name is invalid', () => { // Need to stub/spy on the underlying logger as the "diag" instance is global const spy = sinon.stub(diag, 'warn'); - const sumObserver = meter.createSumObserver('na me'); - assert.ok(sumObserver === api.NOOP_SUM_OBSERVER_METRIC); + const observableCounter = meter.createObservableCounter('na me'); + assert.ok(observableCounter === api.NOOP_OBSERVABLE_COUNTER_METRIC); const args = spy.args[0]; assert.ok( args[0], @@ -798,13 +798,13 @@ describe('Meter', () => { ); }); - it('should create observer with options', () => { - const sumObserver = meter.createSumObserver('name', { + it('should create observable counter with options', () => { + const observableCounter = meter.createObservableCounter('name', { description: 'desc', unit: '1', disabled: false, - }) as SumObserverMetric; - assert.ok(sumObserver instanceof Metric); + }) as ObservableCounterMetric; + assert.ok(observableCounter instanceof Metric); }); it('should set callback and observe value ', async () => { @@ -818,23 +818,23 @@ describe('Meter', () => { return -1; } - const sumObserver = meter.createSumObserver( + const observableCounter = meter.createObservableCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { + (observableResult: api.ObservableResult) => { // simulate async return new Promise(resolve => { setTimeout(() => { - observerResult.observe(getValue(), { pid: '123', core: '1' }); + observableResult.observe(getValue(), { pid: '123', core: '1' }); resolve(); }, 1); }); } - ) as SumObserverMetric; + ) as ObservableCounterMetric; - let metricRecords = await sumObserver.getMetricRecord(); + let metricRecords = await observableCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); let point = metricRecords[0].aggregator.toPoint(); assert.strictEqual(point.value, -1); @@ -843,29 +843,29 @@ describe('Meter', () => { '|#core:1,pid:123' ); - metricRecords = await sumObserver.getMetricRecord(); + metricRecords = await observableCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); point = metricRecords[0].aggregator.toPoint(); assert.strictEqual(point.value, 3); - metricRecords = await sumObserver.getMetricRecord(); + metricRecords = await observableCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); point = metricRecords[0].aggregator.toPoint(); assert.strictEqual(point.value, 3); }); it('should set callback and observe value when callback returns nothing', async () => { - const sumObserver = meter.createSumObserver( + const observableCounter = meter.createObservableCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { - observerResult.observe(1, { pid: '123', core: '1' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(1, { pid: '123', core: '1' }); } - ) as SumObserverMetric; + ) as ObservableCounterMetric; - const metricRecords = await sumObserver.getMetricRecord(); + const metricRecords = await observableCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); }); @@ -873,34 +873,34 @@ describe('Meter', () => { 'should set callback and observe value when callback returns anything' + ' but Promise', async () => { - const sumObserver = meter.createSumObserver( + const observableCounter = meter.createObservableCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { - observerResult.observe(1, { pid: '123', core: '1' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(1, { pid: '123', core: '1' }); return '1'; } - ) as SumObserverMetric; + ) as ObservableCounterMetric; - const metricRecords = await sumObserver.getMetricRecord(); + const metricRecords = await observableCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); } ); it('should reject getMetricRecord when callback throws an error', async () => { - const sumObserver = meter.createSumObserver( + const observableCounter = meter.createObservableCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { - observerResult.observe(1, { pid: '123', core: '1' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(1, { pid: '123', core: '1' }); throw new Error('Boom'); } - ) as SumObserverMetric; - await sumObserver + ) as ObservableCounterMetric; + await observableCounter .getMetricRecord() .then() .catch(e => { @@ -909,30 +909,30 @@ describe('Meter', () => { }); it('should pipe through resource', async () => { - const sumObserver = meter.createSumObserver('name', {}, result => { + const observableCounter = meter.createObservableCounter('name', {}, result => { result.observe(42, { foo: 'bar' }); return Promise.resolve(); - }) as SumObserverMetric; - assert.ok(sumObserver.resource instanceof Resource); + }) as ObservableCounterMetric; + assert.ok(observableCounter.resource instanceof Resource); - const [record] = await sumObserver.getMetricRecord(); + const [record] = await observableCounter.getMetricRecord(); assert.ok(record.resource instanceof Resource); }); }); - describe('#ValueObserver', () => { - it('should create a value observer', () => { - const valueObserver = meter.createValueObserver( + describe('#ObservableGauge', () => { + it('should create an observable gauge', () => { + const observableGauge = meter.createObservableGauge( 'name' - ) as ValueObserverMetric; - assert.ok(valueObserver instanceof Metric); + ) as ObservableGaugeMetric; + assert.ok(observableGauge instanceof Metric); }); - it('should return noop observer when name is invalid', () => { + it('should return noop observable gauge when name is invalid', () => { // Need to stub/spy on the underlying logger as the "diag" instance is global const spy = sinon.stub(diag, 'warn'); - const valueObserver = meter.createValueObserver('na me'); - assert.ok(valueObserver === api.NOOP_VALUE_OBSERVER_METRIC); + const observableGauge = meter.createObservableGauge('na me'); + assert.ok(observableGauge === api.NOOP_OBSERVABLE_GAUGE_METRIC); const args = spy.args[0]; assert.ok( args[0], @@ -940,40 +940,40 @@ describe('Meter', () => { ); }); - it('should create observer with options', () => { - const valueObserver = meter.createValueObserver('name', { + it('should create observable gauge with options', () => { + const observableGauge = meter.createObservableGauge('name', { description: 'desc', unit: '1', disabled: false, - }) as ValueObserverMetric; - assert.ok(valueObserver instanceof Metric); + }) as ObservableGaugeMetric; + assert.ok(observableGauge instanceof Metric); }); it('should set callback and observe value ', async () => { - const valueObserver = meter.createValueObserver( + const observableGauge = meter.createObservableGauge( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { + (observableResult: api.ObservableResult) => { // simulate async return new Promise(resolve => { setTimeout(() => { - observerResult.observe(getCpuUsage(), { pid: '123', core: '1' }); - observerResult.observe(getCpuUsage(), { pid: '123', core: '2' }); - observerResult.observe(getCpuUsage(), { pid: '123', core: '3' }); - observerResult.observe(getCpuUsage(), { pid: '123', core: '4' }); + observableResult.observe(getCpuUsage(), { pid: '123', core: '1' }); + observableResult.observe(getCpuUsage(), { pid: '123', core: '2' }); + observableResult.observe(getCpuUsage(), { pid: '123', core: '3' }); + observableResult.observe(getCpuUsage(), { pid: '123', core: '4' }); resolve(); }, 1); }); } - ) as ValueObserverMetric; + ) as ObservableGaugeMetric; function getCpuUsage() { return Math.random(); } - const metricRecords: MetricRecord[] = await valueObserver.getMetricRecord(); + const metricRecords: MetricRecord[] = await observableGauge.getMetricRecord(); assert.strictEqual(metricRecords.length, 4); const metric1 = metricRecords[0]; @@ -992,29 +992,29 @@ describe('Meter', () => { }); it('should pipe through resource', async () => { - const valueObserver = meter.createValueObserver('name', {}, result => { + const observableGauge = meter.createObservableGauge('name', {}, result => { result.observe(42, { foo: 'bar' }); - }) as ValueObserverMetric; - assert.ok(valueObserver.resource instanceof Resource); + }) as ObservableGaugeMetric; + assert.ok(observableGauge.resource instanceof Resource); - const [record] = await valueObserver.getMetricRecord(); + const [record] = await observableGauge.getMetricRecord(); assert.ok(record.resource instanceof Resource); }); }); - describe('#UpDownSumObserverMetric', () => { - it('should create an UpDownSum observer', () => { - const upDownSumObserver = meter.createUpDownSumObserver( + describe('#ObservableUpDownCounterMetric', () => { + it('should create an ObservableUpDownCounter', () => { + const observableUpDownCounter = meter.createObservableUpDownCounter( 'name' - ) as UpDownSumObserverMetric; - assert.ok(upDownSumObserver instanceof Metric); + ) as ObservableUpDownCounterMetric; + assert.ok(observableUpDownCounter instanceof Metric); }); - it('should return noop observer when name is invalid', () => { + it('should return noop observable up down counter when name is invalid', () => { // Need to stub/spy on the underlying logger as the "diag" instance is global const spy = sinon.stub(diag, 'warn'); - const upDownSumObserver = meter.createUpDownSumObserver('na me'); - assert.ok(upDownSumObserver === api.NOOP_UP_DOWN_SUM_OBSERVER_METRIC); + const observableUpDownCounter = meter.createObservableUpDownCounter('na me'); + assert.ok(observableUpDownCounter === api.NOOP_OBSERVABLE_UP_DOWN_COUNTER_METRIC); const args = spy.args[0]; assert.ok( args[0], @@ -1022,13 +1022,13 @@ describe('Meter', () => { ); }); - it('should create observer with options', () => { - const upDownSumObserver = meter.createUpDownSumObserver('name', { + it('should create observable up down counter with options', () => { + const observableUpDownCounter = meter.createObservableUpDownCounter('name', { description: 'desc', unit: '1', disabled: false, - }) as UpDownSumObserverMetric; - assert.ok(upDownSumObserver instanceof Metric); + }) as ObservableUpDownCounterMetric; + assert.ok(observableUpDownCounter instanceof Metric); }); it('should set callback and observe value ', async () => { @@ -1042,23 +1042,23 @@ describe('Meter', () => { return 3; } - const upDownSumObserver = meter.createUpDownSumObserver( + const observableUpDownCounter = meter.createObservableUpDownCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { + (observableResult: api.ObservableResult) => { // simulate async return new Promise(resolve => { setTimeout(() => { - observerResult.observe(getValue(), { pid: '123', core: '1' }); + observableResult.observe(getValue(), { pid: '123', core: '1' }); resolve(); }, 1); }); } - ) as UpDownSumObserverMetric; + ) as ObservableUpDownCounterMetric; - let metricRecords = await upDownSumObserver.getMetricRecord(); + let metricRecords = await observableUpDownCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); let point = metricRecords[0].aggregator.toPoint(); assert.strictEqual(point.value, 3); @@ -1067,29 +1067,29 @@ describe('Meter', () => { '|#core:1,pid:123' ); - metricRecords = await upDownSumObserver.getMetricRecord(); + metricRecords = await observableUpDownCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); point = metricRecords[0].aggregator.toPoint(); assert.strictEqual(point.value, 2); - metricRecords = await upDownSumObserver.getMetricRecord(); + metricRecords = await observableUpDownCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); point = metricRecords[0].aggregator.toPoint(); assert.strictEqual(point.value, 3); }); it('should set callback and observe value when callback returns nothing', async () => { - const upDownSumObserver = meter.createUpDownSumObserver( + const observableUpDownCounter = meter.createObservableUpDownCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { - observerResult.observe(1, { pid: '123', core: '1' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(1, { pid: '123', core: '1' }); } - ) as UpDownSumObserverMetric; + ) as ObservableUpDownCounterMetric; - const metricRecords = await upDownSumObserver.getMetricRecord(); + const metricRecords = await observableUpDownCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); }); @@ -1097,34 +1097,34 @@ describe('Meter', () => { 'should set callback and observe value when callback returns anything' + ' but Promise', async () => { - const upDownSumObserver = meter.createUpDownSumObserver( + const observableUpDownCounter = meter.createObservableUpDownCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { - observerResult.observe(1, { pid: '123', core: '1' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(1, { pid: '123', core: '1' }); return '1'; } - ) as UpDownSumObserverMetric; + ) as ObservableUpDownCounterMetric; - const metricRecords = await upDownSumObserver.getMetricRecord(); + const metricRecords = await observableUpDownCounter.getMetricRecord(); assert.strictEqual(metricRecords.length, 1); } ); it('should reject getMetricRecord when callback throws an error', async () => { - const upDownSumObserver = meter.createUpDownSumObserver( + const observableUpDownCounter = meter.createObservableUpDownCounter( 'name', { description: 'desc', }, - (observerResult: api.ObserverResult) => { - observerResult.observe(1, { pid: '123', core: '1' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(1, { pid: '123', core: '1' }); throw new Error('Boom'); } - ) as UpDownSumObserverMetric; - await upDownSumObserver + ) as ObservableUpDownCounterMetric; + await observableUpDownCounter .getMetricRecord() .then() .catch(e => { @@ -1133,17 +1133,17 @@ describe('Meter', () => { }); it('should pipe through resource', async () => { - const upDownSumObserver = meter.createUpDownSumObserver( + const observableUpDownCounter = meter.createObservableUpDownCounter( 'name', {}, result => { result.observe(42, { foo: 'bar' }); return Promise.resolve(); } - ) as UpDownSumObserverMetric; - assert.ok(upDownSumObserver.resource instanceof Resource); + ) as ObservableUpDownCounterMetric; + assert.ok(observableUpDownCounter.resource instanceof Resource); - const [record] = await upDownSumObserver.getMetricRecord(); + const [record] = await observableUpDownCounter.getMetricRecord(); assert.ok(record.resource instanceof Resource); }); }); @@ -1162,15 +1162,15 @@ describe('Meter', () => { }); it('should use callback to observe values ', async () => { - const tempMetric = meter.createValueObserver('cpu_temp_per_app', { + const tempMetric = meter.createObservableGauge('cpu_temp_per_app', { description: 'desc', - }) as ValueObserverMetric; + }) as ObservableGaugeMetric; - const cpuUsageMetric = meter.createValueObserver('cpu_usage_per_app', { + const cpuUsageMetric = meter.createObservableGauge('cpu_usage_per_app', { description: 'desc', - }) as ValueObserverMetric; + }) as ObservableGaugeMetric; - meter.createBatchObserver(observerBatchResult => { + meter.createBatchObserver(batchObserverResult => { interface StatItem { usage: number; temp: number; @@ -1209,11 +1209,11 @@ describe('Meter', () => { ]).then((stats: unknown[]) => { const apps = (stats[0] as unknown) as Stat[]; apps.forEach(app => { - observerBatchResult.observe({ app: app.name, core: '1' }, [ + batchObserverResult.observe({ app: app.name, core: '1' }, [ tempMetric.observation(app.core1.temp), cpuUsageMetric.observation(app.core1.usage), ]); - observerBatchResult.observe({ app: app.name, core: '2' }, [ + batchObserverResult.observe({ app: app.name, core: '2' }, [ tempMetric.observation(app.core2.temp), cpuUsageMetric.observation(app.core2.usage), ]); @@ -1255,12 +1255,12 @@ describe('Meter', () => { }); it('should not observe values when timeout', done => { - const cpuUsageMetric = meter.createValueObserver('cpu_usage_per_app', { + const cpuUsageMetric = meter.createObservableGauge('cpu_usage_per_app', { description: 'desc', - }) as ValueObserverMetric; + }) as ObservableGaugeMetric; meter.createBatchObserver( - observerBatchResult => { + batchObserverResult => { Promise.all([ // simulate waiting 11ms new Promise((resolve, reject) => { @@ -1268,8 +1268,8 @@ describe('Meter', () => { }), ]).then(async () => { // try to hack to be able to update - (observerBatchResult as BatchObserverResult).cancelled = false; - observerBatchResult.observe({ foo: 'bar' }, [ + (batchObserverResult as BatchObserverResult).cancelled = false; + batchObserverResult.observe({ foo: 'bar' }, [ cpuUsageMetric.observation(123), ]); @@ -1296,16 +1296,16 @@ describe('Meter', () => { }); it('should pipe through instrumentation library', async () => { - const observer = meter.createValueObserver( + const observableGauge = meter.createObservableGauge( 'name', {}, - (observerResult: api.ObserverResult) => { - observerResult.observe(42, { foo: 'bar' }); + (observableResult: api.ObservableResult) => { + observableResult.observe(42, { foo: 'bar' }); } - ) as ValueObserverMetric; - assert.ok(observer.instrumentationLibrary); + ) as ObservableGaugeMetric; + assert.ok(observableGauge.instrumentationLibrary); - const [record] = await observer.getMetricRecord(); + const [record] = await observableGauge.getMetricRecord(); const { name, version } = record.instrumentationLibrary; assert.strictEqual(name, 'test-meter'); assert.strictEqual(version, undefined); @@ -1370,8 +1370,8 @@ describe('Meter', () => { processor: new CustomProcessor(), }); assert.throws(() => { - const valueRecorder = customMeter.createValueRecorder('myValueRecorder'); - valueRecorder.bind({}).record(1); + const histogram = customMeter.createHistogram('myHistogram'); + histogram.bind({}).record(1); }, /aggregatorFor method not implemented/); }); }); @@ -1396,6 +1396,6 @@ function ensureMetric(metric: MetricRecord, name?: string, value?: LastValue) { assert.strictEqual(descriptor.name, name || 'name'); assert.strictEqual(descriptor.description, 'desc'); assert.strictEqual(descriptor.unit, '1'); - assert.strictEqual(descriptor.metricKind, MetricKind.VALUE_OBSERVER); + assert.strictEqual(descriptor.metricKind, MetricKind.OBSERVABLE_GAUGE); assert.strictEqual(descriptor.valueType, api.ValueType.DOUBLE); } From 043067fa3a376bdf5e15adf86f06bb627cceecc8 Mon Sep 17 00:00:00 2001 From: echoontheway <1152760298@qq.com> Date: Mon, 18 Oct 2021 00:09:02 +0800 Subject: [PATCH 25/29] feat(@opentelemetry/semantic-conventions): change enum to object literals (#2532) Co-authored-by: Valentin Marchaud --- .../resource/SemanticResourceAttributes.ts | 134 +++---- .../src/trace/SemanticAttributes.ts | 329 +++++++++--------- .../templates/SemanticAttributes.ts.j2 | 8 +- 3 files changed, 243 insertions(+), 228 deletions(-) diff --git a/packages/opentelemetry-semantic-conventions/src/resource/SemanticResourceAttributes.ts b/packages/opentelemetry-semantic-conventions/src/resource/SemanticResourceAttributes.ts index 382e315a24a..9e3a9d02aee 100644 --- a/packages/opentelemetry-semantic-conventions/src/resource/SemanticResourceAttributes.ts +++ b/packages/opentelemetry-semantic-conventions/src/resource/SemanticResourceAttributes.ts @@ -476,141 +476,145 @@ As an alternative, consider setting `faas.id` as a span attribute instead. WEBENGINE_DESCRIPTION: 'webengine.description', } -// Enum definitions - -export enum CloudProviderValues { +export const CloudProviderValues = { /** Alibaba Cloud. */ - ALIBABA_CLOUD = 'alibaba_cloud', + ALIBABA_CLOUD: 'alibaba_cloud', /** Amazon Web Services. */ - AWS = 'aws', + AWS: 'aws', /** Microsoft Azure. */ - AZURE = 'azure', + AZURE: 'azure', /** Google Cloud Platform. */ - GCP = 'gcp', -} + GCP: 'gcp', +} as const +export type CloudProviderValues = typeof CloudProviderValues[keyof typeof CloudProviderValues] -export enum CloudPlatformValues { +export const CloudPlatformValues = { /** Alibaba Cloud Elastic Compute Service. */ - ALIBABA_CLOUD_ECS = 'alibaba_cloud_ecs', + ALIBABA_CLOUD_ECS: 'alibaba_cloud_ecs', /** Alibaba Cloud Function Compute. */ - ALIBABA_CLOUD_FC = 'alibaba_cloud_fc', + ALIBABA_CLOUD_FC: 'alibaba_cloud_fc', /** AWS Elastic Compute Cloud. */ - AWS_EC2 = 'aws_ec2', + AWS_EC2: 'aws_ec2', /** AWS Elastic Container Service. */ - AWS_ECS = 'aws_ecs', + AWS_ECS: 'aws_ecs', /** AWS Elastic Kubernetes Service. */ - AWS_EKS = 'aws_eks', + AWS_EKS: 'aws_eks', /** AWS Lambda. */ - AWS_LAMBDA = 'aws_lambda', + AWS_LAMBDA: 'aws_lambda', /** AWS Elastic Beanstalk. */ - AWS_ELASTIC_BEANSTALK = 'aws_elastic_beanstalk', + AWS_ELASTIC_BEANSTALK: 'aws_elastic_beanstalk', /** Azure Virtual Machines. */ - AZURE_VM = 'azure_vm', + AZURE_VM: 'azure_vm', /** Azure Container Instances. */ - AZURE_CONTAINER_INSTANCES = 'azure_container_instances', + AZURE_CONTAINER_INSTANCES: 'azure_container_instances', /** Azure Kubernetes Service. */ - AZURE_AKS = 'azure_aks', + AZURE_AKS: 'azure_aks', /** Azure Functions. */ - AZURE_FUNCTIONS = 'azure_functions', + AZURE_FUNCTIONS: 'azure_functions', /** Azure App Service. */ - AZURE_APP_SERVICE = 'azure_app_service', + AZURE_APP_SERVICE: 'azure_app_service', /** Google Cloud Compute Engine (GCE). */ - GCP_COMPUTE_ENGINE = 'gcp_compute_engine', + GCP_COMPUTE_ENGINE: 'gcp_compute_engine', /** Google Cloud Run. */ - GCP_CLOUD_RUN = 'gcp_cloud_run', + GCP_CLOUD_RUN: 'gcp_cloud_run', /** Google Cloud Kubernetes Engine (GKE). */ - GCP_KUBERNETES_ENGINE = 'gcp_kubernetes_engine', + GCP_KUBERNETES_ENGINE: 'gcp_kubernetes_engine', /** Google Cloud Functions (GCF). */ - GCP_CLOUD_FUNCTIONS = 'gcp_cloud_functions', + GCP_CLOUD_FUNCTIONS: 'gcp_cloud_functions', /** Google Cloud App Engine (GAE). */ - GCP_APP_ENGINE = 'gcp_app_engine', -} + GCP_APP_ENGINE: 'gcp_app_engine', +} as const +export type CloudPlatformValues = typeof CloudPlatformValues[keyof typeof CloudPlatformValues] -export enum AwsEcsLaunchtypeValues { +export const AwsEcsLaunchtypeValues = { /** ec2. */ - EC2 = 'ec2', + EC2: 'ec2', /** fargate. */ - FARGATE = 'fargate', -} + FARGATE: 'fargate', +} as const +export type AwsEcsLaunchtypeValues = typeof AwsEcsLaunchtypeValues[keyof typeof AwsEcsLaunchtypeValues] -export enum HostArchValues { +export const HostArchValues = { /** AMD64. */ - AMD64 = 'amd64', + AMD64: 'amd64', /** ARM32. */ - ARM32 = 'arm32', + ARM32: 'arm32', /** ARM64. */ - ARM64 = 'arm64', + ARM64: 'arm64', /** Itanium. */ - IA64 = 'ia64', + IA64: 'ia64', /** 32-bit PowerPC. */ - PPC32 = 'ppc32', + PPC32: 'ppc32', /** 64-bit PowerPC. */ - PPC64 = 'ppc64', + PPC64: 'ppc64', /** 32-bit x86. */ - X86 = 'x86', -} + X86: 'x86', +} as const +export type HostArchValues = typeof HostArchValues[keyof typeof HostArchValues] -export enum OsTypeValues { +export const OsTypeValues = { /** Microsoft Windows. */ - WINDOWS = 'windows', + WINDOWS: 'windows', /** Linux. */ - LINUX = 'linux', + LINUX: 'linux', /** Apple Darwin. */ - DARWIN = 'darwin', + DARWIN: 'darwin', /** FreeBSD. */ - FREEBSD = 'freebsd', + FREEBSD: 'freebsd', /** NetBSD. */ - NETBSD = 'netbsd', + NETBSD: 'netbsd', /** OpenBSD. */ - OPENBSD = 'openbsd', + OPENBSD: 'openbsd', /** DragonFly BSD. */ - DRAGONFLYBSD = 'dragonflybsd', + DRAGONFLYBSD: 'dragonflybsd', /** HP-UX (Hewlett Packard Unix). */ - HPUX = 'hpux', + HPUX: 'hpux', /** AIX (Advanced Interactive eXecutive). */ - AIX = 'aix', + AIX: 'aix', /** Oracle Solaris. */ - SOLARIS = 'solaris', + SOLARIS: 'solaris', /** IBM z/OS. */ - Z_OS = 'z_os', -} + Z_OS: 'z_os', +} as const +export type OsTypeValues = typeof OsTypeValues[keyof typeof OsTypeValues] -export enum TelemetrySdkLanguageValues { +export const TelemetrySdkLanguageValues = { /** cpp. */ - CPP = 'cpp', + CPP: 'cpp', /** dotnet. */ - DOTNET = 'dotnet', + DOTNET: 'dotnet', /** erlang. */ - ERLANG = 'erlang', + ERLANG: 'erlang', /** go. */ - GO = 'go', + GO: 'go', /** java. */ - JAVA = 'java', + JAVA: 'java', /** nodejs. */ - NODEJS = 'nodejs', + NODEJS: 'nodejs', /** php. */ - PHP = 'php', + PHP: 'php', /** python. */ - PYTHON = 'python', + PYTHON: 'python', /** ruby. */ - RUBY = 'ruby', + RUBY: 'ruby', /** webjs. */ - WEBJS = 'webjs', -} + WEBJS: 'webjs', +} as const +export type TelemetrySdkLanguageValues = typeof TelemetrySdkLanguageValues[keyof typeof TelemetrySdkLanguageValues] diff --git a/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts b/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts index 48fecf29bed..052d36e4c08 100644 --- a/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts +++ b/packages/opentelemetry-semantic-conventions/src/trace/SemanticAttributes.ts @@ -723,343 +723,354 @@ the closest proxy. MESSAGE_UNCOMPRESSED_SIZE: 'message.uncompressed_size', } -// Enum definitions - -export enum DbSystemValues { +export const DbSystemValues = { /** Some other SQL database. Fallback only. See notes. */ - OTHER_SQL = 'other_sql', + OTHER_SQL: 'other_sql', /** Microsoft SQL Server. */ - MSSQL = 'mssql', + MSSQL: 'mssql', /** MySQL. */ - MYSQL = 'mysql', + MYSQL: 'mysql', /** Oracle Database. */ - ORACLE = 'oracle', + ORACLE: 'oracle', /** IBM Db2. */ - DB2 = 'db2', + DB2: 'db2', /** PostgreSQL. */ - POSTGRESQL = 'postgresql', + POSTGRESQL: 'postgresql', /** Amazon Redshift. */ - REDSHIFT = 'redshift', + REDSHIFT: 'redshift', /** Apache Hive. */ - HIVE = 'hive', + HIVE: 'hive', /** Cloudscape. */ - CLOUDSCAPE = 'cloudscape', + CLOUDSCAPE: 'cloudscape', /** HyperSQL DataBase. */ - HSQLDB = 'hsqldb', + HSQLDB: 'hsqldb', /** Progress Database. */ - PROGRESS = 'progress', + PROGRESS: 'progress', /** SAP MaxDB. */ - MAXDB = 'maxdb', + MAXDB: 'maxdb', /** SAP HANA. */ - HANADB = 'hanadb', + HANADB: 'hanadb', /** Ingres. */ - INGRES = 'ingres', + INGRES: 'ingres', /** FirstSQL. */ - FIRSTSQL = 'firstsql', + FIRSTSQL: 'firstsql', /** EnterpriseDB. */ - EDB = 'edb', + EDB: 'edb', /** InterSystems Caché. */ - CACHE = 'cache', + CACHE: 'cache', /** Adabas (Adaptable Database System). */ - ADABAS = 'adabas', + ADABAS: 'adabas', /** Firebird. */ - FIREBIRD = 'firebird', + FIREBIRD: 'firebird', /** Apache Derby. */ - DERBY = 'derby', + DERBY: 'derby', /** FileMaker. */ - FILEMAKER = 'filemaker', + FILEMAKER: 'filemaker', /** Informix. */ - INFORMIX = 'informix', + INFORMIX: 'informix', /** InstantDB. */ - INSTANTDB = 'instantdb', + INSTANTDB: 'instantdb', /** InterBase. */ - INTERBASE = 'interbase', + INTERBASE: 'interbase', /** MariaDB. */ - MARIADB = 'mariadb', + MARIADB: 'mariadb', /** Netezza. */ - NETEZZA = 'netezza', + NETEZZA: 'netezza', /** Pervasive PSQL. */ - PERVASIVE = 'pervasive', + PERVASIVE: 'pervasive', /** PointBase. */ - POINTBASE = 'pointbase', + POINTBASE: 'pointbase', /** SQLite. */ - SQLITE = 'sqlite', + SQLITE: 'sqlite', /** Sybase. */ - SYBASE = 'sybase', + SYBASE: 'sybase', /** Teradata. */ - TERADATA = 'teradata', + TERADATA: 'teradata', /** Vertica. */ - VERTICA = 'vertica', + VERTICA: 'vertica', /** H2. */ - H2 = 'h2', + H2: 'h2', /** ColdFusion IMQ. */ - COLDFUSION = 'coldfusion', + COLDFUSION: 'coldfusion', /** Apache Cassandra. */ - CASSANDRA = 'cassandra', + CASSANDRA: 'cassandra', /** Apache HBase. */ - HBASE = 'hbase', + HBASE: 'hbase', /** MongoDB. */ - MONGODB = 'mongodb', + MONGODB: 'mongodb', /** Redis. */ - REDIS = 'redis', + REDIS: 'redis', /** Couchbase. */ - COUCHBASE = 'couchbase', + COUCHBASE: 'couchbase', /** CouchDB. */ - COUCHDB = 'couchdb', + COUCHDB: 'couchdb', /** Microsoft Azure Cosmos DB. */ - COSMOSDB = 'cosmosdb', + COSMOSDB: 'cosmosdb', /** Amazon DynamoDB. */ - DYNAMODB = 'dynamodb', + DYNAMODB: 'dynamodb', /** Neo4j. */ - NEO4J = 'neo4j', + NEO4J: 'neo4j', /** Apache Geode. */ - GEODE = 'geode', + GEODE: 'geode', /** Elasticsearch. */ - ELASTICSEARCH = 'elasticsearch', + ELASTICSEARCH: 'elasticsearch', /** Memcached. */ - MEMCACHED = 'memcached', + MEMCACHED: 'memcached', /** CockroachDB. */ - COCKROACHDB = 'cockroachdb', -} + COCKROACHDB: 'cockroachdb', +} as const +export type DbSystemValues = typeof DbSystemValues[keyof typeof DbSystemValues] -export enum DbCassandraConsistencyLevelValues { +export const DbCassandraConsistencyLevelValues = { /** all. */ - ALL = 'all', + ALL: 'all', /** each_quorum. */ - EACH_QUORUM = 'each_quorum', + EACH_QUORUM: 'each_quorum', /** quorum. */ - QUORUM = 'quorum', + QUORUM: 'quorum', /** local_quorum. */ - LOCAL_QUORUM = 'local_quorum', + LOCAL_QUORUM: 'local_quorum', /** one. */ - ONE = 'one', + ONE: 'one', /** two. */ - TWO = 'two', + TWO: 'two', /** three. */ - THREE = 'three', + THREE: 'three', /** local_one. */ - LOCAL_ONE = 'local_one', + LOCAL_ONE: 'local_one', /** any. */ - ANY = 'any', + ANY: 'any', /** serial. */ - SERIAL = 'serial', + SERIAL: 'serial', /** local_serial. */ - LOCAL_SERIAL = 'local_serial', -} + LOCAL_SERIAL: 'local_serial', +} as const +export type DbCassandraConsistencyLevelValues = typeof DbCassandraConsistencyLevelValues[keyof typeof DbCassandraConsistencyLevelValues] -export enum FaasTriggerValues { +export const FaasTriggerValues = { /** A response to some data source operation such as a database or filesystem read/write. */ - DATASOURCE = 'datasource', + DATASOURCE: 'datasource', /** To provide an answer to an inbound HTTP request. */ - HTTP = 'http', + HTTP: 'http', /** A function is set to be executed when messages are sent to a messaging system. */ - PUBSUB = 'pubsub', + PUBSUB: 'pubsub', /** A function is scheduled to be executed regularly. */ - TIMER = 'timer', + TIMER: 'timer', /** If none of the others apply. */ - OTHER = 'other', -} + OTHER: 'other', +} as const +export type FaasTriggerValues = typeof FaasTriggerValues[keyof typeof FaasTriggerValues] -export enum FaasDocumentOperationValues { +export const FaasDocumentOperationValues = { /** When a new object is created. */ - INSERT = 'insert', + INSERT: 'insert', /** When an object is modified. */ - EDIT = 'edit', + EDIT: 'edit', /** When an object is deleted. */ - DELETE = 'delete', -} + DELETE: 'delete', +} as const +export type FaasDocumentOperationValues = typeof FaasDocumentOperationValues[keyof typeof FaasDocumentOperationValues] -export enum FaasInvokedProviderValues { +export const FaasInvokedProviderValues = { /** Alibaba Cloud. */ - ALIBABA_CLOUD = 'alibaba_cloud', + ALIBABA_CLOUD: 'alibaba_cloud', /** Amazon Web Services. */ - AWS = 'aws', + AWS: 'aws', /** Microsoft Azure. */ - AZURE = 'azure', + AZURE: 'azure', /** Google Cloud Platform. */ - GCP = 'gcp', -} + GCP: 'gcp', +} as const +export type FaasInvokedProviderValues = typeof FaasInvokedProviderValues[keyof typeof FaasInvokedProviderValues] -export enum NetTransportValues { +export const NetTransportValues = { /** ip_tcp. */ - IP_TCP = 'ip_tcp', + IP_TCP: 'ip_tcp', /** ip_udp. */ - IP_UDP = 'ip_udp', + IP_UDP: 'ip_udp', /** Another IP-based protocol. */ - IP = 'ip', + IP: 'ip', /** Unix Domain socket. See below. */ - UNIX = 'unix', + UNIX: 'unix', /** Named or anonymous pipe. See note below. */ - PIPE = 'pipe', + PIPE: 'pipe', /** In-process communication. */ - INPROC = 'inproc', + INPROC: 'inproc', /** Something else (non IP-based). */ - OTHER = 'other', -} + OTHER: 'other', +} as const +export type NetTransportValues = typeof NetTransportValues[keyof typeof NetTransportValues] -export enum NetHostConnectionTypeValues { +export const NetHostConnectionTypeValues = { /** wifi. */ - WIFI = 'wifi', + WIFI: 'wifi', /** wired. */ - WIRED = 'wired', + WIRED: 'wired', /** cell. */ - CELL = 'cell', + CELL: 'cell', /** unavailable. */ - UNAVAILABLE = 'unavailable', + UNAVAILABLE: 'unavailable', /** unknown. */ - UNKNOWN = 'unknown', -} + UNKNOWN: 'unknown', +} as const +export type NetHostConnectionTypeValues = typeof NetHostConnectionTypeValues[keyof typeof NetHostConnectionTypeValues] -export enum NetHostConnectionSubtypeValues { +export const NetHostConnectionSubtypeValues = { /** GPRS. */ - GPRS = 'gprs', + GPRS: 'gprs', /** EDGE. */ - EDGE = 'edge', + EDGE: 'edge', /** UMTS. */ - UMTS = 'umts', + UMTS: 'umts', /** CDMA. */ - CDMA = 'cdma', + CDMA: 'cdma', /** EVDO Rel. 0. */ - EVDO_0 = 'evdo_0', + EVDO_0: 'evdo_0', /** EVDO Rev. A. */ - EVDO_A = 'evdo_a', + EVDO_A: 'evdo_a', /** CDMA2000 1XRTT. */ - CDMA2000_1XRTT = 'cdma2000_1xrtt', + CDMA2000_1XRTT: 'cdma2000_1xrtt', /** HSDPA. */ - HSDPA = 'hsdpa', + HSDPA: 'hsdpa', /** HSUPA. */ - HSUPA = 'hsupa', + HSUPA: 'hsupa', /** HSPA. */ - HSPA = 'hspa', + HSPA: 'hspa', /** IDEN. */ - IDEN = 'iden', + IDEN: 'iden', /** EVDO Rev. B. */ - EVDO_B = 'evdo_b', + EVDO_B: 'evdo_b', /** LTE. */ - LTE = 'lte', + LTE: 'lte', /** EHRPD. */ - EHRPD = 'ehrpd', + EHRPD: 'ehrpd', /** HSPAP. */ - HSPAP = 'hspap', + HSPAP: 'hspap', /** GSM. */ - GSM = 'gsm', + GSM: 'gsm', /** TD-SCDMA. */ - TD_SCDMA = 'td_scdma', + TD_SCDMA: 'td_scdma', /** IWLAN. */ - IWLAN = 'iwlan', + IWLAN: 'iwlan', /** 5G NR (New Radio). */ - NR = 'nr', + NR: 'nr', /** 5G NRNSA (New Radio Non-Standalone). */ - NRNSA = 'nrnsa', + NRNSA: 'nrnsa', /** LTE CA. */ - LTE_CA = 'lte_ca', -} + LTE_CA: 'lte_ca', +} as const +export type NetHostConnectionSubtypeValues = typeof NetHostConnectionSubtypeValues[keyof typeof NetHostConnectionSubtypeValues] -export enum HttpFlavorValues { +export const HttpFlavorValues = { /** HTTP 1.0. */ - HTTP_1_0 = '1.0', + HTTP_1_0: '1.0', /** HTTP 1.1. */ - HTTP_1_1 = '1.1', + HTTP_1_1: '1.1', /** HTTP 2. */ - HTTP_2_0 = '2.0', + HTTP_2_0: '2.0', /** SPDY protocol. */ - SPDY = 'SPDY', + SPDY: 'SPDY', /** QUIC protocol. */ - QUIC = 'QUIC', -} + QUIC: 'QUIC', +} as const +export type HttpFlavorValues = typeof HttpFlavorValues[keyof typeof HttpFlavorValues] -export enum MessagingDestinationKindValues { +export const MessagingDestinationKindValues = { /** A message sent to a queue. */ - QUEUE = 'queue', + QUEUE: 'queue', /** A message sent to a topic. */ - TOPIC = 'topic', -} + TOPIC: 'topic', +} as const +export type MessagingDestinationKindValues = typeof MessagingDestinationKindValues[keyof typeof MessagingDestinationKindValues] -export enum MessagingOperationValues { +export const MessagingOperationValues = { /** receive. */ - RECEIVE = 'receive', + RECEIVE: 'receive', /** process. */ - PROCESS = 'process', -} + PROCESS: 'process', +} as const +export type MessagingOperationValues = typeof MessagingOperationValues[keyof typeof MessagingOperationValues] -export enum RpcGrpcStatusCodeValues { +export const RpcGrpcStatusCodeValues = { /** OK. */ - OK = 0, + OK: 0, /** CANCELLED. */ - CANCELLED = 1, + CANCELLED: 1, /** UNKNOWN. */ - UNKNOWN = 2, + UNKNOWN: 2, /** INVALID_ARGUMENT. */ - INVALID_ARGUMENT = 3, + INVALID_ARGUMENT: 3, /** DEADLINE_EXCEEDED. */ - DEADLINE_EXCEEDED = 4, + DEADLINE_EXCEEDED: 4, /** NOT_FOUND. */ - NOT_FOUND = 5, + NOT_FOUND: 5, /** ALREADY_EXISTS. */ - ALREADY_EXISTS = 6, + ALREADY_EXISTS: 6, /** PERMISSION_DENIED. */ - PERMISSION_DENIED = 7, + PERMISSION_DENIED: 7, /** RESOURCE_EXHAUSTED. */ - RESOURCE_EXHAUSTED = 8, + RESOURCE_EXHAUSTED: 8, /** FAILED_PRECONDITION. */ - FAILED_PRECONDITION = 9, + FAILED_PRECONDITION: 9, /** ABORTED. */ - ABORTED = 10, + ABORTED: 10, /** OUT_OF_RANGE. */ - OUT_OF_RANGE = 11, + OUT_OF_RANGE: 11, /** UNIMPLEMENTED. */ - UNIMPLEMENTED = 12, + UNIMPLEMENTED: 12, /** INTERNAL. */ - INTERNAL = 13, + INTERNAL: 13, /** UNAVAILABLE. */ - UNAVAILABLE = 14, + UNAVAILABLE: 14, /** DATA_LOSS. */ - DATA_LOSS = 15, + DATA_LOSS: 15, /** UNAUTHENTICATED. */ - UNAUTHENTICATED = 16, -} + UNAUTHENTICATED: 16, +} as const +export type RpcGrpcStatusCodeValues = typeof RpcGrpcStatusCodeValues[keyof typeof RpcGrpcStatusCodeValues] -export enum MessageTypeValues { +export const MessageTypeValues = { /** sent. */ - SENT = 'SENT', + SENT: 'SENT', /** received. */ - RECEIVED = 'RECEIVED', -} + RECEIVED: 'RECEIVED', +} as const +export type MessageTypeValues = typeof MessageTypeValues[keyof typeof MessageTypeValues] diff --git a/scripts/semconv/templates/SemanticAttributes.ts.j2 b/scripts/semconv/templates/SemanticAttributes.ts.j2 index 18004561d98..eb144b93b26 100644 --- a/scripts/semconv/templates/SemanticAttributes.ts.j2 +++ b/scripts/semconv/templates/SemanticAttributes.ts.j2 @@ -44,19 +44,19 @@ export const {{class}} = { {%- endfor %} } -// Enum definitions {%- for attribute in attributes if attribute.is_local and not attribute.ref %} {%- if attribute.is_enum %} {%- set class_name = attribute.fqn | to_camelcase(True) ~ "Values" %} {%- set type = attribute.attr_type.enum_type %} {% if attribute.attr_type.members is defined and attribute.attr_type.members|length > 0 %} -export enum {{class_name}} { +export const {{class_name}} = { {%- for member in attribute.attr_type.members if attribute.is_local and not attribute.ref %} /** {% filter escape %}{{member.brief | to_doc_brief}}.{% endfilter %} */ - {{ member.member_id | to_const_name }} = {{ print_value(type, member.value) }}, + {{ member.member_id | to_const_name }}: {{ print_value(type, member.value) }}, {%- endfor %} -} +} as const +export type {{class_name}} = typeof {{class_name}}[keyof typeof {{class_name}}] {% endif %} {% endif %} From f2a562430bf36997d1e16ac9d2d9cf3d22ce40f0 Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Sun, 17 Oct 2021 18:14:21 +0200 Subject: [PATCH 26/29] chore: remove getting started and link to documentation. (#2493) Co-authored-by: Valentin Marchaud --- README.md | 4 +- getting-started/.eslintrc.js | 6 - getting-started/README.md | 398 ------------------ getting-started/example/app.js | 42 -- getting-started/example/package.json | 15 - getting-started/images/prometheus-graph.png | Bin 90810 -> 0 bytes getting-started/images/prometheus.png | Bin 98150 -> 0 bytes getting-started/images/zipkin-trace.png | Bin 64614 -> 0 bytes getting-started/images/zipkin.png | Bin 36304 -> 0 bytes getting-started/monitored-example/app.js | 45 -- .../monitored-example/monitoring.js | 40 -- .../monitored-example/package.json | 17 - getting-started/traced-example/app.js | 42 -- getting-started/traced-example/package.json | 22 - getting-started/traced-example/tracing.js | 38 -- getting-started/ts-example/.eslintrc | 16 - getting-started/ts-example/README.md | 389 ----------------- getting-started/ts-example/example/app.ts | 40 -- .../ts-example/example/package.json | 20 - .../ts-example/monitored-example/app.ts | 42 -- .../monitored-example/monitoring.ts | 39 -- .../ts-example/monitored-example/package.json | 22 - .../ts-example/traced-example/app.ts | 40 -- .../ts-example/traced-example/package.json | 27 -- .../ts-example/traced-example/tracing.ts | 41 -- package.json | 2 - 26 files changed, 2 insertions(+), 1345 deletions(-) delete mode 100644 getting-started/.eslintrc.js delete mode 100644 getting-started/README.md delete mode 100644 getting-started/example/app.js delete mode 100644 getting-started/example/package.json delete mode 100644 getting-started/images/prometheus-graph.png delete mode 100644 getting-started/images/prometheus.png delete mode 100644 getting-started/images/zipkin-trace.png delete mode 100644 getting-started/images/zipkin.png delete mode 100644 getting-started/monitored-example/app.js delete mode 100644 getting-started/monitored-example/monitoring.js delete mode 100644 getting-started/monitored-example/package.json delete mode 100644 getting-started/traced-example/app.js delete mode 100644 getting-started/traced-example/package.json delete mode 100644 getting-started/traced-example/tracing.js delete mode 100644 getting-started/ts-example/.eslintrc delete mode 100644 getting-started/ts-example/README.md delete mode 100644 getting-started/ts-example/example/app.ts delete mode 100644 getting-started/ts-example/example/package.json delete mode 100644 getting-started/ts-example/monitored-example/app.ts delete mode 100644 getting-started/ts-example/monitored-example/monitoring.ts delete mode 100644 getting-started/ts-example/monitored-example/package.json delete mode 100644 getting-started/ts-example/traced-example/app.ts delete mode 100644 getting-started/ts-example/traced-example/package.json delete mode 100644 getting-started/ts-example/traced-example/tracing.ts diff --git a/README.md b/README.md index ae4eb6f4839..45e83be795a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ---

- Getting Started + Getting Started   •   API Reference   •   @@ -131,7 +131,7 @@ process.on('SIGTERM', () => { node -r ./tracing.js app.js ``` -The above example will emit auto-instrumented telemetry about your Node.js application to the console. For a more in-depth example, see the [Getting Started Guide](https://github.com/open-telemetry/opentelemetry-js/blob/main/getting-started/README.md). For more information about automatic instrumentation see [@opentelemetry/sdk-trace-node][otel-node], which provides auto-instrumentation for Node.js applications. If the automatic instrumentation does not suit your needs, or you would like to create manual traces, see [@opentelemetry/sdk-trace-base][otel-tracing] +The above example will emit auto-instrumented telemetry about your Node.js application to the console. For a more in-depth example, see the [Getting Started Guide](https://opentelemetry.io/docs/js/getting_started/). For more information about automatic instrumentation see [@opentelemetry/sdk-trace-node][otel-node], which provides auto-instrumentation for Node.js applications. If the automatic instrumentation does not suit your needs, or you would like to create manual traces, see [@opentelemetry/sdk-trace-base][otel-tracing] ### Library Author diff --git a/getting-started/.eslintrc.js b/getting-started/.eslintrc.js deleted file mode 100644 index 8580fbfb045..00000000000 --- a/getting-started/.eslintrc.js +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-disable global-require */ -/* eslint-disable strict */ - -module.exports = { - ...require('../examples/.eslintrc.json'), -}; diff --git a/getting-started/README.md b/getting-started/README.md deleted file mode 100644 index 132bd340aec..00000000000 --- a/getting-started/README.md +++ /dev/null @@ -1,398 +0,0 @@ -# Getting started with OpenTelemetry JS - -This guide walks you through the setup and configuration process for a tracing backend (in this case [Zipkin](https://zipkin.io), but [Jaeger](https://www.jaegertracing.io) is simple to use as well), a metrics backend like [Prometheus](https://prometheus.io), and auto-instrumentation of NodeJS. [You can find the guide for TypeScript here](ts-example/README.md#getting-started-with-opentelemetry-js-typescript). - -- [Getting started with OpenTelemetry JS](#getting-started-with-opentelemetry-js) - - [Trace your application with OpenTelemetry](#trace-your-application-with-opentelemetry) - - [Set up a tracing backend](#set-up-a-tracing-backend) - - [Trace your NodeJS application](#trace-your-nodejs-application) - - [Install the required OpenTelemetry libraries](#install-the-required-opentelemetry-libraries) - - [Initialize a global tracer](#initialize-a-global-tracer) - - [Initialize and register a trace exporter](#initialize-and-register-a-trace-exporter) - - [Collect metrics using OpenTelemetry](#collect-metrics-using-opentelemetry) - - [Set up a metrics backend](#set-up-a-metrics-backend) - - [Monitor your NodeJS application](#monitor-your-nodejs-application) - - [Install the required OpenTelemetry metrics libraries](#install-the-required-opentelemetry-metrics-libraries) - - [Initialize a meter and collect metrics](#initialize-a-meter-and-collect-metrics) - - [Initialize and register a metrics exporter](#initialize-and-register-a-metrics-exporter) - -## Trace your application with OpenTelemetry - -([link to TypeScript version](ts-example/README.md#trace-your-application-with-opentelemetry)) - -This guide assumes you're using Zipkin as your tracing backend, but modifying it for Jaeger should be straightforward. - -You can find an example application to use with this guide in the [example directory](example). See what it looks like with tracing enabled in the [traced-example directory](traced-example). - -### Set up a tracing backend - -([link to TypeScript version](ts-example/README.md#set-up-a-tracing-backend)) - -The first thing you need before you can start collecting traces is a tracing backend like Zipkin that you can export traces to. If you already have a supported tracing backend (Zipkin or Jaeger), you can skip this step. If not, you need to run one. - -To set up Zipkin as quickly as possible, run the latest [Docker Zipkin](https://github.com/openzipkin/docker-zipkin) container, exposing port `9411`. If you can’t run Docker containers, you need to download and run Zipkin by following the Zipkin [quickstart guide](https://zipkin.io/pages/quickstart.html). - -```sh -docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin -``` - -Browse to to make sure you can see the Zipkin UI. - -

- -### Trace your NodeJS application - -([link to TypeScript version](ts-example/README.md#trace-your-nodejs-application)) - -This guide uses the example application provided in the [example directory](example), but the steps to instrument your own application should be broadly the same. Here's an overview of what you'll be doing: - -1. Install the required OpenTelemetry libraries -2. Initialize a global tracer -3. Initialize and register a trace exporter - -#### Install the required OpenTelemetry libraries - -([link to TypeScript version](ts-example/README.md#install-the-required-opentelemetry-libraries)) - -To create traces on NodeJS, you need `@opentelemetry/sdk-trace-node`, `@opentelemetry/core`, and any instrumentation required by your application such as gRPC or HTTP. If you're using the example application, you need to install `@opentelemetry/instrumentation-http` and `@opentelemetry/instrumentation-express`. - -```sh -$ npm install \ - @opentelemetry/api \ - @opentelemetry/sdk-trace-node \ - @opentelemetry/instrumentation-http \ - @opentelemetry/instrumentation-express \ - @opentelemetry/instrumentation-grpc -``` - -#### Initialize a global tracer - -([link to TypeScript version](ts-example/README.md#initialize-a-global-tracer)) - -All tracing initialization should happen before your application code runs. The easiest way to do this is to initialize tracing in a separate file that is required using the `node` `-r` option before your application code runs. - -Create a file named `tracing.js` and add the following code: - -```javascript -'use strict'; - -const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); -const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); -const { registerInstrumentations } = require("@opentelemetry/instrumentation"); -const { HttpInstrumentation } = require("@opentelemetry/instrumentation-http"); -const { GrpcInstrumentation } = require("@opentelemetry/instrumentation-grpc"); - -const provider = new NodeTracerProvider(); - -diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); - -provider.register(); - -registerInstrumentations({ - instrumentations: [ - new HttpInstrumentation(), - new GrpcInstrumentation(), - ], -}); - -``` - -Now, if you run your application with `node -r ./tracing.js app.js`, your application will create and propagate traces over HTTP. If an already instrumented service that supports [Trace Context](https://www.w3.org/TR/trace-context/) headers calls your application using HTTP, and you call another application using HTTP, the Trace Context headers will be correctly propagated. - -However, if you want to see a completed trace, you need to register an exporter to send traces to a tracing backend. - -#### Initialize and register a trace exporter - -([link to TypeScript version](ts-example/README.md#initialize-and-register-a-trace-exporter)) - -This guide uses the Zipkin tracing backend. However, if you're using another backend like [Jaeger](https://www.jaegertracing.io), make your change there. - -To export traces, you need a few more dependencies. Install them with the following command: - -```sh -$ npm install \ - @opentelemetry/sdk-trace-base \ - @opentelemetry/exporter-zipkin - -$ # for jaeger you would run this command: -$ # npm install @opentelemetry/exporter-jaeger -``` - -After you install these dependencies, initialize and register them. Modify `tracing.js` so it matches the following code snippet. Optionally replace the service name `"getting-started"` with your own service name: - -```javascript -'use strict'; - -const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api"); -const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node"); -const { Resource } = require('@opentelemetry/resources'); -const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions'); -const { SimpleSpanProcessor } = require("@opentelemetry/sdk-trace-base"); -const { ZipkinExporter } = require("@opentelemetry/exporter-zipkin"); -const { registerInstrumentations } = require("@opentelemetry/instrumentation"); -const { HttpInstrumentation } = require("@opentelemetry/instrumentation-http"); -const { GrpcInstrumentation } = require("@opentelemetry/instrumentation-grpc"); - -const provider = new NodeTracerProvider({ - resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: "getting-started", - }) -}); - -diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); - -provider.addSpanProcessor( - new SimpleSpanProcessor( - new ZipkinExporter({ - // If you are running your tracing backend on another host, - // you can point to it using the `url` parameter of the - // exporter config. - }) - ) -); - -provider.register(); - -registerInstrumentations({ - instrumentations: [ - new HttpInstrumentation(), - new GrpcInstrumentation(), - ], -}); - -console.log("tracing initialized"); -``` - -Now if you run your application with the `tracing.js` file loaded, and you send requests to your application over HTTP (in the sample application just browse to ), you'll see traces exported to your tracing backend that look like this: - -```sh -node -r ./tracing.js app.js -``` - -

- -**Note:** Some spans appear to be duplicated, but they're not. This is because the sample application is both the client and the server for these requests. You see one span which is the client-side request timing, and one span which is the server side request timing. Anywhere they don’t overlap is network time. - -## Collect metrics using OpenTelemetry - -([link to TypeScript version](ts-example/README.md#collect-metrics-using-opentelemetry)) - -This guide assumes you're using Prometheus as your metrics backend. It's currently the only metrics backend supported by OpenTelemetry JS. - -**Note**: This section is a work in progress. - -### Set up a metrics backend - -([link to TypeScript version](ts-example/README.md#set-up-a-metrics-backend)) - -Now that you have end-to-end traces, you can collect and export some basic metrics. - -Currently, the only supported metrics backend is [Prometheus](https://prometheus.io). Go to the [Prometheus download page](https://prometheus.io/download/) and download the latest release of Prometheus for your operating system. - -Open a command line and `cd` into the directory where you downloaded the Prometheus tarball. Untar it into the newly created directory. - -```sh -$ cd Downloads - -$ # Replace the file name below with your downloaded tarball -$ tar xvfz prometheus-2.20.1.darwin-amd64.tar - -$ # Replace the dir below with your created directory -$ cd prometheus-2.20.1.darwin-amd64 - -$ ls -LICENSE console_libraries data prometheus.yml tsdb -NOTICE consoles prometheus promtool -``` - -The created directory should have a file named `prometheus.yml`. This is the file used to configure Prometheus. For now, just make sure Prometheus starts by running the `./prometheus` binary in the folder and browse to . - -```sh -$ ./prometheus -# some output elided for brevity -msg="Starting Prometheus" version="(version=2.14.0, branch=HEAD, revision=edeb7a44cbf745f1d8be4ea6f215e79e651bfe19)" -# some output elided for brevity -level=info ts=2019-11-21T20:39:40.262Z caller=web.go:496 component=web msg="Start listening for connections" address=0.0.0.0:9090 -# some output elided for brevity -level=info ts=2019-11-21T20:39:40.383Z caller=main.go:626 msg="Server is ready to receive web requests." -``` - -

- -Once you confirm that Prometheus starts, replace the contents of `prometheus.yml` with the following: - -```yaml -# my global config -global: - scrape_interval: 15s # Set the scrape interval to every 15 seconds. - -scrape_configs: - - job_name: 'opentelemetry' - # metrics_path defaults to '/metrics' - # scheme defaults to 'http'. - static_configs: - - targets: ['localhost:9464'] -``` - -### Monitor your NodeJS application - -([link to TypeScript version](ts-example/README.md#monitor-your-nodejs-application)) - -You can find an example application to use with this guide in the [example directory](example). See what it looks like with metric monitoring enabled in the [monitored-example directory](monitored-example). - -Here's an overview of what you'll be doing: - -1. Install the required OpenTelemetry metrics libraries -2. Initialize a meter and collect metrics -3. Initialize and register a metrics exporter - -#### Install the required OpenTelemetry metrics libraries - -([link to TypeScript version](ts-example/README.md#install-the-required-opentelemetry-sdk-metrics-base-libraries)) - -To create metrics on NodeJS, you need `@opentelemetry/sdk-metrics-base`. - -```sh -$ npm install \ - @opentelemetry/sdk-metrics-base -``` - -#### Initialize a meter and collect metrics - -([link to TypeScript version](ts-example/README.md#initialize-a-meter-and-collect-metrics)) - -You need a `Meter` to create and monitor metrics. A `Meter` in OpenTelemetry is the mechanism used to create and manage metrics, labels, and metric exporters. - -Create a file named `monitoring.js` and add the following code: - -```javascript -'use strict'; - -const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); - -const meter = new MeterProvider().getMeter('your-meter-name'); -``` - -Now you can require this file from your application code and use the `Meter` to create and manage metrics. The simplest of these metrics is a counter. Create and export from your `monitoring.js` file a middleware function that express can use to count all requests by route. Modify the `monitoring.js` file so it looks like this: - -```javascript -'use strict'; - -const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); - -const meter = new MeterProvider().getMeter('your-meter-name'); - -const requestCount = meter.createCounter("requests", { - description: "Count all incoming requests" -}); - -const boundInstruments = new Map(); - -module.exports.countAllRequests = () => { - return (req, res, next) => { - if (!boundInstruments.has(req.path)) { - const labels = { route: req.path }; - const boundCounter = requestCount.bind(labels); - boundInstruments.set(req.path, boundCounter); - } - - boundInstruments.get(req.path).add(1); - next(); - }; -}; -``` - -Now import and use this middleware in your application code: - -```javascript -const { countAllRequests } = require("./monitoring"); -const app = express(); -app.use(countAllRequests()); -``` - -Now when you make requests to your service, your meter will count all requests. - -**Note**: Creating a new `labelSet` and `binding` on every request is not ideal because creating the `labelSet` can often be an expensive operation. Therefore, the instruments are created and stored in a `Map` according to the route key. - -#### Initialize and register a metrics exporter - -([link to TypeScript version](ts-example/README.md#initialize-and-register-a-metrics-exporter)) - -Counting metrics is only useful if you can export them somewhere where you can see them. For this, w'ere going to use Prometheus. Creating and registering a metrics exporter is much like the tracing exporter above. First you need to install the Prometheus exporter by running the following command: - -```sh -npm install @opentelemetry/exporter-prometheus -``` - -Next, modify your `monitoring.js` file to look like this: - -```javascript -"use strict"; - -const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); -const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); - -const prometheusPort = PrometheusExporter.DEFAULT_OPTIONS.port -const prometheusEndpoint = PrometheusExporter.DEFAULT_OPTIONS.endpoint - -const exporter = new PrometheusExporter( - { - startServer: true, - }, - () => { - console.log( - `prometheus scrape endpoint: http://localhost:${prometheusPort}${prometheusEndpoint}`, - ); - }, -); - -const meter = new MeterProvider({ - exporter, - interval: 1000, -}).getMeter('your-meter-name'); - -const requestCount = meter.createCounter("requests", { - description: "Count all incoming requests" -}); - -const boundInstruments = new Map(); - -module.exports.countAllRequests = () => { - return (req, res, next) => { - if (!boundInstruments.has(req.path)) { - const labels = { route: req.path }; - const boundCounter = requestCount.bind(labels); - boundInstruments.set(req.path, boundCounter); - } - - boundInstruments.get(req.path).add(1); - next(); - }; -}; -``` - -Ensure Prometheus is running by running the `prometheus` binary from earlier and start your application. - -```sh -$ npm start - -> @opentelemetry/getting-started@1.0.0 start /App/opentelemetry-js/getting-started/monitored-example -> node app.js - -prometheus scrape endpoint: http://localhost:9464/metrics -Listening for requests on http://localhost:8080 -``` - -Now each time you browse to you should see "Hello from the backend" in your browser and your metrics in Prometheus should update. You can verify the current metrics by browsing to , which should look like this: - -```sh -# HELP requests Count all incoming requests -# TYPE requests counter -requests{route="/"} 1 -requests{route="/middle-tier"} 2 -requests{route="/backend"} 4 -``` - -You should also be able to see gathered metrics in your Prometheus web UI. - -

diff --git a/getting-started/example/app.js b/getting-started/example/app.js deleted file mode 100644 index 287ab78cb3c..00000000000 --- a/getting-started/example/app.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const PORT = process.env.PORT || '8080'; - -const express = require('express'); -const axios = require('axios'); - -const app = express(); - -app.get('/', (req, res) => { - axios - .get(`http://localhost:${PORT}/middle-tier`) - .then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/middle-tier', (req, res) => { - axios - .get(`http://localhost:${PORT}/backend`) - .then(() => axios.get(`http://localhost:${PORT}/backend`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/backend', (req, res) => { - res.send('Hello from the backend'); -}); - -app.listen(parseInt(PORT, 10), () => { - console.log(`Listening for requests on http://localhost:${PORT}`); -}); diff --git a/getting-started/example/package.json b/getting-started/example/package.json deleted file mode 100644 index 4c4e2894343..00000000000 --- a/getting-started/example/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "@opentelemetry/getting-started-example", - "version": "0.25.0", - "description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", - "main": "app.js", - "scripts": { - "start": "node app.js" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "dependencies": { - "axios": "^0.21.0", - "express": "^4.17.1" - } -} diff --git a/getting-started/images/prometheus-graph.png b/getting-started/images/prometheus-graph.png deleted file mode 100644 index c4e174ffd3424c03ea116ec792fec82501d67a54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 90810 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 uw?cljs;ygXrpu>iqIv#7!2L!dak0q69YNe6 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

)>Z^#8Acrz_P0o!dn$X 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 Cu9A@e diff --git a/getting-started/images/prometheus.png b/getting-started/images/prometheus.png deleted file mode 100644 index ef94a1faf04e74d58c3bdaed1a8e6b168f9a2528..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98150 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 diff --git a/getting-started/images/zipkin-trace.png b/getting-started/images/zipkin-trace.png deleted file mode 100644 index c00c86865df2594c35b228241db7db0a0820327c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64614 zcmag_2Ut@}*FFx@K@d;`QIKLmDFRZYHw8hZDkbzt3B9+_5fD(iNJn}n^bUapq)G1y z5CSN@B!EEZ@Q>#_@9%xD?>mo&>)Od?&&--VYu2oFuX`q+G}M%+DVZn<2neWOy;OKh zKtS$KKtR|)L56=~@NvI`fPiw^T3%k`mApK=hKr+xwH=6n;N_=;Byz1U({%5*FAGKW z*@@mh-+uY%ef)@g5={_@LQHr*`w3{YM&C z1ye49BKeQ=@2a$f+tCz|@Xtio{YBcXHP5VrG#}np&4~OIz5gtkh9G0WB4V6?-Qb?T zH{T=bUipl*cE#@u6xaFWrh+>xU9Zc8RDyJLa3r+%?7}-E2(s7f;G*Jr+Zo~g74=it#4X$=#|F^7pgamfi-I>Um@$@}$^>2Asl5@F5H z9_)bv1;z(HA3abLO2RNd2BzJQUNlu5)P@Zq*W&4k9$8-W_;THeA-q0((7ExUnfvy787*F z#?wmg1`{e|ebg!|_zo2z5!r<*rO! ztqYC7Y^23xYI~d9_Zl2EJf1#j-Z9;{sQr>V0H@fH|*SbgzL{0V@b`) z1=wl7(^3ZB%O>Hx{W|zV>{agf2ssW7E-g|_=tdSW>&uAv8s!8rI_xCt?i%ktsbagi zE(0Po>WBCfVvBF>PQon&YQe4xzKz%BC;)ABJ9ite$dChr9Xncgcs%JzH6GAY=Z954 z7toL?a?-lT&A_3^tHhAo_ol9hOpB+4*!{+21e2nlqS>gHFpGVNhdg1Ikl0`v#id)Ozed`uSHjPn+6BxyH8$G1+iu_qA%FOppbWCpGbycn<_AXp*38IfXpnObP{*5xkCgfoVGi3$Cm2kyym9CKR zQ?L6IN)pt#(b`Pf1>7j^Fdj>;3V=+J?+Y&t(n8bHpM~GF zxwNKpU5xWH!*iH4{EF^uFl`ubyx4fptuv{Rke^zvpX04tr|hnv`eN`Iua5mE{kj?J zI%B4A3l+0bLF+UtC2O!1(87Aybm-@xz9_^55v9jAX$kQu-kXS+WS(?{1dL|c9$A}P z*^OEuJWD?zgppqhn{-_ZS6&SMm@cV7Tew;<4$DZK2Hq?Ml`|CAY1zi;6e5c1qdnf& zzl6R$ZNXL2sP-s7GAdMAjU0;Q(?-ezvJ47*bPhR;qK5J;$9UEl*Y11kdk1<8wxYd_ zyvC_5>&M%+a}%F@b!!vbHwh*|c3jTWD`zhf_GkDHOI z)vlthHnK5zr_o%bBW_V}V4eJjV8j~3tR`?n7CtD1-t=wI)b!2v|I=r$SBU3KZ z?>poB21W?$f*JX9`wRGM`>UTFoR6Pvo+}aEAx1Ml@`y}^?iLR>{g=L5%b-*1Hy3aRuH>I{(K6*{= zWhl)k-c;~Vc$0hc1xw_~H4IBD*NI7_b>!m$X&nI(u6jP4*;hwHYeUDguScL=B%SaL zk}JHQ8at;t{XXUHov%2i$;K`vYsI@+2KEMVP?bNPFidXR*}vEIV(UduoItO0FZmaE zb;oqw)+oKsYt=rAp0Jwqz3|O0-bI?-S+D#S#$s%7esQoh*4kh^^eE%Z<)X4pNrS`l z3u`ir=iE%uv-=`)cc5{g`?0T%3*uFF_!D{0y9SSZUU|fPf3EdlW6*hUI#K8z&CTsE za&e?_H;cIiAGr6afMma)xJbJ|TxEHqjePAs{i6F3Hzc*!;_k)&>wGW3INZ2TZ^k$a zP+5}Yc-wUvyFBtMei_4aRfoR(mhSD!Uv1n!OCq)5W%YVS%_rxnjZe!$W|F2{6Ysxhq$cNusSLKD(> z;5xey2Y?Si6k#=43OQ~JhAwuiRislxYrzRyC%?Wd6#77kJwzv&kcr#v*k1IWujAHS zbmnbYBxZaTP`!=v|8X%#{F$6@LL52CG9l4e%vzo_Nz3wDV#06g&`CL1y92AJZ`OO= zNx@@jnZFl4E6(Iwdwy$Cx5GJi@#&+YN8xE%1uX@iE&N>_m7gmQ_hx;;lsS|=@~^va zzvODwoGhGFbCi&m()6@Av%8oc6?uc&X{vQS$3)DqWyHt^Y<_E@GGYwoH-;?*toxGJ zEN+1g`wPn(jm5nZoa>HL$Lk8zdWLSm#VHiB z-=Ne0=@5p-Hr;StokQnATMru#$+j)$0`}Ms+ow7bVxGi=v++pt1>_v$;lMTX%s%Pf z>W9ZTcbO>flgiBT%Z-$!X=LEH)%ewAemCF*^$c|e(=WCSfAP!ZHl9&P)sLJ2&dc1D zy7kS)0MGMLaXMMS9mO+?Gt3E?X&VOzd(O)+37jm+Bf_d;x-x}jSdIpcW_LNT{Sj4N zKxZHiEXB|Eob~K{)Dv;k_>tE_J(`G9;m3p)!5mh}Vv&TP=)0lXSJ|fq>XgC<(obG3 z$nH*@Npq6+JD_ot+;KYGwf`H7cOwbFI%rB@x@nQFnxx$MCanCc<7 z6G1@3B}p9v^NdX?2|FI^>VR}#S*WTKaO3YO2nfTh2}tmFg!qdIe-RK6$AuD*M|iqACVU%kSAYnr)$Kn|`}j&5ru`)+tqNNX)!H(gZ~2{T7~ zJ`;0CQxKo0z0>a|1X7+7_*;9Bn+dz8y`6)rgs1eqziLR}?|(n$zsLSp6*pVyd%CI` z?DCE-Aoizx!hBEe$xyPhvrD;{TS&ZBQ2bAG{D0E-tlZq3B>4HkU@#w8h|kf*l3zev zT%7-jAitm>FTMt^tCxeDi6^gv>;1ol{Er+3kgJ)CwUe8*qXYYIxhAHL?rzfe?)~oQ z|NZ^_o*+-_|Lw`a^*_VH50L+N3BLf}6aN1v8{bsw_frWCYfq4!u7b5aUOo6eWCX+o z#H9Xe@c&ozzg_;_RNEEgBJXIAZ|NrUzY6|O|39kuThD(z#VcBdQi}ioO_~g)x$F!r0f8LBD}`rTo`hRya$m#Al*8SgjYRvV zLx)9&#qcOqp#m_49($~L2N9RtbBfp`)#*sn zES!&J#^kGI|E**8_j05pB^-;QlcYY9qN-Kfv~~`%ZnT58x2gYqcCuDTOE`8=68F2* zwvw$EQI=Cv9=An$2OD}z6XlUD1eSj`ir=LhRdOaK*(}b*tB;drB-tMg@@-^*#Me36 z=cu5fbsSJCJFveDN9N`(^M~^Le^O!Zy`6S)wy6whADZ={WC62MBdAB%O_3YnfK}=2~tZGd$kuPUc!W?(_QX?jZ({Y+ z&zshB(4%dL4j)#!Hvs$d4ANPl>dV}>rbgqZ8{f4P$yTi1zJ2>C&HkLvw%)U6ff!W7 zaDjTJL%Jjww+d|WtU~*2x7K@LW|+2#AIU8^5h=y*rhS>~Oz==^xFKP#J6_8#-_l1U zGsJu93xL`8@z%06I_m!gehZ!g`MC?=D*GAes zu(Q_p6(cK$WljflN_Bq-1%}bGIq2!>`J<+5EKirEeQ>q8F)}mp98IA9n`r`Op|tEV ztkN?sE-rMqXFT*)2!Y87a?m}VTeEex0C;4;wIZs(pFe+=Se`Xcl~dcLI9R$3RrB%H zh}OH?q}miVxd+dRd`@=SvXD~x^Sa6EBceQmooqmGSm?HXe|J>~ zRJ}b8hjKhM8%~!*S`2+%Cx-Ri$`G=QUS3|Fz8@oHidXMpN@u{yc;@4IYLI>kq5>#u z(CB0W@-Q(VDKTQ_;K<)FJF6d7apuSnvbTb`Dciq|!!ZByK2YfoZOq!9E??T~lMbnO z2r#LG6VQD8^U`}C1Wy9`Hw|}BinTEUeXE8qv^}t6`O4BGXUBV(NTH#flqT-$tzLT; zr)PV^s?%_8bZJ=ihq~5oOqrGDi0AfPtB#hIIVEfquRp@p%Mz^(adfL?%x0|hjTuY* z{>V5{r)O`fFn#r@-)=S zHwQftSKAC;_Y`>VoQtcgYRpt(Mur1EN<9vyLG4V!en%S}COFKAC@C$dgr>B@JPEgaB6td4tYnFMbNY{N3^hjv6&g+3 zkE5TO*V(Eu;v;B*wrv$_pO&@upJB$O22&fSoYWLc(&xnc=cZ$A$Bo{LiB9Ljv2_5^rC>f`e_}??B3%`y61$D@<^qf?DE%KL*bPdJSLsl=3>XFt+S9UyrTQ zOd%mLSu$&Oap&IUX}~4FRNZK<5(@7~3?oZEfh;Uewt%GM2O7Rg42HSd#_*HLic~>x zf_Q4tz+S+`YQV{&B?vTK;eP-ba~1d^MYPq1@<3BA^ zlveVw+?E-~IBmd}CF$b>Yclco^KsP7pteo0Et|asw>Rpwj53d`HmoMkiJ&U&_%qz6HN#yxcjF??#`>B zrKR=gl^tdE#_X=X{r)S$nUQZ(@E=~nYs`r+dWdNHlM(!Zzvf&IHWReU8v0Dti`U92 ze`ZYF?NDqO+*wYmoA*y@k{l-WEwmdr=+|#tb5d)L_|=?+W!`kf?4=(k20URZjT^o{ zlZWbM5%QC3%vn{f$Ee91oBOO~hxsfS8SaSUVZ#etM*qH1Eu@V+B%xQ*Q7Nz~e8|IQRRxs}Gdh&-MfXYehH0Ej@Z`RmsEcikX?k;=^cq%J?-&jqu)nL&#G;Q~S~=rFE3OEC@D( z4Wi-5*o-xI8~Rr6bQ?X~E$qobqcl)6+gRNsRFL!b(NUuW)JHlo<@s z(oL_U*<_uNt-}?x?SBYG6sohyUhD`BOPL`JU8BxdMB!C?!?N?_4%+@Fn1=a!JWSKA zEe#ABaBMwDEOrYF>bB{d(r)uQ#bID@$}K)1Z1(Ul^YS?J+<91PPX%6f@kVFoROzdGc|scV>rX(sXz8@)4djj&6jVn_BM znp`dC?Many)VXgWjKKb$|LCH*3=`9!yUK7z0LJFQ*$@^2aTn}{-xVd=x8fu%|eN0OoGZ}h@eYS^Rk zYI6jSO0hzI+bw%Tg2dTj2P%I6m|6amoW@xm9n_)|!;BhT#yq>cyqJFT?^7L1E6sN` zZd^UT4doraUc?*Nk?5@ko`w>;j%{5{!k`2;``^uno`>MZQi_<_B&Lt8LSq?l;N>F4Ar-zI)O*b%K%>E zmMMA?8r5P1<&w-!8*x5y+HWA@Uk8)Q4V=VbP^dbjv29-gy3sjTHAS!s4|Pp~$*8$+ z>`xB$jcC8JPDr{~`l5ce%h$5=TsA7v6+uLrKFJ3=GLVIRte8GE0fTzpyB-*9jC~6eqJLd~XJB~Ua zw>v@j0>9~{w6YkogMEyvfNaL^lD4$q+jOEdJMq*_B02c@JN>ku^kdqQ8P_{sn^hu% zWugvB8e~Jg&!NLSh}7an-NpGSs?wyx_hH5B2R!`%GaTM;?;`S*8L9L-`sTEs08~#q zML_4F1%jhClsnzFeFQpORtZ)*nxPK(gk#6?66c8PyrCZNagrUz`YUh< zn({mr<6j#-&XOZ+M9qQ0o*JTpXWY9?ybu`XDpS}{^Ewhf?naec1euOn}XL`Ck)2 z%!2j_FMP&TMW?Sk`nu51V|#T@EnR}eBXahsE#hde*w?M4;Mb51Qz1YVsL{7DiGIZ9 zyAy~{<$Eo0+!S}J{pyT3_0C6?*iu+O>2I+-wx6keRm;`?r?r-Gh0|mAX9Pd%m@R1# zK6=_Rom5Gr{p1bz;~Wxp-_XjGD-?TyPtNSlPY(R2`fjL8jXtXLyEtC;Pl=m~Hw5pG zDxLlio@DFN)1ua%RQ{dw;)xsF6({||_fw^MHFlVpI@kx-3gcE^2JNy4`|wQPll4Lv z+w}A_3^)TwFgo~Z-l!{(@#u@(x5#;!K~2mVR?nejE{<-v4~N#&u%q>>Lh5XB)jDIw zFba%~_US36loX86D!)3_+PZ#~gZ3XOs69I@j>u<>^nJw!YSu;YHBqlLTDNW0-O*+b z?Fpv>Gbn&nPmW_5e17#lN>Bpu=+zHKk|f>o?cr;9)nNY55{+9Ws6q=wC=ihgi_0hq42p; zfLoWci2ckGB$@lOnrg2-c4&!>!I%dd2lM#@(Xh1#AWz=b_!lbL*}GR1gkOu9>$@| z?G4`@6|Go%WK~XO=zF!1dmci)>V(0#XAXB3sG313Lwdkeq9WxazNe%nkJP>)EJ@{?+jUa0}enA`{GkvVvQSzT6RlVEux>&MJ@CmZxv%_F zP0%kJ72_@$EhG2uv3CpDt4nenQ1yfHDuvl%r~B)RF{0l4REJq34TONpF`;g8%0DutTO6UaO!y`nIuA(Q4xl@ERO2yCW$SY84W>BtwS>_UkzXT?Q3tP%iGOKbr&^#5I11*v z2JzS%6g{oIP&h}hus6*6L!}QUG{fw2_ywMVNFeC}7svi3l5cbD=UTjQeLNMq-rmjp z23h>P3647NMdDp)Q2ct;odItSwx-7e0z;N5C3wC7fZmrE+n3nwx5s?|7@f{(ao^pw zawb3V(9$23fw*y77(SDDeaegw_>^9fBf2v0L#u_v}3*g@vortziGGTM*t3x7JXPyIcj-5q4Dt@*ap>cPy zko8k$SBxVM4%K`ff@swXSKUaq?{WWL=`dZ4kizuyQ>4q|^$FBVO1sJjqs3#oNd6nw zB=V~4-IZQa)Ej#(C*Z+TQplup;cuXgcJ5*M3wXMaG~alUPpCyE*ZvMP$sG&9rEmN8 z2-8%Oy#%aO)N6O|Q1Q1cATQUHWPfS;WgEIrYJ1H49ZuuX(9c87EbwT~3tYhEVE_zq z79~2j2JbwhA-{anWQoabtA5R9RXT5_`Q-SK?C~d~fb#LBKt;HJ0rg2$2DUfjVl9+z#at+W z_M3!s=Ab4fea-fTmBF;rUEhRrX5%D5KV+$%=E*GEgCW@&z~s9I2lU35i01VBcFOU@v562UXd`617f~*SHQenuO%;m-m zNp1^E=h)*zn~2vh^WU_gGI6i8_x{c@DZNT`{ZP8(>283idNJ> zwk>b!=4;)58(^65U=3N3S)p3NzpQ}y^eE$HZHZe`b$midDL*!W2cVD7W$g!&1!T;c z-0q9!!tfAUtoh@g47R9{h{;26CVmQcv>0>xf;*`+uht4O)K+22?1S6-#0nc|32LHj z3l;EU*qtnnQCU@WoirA_HT7drMgs98BMB^nxa;(QC|t5TijL2ja2n)ecoUB! zPOV%s__w86+?#3lR~p&NQ;C`=H|kw(W11Xx=ByR~n^23w>2`Ay=>t_WbH_oRS`H|s zT|xhj_6WEtZ9dhFdtwr#nl3R3kkKZv+gWJ8*?mRkHwo84D_i?JJdyh{bWT=xJmvVg-l$oi zvMcY&ovT}QgJUVAz|LGdR$H-Z=0`@@dGb9CG*Poa&MQ2FoXe0(D;`GFQfBlX{H|YE zvdOF<%I=GUbZWj{zniGsPW$(ABDkv&`{7E8YC`&@z4Am$#>;7?|Gf2+WlF^6xBr>enAKs^bx6D?Nm;EnJ>t=E zq<$HoU<;qqezh7OTmCe};@BkU#Go6+f@;`*=b(7IfwDVP0Q}UyV%SAWms(^l}qY2ZQ_O|Nmb3PEGo+tAj&;;;f{ras%no|r>O z!c#WUMbYLOq8gN;o&~9$rQM(_AzE0n)ip7FN}!`zShX&eu+%T-nPHNXW64EJ2L{?l z>N`IbYwHN@kq~|8q29f>0Mz;F^5+iFe9?;CH7sTNN|?M;I#xv#MBuR$<% zd`v1-Jw@O5U*gKX?@p5iZqSL@Er@=7S*4#;YfI&EbLv~V&sNCOVv$i00T0FOU=*Qm zR%Kp&v*Ow0*$VLs2Plyb2u*l80y=VV8vb-hrdsd^Q2I9mD0gs0OKgW(IzQs_Du|IyO-3wR}P{+FL_#GkfrCJX|xXecV2fyWLH>+9lrd$`Xnzlx!E5;GS3ufPLS8`u-I3}*2h$%h!vz)Rh=kKZTb}pb-l@Voq8uR# zt!M8e=f$kLy1JYbt113xD*oH9AXBc~mxroxCmSn~q z5jsj@hnX*&Pa)@c%H7>>RP0~(rYB0}yq=*e)pom{0Bc&s&qgPc6q%2r7}u!#O$!4B zAJYz}{BaKqKSH^V>lA^r*BGx3ckoQOmQnTR?wO=DCl?eHhzzwkHflVl-AfHs(q%=2 ztfr3r+W~{DACw=m%8j#E%z|61h8Z*?v6=uu>)@eFMWb}++tu{Lfet*2eUCY;&4J>m z1m~U{qn6u4d8&{k@UI5|4h+~uJRz%9G4b*Am-p%noja!dHeSn}Te;N<&qe5SJT-5xG`#j}e8E}fu8&iJl!}OY33!c8L+B#>X^O0n zEW7!$volYK-oMN7BZO z9+7-=eZ%63dyURuYN7=)^!;|Rw_SSb>ff3Sr}C}$ zs9}Jng%2_L$LALmBw8Ht&DRe4U*byjsg6QfdD_mVn|WoXd@*^S5m5QGv9!F6lk&O| zrT-r0Ifzcs^?4rm?=4euE^^}uVi^Ny{wzlK(_ew7?K8z=UHIf>>*zd-H2&b#)`3^Q zt@IkRA2lTbgmy#uyIgd+CF?&c`I=l7mNdTe^+E#?@);M3@(e2z3kWQmCi#0X+?0)Q zQ7D6!PoF~IL2{e&YftKmn_Aqhk;@~^ST)m`~OVB5IPdAmCvz~)A* zg=au$Pu^}c&G3nm|F@n>UdX|@*qj#*fpGUvEV8CAQ)r@C1l#t-Ogi5|&p*RaCDdvC zr4=#i^k?~hZ<%U*A?m^|{Me2v;2!+^Sk>=}pK_wiDD8g>w}Etc8a}3IVozGsuTXdm zYKm4oJ(o4EpO-!k@@sxqB`Y7J#qa*pT(l}TrMDM@>?w(6fsqh&2OS__ULEZ zKbsXE!D-VKxpZ%*+~}TqgN7b`xmcd$0`*D2MchNvrB1A%$IOhU2lMbHDd^!gzfN)R z)`!1!WybKbfZbN`AioO6=866<(&fB}v}w+0*2g>8z`G@Npdi=}^X-9T+hA{SgKIRK z?R|1qhMRvPug^v`HOLT9OHy(!q#sO z1pLGH*Vlplg;aF+xj22JQ6*++I*2ACW&=3LK(N*SB^dH zoPSYKDwlsas z|Lq9DD-NfvH|VYInrL3?6YOw*!&8*U^b7{d3$J`&JYAt_a9W|PR`s3mA1m@$;co;aL&+KIefFNU-U)rv z$D#Y1yz#e?T=JPVKFn6|3&>V*7lcL+$V??sXJhQ0`gJSxR8}aTKklE7CO1`*Tg3I)+h?<8IWZ&EMpnx9tF#y> z(cTrg8h^LdUSU`bSJ+@Vg(ddNFFYx94z}+NwHNVOCIikKRqx7UhI%!Xk+v%&hmr+x zS{doE5t!FEr_HHqy_AC=y?f(~(?jP?4r#d^IfCO#^O?5HV63yBa@FGOcJ6&2_i8oX zG}KRO1N)O|cacY?Z!LP5{Kx9OG@(mVck?Y%noL{4R8;%MaJRE-%u`Jd9ExpsPyiVk z2=hd3-)%ULsNJt?x#*+TT)M~~K3yp{&PCXU^hUBqHcq;H-M82?D6!otaZ(Lm){z$_lcVo3p(=n79r^ff98_`GUz->uD!}OUxCu0 z2(L2RC;txYj6{!joh>NXG-k9g!rgUqMufjuu;?3fM(vqSod{p!G|DJ5qK76rV}^d> z>TZV0VVYlz2XB8V^2T{ag>4xQyUMdg3ci8IbiPI{{mKNVp3N$V8&Nu3yM@ksHo(|Cu)=M5c5yJt<$?GhfOuFKa=r?NoBVb`Y{Ldt-0QOt zr`*#}lxs%_#mMww z11v*<<;T-JNYpAH${FG#i|s%EMUyKiiD>)cm@fA1;_$$_UQ`tRRw>4hI$^rW-6N69 zNkyKWg7b?giM!tplI&z)-f9GZvXT5}@K(p0C7_ySk%x+I4WpSBFLwm+a6YakpG#SX z*10WuFr%S0=}Sabltkk+3}VBilIlzop2+WRw)@8G9jqFb~(1YcpNy+r?*t0<9T^SFsVUP)#3?7Id?XyeE|#xv@&C@MNe z21b;nEgk%3`ekbfkLosa9bncLxxE@L^dg2KT5ntv!~($#^X#;5D6F1Z?b>LPwdnT* z2kt1K5IxJqe9A3-fxy-Upv=(+wEN=Ii@HpFFd4sZe7e0^QHx?bhWb4@t?`5~FA1Wh zbNMHI54(DTPLn}I=^`dDoc1h$%bgnU2dW+AKL_Dd75s> zZ*u=y&VoLV$H9=K`}@zR+gI*l`LcO^aK~Fp31rF3Fe}Q4h%@wK31knjba!>as~XLg zFzP2^Fuw10I?#%!!@7@d7-!{Enc~28TkhcKpmT4SjcspIYqckNlWi%~d!O7G{H-YO zL!XvaI+kwyR1bXZz-E3X!F_78|IJze-GrM`a-Z5-M17f0K&eL$bq~V372u8>_Xe+y zT$~Z{cm&9O^HJW+RRy!J4>7YC1Q2L{0j?t1p0zfdueP_YY7OatWmuem8z+Vsu_NPc z%xi}&r{LNK+tG=Do0APYOy4ZkK`PA+gU*+Gu5CA)h7CMfHhKsSFC5qV7T?Z2@YYVI zCCc`7wc7#AFK17JQdURE{}K5`X)g4}D4Plb8m~@HnY7J7=N*!I;@#(3Y%>okaw7*% zoI;Gh)=lkeXd{I47Zp?e`-hz2DVff0KsJcp22lsco3Gy$KTnH8M5elW8W$VwjL#pI z{Te;-^T|DxmcdPZMjPHK zipjBznP=uHMy5XA(;c_$)HAkyW`jD!@`E*7R~w+Za+?-8Q zqe9!heNt6ObxRi4Zpe14<@oCrnY9KaDW!X4kL*`lA;U~7_eUdR2@WGZ>R?uP_h(bD zl%>bhZZ_S!HJfta-klP>afX;Y^A0(}r=14b!Jr>(V|pX`mc*cJg?wnP&tdNL$z}OST7a^w`cdhDCNh1`Elzv{k^0 zv_lozjYuPu4wxJ+4{`frF4P-gL~VUPTdfAz!NlLZFJ<{RYU;;TDVlqqSBOrYU(fj2 z2T%Y8m%k_TK}Owd<}zu4R+*|~mg5+aNFqSf!qucvU#%X*MR@_0BCQkgwvCkNlHKpBg? zvE9SA%52tNZ#lCG_(YkfzBZ5U@u$Cqa2#W@JbbV0ACB~Ba&}7~C{mE*z(%>iK|CHg z586APo@2!jAiGV`tt3PC=7*_4FtDM&eu_K<4sO~148$$<>=`XIRQN3?2l9o++iw~b zTXK-XHh-FqE|mz97qvg?)6jvu#MPKG*{oxqiqsY?oLwjNC;lEh40rH$!;Byjy!q-6 z3}7nGz~yctoe@A;6-hvXMaAQuLo~BtJCHg$W0@$=&*<8#ln`0J4g2kVT+lKO5|CH&kQf z8)QSU32Ngq(RvxXih=WQlQzJ0QGkXX2gNrQ8GYTkBzYciLq|vXRX5J{EdI=AMl+}F z?R6E{6%8i<&=?%Bc-6;w#T3YF6xdo3#a5uYCCpf>$^K;GEnq!pPm!8^XVZNH-(!_c zEVxy4a)@bz>GXnt$h^BcMFn6Gtu3wq7TY*^Z;cr z97WYHr+G}JW%BMt#G9bXRH@jGv=hrWHp8y!qbWWY9k{2!m>w7h0;RPafjwi#>fnG8 zw{eAXDlGS&uBhY(I~ULa&Lib}gdq-^O4fAQ^N3?H()M(R$!$D{tQOGZ+8TPuSms8! zd)*@*>byt=-V2fGp=9TQ>SdN~XUd4Y0qD(rCp8U*|182}RSXp~`*Wj8s?|Zm?YMt3 zuHHvk&Sqx8=HclW55iaa%Ov!QEr$o{zIIB4-vLH;D{wyXE^^C`?Va7|BDsn_>0#+x zN3E-M))%6io+!m6uFhj*%*r$`->w?mNGXl3c{btTmF8%q8Hc;I(Tg-Xh=cE0-G?+t zUbTM`Qoc911HFA1exkv!;>!hq&?Ev(?Q8#hb?3@i#U672E`s&r#KjO`ByA zGx@5CzUu;q^i)6@=%28nArVl6yx{p4fwLM85_fW2_{m9q69|j9o?sx6OKWmVlq4k# z%>ysdt-D?A-neET4xZK}zALT9pjXB|8v_2Q$l7=^Js~u_(R*KAmhmexT{OE`_}3^O zJEUOCnN)%QwrHm;AmxgmHK2ao?{?~IDf6bc^CxUq63h^6K_kxzbcY=!e1e8K5ohUN zWL-olO81tz%O&kgp@b%B{d9BmhgeSZt!!EDp2O`Quu36AcCng$F^R;!!XDec56DdT z7xF_sqcUi*uzz6RSDpxIUkfd)VY|t1l)gVlwVcs$vLi(j((xBY$D4dZ#lX1aps}0_K?=``i9jB%XxQAH_8#1vazVibh68W zWJJGoiiA+;GxE0Rbln|t>2*+7NoQ+de$=SYFp{(Tsj?KN9$`38u1^gAB$v|;Bn@Qt z9#76`kUlM^h0&}d=3wBBThQ|m+S1C(shF^niANmn2g_M)U%KyW-zG4MwbBgTUM|PM zs%b@`w6CZ1wxyf$lk*@RK4-IY?mhk6UAFi0nSSOYADy^p3|>kxj%XJwJp>>x z$t~jtJtBG4ufaxg&XLE$e4AkrfCN6irs2GOE+KdJEPhz&%PYZaJ}(1e={u1}MA_QQ zsq5#AD7VG;M7=52*7;^~O2g+1P$6_-cHXgMKh4ri=3L4T$D3=5)d82iq`7R~V4d}& z)*naQX61)727Dd5;59>!CyP?0{L$l#W#hJ!QxknEI>*6rh)(h(hOKCv>Sk)wdok)j z-N31=?dM=km0ODq^}+Dn*CLyH*ZU-SQ2y0EBmYRc>n?_FNESFwvl}^zx`A>Om^$gG z)*80iG9}ynFIU`vFSM`dFv0eQw})S~d@;!F%uV1E*c4=JIk(!~aA}BYc$?BCD}G6m z*^)=$=#lE8-aTSWVkn)5X>({!>d$`#zRee!tNO{?FO|H+Xp{uhSPE|S9%MoY zL~cShD!ngDA-T-t`_R=}jBYylhT11vO9jJ&x?1{vTD@i`Wy1Jco&8gG>uZ~(6?@Hd zAf?Rmc0kTTg`nS4`!!78jj+>SLwyQbw=GHS6O7BN8~cK^V_yg7i4G6!1Ie&^*BjQc z5w#N!J%+wth&+wUzAa+><1O;w#~8VeeQiG_f?So*oOD}QW<3#oY9Gd2qz{f#ak|~I zn+m%VKT|%|oPFTNrr|fr`D7MB+WxI=%Ea$Qfp_bPi{`^$HxIqT4%e25rx~V`>}}NE zVd~K$Qwc&E;?AU|2O*3zufdFQ-C&)YO=M!o1=Oley7dKerOp+$RIzSy%3Dl5DW~K|IOys1Y>& z_%Z}58osB#|8z|;oCquw>d-tQuHF1Rf9${zlzTA!w%6*Zs(S-7bzqTPOIAf+9?ubT zY7l%T`X3p2Il(JdoYJ7Pj3fdiKRjb9g2m}oq3Nn_t5S4fz2Qky^WvbtDXvhd? zq3wokn9678n0qOWyN@`IQ7Y)vb0PK{iuca8&qn>&k_G!|CB1u)YI_|~#sM<|GIGqJ zxJZXIE8|aZz(&s9cVnIzp^lAM-CpT;G=nQq{L)=rP0=+#-{l9&?(kydix@6%pA$Fo-X&wwCHTZ&htLCpHf+Ovh(twrXZ(yuGva|wmgz4?(m zF&gdVFZixy9gD8;)&yMkDQG_7>1nMJR&#LhH<@*?^-1_7Gl@EfrdLl7 zd#mdleCIAih7(X_Rz9aS%ZMJ*0paLf*28Cg?w~CE>h*X5wuCa#jp)`hH5_hyx_^FK z%jMqbJCV&o>^WjG;TpipVR8-7ySqvoeF%{&uI_spT62;7*j1EOg=zMY!|}3$QNU<| zmkzs14*+o_A-VwV3+b`VY?k#*YJLo)wy7v+bK-2xO1lShK6CO}I-hpf+I;GfK}EOi zCVGq0^E8F0qI}qxQ%NueZ{+J-gAxfB8nJkpHtVNdlsNNQz$bP8bUGuvF|mD zLwmB150aqGq8Ge>6n3zVe|&O!dRlA0rf}9Ro7Sa8Wt}k(C2dqmXs$4d=;X_UmB$<} zg*kt8>3`awVz6Fl=uo{Lq^`q>u5RhbJ#l9?(Kx%_uFmXIR{X5iMy*|$WJ=2**SOxG z#F^^c?Tc{{^V3L+g=R|yKex;;iHE6=bX9b^(2Hva1`oJTIuWB0Q`dK(ffSPy%{k1S za~zplTHJGoQM)_0(bI~`Ju?gD!*2H$+u;k;T?XjSZ-k)r2S88UzTKMTJ*vtaQa!OS zyMEOJtApYxEZDE2%-{^~jP#tZXNR10jK;~vJw*c8n^|7|qQ##8I*Kw$t2Ep4a6TD%qV z$jg6HDvx-P0x$-ZvsGYP+`%YCbR48e@2H0@+6iU_UG!rbIh#xv(^hgTXA2<>o!!Jw zzdRK?f?DSah$;KOZCvm2j!j9i1iiAcpFf$xnz_1T8lM$~F38te&Kg_Jyim(=-uO^( zITd(GA_8gBsqy><;e_Ddq*%ARnvFL{lI8U@GySRZU{RZf#jr~6V_nOajhz{V^4?-X z;zbXKRnBgknh;V&-AfKN!$iy9IzhYQmdNR;q_zIp)}wJIsOm->e^Q@)ulWv(GU>rM zY)Tg}SZ2R}!zebtS^|&xs+-DXQ^LCJ!y$>>zpwyQa(eK&DMUux`H($o$|~Q@^%hpg z9G|}Sz=Wld%+1{>TPGjc@0#^D0i*&m`!h(h5EZRcy0Oc1O0KLE$5ZT2# z))junUnFGz+YIR5E2e4~8ymB9nRJ?HbyPB+Wv)VUuR!}jSVH`_4;5>yKpU6pBu{Ka#L|`GhIMJN z#T`q#t&Yp>5|4%+lUt=zh(&sLzSjng2jGNHWS}9aTwxFRCxL+fTj68T*4bR;teBstjLkGS z?;4kA)E#+Ri`Sc6Y@5wg7aUqF%qXz+RlQH*1r&Yo-~pkC3}Nkc&*PaoYio+R`f-%Q z2mRwF{~XzdUzi=*N!#uk+r3!L=7*#6`5%p+J&Ua|pBzl&wYCBY-)E|-@!8Ee8sG2x z@PVkOPV{O~E62!Up--`TUb;Cd&K(?$M~@bD)aB<~2#^~4_TCQ+R0AlD)0P4@WXNWJ z<7>!2*K~*);6M5p8LZCKfW~ zlU?qZ7Oui(vqU~F?J9EZk)@QqRyeTMji2Nv+!|jH7UH6s@H0~$>=ynNYkJ%m-pzV< zLRRois7|=^STaEwa+IX)nwMkRTf+o{X7)e?kZw~SQs8iz$_PS&g^UUW~-c#AXiQ^uxRpjV+ z;Q1_bf7}fZ>!04A@6u~?9|>Lvb++udwND#qWbz{+T_{FPa>+w4K~?A-`O8%0I1SEO zlG)b&bAA~@Z1JA5m$JDSPr5hXT7BO;rlwb`GUhqb{?~tWsYKJ~QRy~!YnTot%dZI( z2H{a=1RG-}`%C=u9sXB)hzb!wS}6gGOXu0 zxbh28{Ew_eN~fC_ZH-Q4f;A>cl^1z65#$Z1`cCFRf86#$>jH{*)VBBt)vvPie=VQy zfoKE^g-%Sk)xBl!CNNkI9w9c|KHllS%LC(pINp4s*;B?kI^XPW`Q=l$(_$OqY_oga z>e`xyo}ONUsEw`dmpHe9e{ZR#wvkK{;A6_WpU#6EDl(svlg=~f@Rna3LFEot*@+$~ zR>(2VRZmK0HlJ^**U6pIcbJvHdMbrM>bS^@>>;tp3!36UZu&fDxDwcIR0qoCabDIG z%@X`9ztQP6x6+CAU9xj>)FdVSjZ93E^aIha-3g7iXxE{y;%R6rV~zBAqetq~(xCfX zy%Zzg0>l?2sQH@WP!Ukj{xQAqHlYPuYJs2T}ls^a9LHS81I?9{x56&^G}#k)W|OmUvp7WzP{-% z^@_<~g<_78xoErKQ+x>L-W^jdFPyiS?epQW6fC>sWalN@L0zZ+%<_M25|qF=T@`QR zO;-NWg|j&R!cA2JnwE4>&M8L>XPZPpR{mY z@xlT0hB)<7I7h2JOHu^kO7yQi+FdhS*lWM4RrzZ#-YfX1i1X~q*jf9Ia|ZOa&-nMq z$PUJX%*G4HZ?-S)(bTZkb_+^w@o-<<(+tNs7(eZ(oU#wNzBIM^JGc}CZx~znEd^o^ zBf@Eh1`o@DJE3Z;ZPra#phxcX%Z(&X_e1H=H=0EQk(x#~&y_=cxopJv_ot3E)a5{Y(7*BhG&v@#lX;K1v6aG&Ng+ZayS94~fG}zE#EJ zcJK4Q7xaE#1P|j@MGg2c)wh%0i3|x8&jZj;Hao7OV`*IS+2Z|$Q_u!-@Y)_W<3?h^!r6b$B_XV&yyN0 z?77W?ywpm70&?26n_;f@qpszjx%Q{90Yi+5iAj0rBxF0hkLS+V@tC4WjrSE4b%*nL z&;&jWYL5+^{~gEUhmqHYi++noW0eE4oN@*_3adej*I?X>(9$#jdjkg#8hIci$QHdP zJ)!1Jh$ z<;tVMp4|xB{tYvjdLg0b-`0D|aladnP)V*Q7g+_Vb*B$iJOXxbaF885%($EsApEbo z8v~ykN>_xe!M;~OG?U!p0w-y z(oXviJB3SAs~NmTf2iVKuy!An`QNMRzi&1lf{4^QZrz9b8`=VEOP%l*Gc(D|v3{olaq=y}UDU7){`M(C@P2-S zdhZVxmG|!G5SJ}_j}KZyDfn#KZZNAZ>I`}zUI884#%MaA?Rabp;AF5?2?MhuRAA$l z;OBUQVgP7vG%>ys)l231vB7cE7@tw0_}!R|#c%b*18>m!iPRc%2my`c+i*yl;Na_^ zhxSlxVd4BUuhT|BUXRd+WPbZCfVEaVrXX12(0p_TnjrN+Pgup-ZtFr%2$@PlDTB#} z;|habSlcdR+6#S=Z>K}sF)G>>(FAy{=A$VF{}{ykq4oef-5kzSOnaDOJY8u7aqkYN zbX|#%ID)qyZv}{)XS|Q+=mZ#H!f^bVa~|G#mn?WstrNU~9N<{M9L~neAj+_N0%KJs zij4qz<-*O9XtpPq#6aX?UC|N%&A{<1qSfXKlo+WNU=wvMMt~ofszMo!uD(5C*?hcH zb+|b>E6+P;SU2xhqy-vIYaKVAePd`k{hYK7AU5i5u&8&>YLaUW-1}FC6cr*oS@?FL(|8Hnyz{}`l57U_C9<%w4Ka%N z8znjcG&zyEdiy+&qiK_zBJjP2po{O0M`=Qf$JtDn=ea?v1&BF)Z`y_c7#Y|a0M0rb zTkVh2_;z`*U0gNzb*NLsa<=xcs<5FbyRY?P+dB99Gw$v+f+Wz)o~GqI=LjMBMt(az zp2~YcLJN;|WbQg>|92W!Ryh?!7jS@r@SjIb^WlUBkLTqJG7-p&4i5vB{Ez!>-dDB( zObc7p2Ak(;P&0sS%jG?SLy)*HoTY*ug;UE~>jf)Cp~L8AaI(u&cwgzl>7etAo*mEv z>TzVl)mDr*1{&Qe;HVD+{MD8x?4W7CCb!M86>_ol5?i<&;Hr%n52ac*(5^^{z#??C zjZISj@frGyZBXfQ+Tb1I2BHBNm$wzNEwf6%dn?7InSX>`!AY-pyM-`SYA6fgOIPQ0 z*~06KI49#R0Na97xr%;|EQVRI488Tk35)rYox36ZMO+7_q^AJU?Lv4-!PgEON3Gs` zk`*B2@U>=Ke2r_ZZro|;mkcF0gEz}kk*SV>uu5y-1XGo2yLwD41VArrd!tb9ZSq)s zGzIX3l6=u=rJD7l);h)+?wO5u;mznoMaYgxJeKetB&YY>lT&bXj%QW##V?lTxdE?>V?|Bg()~Te^M>bo9Pti8W?sW;qw>L-VB$KOWsS zFW=en%oSL~7mYw?A5MouRC%)v06`Uo-Eo^m=zbsY%Zn39_B8%@GpDh5a z#`3g>7EQn=$9{K!sdWxIQ7u8o|58C(;irJz=VQP;PI@S=1A6>(xceN5I+YZKR$mUFUsp`MH(jPu zTQ*T}t&tKAUzC%Rb7};lSn%N8P>aQMW#_@C{&ApEIE;uku`q-Pyo5K4tF{tMQok%? zde+nbrrj+>i<*~r^64rM7rnT#k&#~>S{_KW7#)rI2h7$1=seKX{MEPD(C_q(5jqYb zk;`%j?+c23u)Fa%<5YmB=+_H?M{h&YUuy7J&wm6!729bAhW2r+S}&-bfr#hYdhIrB zvNmql&YlO{U*0X;fdQP&=P>F5GaVz!&CYbh62j{fs?DUxXDQC}U#1%%oqXSXv9*b5 zRmHZ`F1Ac+9oC<;)(ATYC;;%><*oNL|N4}B_b{iw83jm!vQ&icdz$wL1!a%X&hBtj zHcjNplTjssjFPBp68DDVLw5S*Iy`Id^|8EJ!1r6DvTQNg6DUc{C!P=8JX4cDqbv!B-kC_@=IB+C|PQ7;Gf!+VFxE?}W-9gHc~8H5S(7%Qg! zdpwGZ&bz3rW#&No1A}~`A#g74XqDWqS*@`j5}G`CWr=-nPjoAjbLi}N*ZRxt88}`< zE(%M9SDyo~ElE~)Ag@d+_v7(pRZWA4*mzweDatv^&rbn>mG%7@m_yTx<#Ich( z3qa0YS~b6jaYB~y#^*YKVMfMf`ltg7DlWz5wB>&rtwicUQe~*bSbfaZVw7L@l>N}C z5R7DCML;6ZyeS@v{FfT=0MY>Wz*;Ku8FlCp{LPAI%g04c+|TpCX@nJsFa5(}Ujl zSL+JySUti8__X>!Ya(_3>{t62BSMrDSo=u>DgiD3uIAuN1mK#EW}}g`25{(e|8^JQ zA3(Au3ifrF|2M?O5nbGaBTg8eQ>F&8{9ii#e_n|93Zb;TJpEo$Q(QpmAMBav7Aq^m zp1TV}?caRe|4ZNR-y5mo)n@%wo6PN(k?j9iUQbo2b2>CCZ~m4JUZPLnEYa65p7;B+ zy+-3Q8};RY+>z{l_IpR|D>}Hkrb+)lAOj&DaKCOc@cb@*2cW!Fs99VapPdP5)Y}ClGxDFNgu0!k%6C|P{xy%k-532LC^2> z2V}aRo}d4!%{o#Oqv78TAvnuCl>ySLtZ%^h+tX3IB0o`5dUqn9+ApT~dxj}Q%YJIf zd-VJL;z(cf2CoNTnCnD7!hb*v!dtg)0iIF5cl4XM5s;-wcz?d(8}x(UqucW#d4qOu zPDof=nAYzjI08SUS7S}Z8|(LbmZDC7GGr!IF49OzFjZ+3By_&lX>?B=puhpVxT+`x zfp^Fya1d&?=7Y%hX(9^%)yxne!c_s}+^MTXnz{hJJm+i|R9d7$U}gXYDgpdwKOF7^ z4vs3H%r|1a5A4@ze@wE6bzy^0)r+&^FjoB^cD=Vc?%V$UD)*gw#-;kw)=M`4#huX% z{O6q6{Bvml-3iB2=5c@ykFF+8H#imv9Slo2eF|ipd1JfWSA6Hzt?%9+aD~_E%*S#= zz6lms9y&V%NS`BM_{L5%-a7?2p=JOh5JcyndfMxF94a>+&6vwO_rL)}nY7Xp6F0uy z2%{32cRSirYe@dtQHRA?ZqSQ$w%3Vm2>`9(>DZSj*tKZ*45|QL&k~?t9|3rp9wFaL z)>OMbCP>QV{Q7S6W$1?W=r@zydu>~{N_{mFBal(=hhBU6mVb?zU5w6vbIJ>ip;*nQ zJ^t#JCtBks0-ye}mt}B!d@veAQt(^;m!kJ^9}J>{F`=D+@`_1<2VpnxJDpOWi<2vOo!d znL(RVjjb9I76eE~_VuLzl2EGw*i)nVkF)w3R~7)umCcOPtmSNpvmY`YH6of^3UXpi zg@V9(c6C2%qv6>d>3hI&LrZa9^hWut3`YkY1E|9|Nn-#WdGy8p`#7Fy!zkY!w58;{ zWV?s8yv|d40Zk1gb3vDyR`si+U;Ek8!q(p^o&hYw9G!~|6|-(a6*)4?>c`2#a1_|} z%plf29^=_Q0g=5s-*%i^`!xWNaqAXaX;o4Yd_U5nNb-}eu%0^|7>w7u2S2|(%4dM*DNCg7qL-<(Ker3vCEKuWy>Nn~ zW5-e;f*6l=qHPb!7(kJY8suL~<^nK#A5Ys0QoafVe*uvzPO^poay#h`TymeN zgvDJ<-jBnqdqIebdvRY)5{zOG0DfgQFs|9+LMlR1Uwr8%8Ur|l_}w)gSsLbkFnAip zmD^Fg44D3<(=uMEo*;Z?_sG4h`RF-OdMQi45u6%$;i5Pvom7|MmaWzvn;L4oxX3;H zF9tYzvvcCK8{SuV%sEcxd|B?T;}4dhlN=Uej50!gNX{>IfpSiZykqq-~dOIMP-}#3g~B*mUp1L@?YLxppLzW z^#Xk2U63SN#dE_+6~Fcx+Yl z=0?y;8F!v<6qOCO&x8D2V+oRBg5F7*O$VAQvaM@1u7ZOALFiY@&QR z1&3X(zk$J0{RnFywuoyRL@V(YwG1O3jCvf;#T^6 zh7f8>-tN9tA*Dd~>9y?>{QLB1#Eqe9Y~gSnhysxa`yA6vC5fIDc7pS?B!%LNAcq5E zZ+aaF*yeA&z{=y^EZXWZKIC2XWv_g_!Ys+e5k+VR@RZlo%Ho#_nFlI4_+f7}V_WIr z0+eoz4`n3_%Fe93q;-8gO@1Eoe%{P=?;-y@o~pbvht~)c zn4Hb}$U9fC?}g`~2BupR_#+NJr4DuyhX&v8aoXzS#X{<%(U6aT69H%%d1Q7MTgrgJ zm6>5@=#$(@{bv}-b2sJ81FzIi;Ak7gD36MvP!Ke(T1!5R5eeqmDSU)2$=dxYuQYbq z7A~1|!y>5RP~W>JAo}qBh*AJmY7Y^GeE6W~iWP92eQAL&r!rVeBT)4){uy3@M~>Jy zht^!rEp4QUo98{XC4|XejI;)JiE%X>%ldz;*NW;87t*~YKNW>*V^q!ZPANm8|H#k; z)wxHp5j;mG8n|Jc_mfFDK^PRMl9ZabitgdkFl(58 zhw5kLYs5Pi1{vLzrz)$<)qed{Yro&iD-k^;V{N^sBAGT#0jN za9V7;5Qo8dWk0Ki8mG6G@mt;dUsV90z5@s$uU?$K7kmlApFQN~EJLVjYUyO(`BxN) z9_boHmYw045z8$1T?eZ12J8HnAUy>q5?YVtIq#aaC5o0MQHD4DkQ${I-Dfn3wm2VR zcPqa$nRGfYE_J&ZfEyiD)+fNZwtG0Klg2Y^QDqS?<;2qvUQnspv)EJ749yHOPLU~p z^9+^d?o|gmbv>7F0A;XbuB5-8L!B=-dB;wS^49m)=)xaCV3};;L=vkfvoZd8WWg=h zGAk(sz1)1dMfW8?B4h2TL}a&qph8!{9i-G{v5n-ZfVcwP*#Uut_V^w^ip>Fkr{9F; z#H!!MB<0GVTes1-t{#!xo@f;RAytpe4KPVKv*(I&PVTGe+%T36c0SJxLPd@;^&5OJ zoI$6lr${s94>XL4{!=TH>?(-5Hg4C}(%bO|m*X4QoD{0e$2mKMy;ICwlC0BWG(XVrPK> zF?r$(7DHuuUV?FAviFT$)5WA?Ar7NSQuE@7esT`|`#gzKq2vitSXGfs^zSrjy)0@~ zl%R7m-|rTNgBY1>qYyA?m}tWJ2INZ)YlrrhI_*W{k#FaE^;CF_JRqXS%f~UE(Y^g{ zri)2ZWE_&{QAU0CWy!^-FWDMcc3TpLC57LQ_ySm$Q=o6xU_C;L(yZuOEd{NiImMKv z;Q3i^l%jCLA$I7}a6mA52V%%_Lqt~*jx=d1UWdaF)YAB)ZnTn+n9AhFC*mb#YtKm; zxMk7yK{lP1EJ$~!q;7u3n5+fZD*W|zKOWbb(4xx)&uG60U?)W!K#R`tv5m zyp5L1dG!G7&3m5N>^r4zGWF`M;Hnwu_X7gNEjFq1BZ9e1O#&fFen}Rw1qo~+uGX}r z@=mON+61UgczX}0lE+O9=5o;)&u+V5hA7ylY4 zHe0*9@^n2emj3&Avdj@C<1WA&+!ws+%DV_m@l;1Bn57dRmCfE42dZ>pAxfu6a*Zrju1LCG6B^QQMuqDTSG#2`uAN-Zhr1=kt{PVT`&ZBk-(vbv#O%S~l76 z$JZ6*^mwX>>aFHe6x@`8*Kt4#&mN_Iy|UaIQI0+RoOlbD*s8j0^QRuYh(HKMaG=jB ze4es=5fL!S{GGDRVF*VI3KqEu$p)ePZaP;>B7SPlI9%$-=yQQ7DiEW2BDMFa2V;~j zi{7WBV9<$XM^t=t&99xWp{+ zcvl{6pjm^!%+U5viMo8~#gyp|qwv3oDVb#XzL7ZzgaGc{Je8mCDV}L)+hY66F)(Rh z_T!+EX&KnS<)r7uBtZkZ;t!@!67&wlXCysInX#^%WcU0LJh4OhVV?YE_s#L5=H^A-3)(L{ixdBlK78Z$f4+Y@cH2+) zfgTyuFev%WVSj9uODa7lr@PJCKL4ZakN5P4ANhBZ|NYWLcj?&mI*_llHt$cU-ua_L zzsI#HT>H#dANNNG)|O4LsR5>8^U;nf#~-aPk4HSU0=dwy1IfG+9nCxsG0l`^~Bl=QeXQ1G*o^=IM^*j zu=GKXn&qD@t=r*?rf^8ke*W{__=Oz(R1w1}Xw?VfuQh%=1b=6`|4`%aCS+dr$t+i7kQO zaCUT2b@X={|L>xIQz)F?H~9bkHvgi7=mG=Ksn!c3=6|#edpO~xublC}v}%0u`F+c3 zti~va#zlcKQAwW@%}c9+^N|Z;MeH@zFK+0xe!DyygWF#_$zTS}LwFh07$_>8vC=43 zeO{0=3dR@W1x3AJs~X@m1EC)IwKPwNy4^c^{Ie%<0hDgHwn6a74A^GYv)@2=Rvv@( zjjlQ{F!meZfif*HA8H+r_6?s^l4#v>I*NX$IQ*HqSx&9NbI)KhURHR3qy8M&rQ9q{ zdmU!=tFirS0C-*TPMHCi2qXtmu$FFMV8IxCXD^ zr_=+~j#agg@>r;}yeXWuV`3aS)bN0Bg?ae_|IzygW~EV}+5DjPuEi+!s# zuxu51KiWvBgB)y9gGxR7H$WXFOmA%A6Y5#pDfQ|EXll5mrL{#Xm|IlEDuyyF*$QfI zwrA!Cp?SCJYA^IJz!0;D&A<|WA+_3@%WuB&It_qoyo3oI&x=|Qk<*o^gSIQ!hI9T} zudS@;s^3*lPPu_tu|;j(u(k6?Td76~QFt6G_gykSNi*k~Ny5yg}4BT&T9 zH~BiGyB-|iv(s9!dV6zMD)Z*&!VAGhOhHIR_YLzgwiKb%i+UayVSCmcBZpoNP=(`= z2;yRQw&!;E!i>OSJYI?_Q#BUOvFd0^xs^qDs2aJ)^dHy#c#CzPQx6ODGgpz15wRlE z?k&E=-iauD!qf99DNPP)cM8hJMJktFi%M!Af>YXdB)HC6)*1EMA*Mr$ zAA8YSL7Cl}5qag7?1gO?9u9WTi)GY!;Fmn%djtm0r8H5*^0ByFn<`Ul9}#^N3v*D` z4KSbzu%mSaF^aE_j}-@dxo^YuqMIP1!vNfSLggEsKk~&1hr2m;m4sqE4hygEl&ZSk zKEOs3<(t=moUSIz-PeCiXT~iMzdY=rNwh6Ow}}lYH<12tMx;UGF-T zxGupO2UVYeJM?C42IEKp)OkZn2jTQ$*E8)5pRXUyFtb&9qYw{_eUz`!|QLeSvqv(cRkhX9=1!Lo+0qg2cc+hz-oft2;;gL^CekBuN7H00m@|UKS z44GJaxp7|5(5gu!5N%lh#`-W-38}^Ne3@$hu&0>;LHr5W%}evVT?uwxP;p!Aa@qPd zrfkJsV&SDb!O;Db!bac|#G|8y2g8yU&KYJo4pwQ=;*J^%w=oH->*?^uCdPJju}5Ra zE_EeFVjU$#xSzM$)MlZS%Sdn4gEW$T2Qyk;wG-e=B1FA`a`NRUSC=xMezG8OR5-SYOeCnK*Wyc8=HQow93|X{c z5ezVJ-{$pJB)>x3AKdqVI0TQ=Zsl!L6VL1Ag1a633qd_Y7ILe#hpA;+xor#6cFrpJE7K@0{93(K4m&)T-wX>pu%ifL<8wUVro z9j>{=f|9z{T%dsJ&GMKXZ>PO<_gO~FXab{h1O>O$J}260?=$adE~>Vr_l}6I#Vy_0JdzD4ZhB#*!W6ZQ?1SbqIzJXV>hxp~9v96O1Y<2% z$cG=8JPEL2&x+&oHy1VSv~7u#%KwbnO*QB@-!)AE&^ax75-i$x1D|TT{(Hrd3 zQShP*S87GTp1jH}-MyajVEeHYMa&@`3@d=YfwWc!FZZ#k7hALY;_BHomL(_PViY5k~fl{T1y|J2Dj&2{sP+0wHdNx9#dFM>Y`Nb6|0}OQv z_R*Zqr>3~~hM|Z9es3k!YE_6`hyVTFa%>oj#gi?I$Y>@u2Rx(ns{Z3rO~t;OiY?q}y1n{VvW>uub$ zAJCR5U-J55(O_xk+As6IkbtsBQj0Q196GpsgOvY;1%SsyyW`P()>%OeOMcm4o5nuO zkx2O6%1S`6B)9ZHrp+qlqb51MpCos7G`nzFD<2mALgI*L`zEa%387#400f!YRx{Oc zLam-6N2_aEhLd2>BKfMEB1uEM?ky~5@~Yr?`tU%UkHHAc3RgCKuMph4)eGTcA_=)K zByK|x9`ESE(ahH1!*g#1jI^5uLM7Me2&)(mQ4cU8n@6f(@nQV<|TL6ZbLaLx% zo53di5WSZJQG9U7(awYYrb|$Z7}4?;mRVQCHuMP$x!hnw&!-GkDIm6AbZEJ4jg%kd z@cvpmdQZlgZol=>gF?O)iq|3^E`V_;GZ2oauqGKyT9Q{hIIlDHpw+7laTLnGTEEy} z)p~JsF4sowyU7TJoGbSr3*zNKYn8oD9oPBN*)8l`g1uFq$zd28~jh9J@g`AgvtYEwcD zq^tub)0bvp6|4OMsD#fS1fwK7bK~QzNmUVku*1pcz>>+~VySu8eE7+wkH#5#% zwE1Iw1qOpsv+tFXWiVT~wbX|lJnr+j>0%p90~}3jBxR4SLZ`-9b=qbXBdTZ9+E658 z+pf?oiq712Lj1qLNJVwVGee<5zgj z*||=w_bSR#p^Y#3LrrgV9Lcuq5nl@Db=N`J9^U?&a`-)**H|U_#Vm4V!F;UvnEvHA zz%XrK32LY%zy9<(TZYCR7Wu%0{6-qm}=dW;M~^&mOHCtoAAp;^|n^1ssVk-QVZ zorbZsl2-arhc82rq@qWpawM2(zJ^ zVvG}2LG{)jFjMaHf24H~;bD6xsVPDC;K6kCgEZf-^$@&y0X!Hta&U!U#p8AJj5GaQ zv{;#IFCVDoqg;f<(}coC)-rdytFG4#FHAMu6GY9buRs1WgBE$6Pvjns#gsJN+dJnV zgnc0UQ&es|i`PwJD<+FWLsYNoR1Idz*Tj9As~97)!0Z)S8t`($w($ z>*)}ZN6<1}tRuU%j6u0^^!+WXX9`9nP=SvXozeIXh`jRp1cb$_WKGA1|lhfA4?mP z_wTizFq5T5%g^BomjTlHqFbwEwUM+ORhM(=H~`Z7MfE1(bIW_<|%lBHlM5<4P9! z<9KCTt`d`nXW*mqeQoD6@jSq4mpLHphdY-Omc*Z-CcbTCh;x-&kNL)I#Xm7K*xY+@ zvPVvEKdpi?fLXje3LA#q%Xp|yceh;&DO*nG9bt?MwSHsuK{$NIgS1 zKp76K=@2@ZnQV!bdSI^*nkQF!6~$VL+y%>pijJ94D&JgX$NDr`d5CEU2Qh|NXz+qg zrex#}d*AA_3)a?!1PBi8sJT?P3dJrDsL9yHO&98&N6TQzyT}nLdG0=fh>SpM>${BR z!%2fSyXbWV>n$w*p$NAi89w3zpJ?PS;?_^BrfUOXS@x*cKBec$OPw(2zJlC0T^lK) zyZ*(DPLo#5Ftpn#DBX4|tW<(=0wcXg_(fLLqL|$Ts85QGYAKxJtU?jE1pe^g(MPx^ zir=6wux>Yf2r&qX*?hxDSm%xNHUABCyL$> z1i2?8GL`ZAhew~ziw6Rcn9f%NsIRg1;7VflP*DXZ&EsTuvaf1M@u9P`OT0y9P>OrZ zERFo|ogqg1n@)}pU2=W8Z%f#oZ>K*jaTz<{r?BM)Z%CuU^yx;IFuZXG_w5$r(6w6ck$~Bcsc6E)`($lp; z^Z@5BQ@S8uDD~ZK=0IgAZmvW&OPOOeetcJa>!;Uu?DisSqc2A8&{5&~Ucx=)ln;Vi z}UC&^{&3cjVIY8R(G#ED6uIFu# zG)d<>m^~kyEg7I}y8`QX!)TFP7`UZ+!m%$cHxj5&%J@;yffLJZ16yK#L0aTxrNAdq z5pQA9yWU^i*1{a`NdbqUGpG%sR+y@E6okOvO8W)DxO}59`ZS7}h&H1^J+&94wVKlq zwq2nD&t*Hz2RI*(A4Tqw(z@|uk-eTq8CG0H(1?M2dSi^7;t#oB7uohQdQ*+{B?6-W zesib|#P~T48iq&ThXE+9q|Ae_a;GOJ@?--8gi!Y6&o!2JYDwCAzdjwbwRmxt6oWzz zhjccni_^jmuSfTzbQy&_mCi9L|Ndf{5eysE$yC#sc@21Kuq#Fy@oO}A z`MSLaFeEP<(jc1?tJ^C3@2AWxLwW|7Ks_@uTZQ%qn;v^Lo@C%Px$F%MnV)=3WCXQUuwsd_fc)Hxox7v1Z!2yxU5mbOsx2@a*J+jODUlJz}XBvAEO z+gr=w!N>h0!cVUC@F^gN8j1MYXV#gD$XL;ozjK-~Kq}^Ym4&%hb2VBkwKm8p5!ThX zKb!(pDrFq>dr7*K1aqcCu5xuInDj~yT9*Y;1Mh*Fa_lwZm8X1?!vUHSHn78Dw5WxI;1saUdVWbs!1VbK&mvPGIZv4xag% zq!nuK`1x`oR_id?j&0G~<~{PPjA~HJV@tL7tWu&W?ozD*CdxpVbFDye{0L(;J)Jl% zL2#R;@+{fzu^(2$Yv;;cPz_jL@_=nmEKGSlZ!kP3RS%!jk6~~tew3(L^z1$No`BEr zmls){M+=_cEGBWOv*!oOy{(ugqZ-l$#Ze-{gSWf65^O29sKjkzv!^SgQY}{-(gXA- zm}8lc#*;aZ4T$iZ+wpqyDgMDu>?;(MXyzEghpG?&ev z%}cYpUyrY-W-J-FI5{zq__Vy1LEeqym_2EB6bLui&6?_s01}$leQXy2H*{ z)<1h1;w{gJ+bh*AZ@I;2ZLtU%SAdjCkK2*AvB9r@t8G~Zp&fm~A>3b36ffEw)5Go|a zjW%b;D+G$x5$xbgBTrus z=?yW(5$)dmo07;JLPWHYwvR?B@6K5Tlfpn|A;D9LEqT6aC~lpKV~aoZg7|$`<9e3R zXWlHo;j7U6H@TV-*F0VFs6vg&iJ%w`(sFkLt0UtXCuBt>V-7h9E~( z9~X32Z)jLV9A~tI@KsX5cHm`=lkZ=RX*o^%jk~VkW7*Hg1=GfL6@RVna?SgMeN1~| zn{wcIbSrlN%R{9bQ3_2Aaf7$M<5a-iQ_x<)m~&}*=^{*%R$&i>Q%deW;QAQ177xMq zP8&ofCA|R!S(9`Xd|gs~JfV0BZzr52uN4j7$9ab{+CJ7$E~IGGcfx!zt`wqb!&*~p z%CLea&vEM+CkF%=2}LlbU~&9sybR&$Kq+$D`&iJ=F^-q)c*JK{-QO_Fy$c+qMZ}n^ z7=Na*nq4yT0ErN-_hxm_0G1CYJd-ym*(Km#owSVm;nhXkEK_`_4 znR~Jq?_^t*>YW1v)ZwV9?)}%6gB%C$Py^k5dtqd&dwHn6xY9i$2>79^)7T^an0OG` zbWi;J4Fi>$*=h-B27Ffb;Ie%M8}eztADt9g zc)fTo*|dHYufI$M+sFln>PO>Jq+c=^KE#)6GyP0Lhe%$>vk9 zo9fpg)Ni)~nR^MJsb)Oqt%H}5Ko60JV^VkhX(55EZv_}@UACGU z-==P~Z+$%-=C{RMJv;}>)yY9vZdlJKgUxrD#zDB45qzNCC(K&V6j9&H#G zdLX)OtMh?V&OkEU&B=mL<3P}@c3!BUfzkon`*CEpxU~}21)A`OK#%8V9Lh!tgFIW0 z2FVM_g4GX!;gycGw)g&n^p| z4^!(#4X1^P=yjh`?mZ1JD46%iu$cxCLy$;}Xb9F_c9skD7n3y>_V#v5_@L$2Da~{_ zvdPcgpq>jihrTcRp9Jwfa=hym6Ok(IL!z70!MLr#cC?F}u!XEdLGm|_12i@oYaP+8I(%L9(x;f!zIXXomeFY*5qs}6BBMkF}q4yaj-ngGAn9S z4|ECBR|z}j`|kojN&w>TAvJ{tco}=*MJ6U#`aVVpJ~6tz8S2y0o|mAa+tmU$ZvM8_ zD8;t6-Icr5z7V-|i>)5P6gPA!XOu|y!qnJ1|65a_`3P30q+ta_M!Ivqwb8V zGnJTC;LQAO#dHItsXG_D-Nh94wm+)tf0=IoX(xI3Bb3pDDgYC!IKr4er~;rHPW7UN z%-*#P`QaS=?aTk+M{nT=@M06(R*#KPHMRfQ>OcJU_Y-p?GbkjRF4p-62K|jtzy1+M zfSBjDqg2=5_wZLs{{6$Ifa2Ef45dHS$=`|he?LB)hbkA(-d>P;_JN|R^6$(1lB^pz zrUg}l%765`bi-1pa-cN}kY`0(P5zI_^ZyvT%CIQ6t}P)9MF$_;0R)i}=>|!qTRH>=>5}dox`t-pdpPl)^PcY&{lhgEPwl<-+Iz3P*1GR?^D^gz z<~GmO4gYf@z>(+xRocwk=_$|n+|*whuvQ=yj{EgI@h>$7?A>s*Gf%lQ&afE~8SzWn zwNbdW)_0=p1bd8SN=kap2*Gs-p$Vw=aQBb>_Eoow&q6>AU+-ub@nSsWim7N zs0OV;#~!KCNW0I=+D;O=A;0j^JJ9aSL%X{E=C7p4$fQJHV!S%6-hThJc|mrWY^00< z5s>Hv{~1NOdLR*;sCjvL7!dbSp(6gPZ~arV`4t-gFo)C<$}ipRhI^Tb%0E|eIDumh zIKh8DJyQ12H8eE(8@j2N@PjX>ISsyI&vdYpT`hW*jIO9H#YHKQHq7?8ssGhQR=CfhVoj-a^hwn(cgbs$t-JAj2<{awLvh!=c+@ zVY{XO!CqIKi!6_r?w^+bU)$IJpGbhcbVu71a5N^Nc-K{gLRc*A#@Y~lSr{JGD4!$; zX+$|2GeSdThXwb|s?0(k4Xl1$l0m~fVS9xc`4@`sM~xS)r)}_RjDk3}2-y^2$Daea zMgyVNZtW@7xZ7oI2k0`aGp_TMbnX(rpc&BVZyp$+8ho$Q;q2jiCG@z_qI>8rQ^0)e z=@9yfo-_<9cn$jixx}3Uoo}aY=UX#y6X#qxW!+qiLEAMu6MS5eHXKz3}ZJK$bDZ%9bW z-_?Ma?~0bEBTi=M;+#xzfbAI!OmDigA{X=fERA%kr?(#(J~1D+J3IQ$qMSLJm3(ib zxaq9O?8DX`l?x4vz@dWa4xj&JZhJ`0StDZQ2y3P7X0(Fl`AX(vt^6@#q{F!nTRNe& zi=dNy$1S6?>}(&wxf#}&c~bje^LeSP6^;(PRk7}L3=Kb< ze%+CIlQ@ZsctCo-HA`B@l_Ak%O=Tr)?zEIrEoWhSSAaTGWUEwTd}oo`JqaxBHn)G+ z&w^<&QhwVCmt^t$Q}#t7Tacxu&Z$8hlx1Z?YgleP2_k=+M^9e^k`z0zB;OrAb-q0? zcLGb#g4OA`%Xn`HN@OW!5%q}5a~z($nSRBz;jv_?L^%}_!SvI~cN>3ZKLrCq-nX)} z@1vpF-!(nO9_%(>Te@$`lT{&d^6(~`cQk{iWy`}aBM1KD$=$}UjOx_wp6q|4J$e}h z(*`q?5kng>VKs?r)Ww@0O?B}rLsK>atvzF`JWk3UO5pcOo|n#lUdg4+_Sh#ZSXlJe zfe7SrU*wv$uyrLw^Es8V^~CvvUwBw3;KUT``8A>q$n8POaXZlCJXHsG-Un{U4+|d4 zX*e8^^^2La#aTVbH(CkLm!S^L5$W2mtj>$%T~;y%kV@NIqph*d5S`^I z%%8c-&%1??6gn^A?O~AYbqsG=l8YvS`7-m5W3TL}O)F+i?U0q2z7stb&S8l;h8%mc zDb};1HmFi8CA-ShZEl>qnco^cP-L%eNElsr+)OlmZcFWV%Te9Bade>UG%wkwc>6Ph ze}08aRh91JUgv%9{YR%b%4)aTedf zb?pi-$fV>bRS1XAc2E3m<`pZ zZN)jX8#+|Lx}Q(6@Ez)}3wZg0_R$1zR2tE0?Q_{h)$XNh}^>NMGP zt7L^|JU4;+Xwvc1TY;q%V+(_Yod8YNKO_? zQi@X;kVlEr4jq{6t`d?2Z}EFt#8r@9ui4J!S}+gX56(BJHd^jT^C6?D8JD}EKyb7u z*i(-bt8zuG*|s})KFx}*t5?;qN{W4l|INBIuK))1T05H4XS2p@u(V{Pt$#D2nQ#jA z#2hPdn_Fx?2`|?W*3u4|dZVfidhY4o^=9B1gLatOR?XSjO1eJ%K8Kn}LNr$CR_&Ph ziU?a31Dnc_X-oEeSPxiRjr(k++qi#zdYl=F$b=1Ow#exHbgvLarNrL`00j7}ts6la zLi0(+w|QT}3hVS(JkxvfS@&-%gfwg15dg2yCDq;M}Tg_ui1x%8&UR zb7!*>*Mk@V6tzIQywX@CQ5(Jqa0Lrcd&ZGM&-U`v6xP@tO2;|rn&U)Rox|d9W0V4Z z&?$pRy_JIN1tnYV!j`J&t)HYL*}EPUjlkZ8HFU`p23xPH-@V+QG%OBMS30q$o|oNUUK*bm2MY!$CD9^NV zJkbD@>F1he;@1H1+fnR{V`p!U7>DV*>7&-uz(}?V7AXs9+(`z0t3No0x$dmaO;$fb zlN)#i(@L0P%=F*1a;+yN>wG)K<*Y8Gwc92ieyiT*=`u;+;cP2>C}Sy(18GvSICfB( z3DP*g#3>&b9ZArl0tX6;2a8)!g>JD(gqLTYJ}9Q=FE`9_Z2U z#WCmze5=}R%4>PVPPv!Br4XLvzUH%=d1hsp`3A=|J7(!NpI+c1VOnivh4K06c|lo& z1z${Ucfp0Kf^n@3MgIY^*?cRrEYO*pOSR(Xh7t5N2mpt0MO5h}7fFhKc>0NkMC9xl zEh)bxzL#LV3-zW$i*s95eP#YiSdne#f(KXd4pB?BN$k*ZMMba~(>s3Lc%zetr7qU& zbn38MC?ljTRfnH%lwZ$h8#kYv1Ggk!*CYGxF0qq8D;?-e;JH>)-CwsnotULFWqQn( zRSyOSmx6b+C&#YYk7HdR4Gtsy7rnNWxi6U81oPXTjFf>8QE2rFdf-*cj@fl|P~B4Jb@53cH!cRF`c36fAY)4Gfh(|GS#HTMA-kE*PPIBWeslN(xB0JS?7t6x zW*`M-47S@xdC-29KwP4&cazyMn}=;3)SX#h_TCg7yO-%3np?k@V5?*kI-A5_+0idG zZKErwNz@3OSva}T70U`nWC+GZUE|nIHfPgNSUDRlZ9TmOV4QntgYc#diz@d{t;mWx zKAX|yI_4SZin?iWAzz?0-BHCug zJ)HDg&fm1x7HIvjZ^vMi;mA}_e|f4gYpk~D$aM?ql>e72?h2`hmY{3IP4*%0g*GVX zdkS)>a;n^-L+6d%J&cwV4WBVlC%rECbp{&l0b)K#XD8a3jh;*nIdA`9ndN%Wh1(Bo z1xnIZUmnL9oS5#OjJ`9C#MQLkDV4=<#&P`wIuPD(bwA$I6s?7aSA zDNb*!^e91M;A=t6KzaTYu6O6FQ`=#|57Rpx?hvv!9*2R}nbv3VTD9|1BwH<#{B9&R z$0Hi8%v>kjzI|WN0*!{az9T{b^d)Y-$9-<)UGPOrMgN>Vwxy=@owFH7k`5GGsRJvm znyeUe&!a`>{^*eU^bHAD62T*V&E9C#7~(VNN5NlMp1bf!pERePAm8fv3DNmrfQ2>C)r6s*eGe8fhY)8>dFCLL3Ekq1&iFkZ4B35FS z3ZmNS!5qum>L&86G%eE+8{F2%%khLNI&{ud zrBBb#T_$`V?pE^j(~wL@v*x?v+D)Y%p@m^t`8HmU`<UJ{Ci-)=ZxkZA*7t@|% zxZMiCKqH?f1wKC?WhHrTf2UEi{WARCzh2U#T~g*&%Ah!f^{&@so)Oa!E4$zKvjsvWalY=FDm})Q5Jgp2hjJ;F9jPQ;` z{f8_AWIW`EMbZOsHtEV3wRhdCEoZh`5pYEehJf$Wj?lUjr2#RW5CMnUmff~Zz$0mk z^9Mi0|95-+;~d&MHfA<63=>72l$^*@Z*8` zbB#EmMtS{U^Kk2E!?R+NX;T)}cuEtAGymD1tNpOYSy-hkaQvt5pzjU22A$5osc510 z3x|T=UpEs-t2^V&`3+YWG9{i#KFA+?*Yyi}90OjDrl4mR^-9uD4G9%G0G>8!qlQ&? zQ^%&<>OPQp+e?9x#N$)fRbVD8{50h~ooAXECy))rej&ucV(B7{3oPC$f4x3!KG zd-F0f?gESp_W`iFg(uD7OT(jLx1iobCJx3PFuMF2ZBng2mSg0 z*^Q{6^-X6RpPxMncuoKq8o6~v;}R}dTrwE&)kjDgfYrK(j+I2I~EYVXi&t?X5%@JouU z@&Sl5Wzk#q{F+BD9t!~d10Lha&cV4~(g=m806I16zLoN?;qp(hfW>ACcz@{k|ETYO zp9B8&RRz93Jl$g0UXNkNl2=Fpt!5v^=lLe}xSn&g>&Vdi| ztg$1}Re}JOpy{xdvm#J-1w4KZuw9#K*fd@r0HCvp!(afAxdLF|WRwMW9-ja_fCHC= zcQ0P*y(#UNV=ALmIW?I0V!P5Uu+_O(4`5+U0fd(lK+y6^cq=OzqTxz;Nfj68G-f*R zJ6qlPVSN@*s0RGOzHt+<0RdwgAO$zb-vc1Pu>gl(C8Edk-2THx5j#LnlmXE9a3m+Y z4Yq5T=S4;V;5!F^7$$?mpmm|^5={&c`kz<$?fL0oao#Sped#f1Rn`D+`OE(b-Jj@0Ku{w(9Z#2SAG9G zm7to5b%(gSCm@szMeb4h0tmpdVy~$-Xw@z*VXnv*cbW{FvwLJj{@h3hx9Rn08 zN^EsU`dOjwD;d%KK#VFbR1@G^1I&|$Rr&eFCzrPJC6|~wjN0Klb4e#bpdvW=FLW*v z561;4b3n-N1pHM-*nebe5vm5z)Vs9{RGt8#ex;{x(gIaCkmnq^JbylE3!~gPAQN=4 z(ezATjWu=FE%FwgQB~85OwIsmG>9MpCP76^Di_^qt(DVl&!jds9i%V=1tkouNJs!AaE*=-;f+)k)39NtlU6R7N1Uu2M9v)f(@T&~y%JeOujnJ<#> z3lC10!*njETuK<3_7E>TG_kKtY9ZES9``6>savysYpFUtA>Y1Shw#;fsVwgzSJqv7 z0})zgr#gu&#&(CE0P@>jhyCPfxMmUzm}x4QC?4)d=Qtu~+vPW!oYIvQFCYN+_46Q& zZLiMxZnOncF3^Ue2c8B1-fhg>6lkKAW~fyqKt)($ZJFpeBwGe6-GKiY%NM0)@VeQn z!MhZ)a$^{pw)q#h7TPo{VnNMpap3zqyjCTu8;kNr&;d}afd%scUE8}7qOTrl!QAaq zw0^Y7dSCq(k+xQIy?5Ws%s7>Fad$}Ztby9}dH3QuF#s#or@iQ=#43Pdmj^P;q=l*G zNf=NYn|MWr#b;bIV_&x~+D=|lO|qH;z;aphf?B7z|6psKSDz~9*PW~)0IJapfJ1!2 z0ASmybvRy(&N^OB79k&09Y!Ic5?n>W<<|$KpfPTm{U^2-Uk;4*(w<@sL~Aq23$<;x z2C7)Nx{Mnh_5HlJv)# zLGLNv5JozM^mMS*Cxi!qFbEJ9r8jF;i4P>R29gHq0M1R%E+r@LEI6k3o6@XxX;gv} zBFslh*AN_*%(AcGj$_UV1nA*FZHbok$MpcYr`?@cOM0=VYzh06Sh6qHLs?cZ_=<%SsFYezQL z@Q#MS6jtxLC91G(DX-Zq5u~ZpYIuZ{K1q+d>UOl~b?|$a?xTARo#3U>?73dJw+o~j z;5H})u+xSNNTX=2s5$^_TRNWDz}Dk>Ji)w&-CNJ7qbc1ZS>2>X1K34!sPME)j)T#V z)WjhAR|Fx2K9Ixe=?t>hF*M^er6`M!=~zLD60{sxY{3p7%iHB-RgcE>#vVsLXjyhG4nWPQ=sKS?mzNM6?tt5YQYJnEa#NZ$?u2Eg#QCYG1U z8@I{;{{GjeVdeXPK6b6;U}U7^-~cJz2{i#1Z0M&8y%M;JBbb-iSnV#piV^)li^J5k zLK>53nYL$t?&ex|ML)2)1wsUzq@8bIWi^+G_eTF0W;fxRVK^lK+O_PK3Ub1hPiS8x zf4uZi%2+5Mg|1PQ9yPXzEs@YSOx{65|6)Y@R1t=0%!s2XwMZKzht(L?waZ$)-v9b} z|EDIrdrXu7U>C2jh3~eK2mdoc1zxsnmBE}oM;oPtVRVaGpS08=y!7?r)IhP&MqU7T zA=|!8&D5=y&m?9Nv?JAYe>z(PR-$0z6;%IPn(=AYF5edhUOBvWcYu(83pV0x0LTIhmbgpI$WMVp*_q*cbL_?Tz+CP4Cc5sg5`U7qwh8Pr3E4#7 zqz8$Nc~8)c8JBS|n+iOUYq`s|+V(8Gq&97wge|z9M_(y?>5BrKguLIvALS>mr6V&H zqf-Jq1FzTmEB zOz7T4CA4H~%AO}GO1`O((r|Qs)4goECeHo929C8}zS4n98eOYXnP(^8lp!C+_49qW zKX8YY7s_F(m3=L9Oidb0JBaIr(t{)kl;CR#>ISOF>1aPC^}5|^mYiOr&$V$xus5K0eSps9eYp?)Ughqyw_m1M$~_nu-+l5&$ww?1o@} z4B)QbFg*X$I7gtOvec&Ffa`uk7q`7Xbel6MriJfSNV@^4etM)xnV*?6O5;cqeg}vY z`-?`SZdQp3PGK=_T272xRhX^?ry21w9|ld6D+q&!j<;gg%OF0inpY~v7rcTu#E-}c znRV+3I@Y>7A;KTd>kyB>>T4U?NG{HP%^*$z7xI1^``-|2Iv!xmPnbV&q{p=4fEmJG<*kXKRJ5aYWL5fMiCpGnG zy!$MngBjouT_z<%iUAt95XBfTX$&Xl7$l+Y>@|6l0yXc3t=$~G?ydXYIJDO&yVb`$ zg%fbavIwp{X0W*#^h}(s_rM+-ONW>3i&M9I<|oKlK=HYf$si6NfI ztCP0&5l2g}#g^9#U&`rePqDChvkwxm9p?mhZ%XruK@wU(i?h8r=j`4n{I@Vt$8FD5 zjPsLEz0Vh81Lw0bQJ^*v$-u_!I_>eHpIVz5`t`n4fU4~s)8HyQT+sOkb_}&7RfmT? z>Y#z{**nX}2Bp-ek#9~C?YsF#M}4gdYRh-)&Vf_)2`kE2zFj{X9lN?eyQO`pI;~@QjS!?;2o4)f?5#M6jp^Q8UlM311 zQ2?(AaB7N?a2TkLL=E~(&*Dil;31@LujrPmUe2Clpv+h#fODoUEt{nXomq!vO7`Z# zVZDu|v%$OzX#7VKg^x~9*56r4lB8CDA%Xk5HQ5gO7(Q|!Eq};OH;k?sB_U%mSC=LY z=XrV$d8?bKimFyjon~E`fP$ckx2}khk7Q9#UP|Xd2#aT$d?il4|L(l&;>(j)2_#yI zuCI8+kwq)VQr2mw;sqs?+I>2@m*Bk@ zTV-V%Vi93=rP4JA`OKv{i=%k5g2BFb3Br5tVlOpj&KwTc9h6z<^yPyA@>G*OBA~F# zH&>?{1SW;ky$pW?y=+Ewc_xTB&FBUq=ipBwd}28=*vHuiN%K^Qi^teMxQmm1d#q)H z&femn&R*9(Ao)ShpM&g@F2HEnkr~Dl+t2&y8+Mk8Z%M>DPmnowa|k+&adh5c#-`j( zyLhFYl0Os6fDDbqpB3uUHnN%RQGUr#n~*LzLQC?vr4m4>!Al6xca$VB-FX{|#FC9sf%~@*n)~wGCpahtyI5crOj; z382c@#;6d0TEg9lVkn0zL_S0>!aQ$q+>bC;VXf`pk|k-%i8M{p^SDE2$-?#p=j{h$ z- zuVNk94-o5N(p0fMfpu^A`r%b0LqsnqU~gW0KD>5~bz1hZ*mI_j;sJ_zC~tU8+7%}>FEP?jMUz2I04a)%E13xm?K@Z0Cy@Dqk6>fy^a z$#C43Y?FgVy{_7`Zs)qM`cV&X6u!2@=SaWH&qOWzpkD{jgF*?%phLz4c|o6v_!v{) z4TUZ_8=o*#P>;&-*zWHzVQ|tlOT$j8#+Kd!X_0;i{@~panA4c!*nMvw8g$4ZU}Pm6 zjmr2JvTfX>^Omgwz|jz~oUI~P)Tv$D&2>#{4-^K-i_1YaG52s=?@@Dabma60_e4r!?zao(Daq{$NRGG%xLtm zE=}1?_l-w<75eB2?UKKPPWeoLAi6kPV9_2)ukJ{Xa0HPWIP0f zwj>)fS6uCx2!aHRon-XIZ>ni%aa0TxXS0PhaR=S}|AB)?6wpm-Taqr=rd{uO3Q~EEL9huXZM+CpJo2kB_3clyuu*6-B7K3Oz` zPrmBbUt8%&4fmEva6b0qde|L+;@3#BW@|VX(fq~GP{Hsfmp+Cbd5BB?P3ec!{8qeo zLFfZd#{d^e+ELXsX^A1G!7WaLSfe9dkEol!?$cWke7JXMrK6?23xu5mu(@r6}w%_A$@H}*r z@!mj%?|~_Fq{rkytn4yr6HyE~V4KUM;1=UCn&)ks) z$$Z4UJgQ3CZ2IFFHbWcs@!>6fp;WJ_Gl_0MZ(=R@@2tuO z0L_z?YhWOBh|`BAHZ z_$!r|Nd@Ryzp&rn08NCnrnqiMxj#A?fhmZV2LK!6SdED}n89({^M*G$p9SjPv7~jB zI?7C3IsdZ8n!X&_5$5uAFAM0imcykU!g#oqM}Ye1~@DZ>R% z4(N+}qteFl5Y+ts{4I7P`9Z&(1GOjOVbueO;92+ z_A7oyQecxk>fM3g6ywKMnY!_|BsQK(Jc^u>BBA^eeLQlr@rwXF#b=kcl?LZUW=eCa zG6R-RXs!jng<*puy+c1QMwTNe$VMpwt=^%osjc~KdJ_6@{LM3|(JqJqXx;@2gOZXY zv10`Hzre>1R%v^re}j+vEDj)*%)gTY$2>!~A)VX45rAJ_8W@Cav;aa8i0X@HNU#xy zP~T~kbNF^ivf-0s>)|mxE_K?LwVoSNPUuhP=A-@~8<*MvG;mkHO(h!eMAC&e-_5@5 zC$#(({}ebK2nh)Gfq6-K_Xo)mAHR>W@2A?cVni^Hw+X`nywJQj+e~o9E@oX`YmV~C zA#I;o0NicigU|!&7ZwaJm5?%25^8ogZCI7l-a=mcVRdWbBs2w!GQl2QdiFkA3?c=$V-}kN zwW?saQNx^SoWmVeDO{X-$JYsactRkkBW2=~$G-0!p5TxU=zL_m)wns*1F&)EuF`o~ ziZw8&PbBr_hsOY69s}Gr@3(K4U=-$u;iM{x>pXV<=FG=SvZxBS$EFkOqv^|xTvHd0 zatig;a^Pt?j{OvXes@e(N?1*nzM8hk zupwTkPe-o}u3NXiy>qXg40^+!0Mbhs#BN0oM|8_gjE98ee9u`#&QtlH>uU<(z-0*z zWF~008#%!sbb*KY0#SQ@bGS&aVwO&D5W4>e2{&LD_10tQe(e=8=B60KcDT90CEG-A z`Jv6X056`AAj~Wv6<1cDrU)}Nxht2Xv-xr1m#|(|z3B~rvv3rng*b)PHfhW-OUiN! zUgPu3K~TeNgc{IRiRfavV|nXQNl#Qk5_AeULV~?B4I( z9%mJ#?dd*Lp>7vzYlW#3U^v&@2(aW`wl(>B%a|v2fEUacxifDTYFU~Z40MRllf^luUh{$BOvzE<~F|2=|;1^zF>yiZuSm|Ja?_;|JEDc#`L z9EgWSMZMf+*~Q>Kg$gr~cE`a_a2>c$GW#4IBZ-Xqjo%8R9474bv3;JycckBbw@n#f zH+Wqdj4o<}$3dH-P3==hGE9cVgusw@1A=prpf9@=5pRqLia{~H&u!lt2Y;HH>DUkB zZ8&iw_-2E?O!i5O3Z)bK&Z3u6?YtJiY^^|v4m#^+?N>^j2K^?riyQE@^RbwK_oR4} zT&IHQHj5OM>I$9%7MDOvwN}wa;o--G*No443b9P>U6Ep?$%Da8f#$jz9li4&1AdzT zE9q#y#Kkk~*Rc&&%xnCs(9Iw+g4-)IpPgbj+a2{P!wRY0D4a@15%Mww;?|1!y%jUs zv?Gv_7`PpR=U_a7;H7P%p65`Kz`8=+iuLS`ln@HoUQ@|4rge#W3;^KIlk^6!U6*gu zJm|nk07+8*rdDy95g^vVVY7TGbDsb{jh+uUs0As7Rpz*ua5p&X`vU2Ei-W9E^F9g% zaK9-JFi?N}&L|`RmrH9~qvCT4+hCu0O{Uku+g-BW{=T3$WzKfVkaX6@%XTN_$Fxlh=_jK2Pcc@L#~Y$eaeiVCRKvXOrf zV-WI5VDectW%Up-s02QVQ8+aopy03HL{doFPSh=^LOHil)l7defYdpSPh(JG3H`6r0hZut3X=y z(qW5Tk3M4B^oKVpX)4=ETN4DEbH-x0tGJMR7v@+ge0v8aeqnIk_>9eARgHMj8SXW|DFF z^YL-J%K(zn<-STApSv~U@B()5nB%ZkG+`DfWrr0dHge zg{GzIC!d_L+1G2{IJ|jq@|1X!tfE74lBl(z$Y}&-HYTe5CgC?ZxX`+=FoLZeOGJxL zSsK>MCVH3_KIeQ)idqmBblua!a^3bs^p!+y*eu)-6@mEVqK(yLgWW?^MW~syM+1MA zq~bddN1LJc!h-Ft`C)ka^_Eh@ zLiQ@USN%#7x*Zlhjh9^vdJ~QRos>HjZ(;3jI@POgvt{{fpWRb7Avv3FCDl{a(;sJ` z`LwH;587y`bQeBocH2l?lMwf&5q+I`h-7-6#TA>Dl|>iXxdon1ul_uh-#ykauf(X^wk$(N@ku#u)z(_O!pxWz1`7<9Pq(i6DoGN}f_yCdo)8i`Ij zG!$M!>6he{DJRqg4iI@VCsAb;4XSFXqjPaZ_CMO&30@}Mx$*c+k8t$CPU=kSlcqc8 zDS6QxefqoWxQF<6I*dJ1s5~FSsB7_U-ilPEJ;vh|wg}11 zDsBc7Yv+9}YAG)a5()Y0nND!1icT{pVgBYC3aTo}+Z2-;;#SO$hK z)v||vXo161yN{~0s@t^5K40v_QNoze3iD0_r_ttkcL?|A%BmA_@6UnhLrAF8aa2V( zrRUEuG+WQ-d40ws>c=Bc)`o;}oVA~3spM?G#dXI#G@uXtA~Gi&uy^}RKqWy1!4-s= zY`<37yvP1FrESJO7~Fi^>_1&}aiqm|!aH`ZpZt}t+1<%d9p-p@V%cO^V{U?O1`qZe zgcmb{ihn<7IJB`qC6%CnafhE{=rH?5-|nN5&OwVw?x^J*qsX=+3T2&EyPB|7oI`%W zXYoUp8L~0XdyW9#D;@i7>XYa#h8?O~^`6bjua>h3#WqDG1E#6xz8L9fgpwiO)~lsG zuAc+*tcEy&=fRIwn@?ZyN{#RG7S+F`Zk#y+D#^<~?_-tAaV`yRaPdGf&t{V+x_Ks% zB97|MJW?cH+ZSndqxsbK42iD;S}kpMH>$zd1bCBM%+0b+`$7PzqjN)`M-vZ(F_}E2 zHxI~Kj4c;QybY%56qyLe>D1}vI8JgKtew&7-{gAU^A$a#p^U8xnj=nRfyg;7%OZ%?2}WdXCHh>LdO?Wb}n;T9Q@ZEUe^FDso93AO5orB z`Ny~ZBOdh6_wjU|6CLHvMfNfL-Il+v|0PGDH;lc*!wlQwnUQAy>+sOFzwvm6g_EsoML=7214fH? zs2RH>5aqOb#e!%N2P_WNHd;nnPAGk>t;{oZT`nSxQ!xbnBK&LGH}B z%k?tqP_I*KLAS9Ve}elal$5dDd4M-Ec%J#S#ZbKPepBthp7SKD0o(r%!3* zk(JiEAAd&VXr8~%T=uexD5zcaLL^c=7hY~XeYa@7rImy;Vf%XQ@S7%aN8dpM!RNX+LX8R@R}Qdo*IrgH>5zHWy(s zEeeqFB%GZ1s8H;E&tg^>xVN8KA!M$N^N>1<*yE%VF|bA)>OxgiVp>VP1yC32}TB$^7y;cP3TU-H@kfc_!L;zxP7Cnnc!-Qh z2g;Ua)H#RNxic)CuFeipb(Vw~ub4(X4cRDpw$6rHkLFqjx3{hmq4ZqXT+!*S%T(_n z{PA2yL8ZeQv|Cr6ai&jYwK`q%aqdQGNkX(+vnU|>*hv@3qbFYg)|^Ku0}on#5oFd9 z7du|v%^rtB+I4YioCIZlk7QDZ8TWj77Ip$)!)(SoPO@G>+)sAplfy#JlJ`_X1c=3Y z>@*FjJP#yK)18sq&MWR}Q|h^OJeX1iZH*m!)3%2E4x2-g>|b(qgsqB>(`ju^PPSe} zw4ZCcjrAiU60Qq+E+OV7+V{UE!a5Ge>e_HZuxE$2DhBwW)4bh@9n?xB6XofGhE<%0 zD@nN2@dr~@feB$}qV~uqIQTXjJq+$k>?jj%EYcABN<^iJn)i`m<2S@AbEvv)pB?kO7#?LO+_=br)@J&2BpnLt*o``CFz5_?QZhmbS z*jQbwUxAjLdDSen_WSesVV-nM`^>_twnp8D&={&xZjHO+)pU63InyVT8(k^ZmBVao zHGGur{nr=ucfK5_Yj8~1qic60J3er*ou%VrC;Q4-Z+cO=w&A!X_}muVR=L(pv9}_3 zyEhGNdeM`}W!THJn(N}=_zrvF!fmH+W!qIVtIK^&G6nHQ2f1H}vSBy9I8T1)X?F7Z z;AE4?In%&iSMY@6S%6+X9kDyO8{MiRqI}T+VV`cd*>#w8y~H@3vOK0ryR0oe#A3EE zVD~#kL$EpdUCyfH>JDyK&`KHjRF}%`w75DdBYC>!9$j^I%!T^#OPwn4Xgk7NkmAc# zGDx9Bkr1j#8_eJrSe^}_+t!Q5O?dBGXdX%}pcB z-+$9dJ(kOdF6}U4SePqu=hS^@6nQqWT)pS<#mH%mYFv;JynEf9XDuP#Cn~vqCUeQ| zn0{4+t*7Jk{3~(#z?6**hsE9-K7m7~8ze;bzeVr+xhDwNYw+K}l|X(d(0Q4#C&WZ0 z8-_wLT4)r&Jk!P-!fC&{Pzp<6$e35Ee#oM^|5Dwk83w>Ax5J`yRTwy9aZl!4*K*AP z#E!5(X^3k#qN|@0S9qf8Qw%wu-y7DBN3Jnz_mhuHz|RcbVP!&#J8PcXN+s`f4`_5w zT&cR`uxK(?Nb#Noeo0 z7LRSR7GT8`CyRUI-9aqlLCYL|9KuXJlH_0cFAl9q9yt?%A*(M2`hx_mZ48T9yHQ3s z1NT`lJ1sHtJ$IKR_B>k5y$i#>pLPfiZ#%jw%~e1y`Vr*=tW177kbPl+bnArc(LeH8k1 zmsilGKCc6}U{je(_{?WWHBFd}%e#P_HpivM!_r#4%B~jd0ng1DsMxa^qwa#9tLz@v zb0%K|6bRmFVIL`rF%-Z>q5LXrJ)~*g9Zj((AcEYfj2RwJy=uQf$H2l~aEarCV5VAR zx0vs~Dw1BFg@lUit^Pn4Cq2(lZOzeugw3S#OnqjrH*(HO@^Egl}SDDP7w2zpE< zAm-OL8H-KnL@5?0d#3K5lQgtvuxcfd>VeDvB$as;8 z-}&GzblT$!!p}GtYgcN?Ji_GkP4s%azSR`xz(KxXgadkahus<)Q(&d70o5$&Yd49A z=#Bjd{iy{&cWeS?6Dkslop@K3ms0k>@qxf#VgC;M3z6{UQ=vT;|4hn?IE_Jp`7Zxk z)iL~^coaV$rU#xc!4ZfH!RnVhLYQOoXIB_%D5x91#mrY|eX<=oMX*`Pa6GreeoAo{ zHGyMcYuR3u%R4RaZn0OE@}|}@18N|7ar2XA&x>%T0so{D_dWIsHg{g|eDOG7W2FB^T*x=E_2P+epIRP~ZP=W#YIl0D*M|LGLTk^o<9M;$*z1!e(_ucY z{<6b7lYH`3S@hWX2@$u=tw27ALDF=ac-=Z+AZ6%ae$%;Db=??d%y+ajS%htVj3s$M) zzV!~V5SrL`7Jx*~tX9X1O^=9S-+-u2C11T7L8U@?+K()yKi_b)dbRt+ZG*915h!;G zS@AVUPNMpT(yxK@;Cx;=Uv7)nQYD#L+rjF6wQci1@stQZX!7}`p0mQI)w z^+Q~{r!*IY_bwb3tQPe-l6REt{kE76+@8L}p3T`ysD~xGncAPqC_5zy327yAHD9?X zZTyDlOcZdQbQo~bJP%mg-`~%W3>@kf8PEGFjSx6M0$7x+(GufO(~3MxV~9r=du`gr zonn#Yp13Hg4ro_f_T)=B!~Rx}dX8HNIxy1GQDCV#_|8&VC8Sfc`cw3cDaYq-o;VRY z4zM`A8iqyYjkYPRv)<2$na|%X6VK0HU7WghFC&GWoo+{f>aVb#ks_IT3VE_3ZM=%n=+G6Pe~#9h!U>>yC@7@n;E zxRGLA>OQS^<6Y-wpLg9Nhv1J7Dj>YK^kPt*Llh`0))_Z0CNj-@OEzp}Ts9zmQhrNg zh{CKY9Bd--kJHef7^1(y^SM>QZryF3{sp7m+Wf zJiBft{rId2Qs6~_PP1z5g6b$aoL@vAyyiid0?wI=z0M8{kAD1dLP^oqE#3kL^l3MD z_kr=lIF>c%gs8X*2E5Ta+xiwT!_jzBti}%yAW%gu(HZ9iHC|L}4)t9Wfo?e+VGAX< z&6-%$hWUrzJxrjWqgEu*q56ci?KIXIj-?UHzXbfZPfM2;>(;l=ge$();C!QA;LHnP zzB(KbNqhYhjDh_h_=HUNSEX#fkSc4^uv0;Ih2tN7V(3Z|;_FHlDflwo9yD!t>JpOr zAC8ZM_Kg!E1}q(~`T4s=1cib$4No z0YIovW1U!;sf`~0Sn~XYct;zZmWeO&8mB>Rim{v-BdkZ&IN@(>K@liZE*3~K80(|E ze|PiW>N4UBcyp>9I5g4hwZ<|g@kn2!)J*&3>7xBmP+kqb_<(Ci8MR)kX2RQ6tGSfv zD)R?bFZ;#mFD)!S5rSQhe!us(r|Rl}-bGos|Z4oN=h zNWuI`8(%d%=}8`j2(>a*yCAAtfbcAGBZg(70-;z9X7)8@0^L zL4xgSxrn9^Ub>9uD+qZlufFriT|k1WRku&BvQYqq=J@RoH+fp@>eX_|jsP5<8La-@ zKVA=ibNtgA+YYu>sO2BGu`iQz8rf#gzt~H)5}pXATfD(8@1lRc;JeC_wvT? z_(1HUyR7$0j|4i%f%(bWmkhtF`+En_LFlyHD~!Z{sr$bk6E#K^5)xWE+6Yp*dMyGy zmlkcccFccs)m{cjFoh2IZpg^Pp9F{;fweQop5>>qBmUhLz7_NR;ZOSU2L1Q2#hZNp z{Huo;XrP3Ub8{yCPsW!9m~w_^FXo@Yf1(NegxTNCQ0o)>OeL?LbY>uIY;0iO{mLtW zNoQ=OadiL&h&t@MX|-A#<@<&Fq|Xvi4gZaYbXTsI*Py@s5p>FHaO}N)<;Dc);2#0Q zqNJbbVYU|#F#PQmy4Kah*WiNw`%<`b%}oAkAu?#B^qHhzVDi$xCoGh))&IXS0D-5g KpUXO@geCx9V=49k diff --git a/getting-started/images/zipkin.png b/getting-started/images/zipkin.png deleted file mode 100644 index 77e23745b49cdc418b7211a3932ea866cafa4e7e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36304 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

- -### Trace Your NodeJS Application - -([link to JavaScript version](../README.md#trace-your-nodejs-application)) - -This guide uses the example application provided in the [example directory](example) but the steps to instrument your own application should be broadly the same. Here is an overview of what we will be doing. - -1. Install the required OpenTelemetry libraries -2. Initialize a global tracer -3. Initialize and register a trace exporter - -#### Install the required OpenTelemetry libraries - -([link to JavaScript version](../README.md#install-the-required-opentelemetry-libraries)) - -To create traces on NodeJS, you will need `@opentelemetry/sdk-trace-node`, `@opentelemetry/api`, and any plugins required by your application such as gRPC, or HTTP. If you are using the example application, you will need to install `@opentelemetry/instrumentation-http` and `@opentelemetry/instrumentation-express`. - -```sh -$ npm install \ - @opentelemetry/api \ - @opentelemetry/sdk-trace-node \ - @opentelemetry/instrumentation \ - @opentelemetry/instrumentation-http \ - @opentelemetry/instrumentation-express \ - @@opentelemetry/resources \ - @opentelemetry/semantic-conventions -``` - -#### Initialize a global tracer - -([link to JavaScript version](../README.md#initialize-a-global-tracer)) - -All tracing initialization should happen before your application’s code runs. The easiest way to do this is to initialize tracing in a separate file that is required using node’s `-r` option before application code runs. - -Create a file named `tracing.ts` and add the following code: - -```typescript -import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; -import { registerInstrumentations } from '@opentelemetry/instrumentation'; -import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; -import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; - - -const provider: NodeTracerProvider = new NodeTracerProvider(); - -diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); - -provider.register(); - -registerInstrumentations({ - instrumentations: [ - new ExpressInstrumentation(), - new HttpInstrumentation(), - ], -}); - -``` - -If you run your application now with `ts-node -r ./tracing.ts app.ts`, your application will create and propagate traces over HTTP. If an already instrumented service that supports [Trace Context](https://www.w3.org/TR/trace-context/) headers calls your application using HTTP, and you call another application using HTTP, the Trace Context headers will be correctly propagated. - -If you wish to see a completed trace, however, there is one more step. You must register an exporter to send traces to a tracing backend. - -#### Initialize and Register a Trace Exporter - -([link to JavaScript version](../README.md#initialize-and-register-a-trace-exporter)) - -This guide uses the Zipkin tracing backend, but if you are using another backend like [Jaeger](https://www.jaegertracing.io), this is where you would make your change. - -To export traces, we will need a few more dependencies. Install them with the following command: - -```sh -$ npm install \ - @opentelemetry/sdk-trace-base \ - @opentelemetry/exporter-zipkin - -$ # for jaeger you would run this command: -$ # npm install @opentelemetry/exporter-jaeger -``` - -After these dependencies are installed, we will need to initialize and register them. Modify `tracing.ts` so that it matches the following code snippet, replacing the service name `"getting-started"` with your own service name if you wish. - -```typescript -import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; -import { registerInstrumentations } from '@opentelemetry/instrumentation'; -import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; -import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -import { Resource } from '@opentelemetry/resources' -import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' -import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; -import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; -// For Jaeger, use the following line instead: -// import { JaegerExporter } from '@opentelemetry/exporter-jaeger'; - -const provider: NodeTracerProvider = new NodeTracerProvider({ - resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'getting-started', - }), -}); - -diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); - -provider.addSpanProcessor( - new SimpleSpanProcessor( - new ZipkinExporter({ - // For Jaeger, use the following line instead: - // new JaegerExporter({ - // If you are running your tracing backend on another host, - // you can point to it using the `url` parameter of the - // exporter config. - }), - ), -); -provider.register(); - -registerInstrumentations({ - instrumentations: [ - new ExpressInstrumentation(), - new HttpInstrumentation(), - ], -}); - -console.log('tracing initialized'); -``` - -Now if you run your application with the `tracing.ts` file loaded, and you send requests to your application over HTTP (in the sample application just browse to you will see traces exported to your tracing backend that look like this: - -```sh -ts-node -r ./tracing.ts app.ts -``` - -

- -**Note:** Some spans appear to be duplicated, but they are not. This is because the sample application is both the client and the server for these requests. You see one span that is the client side request timing, and one span that is the server side request timing. Anywhere they don’t overlap is network time. - -## Collect Metrics Using OpenTelemetry - -([link to JavaScript version](../README.md#collect-metrics-using-opentelemetry)) - -This guide assumes you are going to be using Prometheus as your metrics backend. It is currently the only metrics backend supported by OpenTelemetry JS. - -**Note**: This section is a work in progress - -### Set up a Metrics Backend - -([link to JavaScript version](../README.md#set-up-a-metrics-backend)) - -Now that we have end-to-end traces, we will collect and export some basic metrics. - -Currently, the only supported metrics backend is [Prometheus](https://prometheus.io). Head to the [Prometheus download page](https://prometheus.io/download/) and download the latest release of Prometheus for your operating system. - -Open a command line and `cd` into the directory where you downloaded the Prometheus tarball. Untar it and change into the newly created directory. - -```sh -$ cd Downloads - -$ # Replace the file name below with your downloaded tarball -$ tar xvfz prometheus-2.20.1.darwin-amd64.tar - -$ # Replace the dir below with your created directory -$ cd prometheus-2.20.1.darwin-amd64 - -$ ls -LICENSE console_libraries data prometheus.yml tsdb -NOTICE consoles prometheus promtool -``` - -The created directory should have a file named `prometheus.yml`. This is the file used to configure Prometheus. For now, just make sure Prometheus starts by running the `./prometheus` binary in the folder and browse to . - -```sh -$ ./prometheus -# some output elided for brevity -msg="Starting Prometheus" version="(version=2.14.0, branch=HEAD, revision=edeb7a44cbf745f1d8be4ea6f215e79e651bfe19)" -# some output elided for brevity -level=info ts=2019-11-21T20:39:40.262Z caller=web.go:496 component=web msg="Start listening for connections" address=0.0.0.0:9090 -# some output elided for brevity -level=info ts=2019-11-21T20:39:40.383Z caller=main.go:626 msg="Server is ready to receive web requests." -``` - -

- -Once we know prometheus starts, replace the contents of `prometheus.yml` with the following: - -```yaml -# my global config -global: - scrape_interval: 15s # Set the scrape interval to every 15 seconds. - -scrape_configs: - - job_name: 'opentelemetry' - # metrics_path defaults to '/metrics' - # scheme defaults to 'http'. - static_configs: - - targets: ['localhost:9464'] -``` - -### Monitor Your NodeJS Application - -([link to JavaScript version](../README.md#monitor-your-nodejs-application)) - -An example application which can be used with this guide can be found at in the [example directory](example). You can see what it looks like with metric monitoring enabled in the [monitored-example directory](monitored-example). - -1. Install the required OpenTelemetry metrics libraries -2. Initialize a meter and collect metrics -3. Initialize and register a metrics exporter - -#### Install the required OpenTelemetry metrics libraries - -([link to JavaScript version](../README.md#install-the-required-opentelemetry-sdk-metrics-base-libraries)) - -To create metrics on NodeJS, you will need `@opentelemetry/sdk-metrics-base`. - -```sh -npm install @opentelemetry/sdk-metrics-base -``` - -#### Initialize a meter and collect metrics - -([link to JavaScript version](../README.md#initialize-a-meter-and-collect-metrics)) - -In order to create and monitor metrics, we will need a `Meter`. In OpenTelemetry, a `Meter` is the mechanism used to create and manage metrics, labels, and metric exporters. - -Create a file named `monitoring.ts` and add the following code: - -```typescript -import { MeterProvider } from '@opentelemetry/sdk-metrics-base'; - -const meter = new MeterProvider().getMeter('your-meter-name'); -``` - -Now, you can require this file from your application code and use the `Meter` to create and manage metrics. The simplest of these metrics is a counter. Let's create and export from our `monitoring.ts` file a middleware function that express can use to count all requests by route. Modify the `monitoring.ts` file so that it looks like this: - -```typescript -import { MeterProvider } from '@opentelemetry/sdk-metrics-base'; -import { Request, Response, NextFunction } from 'express'; - -const meter = new MeterProvider().getMeter('your-meter-name'); - -const requestCount = meter.createCounter('requests', { - description: 'Count all incoming requests', -}); - -const handles = new Map(); - -export const countAllRequests = () => { - return (req: Request, _res: Response, next: NextFunction) => { - if (!handles.has(req.path)) { - const labels = { route: req.path }; - const handle = requestCount.bind(labels); - handles.set(req.path, handle); - } - - handles.get(req.path).add(1); - next(); - }; -}; -``` - -Now let's import and use this middleware in our application code: - -```typescript -import { countAllRequests } from './monitoring'; -const app = express(); -app.use(countAllRequests()); -``` - -Now, when we make requests to our service our meter will count all requests. - -**Note**: Creating a new `labelSet` and `handle` on every request is not ideal as creating the `labelSet` can often be an expensive operation. This is why handles are created and stored in a `Map` according to the route key. - -#### Initialize and register a metrics exporter - -([link to JavaScript version](../README.md#initialize-and-register-a-metrics-exporter)) - -Counting metrics is only useful if we can export them somewhere that we can see them. For this, we're going to use prometheus. Creating and registering a metrics exporter is much like the tracing exporter above. First we will need to install the prometheus exporter. - -```sh -npm install @opentelemetry/exporter-prometheus -``` - -Next, modify your `monitoring.ts` file to look like this: - -```typescript -import { Request, Response, NextFunction } from 'express'; -import { MeterProvider } from '@opentelemetry/sdk-metrics-base'; -import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'; - -const prometheusPort = PrometheusExporter.DEFAULT_OPTIONS.port; -const prometheusEndpoint = PrometheusExporter.DEFAULT_OPTIONS.endpoint; - -const exporter = new PrometheusExporter( - { - startServer: true, - }, - () => { - console.log( - `prometheus scrape endpoint: http://localhost:${prometheusPort}${prometheusEndpoint}`, - ); - }, -); - -const meter = new MeterProvider({ - exporter, - interval: 1000, -}).getMeter('your-meter-name'); - -const requestCount = meter.createCounter('requests', { - description: 'Count all incoming requests', -}); - -const handles = new Map(); - -export const countAllRequests = () => { - return (req: Request, _res: Response, next: NextFunction) => { - if (!handles.has(req.path)) { - const labels = { route: req.path }; - const handle = requestCount.bind(labels); - handles.set(req.path, handle); - } - - handles.get(req.path).add(1); - next(); - }; -}; -``` - -Ensure prometheus is running by running the `prometheus` binary from earlier and start your application. - -```sh -$ ts-node app.ts -prometheus scrape endpoint: http://localhost:9464/metrics -Listening for requests on http://localhost:8080 -``` - -Now, each time you browse to you should see "Hello from the backend" in your browser and your metrics in prometheus should update. You can verify the current metrics by browsing to , which should look like this: - -```sh -# HELP requests Count all incoming requests -# TYPE requests counter -requests{route="/"} 1 -requests{route="/middle-tier"} 2 -requests{route="/backend"} 4 -``` - -You should also be able to see gathered metrics in your prometheus web UI. - -

diff --git a/getting-started/ts-example/example/app.ts b/getting-started/ts-example/example/app.ts deleted file mode 100644 index a252668ebef..00000000000 --- a/getting-started/ts-example/example/app.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as express from 'express'; -import axios from 'axios'; - -const PORT: string = process.env.PORT || '8080'; - -const app = express(); - -app.get('/', (req, res) => { - axios - .get(`http://localhost:${PORT}/middle-tier`) - .then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) - .then((response) => { - res.send(response.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/middle-tier', (req, res) => { - axios - .get(`http://localhost:${PORT}/backend`) - .then(() => axios.get(`http://localhost:${PORT}/backend`)) - .then((response) => { - res.send(response.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/backend', (req, res) => { - res.send('Hello from the backend'); -}); - -app.listen(parseInt(PORT, 10), () => { - console.log(`Listening for requests on http://localhost:${PORT}`); -}); diff --git a/getting-started/ts-example/example/package.json b/getting-started/ts-example/example/package.json deleted file mode 100644 index 08ab0b4634b..00000000000 --- a/getting-started/ts-example/example/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "@opentelemetry/getting-started-ts-example", - "version": "0.25.0", - "description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", - "main": "app.ts", - "scripts": { - "start": "ts-node app.ts" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "devDependencies": { - "@types/express": "4.17.13", - "@types/node": "14.17.11", - "ts-node": "10.2.1" - }, - "dependencies": { - "axios": "^0.21.0", - "express": "^4.17.1" - } -} diff --git a/getting-started/ts-example/monitored-example/app.ts b/getting-started/ts-example/monitored-example/app.ts deleted file mode 100644 index 9307eba1ac2..00000000000 --- a/getting-started/ts-example/monitored-example/app.ts +++ /dev/null @@ -1,42 +0,0 @@ -import * as express from 'express'; -import axios from 'axios'; - -import { countAllRequests } from './monitoring'; - -const PORT: string = process.env.PORT || '8080'; -const app = express(); -app.use(countAllRequests()); - -app.get('/', (req, res) => { - axios - .get(`http://localhost:${PORT}/middle-tier`) - .then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/middle-tier', (req, res) => { - axios - .get(`http://localhost:${PORT}/backend`) - .then(() => axios.get(`http://localhost:${PORT}/backend`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/backend', (req, res) => { - res.send('Hello from the backend'); -}); - -app.listen(parseInt(PORT, 10), () => { - console.log(`Listening for requests on http://localhost:${PORT}`); -}); diff --git a/getting-started/ts-example/monitored-example/monitoring.ts b/getting-started/ts-example/monitored-example/monitoring.ts deleted file mode 100644 index 5e933e4a937..00000000000 --- a/getting-started/ts-example/monitored-example/monitoring.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Request, Response, NextFunction } from 'express'; -import { MeterProvider } from '@opentelemetry/sdk-metrics-base'; -import { PrometheusExporter } from '@opentelemetry/exporter-prometheus'; - -const prometheusPort = PrometheusExporter.DEFAULT_OPTIONS.port; -const prometheusEndpoint = PrometheusExporter.DEFAULT_OPTIONS.endpoint; - -const exporter = new PrometheusExporter( - { - startServer: true, - }, - () => { - console.log( - `prometheus scrape endpoint: http://localhost:${prometheusPort}${prometheusEndpoint}`, - ); - }, -); - -const meter = new MeterProvider({ - exporter, - interval: 1000, -}).getMeter('your-meter-name'); - -const requestCount = meter.createCounter('requests', { - description: 'Count all incoming requests', -}); - -const handles = new Map(); - -export const countAllRequests = () => (req: Request, _res: Response, next: NextFunction): void => { - if (!handles.has(req.path)) { - const labels = { route: req.path }; - const handle = requestCount.bind(labels); - handles.set(req.path, handle); - } - - handles.get(req.path).add(1); - next(); -}; diff --git a/getting-started/ts-example/monitored-example/package.json b/getting-started/ts-example/monitored-example/package.json deleted file mode 100644 index 3e4138059ea..00000000000 --- a/getting-started/ts-example/monitored-example/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@opentelemetry/getting-started-monitored-ts-example", - "version": "0.25.0", - "description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", - "main": "app.ts", - "scripts": { - "start": "ts-node app.ts" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "devDependencies": { - "@types/express": "4.17.13", - "@types/node": "14.17.11", - "ts-node": "10.2.1" - }, - "dependencies": { - "@opentelemetry/exporter-prometheus": "0.25.0", - "@opentelemetry/sdk-metrics-base": "0.25.0", - "axios": "^0.21.0", - "express": "^4.17.1" - } -} diff --git a/getting-started/ts-example/traced-example/app.ts b/getting-started/ts-example/traced-example/app.ts deleted file mode 100644 index 58fb8ab5890..00000000000 --- a/getting-started/ts-example/traced-example/app.ts +++ /dev/null @@ -1,40 +0,0 @@ -import * as express from 'express'; -import axios from 'axios'; - -const PORT: string = process.env.PORT || '8080'; - -const app = express(); - -app.get('/', (req, res) => { - axios - .get(`http://localhost:${PORT}/middle-tier`) - .then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/middle-tier', (req, res) => { - axios - .get(`http://localhost:${PORT}/backend`) - .then(() => axios.get(`http://localhost:${PORT}/backend`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/backend', (req, res) => { - res.send('Hello from the backend'); -}); - -app.listen(parseInt(PORT, 10), () => { - console.log(`Listening for requests on http://localhost:${PORT}`); -}); diff --git a/getting-started/ts-example/traced-example/package.json b/getting-started/ts-example/traced-example/package.json deleted file mode 100644 index f157176404f..00000000000 --- a/getting-started/ts-example/traced-example/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "@opentelemetry/getting-started-traced-ts-example", - "version": "0.25.0", - "description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", - "main": "app.ts", - "scripts": { - "start": "ts-node app.ts" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "devDependencies": { - "@types/express": "4.17.13", - "@types/node": "14.17.11", - "ts-node": "10.2.1" - }, - "dependencies": { - "@opentelemetry/core": "1.0.0", - "@opentelemetry/exporter-zipkin": "1.0.0", - "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/instrumentation-express": "^0.24.0", - "@opentelemetry/sdk-trace-node": "1.0.0", - "@opentelemetry/instrumentation-http": "0.25.0", - "@opentelemetry/sdk-trace-base": "1.0.0", - "axios": "^0.21.0", - "express": "^4.17.1" - } -} diff --git a/getting-started/ts-example/traced-example/tracing.ts b/getting-started/ts-example/traced-example/tracing.ts deleted file mode 100644 index 8d4628a06e9..00000000000 --- a/getting-started/ts-example/traced-example/tracing.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api'; -import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; -import { registerInstrumentations } from '@opentelemetry/instrumentation'; -import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express'; -import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -import { Resource } from '@opentelemetry/resources' -import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions' -import { SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base'; -import { ZipkinExporter } from '@opentelemetry/exporter-zipkin'; -// For Jaeger, use the following line instead: -// import { JaegerExporter } from '@opentelemetry/exporter-jaeger'; - -const provider: NodeTracerProvider = new NodeTracerProvider({ - resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'getting-started', - }), -}); - -diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ALL); - -provider.addSpanProcessor( - new SimpleSpanProcessor( - new ZipkinExporter({ - // For Jaeger, use the following line instead: - // new JaegerExporter({ - // If you are running your tracing backend on another host, - // you can point to it using the `url` parameter of the - // exporter config. - }), - ), -); -provider.register(); - -registerInstrumentations({ - instrumentations: [ - new ExpressInstrumentation(), - new HttpInstrumentation(), - ], -}); - -console.log('tracing initialized'); \ No newline at end of file diff --git a/package.json b/package.json index 03f45c704f3..702e0cde245 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,6 @@ "lint:fix:changed": "lerna run --concurrency 1 --stream lint:fix --since HEAD --exclude-dependents", "lint:examples": "eslint --no-error-on-unmatched-pattern ./examples/**/*.js", "lint:examples:fix": "eslint --no-error-on-unmatched-pattern ./examples/**/*.js --fix", - "lint:getting-started": "eslint --no-error-on-unmatched-pattern ./getting-started/**/*.{js,ts}", - "lint:getting-started:fix": "eslint --no-error-on-unmatched-pattern ./getting-started/**/*.{js,ts} --fix", "lint:markdown": "./node_modules/.bin/markdownlint $(git ls-files '*.md') -i ./CHANGELOG.md", "lint:markdown:fix": "./node_modules/.bin/markdownlint $(git ls-files '*.md') -i ./CHANGELOG.md --fix", "reset": "lerna clean -y && rm -rf node_modules && npm i && npm run compile && npm run lint:fix", From c160ad8b2a6f88c25c3abbe449c998987964b999 Mon Sep 17 00:00:00 2001 From: Ivan Santos Date: Sun, 17 Oct 2021 11:25:28 -0500 Subject: [PATCH 27/29] chore: expand pull request template with action items (#2509) Co-authored-by: Rauno Viskus Co-authored-by: Bartlomiej Obecny Co-authored-by: Valentin Marchaud --- .github/PULL_REQUEST_TEMPLATE.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1d576cc70db..c15dc709efe 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,8 +15,29 @@ Before creating a pull request, please make sure: ## Which problem is this PR solving? -- +Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes # (issue) ## Short description of the changes -- +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +# How Has This Been Tested? + +Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration + +- [ ] Test A + +# Checklist: + +- [ ] Followed the style guidelines of this project +- [ ] Unit tests have been added +- [ ] Documentation has been updated From 3045eba229f031e1510785dbb9713f24daf17ed1 Mon Sep 17 00:00:00 2001 From: legendecas Date: Wed, 20 Oct 2021 20:56:36 +0800 Subject: [PATCH 28/29] chore: slim font size for section title in PR template (#2541) --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index c15dc709efe..554b4ebfee5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -30,13 +30,13 @@ Please delete options that are not relevant. - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update -# How Has This Been Tested? +## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Test A -# Checklist: +## Checklist: - [ ] Followed the style guidelines of this project - [ ] Unit tests have been added From 9df2132398955eb25fc74ea9ae467da990d3204f Mon Sep 17 00:00:00 2001 From: legendecas Date: Fri, 22 Oct 2021 02:05:10 +0800 Subject: [PATCH 29/29] fix(sdk-metrics-base): remove metric kind BATCH_OBSERVER (#2540) BATCH_OBSERVER is no longer a metric. --- .../packages/opentelemetry-sdk-metrics-base/src/export/types.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts index 33206ea9363..61b22f45132 100644 --- a/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts +++ b/experimental/packages/opentelemetry-sdk-metrics-base/src/export/types.ts @@ -31,7 +31,6 @@ export enum MetricKind { OBSERVABLE_COUNTER, OBSERVABLE_UP_DOWN_COUNTER, OBSERVABLE_GAUGE, - BATCH_OBSERVER, } export const MetricKindValues = Object.values(MetricKind);

v>zb@rTsa~fx6>%U9I@A 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 { - axios - .get(`http://localhost:${PORT}/middle-tier`) - .then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/middle-tier', (req, res) => { - axios - .get(`http://localhost:${PORT}/backend`) - .then(() => axios.get(`http://localhost:${PORT}/backend`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/backend', (req, res) => { - res.send('Hello from the backend'); -}); - -app.listen(parseInt(PORT, 10), () => { - console.log(`Listening for requests on http://localhost:${PORT}`); -}); diff --git a/getting-started/monitored-example/monitoring.js b/getting-started/monitored-example/monitoring.js deleted file mode 100644 index ca20e8d2fdd..00000000000 --- a/getting-started/monitored-example/monitoring.js +++ /dev/null @@ -1,40 +0,0 @@ -'use strict'; - -const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); -const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); - -const prometheusPort = PrometheusExporter.DEFAULT_OPTIONS.port; -const prometheusEndpoint = PrometheusExporter.DEFAULT_OPTIONS.endpoint; - -const exporter = new PrometheusExporter( - { - startServer: true, - }, - () => { - console.log( - `prometheus scrape endpoint: http://localhost:${prometheusPort}${prometheusEndpoint}`, - ); - }, -); - -const meter = new MeterProvider({ - exporter, - interval: 1000, -}).getMeter('your-meter-name'); - -const requestCount = meter.createCounter('requests', { - description: 'Count all incoming requests', -}); - -const boundInstruments = new Map(); - -module.exports.countAllRequests = () => (req, res, next) => { - if (!boundInstruments.has(req.path)) { - const labels = { route: req.path }; - const boundCounter = requestCount.bind(labels); - boundInstruments.set(req.path, boundCounter); - } - - boundInstruments.get(req.path).add(1); - next(); -}; diff --git a/getting-started/monitored-example/package.json b/getting-started/monitored-example/package.json deleted file mode 100644 index a8b6c3a66c4..00000000000 --- a/getting-started/monitored-example/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@opentelemetry/getting-started-monitored-example", - "version": "0.25.0", - "description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", - "main": "app.js", - "scripts": { - "start": "node app.js" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/exporter-prometheus": "0.25.0", - "@opentelemetry/sdk-metrics-base": "0.25.0", - "axios": "^0.21.0", - "express": "^4.17.1" - } -} diff --git a/getting-started/traced-example/app.js b/getting-started/traced-example/app.js deleted file mode 100644 index 287ab78cb3c..00000000000 --- a/getting-started/traced-example/app.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const PORT = process.env.PORT || '8080'; - -const express = require('express'); -const axios = require('axios'); - -const app = express(); - -app.get('/', (req, res) => { - axios - .get(`http://localhost:${PORT}/middle-tier`) - .then(() => axios.get(`http://localhost:${PORT}/middle-tier`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/middle-tier', (req, res) => { - axios - .get(`http://localhost:${PORT}/backend`) - .then(() => axios.get(`http://localhost:${PORT}/backend`)) - .then((result) => { - res.send(result.data); - }) - .catch((err) => { - console.error(err); - res.status(500).send(); - }); -}); - -app.get('/backend', (req, res) => { - res.send('Hello from the backend'); -}); - -app.listen(parseInt(PORT, 10), () => { - console.log(`Listening for requests on http://localhost:${PORT}`); -}); diff --git a/getting-started/traced-example/package.json b/getting-started/traced-example/package.json deleted file mode 100644 index 8268cd9ddc8..00000000000 --- a/getting-started/traced-example/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "@opentelemetry/getting-started-traced-example", - "version": "0.25.0", - "description": "This repository provides everything required to follow the OpenTelemetry Getting Started Guide", - "main": "app.js", - "scripts": { - "start": "node -r ./tracing.js app.js" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.0.0", - "@opentelemetry/exporter-zipkin": "1.0.0", - "@opentelemetry/instrumentation-express": "^0.24.0", - "@opentelemetry/instrumentation-http": "0.25.0", - "@opentelemetry/instrumentation": "0.25.0", - "@opentelemetry/sdk-trace-node": "1.0.0", - "@opentelemetry/sdk-trace-base": "1.0.0", - "axios": "^0.21.0", - "express": "^4.17.1" - } -} diff --git a/getting-started/traced-example/tracing.js b/getting-started/traced-example/tracing.js deleted file mode 100644 index ae6b88b015d..00000000000 --- a/getting-started/traced-example/tracing.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node'); -const { SimpleSpanProcessor } = require('@opentelemetry/sdk-trace-base'); -const { Resource } = require('@opentelemetry/resources'); -const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions'); -const { ZipkinExporter } = require('@opentelemetry/exporter-zipkin'); -const { registerInstrumentations } = require('@opentelemetry/instrumentation'); -const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express'); -const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http'); - -const provider = new NodeTracerProvider({ - resource: new Resource({ - [SemanticResourceAttributes.SERVICE_NAME]: 'getting-started', - }), -}); - -provider.addSpanProcessor( - new SimpleSpanProcessor( - new ZipkinExporter({ - // If you are running your tracing backend on another host, - // you can point to it using the `url` parameter of the - // exporter config. - }), - ), -); - -provider.register(); - -// load old default plugins -registerInstrumentations({ - instrumentations: [ - new ExpressInstrumentation(), - new HttpInstrumentation(), - ], -}); - -console.log('tracing initialized'); diff --git a/getting-started/ts-example/.eslintrc b/getting-started/ts-example/.eslintrc deleted file mode 100644 index 6564779085e..00000000000 --- a/getting-started/ts-example/.eslintrc +++ /dev/null @@ -1,16 +0,0 @@ -{ - "plugins": ["@typescript-eslint", "node"], - "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - "parser": "@typescript-eslint/parser", - "rules": { - "@typescript-eslint/no-var-requires": 0, - "import/prefer-default-export": "off", - "import/extensions": [ - "error", - "ignorePackages", - { - "": "never" - } - ] - } -} diff --git a/getting-started/ts-example/README.md b/getting-started/ts-example/README.md deleted file mode 100644 index a1ccd6a1cb6..00000000000 --- a/getting-started/ts-example/README.md +++ /dev/null @@ -1,389 +0,0 @@ -# Getting Started with OpenTelemetry JS (TypeScript) - -This TypeScript guide will walk you through the setup and configuration process for a tracing backend (in this case [Zipkin](https://zipkin.io), but [Jaeger](https://www.jaegertracing.io) would be simple to use as well), a metrics backend like [Prometheus](https://prometheus.io), and auto-instrumentation of NodeJS. [You can find the guide for JavaScript here](../README.md#getting-started-with-opentelemetry-js). - -- [Getting Started with OpenTelemetry JS (TypeScript)](#getting-started-with-opentelemetry-js-typescript) - - [Tracing Your Application with OpenTelemetry](#tracing-your-application-with-opentelemetry) - - [Setting up a Tracing Backend](#setting-up-a-tracing-backend) - - [Trace Your NodeJS Application](#trace-your-nodejs-application) - - [Install the required OpenTelemetry libraries](#install-the-required-opentelemetry-libraries) - - [Initialize a global tracer](#initialize-a-global-tracer) - - [Initialize and Register a Trace Exporter](#initialize-and-register-a-trace-exporter) - - [Collect Metrics Using OpenTelemetry](#collect-metrics-using-opentelemetry) - - [Set up a Metrics Backend](#set-up-a-metrics-backend) - - [Monitor Your NodeJS Application](#monitor-your-nodejs-application) - - [Install the required OpenTelemetry metrics libraries](#install-the-required-opentelemetry-sdk-metrics-base-libraries) - - [Initialize a meter and collect metrics](#initialize-a-meter-and-collect-metrics) - - [Initialize and register a metrics exporter](#initialize-and-register-a-metrics-exporter) - -## Tracing Your Application with OpenTelemetry - -([link to JavaScript version](../README.md#tracing-your-application-with-opentelemetry)) - -This guide assumes you are going to be using Zipkin as your tracing backend, but modifying it for Jaeger should be straightforward. - -An example application which can be used with this guide can be found in the [example directory](example). You can see what it looks like with tracing enabled in the [traced-example directory](traced-example). - -### Setting up a Tracing Backend - -([link to JavaScript version](../README.md#setting-up-a-tracing-backend)) - -The first thing we will need before we can start collecting traces is a tracing backend like Zipkin that we can export traces to. If you already have a supported tracing backend (Zipkin or Jaeger), you can skip this step. If not, you will need to run one. - -In order to set up Zipkin as quickly as possible, run the latest [Docker Zipkin](https://github.com/openzipkin/docker-zipkin) container, exposing port `9411`. If you can’t run Docker containers, you will need to download and run Zipkin by following the Zipkin [quickstart guide](https://zipkin.io/pages/quickstart.html). - -```sh -docker run --rm -d -p 9411:9411 --name zipkin openzipkin/zipkin -``` - -Browse to to ensure that you can see the Zipkin UI. - -