From 499a4313cce67fc2207a86a27d246bbfabe1c7d7 Mon Sep 17 00:00:00 2001 From: Matthew Wear Date: Tue, 22 Nov 2022 13:34:14 -0800 Subject: [PATCH] Prepare release for launcher v1.3 (#60) * update deps to latest * add metrics support * add a counter to the example * update readme with metrics options * update changelog for v1.3 release * lockdown types --- CHANGELOG.md | 8 +++ README.md | 21 ++++---- example/index.js | 15 +++--- package.json | 32 ++++++------ src/lightstep-opentelemetry-launcher-node.ts | 49 +++++++++++++++++-- src/types.ts | 7 +++ src/version.ts | 2 +- ...htstep-opentelemetry-launcher-node.test.ts | 46 ++++++++++++++++- 8 files changed, 143 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd18867..56ccaac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. ## Unreleased +## 1.3.0 +* OpenTelemetry dependencies have been upgraded to API v1.3.0, core v1.8.0, + with auto-instrumentations-node v0.35.0. +* Support for the recently GA'd metrics SDK has been added. This functionality + is opt-in and users will need to set `metricsEnabeld: true` in code, or via + the environment by setting `LS_METRICS_ENABLED=true`. Refer to the README + for all metrics related configuration options. + ## 1.2.0 * This release changes the default export format for launcher from OTLP/JSON to OTLP/proto (e.g. proto over HTTP). Aside from the change in export format, this diff --git a/README.md b/README.md index f00c17d..a91ce5c 100644 --- a/README.md +++ b/README.md @@ -45,15 +45,18 @@ OpenTelemetry API and some examples of its usage: ### Configuration Options -| Config Option | Env Variable | Required | Default | -| -------------- | -------------------------------- | -------- | --------------------------------------------- | -| serviceName | LS_SERVICE_NAME | y | - | -| serviceVersion | LS_SERVICE_VERSION | n | unknown | -| spanEndpoint | OTEL_EXPORTER_OTLP_SPAN_ENDPOINT | n | https://ingest.lightstep.com/traces/otlp/v0.9 | -| accessToken | LS_ACCESS_TOKEN | n | - | -| logLevel | OTEL_LOG_LEVEL | n | info | -| propagators | OTEL_PROPAGATORS | n | b3 | -| resource | OTEL_RESOURCE_ATTRIBUTES | n | - | +| Config Option | Env Variable | Required | Default | +| ---------------------- | ----------------------------------- | -------- | ---------------------------------------------- | +| serviceName | LS_SERVICE_NAME | y | - | +| serviceVersion | LS_SERVICE_VERSION | n | unknown | +| spanEndpoint | OTEL_EXPORTER_OTLP_TRACES_ENDPOINT | n | https://ingest.lightstep.com/traces/otlp/v0.9 | +| metricsEndpoint | OTEL_EXPORTER_OTLP_METRICS_ENDPOINT | n | https://ingest.lightstep.com/metrics/otlp/v0.9 | +| metricsReportingPeriod | OTEL_EXPORTER_OTLP_METRICS_PERIOD | n | 30000 | +| metricsEnabled | LS_METRICS_ENABLED | n | false | +| accessToken | LS_ACCESS_TOKEN | n | - | +| logLevel | OTEL_LOG_LEVEL | n | info | +| propagators | OTEL_PROPAGATORS | n | b3 | +| resource | OTEL_RESOURCE_ATTRIBUTES | n | - | #### Additional Options diff --git a/example/index.js b/example/index.js index d64146b..19ed903 100644 --- a/example/index.js +++ b/example/index.js @@ -7,21 +7,24 @@ const accessToken = 'YOUR ACCESS TOKEN'; const sdk = lightstep.configureOpenTelemetry({ accessToken, - serviceName: 'locl-ex', - metricInterval: 3000, + serviceName: 'launcher-node-ex', + metricsEnabled: true, // default is false + metricsReportingPeriod: 10000, // default is 30000 logLevel: DiagLogLevel.ALL, }); +const appName = 'launcher-node-example'; + sdk.start().then(() => { - const tracer = opentelemetry.trace.getTracer('locl-node-example'); + const tracer = opentelemetry.trace.getTracer(appName); + const meter = opentelemetry.metrics.getMeter(appName); + const counter = meter.createCounter('test-counter'); let count = 0; setInterval(() => { count++; const span = tracer.startSpan('test-span'); span.setAttribute('count', count); span.end(); - - // force to export traces - // tracer.getActiveSpanProcessor().forceFlush(); + counter.add(1); }, 10000); }, console.log); diff --git a/package.json b/package.json index 5b7fd71..9ce10f8 100644 --- a/package.json +++ b/package.json @@ -46,20 +46,20 @@ "access": "public" }, "dependencies": { - "@opentelemetry/api": "^1.2.0", - "@opentelemetry/api-metrics": "^0.33.0", - "@opentelemetry/auto-instrumentations-node": "~0.33.1", - "@opentelemetry/core": "~1.7.0", - "@opentelemetry/exporter-trace-otlp-proto": "~0.33.0", - "@opentelemetry/propagator-b3": "~1.7.0", - "@opentelemetry/resource-detector-aws": "~1.1.2", - "@opentelemetry/resource-detector-gcp": "~0.27.2", - "@opentelemetry/resources": "~1.7.0", - "@opentelemetry/sdk-metrics": "~0.33.0", - "@opentelemetry/sdk-node": "^0.33.0", - "@opentelemetry/sdk-trace-base": "~1.7.0", - "@opentelemetry/sdk-trace-node": "~1.7.0", - "@opentelemetry/semantic-conventions": "~1.7.0" + "@opentelemetry/api": "^1.3.0", + "@opentelemetry/auto-instrumentations-node": "~0.35.0", + "@opentelemetry/core": "~1.8.0", + "@opentelemetry/exporter-metrics-otlp-proto": "~0.34.0", + "@opentelemetry/exporter-trace-otlp-proto": "~0.34.0", + "@opentelemetry/propagator-b3": "~1.8.0", + "@opentelemetry/resource-detector-aws": "~1.2.1", + "@opentelemetry/resource-detector-gcp": "~0.27.4", + "@opentelemetry/resources": "~1.8.0", + "@opentelemetry/sdk-metrics": "~1.8.0", + "@opentelemetry/sdk-node": "^0.34.0", + "@opentelemetry/sdk-trace-base": "~1.8.0", + "@opentelemetry/sdk-trace-node": "~1.8.0", + "@opentelemetry/semantic-conventions": "~1.8.0" }, "devDependencies": { "@types/mocha": "9.1.1", @@ -79,6 +79,6 @@ "package-json": "^7.0.0", "sinon": "^14.0.0", "ts-mocha": "10.0.0", - "typescript": "^4.4.4" + "typescript": "4.4.4" } -} +} \ No newline at end of file diff --git a/src/lightstep-opentelemetry-launcher-node.ts b/src/lightstep-opentelemetry-launcher-node.ts index 321bcd2..1125113 100644 --- a/src/lightstep-opentelemetry-launcher-node.ts +++ b/src/lightstep-opentelemetry-launcher-node.ts @@ -14,6 +14,8 @@ import { B3InjectEncoding, B3Propagator } from '@opentelemetry/propagator-b3'; import { NodeSDK } from '@opentelemetry/sdk-node'; import * as types from './types'; import { VERSION } from './version'; +import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics'; +import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto'; import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { Resource, ResourceAttributes } from '@opentelemetry/resources'; @@ -45,6 +47,9 @@ const PROPAGATOR_LOOKUP_MAP: { /** Default values for LightstepNodeSDKConfiguration */ const LS_DEFAULTS: Partial = { spanEndpoint: 'https://ingest.lightstep.com/traces/otlp/v0.9', + metricsEndpoint: 'https://ingest.lightstep.com/metrics/otlp/v0.9', + metricsReportingPeriod: 30000, + metricsEnabled: false, propagators: PROPAGATION_FORMATS.B3, }; @@ -71,6 +76,7 @@ export function configureOpenTelemetry( configureBaseResource(config); configurePropagation(config); configureTraceExporter(config); + configureMetricExporter(config); configureInstrumentations(config); return new NodeSDK(config); @@ -134,12 +140,9 @@ function logConfig( lsConfig: Partial, mergedConfig: Partial ) { - diag.debug('Default config: ', defaults); diag.debug('Default config: ', defaults); diag.debug('Config from environment', envConfig); - diag.debug('Default config: ', defaults); diag.debug('Config from code: ', lsConfig); - diag.debug('Default config: ', defaults); diag.debug('Merged Config', mergedConfig); } @@ -153,8 +156,19 @@ function configFromEnvironment(): Partial { if (env.LS_ACCESS_TOKEN) envConfig.accessToken = env.LS_ACCESS_TOKEN; if (env.LS_SERVICE_NAME) envConfig.serviceName = env.LS_SERVICE_NAME; if (env.LS_SERVICE_VERSION) envConfig.serviceVersion = env.LS_SERVICE_VERSION; + // for backwards compatibility only, this has been renamed to `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` if (env.OTEL_EXPORTER_OTLP_SPAN_ENDPOINT) envConfig.spanEndpoint = env.OTEL_EXPORTER_OTLP_SPAN_ENDPOINT; + if (env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT) + envConfig.spanEndpoint = env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT; + if (env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT) + envConfig.metricsEndpoint = env.OTEL_EXPORTER_OTLP_METRICS_ENDPOINT; + if (env.OTEL_EXPORTER_OTLP_METRICS_PERIOD) + envConfig.metricsReportingPeriod = parseInt( + env.OTEL_EXPORTER_OTLP_METRICS_PERIOD + ); + if (env.LS_METRICS_ENABLED) + envConfig.metricsEnabled = env.LS_METRICS_ENABLED === 'true'; if (env.OTEL_PROPAGATORS) envConfig.propagators = env.OTEL_PROPAGATORS; return envConfig; } @@ -260,7 +274,7 @@ function configureInstrumentations( } /** - * Configures export as JSON over HTTP to the configured spanEndpoint + * Configures export as proto over HTTP to the configured spanEndpoint * @param config */ function configureTraceExporter( @@ -281,6 +295,33 @@ function configureTraceExporter( }); } +/** + * Configures export as proto over HTTP to the configured metricsEndpoint + * @param config + */ +function configureMetricExporter( + config: Partial +) { + if (!config.metricsEnabled || config.metricReader) { + return; + } + + const headers: { [key: string]: string } = {}; + if (config.accessToken) { + headers[ACCESS_TOKEN_HEADER] = config.accessToken; + } + + const metricExporter = new OTLPMetricExporter({ + url: config.metricsEndpoint, + headers, + }); + + config.metricReader = new PeriodicExportingMetricReader({ + exporter: metricExporter, + exportIntervalMillis: config.metricsReportingPeriod, + }); +} + /** * Instantiates a propagator based on a string name where the name appears in * as a key in the PROPAGATOR_LOOKUP_MAP. Current supported names are: b3, diff --git a/src/types.ts b/src/types.ts index 488c70e..cbebad7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,9 @@ export interface LightstepConfigType { serviceName?: string; serviceVersion?: string; spanEndpoint?: string; + metricsEndpoint?: string; + metricsReportingPeriod?: number; + metricsEnabled?: boolean; propagators?: string; logger?: DiagLogger; logLevel?: DiagLogLevel; @@ -21,6 +24,10 @@ export interface LightstepEnvType { LS_SERVICE_NAME?: string; LS_SERVICE_VERSION?: string; OTEL_EXPORTER_OTLP_SPAN_ENDPOINT?: string; + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT?: string; + OTEL_EXPORTER_OTLP_METRICS_ENDPOINT?: string; + OTEL_EXPORTER_OTLP_METRICS_PERIOD?: string; + LS_METRICS_ENABLED?: string; OTEL_PROPAGATORS?: string; } diff --git a/src/version.ts b/src/version.ts index bbfff31..932bbb7 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,2 +1,2 @@ // this is autogenerated file, see scripts/version-update.js -export const VERSION = '1.2.0'; +export const VERSION = '1.3.0'; diff --git a/test/lightstep-opentelemetry-launcher-node.test.ts b/test/lightstep-opentelemetry-launcher-node.test.ts index c2b40bb..1396636 100644 --- a/test/lightstep-opentelemetry-launcher-node.test.ts +++ b/test/lightstep-opentelemetry-launcher-node.test.ts @@ -1,4 +1,11 @@ -import { context, DiagLogLevel, propagation, trace } from '@opentelemetry/api'; +import { + context, + DiagLogLevel, + propagation, + trace, + metrics, + createNoopMeter, +} from '@opentelemetry/api'; import { CompositePropagator, W3CTraceContextPropagator, @@ -343,5 +350,42 @@ describe('Lightstep OpenTelemetry Launcher Node', () => { ); }); }); + + describe('metrics', () => { + const noopMeter = createNoopMeter(); + + it('is disabled by default', async () => { + const sdk = lightstep.configureOpenTelemetry(minimalConfig); + assert.ok(sdk instanceof NodeSDK); + + await sdk.start(); + + assert.strictEqual(metrics.getMeter('test'), noopMeter); + }); + + it('can be enabled by code', async () => { + const sdk = lightstep.configureOpenTelemetry({ + ...minimalConfig, + metricsEnabled: true, + }); + assert.ok(sdk instanceof NodeSDK); + + await sdk.start(); + + // a non-noop meter indicates the metrics sdk was configured + assert.notStrictEqual(metrics.getMeter('test'), noopMeter); + }); + + it('can be enabled by environment variable', async () => { + process.env.LS_METRICS_ENABLED = 'true'; + const sdk = lightstep.configureOpenTelemetry(minimalConfig); + assert.ok(sdk instanceof NodeSDK); + + await sdk.start(); + + // a non-noop meter indicates the metrics sdk was configured + assert.notStrictEqual(metrics.getMeter('test'), noopMeter); + }); + }); }); });