diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index b243275d08..b587d65c30 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -33,7 +33,7 @@ jobs: packages/*/package-lock.json experimental/packages/*/node_modules experimental/packages/*/package-lock.json - key: node-tests-${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('package.json', 'packages/*/package.json', 'experimental/packages/*/package.json') }}-04142022 + key: node-tests-${{ runner.os }}-${{ matrix.node_version }}-${{ hashFiles('package.json', 'packages/*/package.json', 'experimental/packages/*/package.json') }}-04292022 - name: Bootstrap run: | @@ -72,7 +72,7 @@ jobs: packages/*/package-lock.json experimental/packages/*/node_modules experimental/packages/*/package-lock.json - key: browser-tests-${{ runner.os }}-${{ hashFiles('package.json', 'packages/*/package.json', 'experimental/packages/*/package.json') }}-04142022 + key: browser-tests-${{ runner.os }}-${{ hashFiles('package.json', 'packages/*/package.json', 'experimental/packages/*/package.json') }}-04292022 - name: Bootstrap run: | @@ -112,7 +112,7 @@ jobs: packages/*/package-lock.json experimental/packages/*/node_modules experimental/packages/*/package-lock.json - key: webworker-tests-${{ runner.os }}-${{ hashFiles('package.json', 'packages/*/package.json', 'experimental/packages/*/package.json') }}-04142022 + key: webworker-tests-${{ runner.os }}-${{ hashFiles('package.json', 'packages/*/package.json', 'experimental/packages/*/package.json') }}-04292022 - name: Bootstrap run: | diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c6e27cc1..6c5dbd9bc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ All notable changes to this project will be documented in this file. * feat(ConsoleSpanExporter): export span links [#2917](https://github.com/open-telemetry/opentelemetry-js/pull/2917) @trentm * feat: warn when hooked module is already loaded [#2926](https://github.com/open-telemetry/opentelemetry-js/pull/2926) @nozik +* feat: implement OSDetector [#2927](https://github.com/open-telemetry/opentelemetry-js/pull/2927) @rauno56 +* feat: implement HostDetector [#2921](https://github.com/open-telemetry/opentelemetry-js/pull/2921) @rauno56 ### :bug: (Bug Fix) @@ -28,6 +30,7 @@ All notable changes to this project will be documented in this file. * fix: sanitize attributes inputs [#2881](https://github.com/open-telemetry/opentelemetry-js/pull/2881) @legendecas * fix: support earlier API versions [#2892](https://github.com/open-telemetry/opentelemetry-js/pull/2892) @dyladan * fix: support extract one digit '0' in jaeger traceFlag [#2905](https://github.com/open-telemetry/opentelemetry-js/issues/2905) @shmilyoo +* fix(resources): extend ResourceAttributes interface to comply with spec [#2924](https://github.com/open-telemetry/opentelemetry-js/pull/2924) @blumamir ### :books: (Refine Doc) diff --git a/examples/prometheus/images/prom-counter.png b/examples/prometheus/images/prom-counter.png deleted file mode 100644 index 8d05e0fe59..0000000000 Binary files a/examples/prometheus/images/prom-counter.png and /dev/null differ diff --git a/examples/prometheus/images/prom-updowncounter.png b/examples/prometheus/images/prom-updowncounter.png deleted file mode 100644 index 3caa89ba19..0000000000 Binary files a/examples/prometheus/images/prom-updowncounter.png and /dev/null differ diff --git a/examples/prometheus/index.js b/examples/prometheus/index.js deleted file mode 100644 index 8f638d66a1..0000000000 --- a/examples/prometheus/index.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); -const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); - -const { endpoint, port } = PrometheusExporter.DEFAULT_OPTIONS; - -const exporter = new PrometheusExporter({}, () => { - console.log( - `prometheus scrape endpoint: http://localhost:${port}${endpoint}`, - ); -}); - -const meter = new MeterProvider({ - exporter, - interval: 1000, -}).getMeter('example-prometheus'); - -const requestCounter = meter.createCounter('requests', { - description: 'Example of a Counter', -}); - -const upDownCounter = meter.createUpDownCounter('test_up_down_counter', { - description: 'Example of a UpDownCounter', -}); - -const labels = { pid: process.pid, environment: 'staging' }; - -setInterval(() => { - requestCounter.add(1, labels); - upDownCounter.add(Math.random() > 0.5 ? 1 : -1, labels); -}, 1000); diff --git a/experimental/examples/.eslintrc.js b/experimental/examples/.eslintrc.js new file mode 100644 index 0000000000..7927fa0c36 --- /dev/null +++ b/experimental/examples/.eslintrc.js @@ -0,0 +1,7 @@ +module.exports = { + "env": { + "mocha": true, + "node": true + }, + ...require('../../eslint.config.js') +} diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/README.md b/experimental/examples/README.md similarity index 100% rename from experimental/packages/opentelemetry-sdk-metrics-base/examples/README.md rename to experimental/examples/README.md diff --git a/examples/prometheus/README.md b/experimental/examples/prometheus/README.md similarity index 100% rename from examples/prometheus/README.md rename to experimental/examples/prometheus/README.md diff --git a/experimental/examples/prometheus/images/prom-counter.png b/experimental/examples/prometheus/images/prom-counter.png new file mode 100644 index 0000000000..2628066088 Binary files /dev/null and b/experimental/examples/prometheus/images/prom-counter.png differ diff --git a/experimental/examples/prometheus/images/prom-updowncounter.png b/experimental/examples/prometheus/images/prom-updowncounter.png new file mode 100644 index 0000000000..9f595b806c Binary files /dev/null and b/experimental/examples/prometheus/images/prom-updowncounter.png differ diff --git a/experimental/examples/prometheus/index.js b/experimental/examples/prometheus/index.js new file mode 100644 index 0000000000..17da9c3b00 --- /dev/null +++ b/experimental/examples/prometheus/index.js @@ -0,0 +1,38 @@ +'use strict'; + +const { DiagConsoleLogger, DiagLogLevel, diag } = require('@opentelemetry/api'); +const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); +const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); + +// Optional and only needed to see the internal diagnostic logging (during development) +diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); + +const { endpoint, port } = PrometheusExporter.DEFAULT_OPTIONS; + +const exporter = new PrometheusExporter({}, () => { + console.log( + `prometheus scrape endpoint: http://localhost:${port}${endpoint}`, + ); +}); + +// Creates MeterProvider and installs the exporter as a MetricReader +const meterProvider = new MeterProvider(); +meterProvider.addMetricReader(exporter); +const meter = meterProvider.getMeter('example-prometheus'); + +// Creates metric instruments +const requestCounter = meter.createCounter('requests', { + description: 'Example of a Counter', +}); + +const upDownCounter = meter.createUpDownCounter('test_up_down_counter', { + description: 'Example of a UpDownCounter', +}); + +const attributes = { pid: process.pid, environment: 'staging' }; + +// Record metrics +setInterval(() => { + requestCounter.add(1, attributes); + upDownCounter.add(Math.random() > 0.5 ? 1 : -1, attributes); +}, 1000); diff --git a/examples/prometheus/package.json b/experimental/examples/prometheus/package.json similarity index 73% rename from examples/prometheus/package.json rename to experimental/examples/prometheus/package.json index d6b75714e1..a3c5dbca51 100644 --- a/examples/prometheus/package.json +++ b/experimental/examples/prometheus/package.json @@ -1,6 +1,6 @@ { "name": "prometheus-example", - "version": "0.25.0", + "version": "0.28.0", "description": "Example of using @opentelemetry/sdk-metrics-base and @opentelemetry/exporter-prometheus", "main": "index.js", "scripts": { @@ -10,7 +10,7 @@ "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.0.2", - "@opentelemetry/exporter-prometheus": "0.25.0", - "@opentelemetry/sdk-metrics-base": "0.25.0" + "@opentelemetry/exporter-prometheus": "0.28.0", + "@opentelemetry/sdk-metrics-base": "0.28.0" } } diff --git a/examples/prometheus/prometheus.yml b/experimental/examples/prometheus/prometheus.yml similarity index 100% rename from examples/prometheus/prometheus.yml rename to experimental/examples/prometheus/prometheus.yml diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/.eslintrc.json b/experimental/packages/opentelemetry-sdk-metrics-base/examples/.eslintrc.json deleted file mode 100644 index 6000f93619..0000000000 --- a/experimental/packages/opentelemetry-sdk-metrics-base/examples/.eslintrc.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "env": { - "node": true - }, - "extends": "airbnb-base", - "parserOptions": { - "sourceType": "script" - }, - "rules": { - "strict": ["error", "global"], - "no-use-before-define": ["error", "nofunc"], - "no-console": "off", - "import/no-unresolved": "off", - "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }] - }, - "ignorePatterns": "**/*_pb.js" -} diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/README.md b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/README.md deleted file mode 100644 index 5578b239c3..0000000000 --- a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Overview - -OpenTelemetry metrics allow a user to collect data and export it to a metrics backend like Prometheus. - -This is a simple example that demonstrates basic metrics collection and exports those metrics to a Prometheus compatible endpoint. - -## Installation - -```sh -# from this directory -npm install -``` - -How to setup [Prometheus](https://prometheus.io/docs/prometheus/latest/getting_started/) please check -[Setup Prometheus](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-exporter-prometheus) - -## Run the Application - -- Run the example - -### Observer - -```sh -npm run start:observer -``` - -### Prometheus - -1. In prometheus search for "cpu_core_usage", "cpu_temp_per_app", "cpu_usage_per_app" - -### Links - -1. Prometheus Scrape Endpoint -2. Prometheus graph - -### Example - -![Screenshot of the running example](metrics/observer.png) -![Screenshot of the running example](metrics/observer_batch.png) -![Screenshot of the running example](metrics/observer_batch2.png) - -## Useful links - -- For more information on OpenTelemetry, visit: -- For more information on OpenTelemetry metrics, visit: - -## LICENSE - -Apache License 2.0 diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js deleted file mode 100644 index 87d0e3817c..0000000000 --- a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.js +++ /dev/null @@ -1,42 +0,0 @@ -'use strict'; - -const { MeterProvider } = require('@opentelemetry/sdk-metrics-base'); -const { DiagConsoleLogger, DiagLogLevel, diag } = require('@opentelemetry/api'); -const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); - -// Optional and only needed to see the internal diagnostic logging (during development) -diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG); - -const { endpoint, port } = PrometheusExporter.DEFAULT_OPTIONS; - -const exporter = new PrometheusExporter({}, () => { - console.log( - `prometheus scrape endpoint: http://localhost:${port}${endpoint}`, - ); -}); - -const meter = new MeterProvider({ - exporter, - interval: 2000, -}).getMeter('example-meter'); - -// async callback - for operation that needs to wait for value -meter.createObservableGauge('cpu_core_usage', { - description: 'Example of an async observable gauge with callback', -}, async (observableResult) => { - const value = await getAsyncValue(); - observableResult.observe(value, { core: '1' }); - observableResult.observe(value, { core: '2' }); -}); - -function getAsyncValue() { - return new Promise((resolve) => { - setTimeout(() => { - resolve(Math.random()); - }, 100); - }); -} - -setInterval(function () { - console.log("simulating an app being kept open") -}, 5000); diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.png b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.png deleted file mode 100644 index b8c3c48910..0000000000 Binary files a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer.png and /dev/null differ diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer_batch.png b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer_batch.png deleted file mode 100644 index 32b5f25fe2..0000000000 Binary files a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer_batch.png and /dev/null differ diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer_batch2.png b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer_batch2.png deleted file mode 100644 index a8792e913a..0000000000 Binary files a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/metrics/observer_batch2.png and /dev/null differ diff --git a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/package.json b/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/package.json deleted file mode 100644 index eb518107c5..0000000000 --- a/experimental/packages/opentelemetry-sdk-metrics-base/examples/metrics/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "example-metrics", - "private": true, - "version": "0.27.0", - "description": "Example of using @opentelemetry/sdk-metrics-base", - "main": "index.js", - "scripts": { - "start:observer": "node metrics/observer.js" - }, - "repository": { - "type": "git", - "url": "git+ssh://git@github.com/open-telemetry/opentelemetry-js.git" - }, - "keywords": [ - "opentelemetry", - "http", - "tracing", - "metrics" - ], - "engines": { - "node": ">=8" - }, - "author": "OpenTelemetry Authors", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/open-telemetry/opentelemetry-js/issues" - }, - "dependencies": { - "@opentelemetry/api": "^1.0.0", - "@opentelemetry/core": "^1.1.1", - "@opentelemetry/exporter-prometheus": "^0.27.0", - "@opentelemetry/sdk-metrics-base": "^0.27.0" - }, - "homepage": "https://github.com/open-telemetry/opentelemetry-js#readme" -} diff --git a/packages/opentelemetry-resources/src/detectors/HostDetector.ts b/packages/opentelemetry-resources/src/detectors/HostDetector.ts new file mode 100644 index 0000000000..a14c80c5e1 --- /dev/null +++ b/packages/opentelemetry-resources/src/detectors/HostDetector.ts @@ -0,0 +1,52 @@ +/* + * Copyright The 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 { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { Resource } from '../Resource'; +import { Detector, ResourceAttributes } from '../types'; +import { ResourceDetectionConfig } from '../config'; +import { arch, hostname } from 'os'; + +/** + * HostDetector detects the resources related to the host current process is + * running on. Currently only non-cloud-based attributes are included. + */ +class HostDetector implements Detector { + async detect(_config?: ResourceDetectionConfig): Promise { + const attributes: ResourceAttributes = { + [SemanticResourceAttributes.HOST_NAME]: hostname(), + [SemanticResourceAttributes.HOST_ARCH]: this._normalizeArch(arch()), + }; + return new Resource(attributes); + } + + private _normalizeArch(nodeArchString: string): string { + // Maps from https://nodejs.org/api/os.html#osarch to arch values in spec: + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/host.md + switch (nodeArchString) { + case 'arm': + return 'arm32'; + case 'ppc': + return 'ppc32'; + case 'x64': + return 'amd64'; + default: + return nodeArchString; + } + } +} + +export const hostDetector = new HostDetector(); diff --git a/packages/opentelemetry-resources/src/detectors/OSDetector.ts b/packages/opentelemetry-resources/src/detectors/OSDetector.ts new file mode 100644 index 0000000000..979b48fda0 --- /dev/null +++ b/packages/opentelemetry-resources/src/detectors/OSDetector.ts @@ -0,0 +1,50 @@ +/* + * Copyright The 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 { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { Resource } from '../Resource'; +import { Detector, ResourceAttributes } from '../types'; +import { ResourceDetectionConfig } from '../config'; +import { platform, release } from 'os'; + +/** + * OSDetector detects the resources related to the operating system (OS) on + * which the process represented by this resource is running. + */ +class OSDetector implements Detector { + async detect(_config?: ResourceDetectionConfig): Promise { + const attributes: ResourceAttributes = { + [SemanticResourceAttributes.OS_TYPE]: this._normalizeType(platform()), + [SemanticResourceAttributes.OS_VERSION]: release(), + }; + return new Resource(attributes); + } + + private _normalizeType(nodePlatform: string): string { + // Maps from https://nodejs.org/api/os.html#osplatform to arch values in spec: + // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/os.md + switch (nodePlatform) { + case 'sunos': + return 'solaris'; + case 'win32': + return 'windows'; + default: + return nodePlatform; + } + } +} + +export const osDetector = new OSDetector(); diff --git a/packages/opentelemetry-resources/src/detectors/index.ts b/packages/opentelemetry-resources/src/detectors/index.ts index 3a69a099bc..db9296d266 100644 --- a/packages/opentelemetry-resources/src/detectors/index.ts +++ b/packages/opentelemetry-resources/src/detectors/index.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +export * from './BrowserDetector'; export * from './EnvDetector'; +export * from './OSDetector'; +export * from './HostDetector'; export * from './ProcessDetector'; -export * from './BrowserDetector'; diff --git a/packages/opentelemetry-resources/src/types.ts b/packages/opentelemetry-resources/src/types.ts index 94d5e4b892..717f71381d 100644 --- a/packages/opentelemetry-resources/src/types.ts +++ b/packages/opentelemetry-resources/src/types.ts @@ -16,11 +16,14 @@ import { Resource } from './Resource'; import { ResourceDetectionConfig } from './config'; +import { SpanAttributes } from '@opentelemetry/api'; -/** Interface for Resource attributes */ -export interface ResourceAttributes { - [key: string]: number | string | boolean; -} +/** + * Interface for Resource attributes. + * General `Attributes` interface is added in api v1.1.0. + * To backward support older api (1.0.x), the deprecated `SpanAttributes` is used here. + */ +export type ResourceAttributes = SpanAttributes; /** * Interface for a Resource Detector. In order to detect resources in parallel diff --git a/packages/opentelemetry-resources/test/detectors/node/HostDetector.test.ts b/packages/opentelemetry-resources/test/detectors/node/HostDetector.test.ts new file mode 100644 index 0000000000..3c809d500d --- /dev/null +++ b/packages/opentelemetry-resources/test/detectors/node/HostDetector.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright The 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 sinon from 'sinon'; +import * as assert from 'assert'; +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { describeNode } from '../../util'; +import { hostDetector, Resource } from '../../../src'; + +describeNode('hostDetector() on Node.js', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should return resource information about the host', async () => { + const os = require('os'); + + sinon.stub(os, 'arch').returns('x64'); + sinon.stub(os, 'hostname').returns('opentelemetry-test'); + + const resource: Resource = await hostDetector.detect(); + + assert.strictEqual( + resource.attributes[SemanticResourceAttributes.HOST_NAME], + 'opentelemetry-test' + ); + assert.strictEqual( + resource.attributes[SemanticResourceAttributes.HOST_ARCH], + 'amd64' + ); + }); + + it('should pass through arch string if unknown', async () => { + const os = require('os'); + + sinon.stub(os, 'arch').returns('some-unknown-arch'); + + const resource: Resource = await hostDetector.detect(); + + assert.strictEqual( + resource.attributes[SemanticResourceAttributes.HOST_ARCH], + 'some-unknown-arch' + ); + }); +}); diff --git a/packages/opentelemetry-resources/test/detectors/node/OSDetector.test.ts b/packages/opentelemetry-resources/test/detectors/node/OSDetector.test.ts new file mode 100644 index 0000000000..dd3ec3e24b --- /dev/null +++ b/packages/opentelemetry-resources/test/detectors/node/OSDetector.test.ts @@ -0,0 +1,58 @@ +/* + * Copyright The 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 sinon from 'sinon'; +import * as assert from 'assert'; +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { describeNode } from '../../util'; +import { osDetector, Resource } from '../../../src'; + +describeNode('osDetector() on Node.js', () => { + afterEach(() => { + sinon.restore(); + }); + + it('should return resource information from process', async () => { + const os = require('os'); + + sinon.stub(os, 'platform').returns('win32'); + sinon.stub(os, 'release').returns('2.2.1(0.289/5/3)'); + + const resource: Resource = await osDetector.detect(); + + assert.strictEqual( + resource.attributes[SemanticResourceAttributes.OS_TYPE], + 'windows' + ); + assert.strictEqual( + resource.attributes[SemanticResourceAttributes.OS_VERSION], + '2.2.1(0.289/5/3)' + ); + }); + + it('should pass through type string if unknown', async () => { + const os = require('os'); + + sinon.stub(os, 'platform').returns('some-unknown-platform'); + + const resource: Resource = await osDetector.detect(); + + assert.strictEqual( + resource.attributes[SemanticResourceAttributes.OS_TYPE], + 'some-unknown-platform' + ); + }); +});