diff --git a/packages/opentelemetry-resource-detector-aws/.eslintignore b/packages/opentelemetry-resource-detector-aws/.eslintignore
new file mode 100644
index 00000000000..378eac25d31
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/.eslintignore
@@ -0,0 +1 @@
+build
diff --git a/packages/opentelemetry-resource-detector-aws/.eslintrc.js b/packages/opentelemetry-resource-detector-aws/.eslintrc.js
new file mode 100644
index 00000000000..9dfe62f9b8c
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/.eslintrc.js
@@ -0,0 +1,9 @@
+module.exports = {
+ "env": {
+ "mocha": true,
+ "commonjs": true,
+ "node": true,
+ "browser": true
+ },
+ ...require('../../eslint.config.js')
+}
diff --git a/packages/opentelemetry-resource-detector-aws/.npmignore b/packages/opentelemetry-resource-detector-aws/.npmignore
new file mode 100644
index 00000000000..9505ba9450f
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/.npmignore
@@ -0,0 +1,4 @@
+/bin
+/coverage
+/doc
+/test
diff --git a/packages/opentelemetry-resource-detector-aws/LICENSE b/packages/opentelemetry-resource-detector-aws/LICENSE
new file mode 100644
index 00000000000..6b91a297c81
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [2020] 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
+
+ http://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.
diff --git a/packages/opentelemetry-resource-detector-aws/README.md b/packages/opentelemetry-resource-detector-aws/README.md
new file mode 100644
index 00000000000..e3551cc496a
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/README.md
@@ -0,0 +1,44 @@
+# OpenTelemetry Resource Detector for AWS
+
+[![Gitter chat][gitter-image]][gitter-url]
+[![NPM Published Version][npm-img]][npm-url]
+[![dependencies][dependencies-image]][dependencies-url]
+[![devDependencies][devDependencies-image]][devDependencies-url]
+[![Apache License][license-image]][license-image]
+
+The OpenTelemetry Resource is an immutable representation of the entity producing telemetry. For example, a process producing telemetry that is running in a container on Kubernetes has a Pod name, it is in a namespace and possibly is part of a Deployment which also has a name. All three of these attributes can be included in the `Resource`.
+
+[This document][resource-semantic_conventions] defines standard attributes for resources.
+
+## Installation
+
+```bash
+npm install --save @opentelemetry/resource-detector-aws
+```
+
+## Usage
+
+> TODO
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more about OpenTelemetry JavaScript:
+- For help or feedback on this project, join us on [gitter][gitter-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg
+[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-resources
+[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-resources
+[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-resources
+[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-resources&type=dev
+[npm-url]: https://www.npmjs.com/package/@opentelemetry/resources
+[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fresources.svg
+
+[resource-semantic_conventions]: https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/resource/semantic_conventions
diff --git a/packages/opentelemetry-resource-detector-aws/package.json b/packages/opentelemetry-resource-detector-aws/package.json
new file mode 100644
index 00000000000..8cc341f78b2
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "@opentelemetry/resource-detector-aws",
+ "version": "0.10.2",
+ "description": "OpenTelemetry SDK resource detector for AWS",
+ "main": "build/src/index.js",
+ "types": "build/src/index.d.ts",
+ "repository": "open-telemetry/opentelemetry-js",
+ "scripts": {
+ "lint": "eslint . --ext .ts",
+ "lint:fix": "eslint . --ext .ts --fix",
+ "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
+ "tdd": "npm run test -- --watch-extensions ts --watch",
+ "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
+ "clean": "rimraf build/*",
+ "precompile": "tsc --version",
+ "version:update": "node ../../scripts/version-update.js",
+ "compile": "npm run version:update && tsc -p .",
+ "prepare": "npm run compile"
+ },
+ "keywords": [
+ "opentelemetry",
+ "nodejs",
+ "resources",
+ "stats",
+ "profiling"
+ ],
+ "author": "OpenTelemetry Authors",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8.0.0"
+ },
+ "files": [
+ "build/src/**/*.js",
+ "build/src/**/*.js.map",
+ "build/src/**/*.d.ts",
+ "doc",
+ "LICENSE",
+ "README.md"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "devDependencies": {
+ "@types/mocha": "8.0.1",
+ "@types/node": "14.0.27",
+ "@types/sinon": "9.0.4",
+ "codecov": "3.7.2",
+ "gts": "2.0.2",
+ "mocha": "7.2.0",
+ "nock": "12.0.3",
+ "nyc": "15.1.0",
+ "rimraf": "3.0.2",
+ "sinon": "9.0.2",
+ "ts-mocha": "7.0.0",
+ "ts-node": "8.10.2",
+ "typescript": "3.9.7"
+ },
+ "dependencies": {
+ "@opentelemetry/api": "^0.10.2",
+ "@opentelemetry/core": "^0.10.2",
+ "@opentelemetry/resources": "^0.10.2"
+ }
+}
diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts b/packages/opentelemetry-resource-detector-aws/src/detectors/AwsEc2Detector.ts
similarity index 79%
rename from packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts
rename to packages/opentelemetry-resource-detector-aws/src/detectors/AwsEc2Detector.ts
index 3b7cf720d9d..04342d91e85 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/AwsEc2Detector.ts
+++ b/packages/opentelemetry-resource-detector-aws/src/detectors/AwsEc2Detector.ts
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+import {
+ Detector,
+ Resource,
+ CLOUD_RESOURCE,
+ HOST_RESOURCE,
+ ResourceDetectionConfigWithLogger,
+} from '@opentelemetry/resources';
import * as http from 'http';
-import { Resource } from '../../../Resource';
-import { CLOUD_RESOURCE, HOST_RESOURCE } from '../../../constants';
-import { Detector } from '../../../types';
-import { ResourceDetectionConfigWithLogger } from '../../../config';
/**
* The AwsEc2Detector can be used to detect if a process is running in AWS EC2
@@ -47,34 +50,29 @@ class AwsEc2Detector implements Detector {
* empty {@link Resource} if the connection or parsing of the identity
* document fails.
*
- * @param config The resource detection config with a required logger
+ * @param config (unused) The resource detection config with a required logger
*/
- async detect(config: ResourceDetectionConfigWithLogger): Promise {
- try {
- const token = await this._fetchToken();
- const {
- accountId,
- instanceId,
- instanceType,
- region,
- availabilityZone,
- } = await this._fetchIdentity(token);
- const hostname = await this._fetchHost(token);
+ async detect(_config: ResourceDetectionConfigWithLogger): Promise {
+ const token = await this._fetchToken();
+ const {
+ accountId,
+ instanceId,
+ instanceType,
+ region,
+ availabilityZone,
+ } = await this._fetchIdentity(token);
+ const hostname = await this._fetchHost(token);
- return new Resource({
- [CLOUD_RESOURCE.PROVIDER]: 'aws',
- [CLOUD_RESOURCE.ACCOUNT_ID]: accountId,
- [CLOUD_RESOURCE.REGION]: region,
- [CLOUD_RESOURCE.ZONE]: availabilityZone,
- [HOST_RESOURCE.ID]: instanceId,
- [HOST_RESOURCE.TYPE]: instanceType,
- [HOST_RESOURCE.NAME]: hostname,
- [HOST_RESOURCE.HOSTNAME]: hostname,
- });
- } catch (e) {
- config.logger.debug(`AwsEc2Detector failed: ${e.message}`);
- return Resource.empty();
- }
+ return new Resource({
+ [CLOUD_RESOURCE.PROVIDER]: 'aws',
+ [CLOUD_RESOURCE.ACCOUNT_ID]: accountId,
+ [CLOUD_RESOURCE.REGION]: region,
+ [CLOUD_RESOURCE.ZONE]: availabilityZone,
+ [HOST_RESOURCE.ID]: instanceId,
+ [HOST_RESOURCE.TYPE]: instanceType,
+ [HOST_RESOURCE.NAME]: hostname,
+ [HOST_RESOURCE.HOSTNAME]: hostname,
+ });
}
private async _fetchToken(): Promise {
diff --git a/packages/opentelemetry-resource-detector-aws/src/detectors/index.ts b/packages/opentelemetry-resource-detector-aws/src/detectors/index.ts
new file mode 100644
index 00000000000..215622744f8
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/src/detectors/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+export * from './AwsEc2Detector';
diff --git a/packages/opentelemetry-resource-detector-aws/src/index.ts b/packages/opentelemetry-resource-detector-aws/src/index.ts
new file mode 100644
index 00000000000..0acba8788cf
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/src/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+export * from './detectors';
diff --git a/packages/opentelemetry-resource-detector-aws/src/version.ts b/packages/opentelemetry-resource-detector-aws/src/version.ts
new file mode 100644
index 00000000000..ea45ee2fc46
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/src/version.ts
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// this is autogenerated file, see scripts/version-update.js
+export const VERSION = '0.10.2';
diff --git a/packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts b/packages/opentelemetry-resource-detector-aws/test/detectors/AwsEc2Detector.test.ts
similarity index 75%
rename from packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts
rename to packages/opentelemetry-resource-detector-aws/test/detectors/AwsEc2Detector.test.ts
index 910524d8688..99461164fd1 100644
--- a/packages/opentelemetry-resources/test/detectors/AwsEc2Detector.test.ts
+++ b/packages/opentelemetry-resource-detector-aws/test/detectors/AwsEc2Detector.test.ts
@@ -16,13 +16,12 @@
import * as nock from 'nock';
import * as assert from 'assert';
-import { Resource } from '../../src';
-import { awsEc2Detector } from '../../src/platform/node/detectors/AwsEc2Detector';
+import { Resource } from '@opentelemetry/resources';
+import { awsEc2Detector } from '../../src';
import {
assertCloudResource,
assertHostResource,
- assertEmptyResource,
-} from '../util/resource-assertions';
+} from '@opentelemetry/resources/test/util/resource-assertions';
import { NoopLogger } from '@opentelemetry/core';
const AWS_HOST = 'http://' + awsEc2Detector.AWS_IDMS_ENDPOINT;
@@ -89,7 +88,8 @@ describe('awsEc2Detector', () => {
});
describe('with unsuccessful request', () => {
- it('should return empty resource when receiving error response code', async () => {
+ it('should throw when receiving error response code', async () => {
+ const expectedError = new Error('Failed to load page, status code: 404');
const scope = nock(AWS_HOST)
.persist()
.put(AWS_TOKEN_PATH)
@@ -100,19 +100,22 @@ describe('awsEc2Detector', () => {
.reply(200, () => mockedIdentityResponse)
.get(AWS_HOST_PATH)
.matchHeader(AWS_METADATA_TOKEN_HEADER, mockedTokenResponse)
- .reply(404, () => new Error('NOT FOUND'));
+ .reply(404, () => new Error());
- const resource: Resource = await awsEc2Detector.detect({
- logger: new NoopLogger(),
- });
+ try {
+ await awsEc2Detector.detect({
+ logger: new NoopLogger(),
+ });
+ assert.ok(false, 'Expected to throw');
+ } catch (err) {
+ assert.deepStrictEqual(err, expectedError);
+ }
scope.done();
-
- assert.ok(resource);
- assertEmptyResource(resource);
});
- it('should return empty resource when timeout', async () => {
+ it('should throw when timed out', async () => {
+ const expectedError = new Error('EC2 metadata api request timed out.');
const scope = nock(AWS_HOST)
.put(AWS_TOKEN_PATH)
.matchHeader(AWS_METADATA_TTL_HEADER, '60')
@@ -125,33 +128,38 @@ describe('awsEc2Detector', () => {
.delayConnection(2000)
.reply(200, () => mockedHostResponse);
- const resource: Resource = await awsEc2Detector.detect({
- logger: new NoopLogger(),
- });
+ try {
+ await awsEc2Detector.detect({
+ logger: new NoopLogger(),
+ });
+ assert.ok(false, 'Expected to throw');
+ } catch (err) {
+ assert.deepStrictEqual(err, expectedError);
+ }
scope.done();
-
- assert.ok(resource);
- assertEmptyResource(resource);
});
- it('should return empty resource when replied Error', async () => {
+ it('should throw when replied with an Error', async () => {
+ const expectedError = new Error('NOT FOUND');
const scope = nock(AWS_HOST)
.put(AWS_TOKEN_PATH)
.matchHeader(AWS_METADATA_TTL_HEADER, '60')
.reply(200, () => mockedTokenResponse)
.get(AWS_IDENTITY_PATH)
.matchHeader(AWS_METADATA_TOKEN_HEADER, mockedTokenResponse)
- .replyWithError('NOT FOUND');
+ .replyWithError(expectedError.message);
- const resource: Resource = await awsEc2Detector.detect({
- logger: new NoopLogger(),
- });
+ try {
+ await awsEc2Detector.detect({
+ logger: new NoopLogger(),
+ });
+ assert.ok(false, 'Expected to throw');
+ } catch (err) {
+ assert.deepStrictEqual(err, expectedError);
+ }
scope.done();
-
- assert.ok(resource);
- assertEmptyResource(resource);
});
});
});
diff --git a/packages/opentelemetry-resource-detector-aws/tsconfig.json b/packages/opentelemetry-resource-detector-aws/tsconfig.json
new file mode 100644
index 00000000000..e4b3b29e6a2
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-aws/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../tsconfig.base",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "build"
+ },
+ "include": ["src/**/*.ts", "test/**/*.ts"]
+}
diff --git a/packages/opentelemetry-resource-detector-gcp/.eslintignore b/packages/opentelemetry-resource-detector-gcp/.eslintignore
new file mode 100644
index 00000000000..378eac25d31
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/.eslintignore
@@ -0,0 +1 @@
+build
diff --git a/packages/opentelemetry-resource-detector-gcp/.eslintrc.js b/packages/opentelemetry-resource-detector-gcp/.eslintrc.js
new file mode 100644
index 00000000000..9dfe62f9b8c
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/.eslintrc.js
@@ -0,0 +1,9 @@
+module.exports = {
+ "env": {
+ "mocha": true,
+ "commonjs": true,
+ "node": true,
+ "browser": true
+ },
+ ...require('../../eslint.config.js')
+}
diff --git a/packages/opentelemetry-resource-detector-gcp/.npmignore b/packages/opentelemetry-resource-detector-gcp/.npmignore
new file mode 100644
index 00000000000..9505ba9450f
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/.npmignore
@@ -0,0 +1,4 @@
+/bin
+/coverage
+/doc
+/test
diff --git a/packages/opentelemetry-resource-detector-gcp/LICENSE b/packages/opentelemetry-resource-detector-gcp/LICENSE
new file mode 100644
index 00000000000..6b91a297c81
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [2020] 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
+
+ http://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.
diff --git a/packages/opentelemetry-resource-detector-gcp/README.md b/packages/opentelemetry-resource-detector-gcp/README.md
new file mode 100644
index 00000000000..ccb2af7b091
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/README.md
@@ -0,0 +1,44 @@
+# OpenTelemetry Resource Detector for GCP
+
+[![Gitter chat][gitter-image]][gitter-url]
+[![NPM Published Version][npm-img]][npm-url]
+[![dependencies][dependencies-image]][dependencies-url]
+[![devDependencies][devDependencies-image]][devDependencies-url]
+[![Apache License][license-image]][license-image]
+
+The OpenTelemetry Resource is an immutable representation of the entity producing telemetry. For example, a process producing telemetry that is running in a container on Kubernetes has a Pod name, it is in a namespace and possibly is part of a Deployment which also has a name. All three of these attributes can be included in the `Resource`.
+
+[This document][resource-semantic_conventions] defines standard attributes for resources.
+
+## Installation
+
+```bash
+npm install --save @opentelemetry/resource-detector-gcp
+```
+
+## Usage
+
+> TODO
+
+## Useful links
+
+- For more information on OpenTelemetry, visit:
+- For more about OpenTelemetry JavaScript:
+- For help or feedback on this project, join us on [gitter][gitter-url]
+
+## License
+
+Apache 2.0 - See [LICENSE][license-url] for more information.
+
+[gitter-image]: https://badges.gitter.im/open-telemetry/opentelemetry-js.svg
+[gitter-url]: https://gitter.im/open-telemetry/opentelemetry-node?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
+[license-url]: https://github.com/open-telemetry/opentelemetry-js/blob/master/LICENSE
+[license-image]: https://img.shields.io/badge/license-Apache_2.0-green.svg?style=flat
+[dependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/status.svg?path=packages/opentelemetry-resources
+[dependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-resources
+[devDependencies-image]: https://david-dm.org/open-telemetry/opentelemetry-js/dev-status.svg?path=packages/opentelemetry-resources
+[devDependencies-url]: https://david-dm.org/open-telemetry/opentelemetry-js?path=packages%2Fopentelemetry-resources&type=dev
+[npm-url]: https://www.npmjs.com/package/@opentelemetry/resources
+[npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fresources.svg
+
+[resource-semantic_conventions]: https://github.com/open-telemetry/opentelemetry-specification/tree/master/specification/resource/semantic_conventions
diff --git a/packages/opentelemetry-resource-detector-gcp/package.json b/packages/opentelemetry-resource-detector-gcp/package.json
new file mode 100644
index 00000000000..c059e00f937
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/package.json
@@ -0,0 +1,64 @@
+{
+ "name": "@opentelemetry/resource-detector-gcp",
+ "version": "0.10.2",
+ "description": "OpenTelemetry SDK resource detector for GCP",
+ "main": "build/src/index.js",
+ "types": "build/src/index.d.ts",
+ "repository": "open-telemetry/opentelemetry-js",
+ "scripts": {
+ "lint": "eslint . --ext .ts",
+ "lint:fix": "eslint . --ext .ts --fix",
+ "test": "nyc ts-mocha -p tsconfig.json 'test/**/*.test.ts'",
+ "tdd": "npm run test -- --watch-extensions ts --watch",
+ "codecov": "nyc report --reporter=json && codecov -f coverage/*.json -p ../../",
+ "clean": "rimraf build/*",
+ "precompile": "tsc --version",
+ "version:update": "node ../../scripts/version-update.js",
+ "compile": "npm run version:update && tsc -p .",
+ "prepare": "npm run compile"
+ },
+ "keywords": [
+ "opentelemetry",
+ "nodejs",
+ "resources",
+ "stats",
+ "profiling"
+ ],
+ "author": "OpenTelemetry Authors",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8.0.0"
+ },
+ "files": [
+ "build/src/**/*.js",
+ "build/src/**/*.js.map",
+ "build/src/**/*.d.ts",
+ "doc",
+ "LICENSE",
+ "README.md"
+ ],
+ "publishConfig": {
+ "access": "public"
+ },
+ "devDependencies": {
+ "@types/mocha": "8.0.1",
+ "@types/node": "14.0.27",
+ "@types/sinon": "9.0.4",
+ "codecov": "3.7.2",
+ "gts": "2.0.2",
+ "mocha": "7.2.0",
+ "nock": "12.0.3",
+ "nyc": "15.1.0",
+ "rimraf": "3.0.2",
+ "sinon": "9.0.2",
+ "ts-mocha": "7.0.0",
+ "ts-node": "8.10.2",
+ "typescript": "3.9.7"
+ },
+ "dependencies": {
+ "@opentelemetry/api": "^0.10.2",
+ "@opentelemetry/core": "^0.10.2",
+ "@opentelemetry/resources": "^0.10.2",
+ "gcp-metadata": "^3.5.0"
+ }
+}
diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts b/packages/opentelemetry-resource-detector-gcp/src/detectors/GcpDetector.ts
similarity index 94%
rename from packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts
rename to packages/opentelemetry-resource-detector-gcp/src/detectors/GcpDetector.ts
index 48195995116..2cc793bc167 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/GcpDetector.ts
+++ b/packages/opentelemetry-resource-detector-gcp/src/detectors/GcpDetector.ts
@@ -16,15 +16,16 @@
import * as os from 'os';
import * as gcpMetadata from 'gcp-metadata';
-import { Resource } from '../../../Resource';
-import { Detector, ResourceAttributes } from '../../../types';
import {
+ Detector,
+ ResourceDetectionConfigWithLogger,
+ Resource,
+ ResourceAttributes,
CLOUD_RESOURCE,
HOST_RESOURCE,
K8S_RESOURCE,
CONTAINER_RESOURCE,
-} from '../../../constants';
-import { ResourceDetectionConfigWithLogger } from '../../../config';
+} from '@opentelemetry/resources';
/**
* The GcpDetector can be used to detect if a process is running in the Google
diff --git a/packages/opentelemetry-resource-detector-gcp/src/detectors/index.ts b/packages/opentelemetry-resource-detector-gcp/src/detectors/index.ts
new file mode 100644
index 00000000000..9e856721bc4
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/src/detectors/index.ts
@@ -0,0 +1,17 @@
+/*
+ * 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.
+ */
+
+export * from './GcpDetector';
diff --git a/packages/opentelemetry-resource-detector-gcp/src/index.ts b/packages/opentelemetry-resource-detector-gcp/src/index.ts
new file mode 100644
index 00000000000..f281d4fdcdf
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/src/index.ts
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+export * from './detectors';
+
+// Internal - used for tests only
+export { resetIsAvailableCache } from 'gcp-metadata';
diff --git a/packages/opentelemetry-resource-detector-gcp/src/version.ts b/packages/opentelemetry-resource-detector-gcp/src/version.ts
new file mode 100644
index 00000000000..ea45ee2fc46
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/src/version.ts
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+// this is autogenerated file, see scripts/version-update.js
+export const VERSION = '0.10.2';
diff --git a/packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts b/packages/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts
similarity index 97%
rename from packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts
rename to packages/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts
index a4207c8918d..f2ae5815538 100644
--- a/packages/opentelemetry-resources/test/detectors/GcpDetector.test.ts
+++ b/packages/opentelemetry-resource-detector-gcp/test/detectors/GcpDetector.test.ts
@@ -23,16 +23,16 @@ import {
resetIsAvailableCache,
} from 'gcp-metadata';
import * as nock from 'nock';
-import { Resource } from '../../src';
-import { gcpDetector } from '../../src/platform/node/detectors';
+import { gcpDetector } from '../../src';
import {
assertCloudResource,
assertHostResource,
assertK8sResource,
assertContainerResource,
assertEmptyResource,
-} from '../util/resource-assertions';
+} from '@opentelemetry/resources/test/util/resource-assertions';
import { NoopLogger } from '@opentelemetry/core';
+import { Resource } from '@opentelemetry/resources';
const HEADERS = {
[HEADER_NAME.toLowerCase()]: HEADER_VALUE,
diff --git a/packages/opentelemetry-resource-detector-gcp/tsconfig.json b/packages/opentelemetry-resource-detector-gcp/tsconfig.json
new file mode 100644
index 00000000000..e4b3b29e6a2
--- /dev/null
+++ b/packages/opentelemetry-resource-detector-gcp/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../tsconfig.base",
+ "compilerOptions": {
+ "rootDir": ".",
+ "outDir": "build"
+ },
+ "include": ["src/**/*.ts", "test/**/*.ts"]
+}
diff --git a/packages/opentelemetry-resources/LICENSE b/packages/opentelemetry-resources/LICENSE
index b0e74c7d159..6b91a297c81 100644
--- a/packages/opentelemetry-resources/LICENSE
+++ b/packages/opentelemetry-resources/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [2020] [name of copyright owner]
+ Copyright [2020] OpenTelemetry Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/packages/opentelemetry-resources/package.json b/packages/opentelemetry-resources/package.json
index b4f6c8d54d1..51f6ea5efc9 100644
--- a/packages/opentelemetry-resources/package.json
+++ b/packages/opentelemetry-resources/package.json
@@ -61,7 +61,6 @@
},
"dependencies": {
"@opentelemetry/api": "^0.10.2",
- "@opentelemetry/core": "^0.10.2",
- "gcp-metadata": "^3.5.0"
+ "@opentelemetry/core": "^0.10.2"
}
}
diff --git a/packages/opentelemetry-resources/src/config.ts b/packages/opentelemetry-resources/src/config.ts
index 8eb9007eb6a..250d055f7ee 100644
--- a/packages/opentelemetry-resources/src/config.ts
+++ b/packages/opentelemetry-resources/src/config.ts
@@ -15,6 +15,7 @@
*/
import { Logger } from '@opentelemetry/api';
+import type { Detector } from './types';
/**
* ResourceDetectionConfig provides an interface for configuring resource auto-detection.
@@ -22,6 +23,7 @@ import { Logger } from '@opentelemetry/api';
export interface ResourceDetectionConfig {
/** Optional Logger. */
logger?: Logger;
+ detectors?: Array;
}
/**
diff --git a/packages/opentelemetry-resources/src/index.ts b/packages/opentelemetry-resources/src/index.ts
index f5a851015ae..2cfef2d182f 100644
--- a/packages/opentelemetry-resources/src/index.ts
+++ b/packages/opentelemetry-resources/src/index.ts
@@ -18,3 +18,4 @@ export * from './Resource';
export * from './platform';
export * from './constants';
export * from './types';
+export * from './config';
diff --git a/packages/opentelemetry-resources/src/platform/index.ts b/packages/opentelemetry-resources/src/platform/index.ts
index a12506ffa92..cdaf8858ce5 100644
--- a/packages/opentelemetry-resources/src/platform/index.ts
+++ b/packages/opentelemetry-resources/src/platform/index.ts
@@ -13,4 +13,5 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
export * from './node';
diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
index 62a3ac8c194..37fa35278d5 100644
--- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts
@@ -15,8 +15,6 @@
*/
import { Resource } from '../../Resource';
-import { envDetector, awsEc2Detector, gcpDetector } from './detectors';
-import { Detector } from '../../types';
import {
ResourceDetectionConfig,
ResourceDetectionConfigWithLogger,
@@ -25,8 +23,6 @@ import { Logger } from '@opentelemetry/api';
import * as util from 'util';
import { NoopLogger } from '@opentelemetry/core';
-const DETECTORS: Array = [envDetector, awsEc2Detector, gcpDetector];
-
/**
* Runs all resource detectors and returns the results merged into a single
* Resource.
@@ -44,10 +40,13 @@ export const detectResources = async (
);
const resources: Array = await Promise.all(
- DETECTORS.map(d => {
+ (internalConfig.detectors || []).map(async d => {
try {
- return d.detect(internalConfig);
- } catch {
+ const resource = await d.detect(internalConfig);
+ config.logger?.debug(`${d.constructor.name} found resource.`, resource);
+ return resource;
+ } catch (e) {
+ config.logger?.debug(`${d.constructor.name} failed: ${e.message}`);
return Resource.empty();
}
})
@@ -69,7 +68,7 @@ export const detectResources = async (
* @param resources The array of {@link Resource} that should be logged. Empty entried will be ignored.
*/
const logResources = (logger: Logger, resources: Array) => {
- resources.forEach((resource, index) => {
+ resources.forEach(resource => {
// Print only populated resources
if (Object.keys(resource.attributes).length > 0) {
const resourceDebugString = util.inspect(resource.attributes, {
@@ -78,10 +77,6 @@ const logResources = (logger: Logger, resources: Array) => {
sorted: true,
compact: false,
});
- const detectorName = DETECTORS[index].constructor
- ? DETECTORS[index].constructor.name
- : 'Unknown detector';
- logger.debug(`${detectorName} found resource.`);
logger.debug(resourceDebugString);
}
});
diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts
index 7e22bdf786a..a448a11d1f0 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts
@@ -14,9 +14,12 @@
* limitations under the License.
*/
-import { Resource } from '../../../Resource';
-import { Detector, ResourceAttributes } from '../../../types';
-import { ResourceDetectionConfigWithLogger } from '../../../config';
+import {
+ Detector,
+ Resource,
+ ResourceDetectionConfigWithLogger,
+ ResourceAttributes,
+} from '../../../';
/**
* EnvDetector can be used to detect the presence of and create a Resource
@@ -103,10 +106,10 @@ class EnvDetector implements Detector {
key = key.trim();
value = value.trim().split('^"|"$').join('');
if (!this._isValidAndNotEmpty(key)) {
- throw new Error(`Label key ${this._ERROR_MESSAGE_INVALID_CHARS}`);
+ throw new Error(`Attribute key ${this._ERROR_MESSAGE_INVALID_CHARS}`);
}
if (!this._isValid(value)) {
- throw new Error(`Label value ${this._ERROR_MESSAGE_INVALID_VALUE}`);
+ throw new Error(`Attribute value ${this._ERROR_MESSAGE_INVALID_VALUE}`);
}
attributes[key] = value;
}
diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/index.ts b/packages/opentelemetry-resources/src/platform/node/detectors/index.ts
index c0c3c37b2c8..f2b4223be18 100644
--- a/packages/opentelemetry-resources/src/platform/node/detectors/index.ts
+++ b/packages/opentelemetry-resources/src/platform/node/detectors/index.ts
@@ -14,6 +14,4 @@
* limitations under the License.
*/
-export { awsEc2Detector } from './AwsEc2Detector';
-export { envDetector } from './EnvDetector';
-export { gcpDetector } from './GcpDetector';
+export * from './EnvDetector';
diff --git a/packages/opentelemetry-resources/src/platform/node/index.ts b/packages/opentelemetry-resources/src/platform/node/index.ts
index f90eb34a5fe..7e82a09dd5d 100644
--- a/packages/opentelemetry-resources/src/platform/node/index.ts
+++ b/packages/opentelemetry-resources/src/platform/node/index.ts
@@ -15,3 +15,4 @@
*/
export * from './detect-resources';
+export * from './detectors';
diff --git a/packages/opentelemetry-resources/test/detect-resources.test.ts b/packages/opentelemetry-resources/test/detect-resources.test.ts
deleted file mode 100644
index ee6e091702d..00000000000
--- a/packages/opentelemetry-resources/test/detect-resources.test.ts
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * 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 nock from 'nock';
-import * as sinon from 'sinon';
-import * as assert from 'assert';
-import { Resource, detectResources } from '../src';
-import { awsEc2Detector } from '../src/platform/node/detectors';
-import {
- assertServiceResource,
- assertCloudResource,
- assertHostResource,
-} from './util/resource-assertions';
-import {
- BASE_PATH,
- HEADER_NAME,
- HEADER_VALUE,
- HOST_ADDRESS,
- SECONDARY_HOST_ADDRESS,
- resetIsAvailableCache,
-} from 'gcp-metadata';
-
-const HEADERS = {
- [HEADER_NAME.toLowerCase()]: HEADER_VALUE,
-};
-const INSTANCE_PATH = BASE_PATH + '/instance';
-const INSTANCE_ID_PATH = BASE_PATH + '/instance/id';
-const PROJECT_ID_PATH = BASE_PATH + '/project/project-id';
-const ZONE_PATH = BASE_PATH + '/instance/zone';
-const CLUSTER_NAME_PATH = BASE_PATH + '/instance/attributes/cluster-name';
-
-const AWS_HOST = 'http://' + awsEc2Detector.AWS_IDMS_ENDPOINT;
-const AWS_TOKEN_PATH = awsEc2Detector.AWS_INSTANCE_TOKEN_DOCUMENT_PATH;
-const AWS_IDENTITY_PATH = awsEc2Detector.AWS_INSTANCE_IDENTITY_DOCUMENT_PATH;
-const AWS_HOST_PATH = awsEc2Detector.AWS_INSTANCE_HOST_DOCUMENT_PATH;
-const AWS_METADATA_TTL_HEADER = awsEc2Detector.AWS_METADATA_TTL_HEADER;
-const AWS_METADATA_TOKEN_HEADER = awsEc2Detector.AWS_METADATA_TOKEN_HEADER;
-
-const mockedTokenResponse = 'my-token';
-const mockedIdentityResponse = {
- instanceId: 'my-instance-id',
- instanceType: 'my-instance-type',
- accountId: 'my-account-id',
- region: 'my-region',
- availabilityZone: 'my-zone',
-};
-const mockedHostResponse = 'my-hostname';
-
-describe('detectResources', async () => {
- beforeEach(() => {
- nock.disableNetConnect();
- process.env.OTEL_RESOURCE_ATTRIBUTES =
- 'service.instance.id=627cc493,service.name=my-service,service.namespace=default,service.version=0.0.1';
- });
-
- afterEach(() => {
- nock.cleanAll();
- nock.enableNetConnect();
- delete process.env.OTEL_RESOURCE_ATTRIBUTES;
- });
-
- describe('in GCP environment', () => {
- after(() => {
- resetIsAvailableCache();
- });
-
- it('returns a merged resource', async () => {
- const gcpScope = nock(HOST_ADDRESS)
- .get(INSTANCE_PATH)
- .reply(200, {}, HEADERS)
- .get(INSTANCE_ID_PATH)
- .reply(200, () => 452003179927758, HEADERS)
- .get(PROJECT_ID_PATH)
- .reply(200, () => 'my-project-id', HEADERS)
- .get(ZONE_PATH)
- .reply(200, () => 'project/zone/my-zone', HEADERS)
- .get(CLUSTER_NAME_PATH)
- .reply(404);
- const gcpSecondaryScope = nock(SECONDARY_HOST_ADDRESS)
- .get(INSTANCE_PATH)
- .reply(200, {}, HEADERS);
- const awsScope = nock(AWS_HOST)
- .persist()
- .put(AWS_TOKEN_PATH)
- .matchHeader(AWS_METADATA_TTL_HEADER, '60')
- .replyWithError({ code: 'ENOTFOUND' });
- const resource: Resource = await detectResources();
- awsScope.done();
- gcpSecondaryScope.done();
- gcpScope.done();
-
- assertCloudResource(resource, {
- provider: 'gcp',
- accountId: 'my-project-id',
- zone: 'my-zone',
- });
- assertHostResource(resource, { id: '452003179927758' });
- assertServiceResource(resource, {
- instanceId: '627cc493',
- name: 'my-service',
- namespace: 'default',
- version: '0.0.1',
- });
- });
- });
-
- describe('in AWS environment', () => {
- it('returns a merged resource', async () => {
- const gcpScope = nock(HOST_ADDRESS).get(INSTANCE_PATH).replyWithError({
- code: 'ENOTFOUND',
- });
- const gcpSecondaryScope = nock(SECONDARY_HOST_ADDRESS)
- .get(INSTANCE_PATH)
- .replyWithError({
- code: 'ENOTFOUND',
- });
- const awsScope = nock(AWS_HOST)
- .persist()
- .put(AWS_TOKEN_PATH)
- .matchHeader(AWS_METADATA_TTL_HEADER, '60')
- .reply(200, () => mockedTokenResponse)
- .get(AWS_IDENTITY_PATH)
- .matchHeader(AWS_METADATA_TOKEN_HEADER, mockedTokenResponse)
- .reply(200, () => mockedIdentityResponse)
- .get(AWS_HOST_PATH)
- .matchHeader(AWS_METADATA_TOKEN_HEADER, mockedTokenResponse)
- .reply(200, () => mockedHostResponse);
- const resource: Resource = await detectResources();
- gcpSecondaryScope.done();
- gcpScope.done();
- awsScope.done();
-
- assertCloudResource(resource, {
- provider: 'aws',
- accountId: 'my-account-id',
- region: 'my-region',
- zone: 'my-zone',
- });
- assertHostResource(resource, {
- id: 'my-instance-id',
- hostType: 'my-instance-type',
- name: 'my-hostname',
- hostName: 'my-hostname',
- });
- assertServiceResource(resource, {
- instanceId: '627cc493',
- name: 'my-service',
- namespace: 'default',
- version: '0.0.1',
- });
- });
- });
-
- describe('with a buggy detector', () => {
- it('returns a merged resource', async () => {
- const stub = sinon.stub(awsEc2Detector, 'detect').throws();
- const resource: Resource = await detectResources();
-
- assertServiceResource(resource, {
- instanceId: '627cc493',
- name: 'my-service',
- namespace: 'default',
- version: '0.0.1',
- });
-
- stub.restore();
- });
- });
-
- describe('with a debug logger', () => {
- // Local functions to test if a mocked method is ever called with a specific argument or regex matching for an argument.
- // Needed because of race condition with parallel detectors.
- const callArgsContains = (
- mockedFunction: sinon.SinonSpy,
- arg: any
- ): boolean => {
- return mockedFunction.getCalls().some(call => {
- return call.args.some(callarg => arg === callarg);
- });
- };
- const callArgsMatches = (
- mockedFunction: sinon.SinonSpy,
- regex: RegExp
- ): boolean => {
- return mockedFunction.getCalls().some(call => {
- return regex.test(call.args.toString());
- });
- };
-
- it('prints detected resources and debug messages to the logger', async () => {
- // This test depends on the env detector to be functioning as intended
- const mockedLoggerMethod = sinon.fake();
- await detectResources({
- logger: {
- debug: mockedLoggerMethod,
- info: sinon.fake(),
- warn: sinon.fake(),
- error: sinon.fake(),
- },
- });
-
- // Test for AWS and GCP Detector failure
- assert.ok(
- callArgsContains(
- mockedLoggerMethod,
- 'GcpDetector failed: GCP Metadata unavailable.'
- )
- );
- assert.ok(
- callArgsContains(
- mockedLoggerMethod,
- 'AwsEc2Detector failed: Nock: Disallowed net connect for "169.254.169.254:80/latest/api/token"'
- )
- );
- // Test that the Env Detector successfully found its resource and populated it with the right values.
- assert.ok(
- callArgsContains(mockedLoggerMethod, 'EnvDetector found resource.')
- );
- // Regex formatting accounts for whitespace variations in util.inspect output over different node versions
- assert.ok(
- callArgsMatches(
- mockedLoggerMethod,
- /{\s+'service\.instance\.id':\s+'627cc493',\s+'service\.name':\s+'my-service',\s+'service\.namespace':\s+'default',\s+'service\.version':\s+'0\.0\.1'\s+}\s*/
- )
- );
- });
-
- describe('with missing environemnt variable', () => {
- beforeEach(() => {
- delete process.env.OTEL_RESOURCE_ATTRIBUTES;
- });
-
- it('prints correct error messages when EnvDetector has no env variable', async () => {
- const mockedLoggerMethod = sinon.fake();
- await detectResources({
- logger: {
- debug: mockedLoggerMethod,
- info: sinon.fake(),
- warn: sinon.fake(),
- error: sinon.fake(),
- },
- });
-
- assert.ok(
- callArgsContains(
- mockedLoggerMethod,
- 'EnvDetector failed: Environment variable "OTEL_RESOURCE_ATTRIBUTES" is missing.'
- )
- );
- });
- });
-
- describe('with a faulty environment variable', () => {
- beforeEach(() => {
- process.env.OTEL_RESOURCE_ATTRIBUTES = 'bad=~label';
- });
-
- it('prints correct error messages when EnvDetector has an invalid variable', async () => {
- const mockedLoggerMethod = sinon.fake();
- await detectResources({
- logger: {
- debug: mockedLoggerMethod,
- info: sinon.fake(),
- warn: sinon.fake(),
- error: sinon.fake(),
- },
- });
-
- assert.ok(
- callArgsContains(
- mockedLoggerMethod,
- 'EnvDetector failed: Label value should be a ASCII string with a length not exceed 255 characters.'
- )
- );
- });
- });
- });
-});
diff --git a/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts b/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts
index adc1e013a55..df45725cb9d 100644
--- a/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts
+++ b/packages/opentelemetry-resources/test/detectors/EnvDetector.test.ts
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-import { Resource } from '../../src/Resource';
-import { envDetector } from '../../src/platform/node/detectors/EnvDetector';
+import { envDetector, K8S_RESOURCE, Resource } from '../../src';
import {
assertK8sResource,
assertEmptyResource,
} from '../util/resource-assertions';
-import { K8S_RESOURCE } from '../../src';
import { NoopLogger } from '@opentelemetry/core';
describe('envDetector()', () => {
diff --git a/packages/opentelemetry-resources/test/util/sample-detector.ts b/packages/opentelemetry-resources/test/util/sample-detector.ts
new file mode 100644
index 00000000000..1ed6f258efd
--- /dev/null
+++ b/packages/opentelemetry-resources/test/util/sample-detector.ts
@@ -0,0 +1,32 @@
+/*
+ * 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 { Detector, Resource, CLOUD_RESOURCE, HOST_RESOURCE } from '../../src';
+
+class SampleDetector implements Detector {
+ async detect(): Promise {
+ return new Resource({
+ [CLOUD_RESOURCE.PROVIDER]: 'provider',
+ [CLOUD_RESOURCE.ACCOUNT_ID]: 'accountId',
+ [CLOUD_RESOURCE.REGION]: 'region',
+ [CLOUD_RESOURCE.ZONE]: 'zone',
+ [HOST_RESOURCE.ID]: 'instanceId',
+ [HOST_RESOURCE.TYPE]: 'instanceType',
+ });
+ }
+}
+
+export const sampleDetector = new SampleDetector();
diff --git a/packages/opentelemetry-sdk-node/package.json b/packages/opentelemetry-sdk-node/package.json
index 4eea2e65502..e87a38d71a1 100644
--- a/packages/opentelemetry-sdk-node/package.json
+++ b/packages/opentelemetry-sdk-node/package.json
@@ -48,7 +48,10 @@
"@opentelemetry/metrics": "^0.10.2",
"@opentelemetry/node": "^0.10.2",
"@opentelemetry/resources": "^0.10.2",
- "@opentelemetry/tracing": "^0.10.2"
+ "@opentelemetry/tracing": "^0.10.2",
+ "@opentelemetry/resource-detector-aws": "^0.10.2",
+ "@opentelemetry/resource-detector-gcp": "^0.10.2",
+ "nock": "12.0.3"
},
"devDependencies": {
"@opentelemetry/context-async-hooks": "^0.10.2",
@@ -56,6 +59,7 @@
"@types/node": "14.0.27",
"@types/sinon": "9.0.4",
"codecov": "3.7.2",
+ "gcp-metadata": "^3.5.0",
"gts": "2.0.2",
"istanbul-instrumenter-loader": "3.0.1",
"mocha": "7.2.0",
diff --git a/packages/opentelemetry-sdk-node/src/sdk.ts b/packages/opentelemetry-sdk-node/src/sdk.ts
index 3b27e1331ec..3ab7d614e2a 100644
--- a/packages/opentelemetry-sdk-node/src/sdk.ts
+++ b/packages/opentelemetry-sdk-node/src/sdk.ts
@@ -18,9 +18,16 @@ import { HttpTextPropagator, metrics } from '@opentelemetry/api';
import { ContextManager } from '@opentelemetry/context-base';
import { MeterConfig, MeterProvider } from '@opentelemetry/metrics';
import { NodeTracerConfig, NodeTracerProvider } from '@opentelemetry/node';
-import { detectResources, Resource } from '@opentelemetry/resources';
+import {
+ detectResources,
+ Resource,
+ ResourceDetectionConfig,
+ envDetector,
+} from '@opentelemetry/resources';
import { BatchSpanProcessor, SpanProcessor } from '@opentelemetry/tracing';
import { NodeSDKConfiguration } from './types';
+import { awsEc2Detector } from '@opentelemetry/resource-detector-aws';
+import { gcpDetector } from '@opentelemetry/resource-detector-gcp';
/** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */
export class NodeSDK {
@@ -119,8 +126,13 @@ export class NodeSDK {
}
/** Detect resource attributes */
- public async detectResources() {
- this.addResource(await detectResources());
+ public async detectResources(config?: ResourceDetectionConfig) {
+ const internalConfig: ResourceDetectionConfig = {
+ detectors: [awsEc2Detector, gcpDetector, envDetector],
+ ...config,
+ };
+
+ this.addResource(await detectResources(internalConfig));
}
/** Manually add a resource */
diff --git a/packages/opentelemetry-sdk-node/test/sdk.test.ts b/packages/opentelemetry-sdk-node/test/sdk.test.ts
index 083a7681fb3..0cb51a898ef 100644
--- a/packages/opentelemetry-sdk-node/test/sdk.test.ts
+++ b/packages/opentelemetry-sdk-node/test/sdk.test.ts
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+import * as nock from 'nock';
import {
context,
metrics,
@@ -36,6 +37,47 @@ import * as assert from 'assert';
import { NodeSDK } from '../src';
import * as NodeConfig from '@opentelemetry/node/build/src/config';
import * as Sinon from 'sinon';
+import { awsEc2Detector } from '@opentelemetry/resource-detector-aws';
+import { resetIsAvailableCache } from '@opentelemetry/resource-detector-gcp';
+import {
+ assertServiceResource,
+ assertCloudResource,
+ assertHostResource,
+} from '@opentelemetry/resources/test/util/resource-assertions';
+import {
+ BASE_PATH,
+ HEADER_NAME,
+ HEADER_VALUE,
+ HOST_ADDRESS,
+ SECONDARY_HOST_ADDRESS,
+} from 'gcp-metadata';
+import { Resource } from '@opentelemetry/resources';
+
+const HEADERS = {
+ [HEADER_NAME.toLowerCase()]: HEADER_VALUE,
+};
+const INSTANCE_PATH = BASE_PATH + '/instance';
+const INSTANCE_ID_PATH = BASE_PATH + '/instance/id';
+const PROJECT_ID_PATH = BASE_PATH + '/project/project-id';
+const ZONE_PATH = BASE_PATH + '/instance/zone';
+const CLUSTER_NAME_PATH = BASE_PATH + '/instance/attributes/cluster-name';
+
+const AWS_HOST = 'http://' + awsEc2Detector.AWS_IDMS_ENDPOINT;
+const AWS_TOKEN_PATH = awsEc2Detector.AWS_INSTANCE_TOKEN_DOCUMENT_PATH;
+const AWS_IDENTITY_PATH = awsEc2Detector.AWS_INSTANCE_IDENTITY_DOCUMENT_PATH;
+const AWS_HOST_PATH = awsEc2Detector.AWS_INSTANCE_HOST_DOCUMENT_PATH;
+const AWS_METADATA_TTL_HEADER = awsEc2Detector.AWS_METADATA_TTL_HEADER;
+const AWS_METADATA_TOKEN_HEADER = awsEc2Detector.AWS_METADATA_TOKEN_HEADER;
+
+const mockedTokenResponse = 'my-token';
+const mockedIdentityResponse = {
+ instanceId: 'my-instance-id',
+ instanceType: 'my-instance-type',
+ accountId: 'my-account-id',
+ region: 'my-region',
+ availabilityZone: 'my-zone',
+};
+const mockedHostResponse = 'my-hostname';
describe('Node SDK', () => {
before(() => {
@@ -128,4 +170,276 @@ describe('Node SDK', () => {
assert.ok(metrics.getMeterProvider() instanceof MeterProvider);
});
});
+
+ describe('detectResources', async () => {
+ beforeEach(() => {
+ nock.disableNetConnect();
+ process.env.OTEL_RESOURCE_ATTRIBUTES =
+ 'service.instance.id=627cc493,service.name=my-service,service.namespace=default,service.version=0.0.1';
+ });
+
+ afterEach(() => {
+ nock.cleanAll();
+ nock.enableNetConnect();
+ delete process.env.OTEL_RESOURCE_ATTRIBUTES;
+ });
+
+ describe('in GCP environment', () => {
+ after(() => {
+ resetIsAvailableCache();
+ });
+
+ it('returns a merged resource', async () => {
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ const gcpScope = nock(HOST_ADDRESS)
+ .get(INSTANCE_PATH)
+ .reply(200, {}, HEADERS)
+ .get(INSTANCE_ID_PATH)
+ .reply(200, () => 452003179927758, HEADERS)
+ .get(PROJECT_ID_PATH)
+ .reply(200, () => 'my-project-id', HEADERS)
+ .get(ZONE_PATH)
+ .reply(200, () => 'project/zone/my-zone', HEADERS)
+ .get(CLUSTER_NAME_PATH)
+ .reply(404);
+ const gcpSecondaryScope = nock(SECONDARY_HOST_ADDRESS)
+ .get(INSTANCE_PATH)
+ .reply(200, {}, HEADERS);
+ const awsScope = nock(AWS_HOST)
+ .persist()
+ .put(AWS_TOKEN_PATH)
+ .matchHeader(AWS_METADATA_TTL_HEADER, '60')
+ .replyWithError({ code: 'ENOTFOUND' });
+ await sdk.detectResources();
+ const resource = sdk['_resource'];
+
+ awsScope.done();
+ gcpSecondaryScope.done();
+ gcpScope.done();
+
+ assertCloudResource(resource, {
+ provider: 'gcp',
+ accountId: 'my-project-id',
+ zone: 'my-zone',
+ });
+ assertHostResource(resource, { id: '452003179927758' });
+ assertServiceResource(resource, {
+ instanceId: '627cc493',
+ name: 'my-service',
+ namespace: 'default',
+ version: '0.0.1',
+ });
+ });
+ });
+
+ describe('in AWS environment', () => {
+ it('returns a merged resource', async () => {
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ const gcpScope = nock(HOST_ADDRESS).get(INSTANCE_PATH).replyWithError({
+ code: 'ENOTFOUND',
+ });
+ const gcpSecondaryScope = nock(SECONDARY_HOST_ADDRESS)
+ .get(INSTANCE_PATH)
+ .replyWithError({
+ code: 'ENOTFOUND',
+ });
+ const awsScope = nock(AWS_HOST)
+ .persist()
+ .put(AWS_TOKEN_PATH)
+ .matchHeader(AWS_METADATA_TTL_HEADER, '60')
+ .reply(200, () => mockedTokenResponse)
+ .get(AWS_IDENTITY_PATH)
+ .matchHeader(AWS_METADATA_TOKEN_HEADER, mockedTokenResponse)
+ .reply(200, () => mockedIdentityResponse)
+ .get(AWS_HOST_PATH)
+ .matchHeader(AWS_METADATA_TOKEN_HEADER, mockedTokenResponse)
+ .reply(200, () => mockedHostResponse);
+ await sdk.detectResources();
+ const resource: Resource = sdk['_resource'];
+ gcpSecondaryScope.done();
+ gcpScope.done();
+ awsScope.done();
+
+ assertCloudResource(resource, {
+ provider: 'aws',
+ accountId: 'my-account-id',
+ region: 'my-region',
+ zone: 'my-zone',
+ });
+ assertHostResource(resource, {
+ id: 'my-instance-id',
+ hostType: 'my-instance-type',
+ name: 'my-hostname',
+ hostName: 'my-hostname',
+ });
+ assertServiceResource(resource, {
+ instanceId: '627cc493',
+ name: 'my-service',
+ namespace: 'default',
+ version: '0.0.1',
+ });
+ });
+ });
+
+ describe('in no environment', () => {
+ it('should return empty resource', async () => {
+ const scope = nock(AWS_HOST).put(AWS_TOKEN_PATH).replyWithError({
+ code: 'ENOTFOUND',
+ });
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ await sdk.detectResources({
+ detectors: [awsEc2Detector],
+ });
+ const resource: Resource = sdk['_resource'];
+ assert.ok(resource);
+ assert.deepStrictEqual(resource, Resource.createTelemetrySDKResource());
+
+ scope.done();
+ });
+ });
+
+ describe('with a buggy detector', () => {
+ it('returns a merged resource', async () => {
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ const stub = Sinon.stub(awsEc2Detector, 'detect').throws();
+ await sdk.detectResources();
+ const resource = sdk['_resource'];
+
+ assertServiceResource(resource, {
+ instanceId: '627cc493',
+ name: 'my-service',
+ namespace: 'default',
+ version: '0.0.1',
+ });
+
+ stub.restore();
+ });
+ });
+
+ describe('with a debug logger', () => {
+ // Local functions to test if a mocked method is ever called with a specific argument or regex matching for an argument.
+ // Needed because of race condition with parallel detectors.
+ const callArgsContains = (
+ mockedFunction: sinon.SinonSpy,
+ arg: any
+ ): boolean => {
+ return mockedFunction.getCalls().some(call => {
+ return call.args.some(callarg => arg === callarg);
+ });
+ };
+ const callArgsMatches = (
+ mockedFunction: sinon.SinonSpy,
+ regex: RegExp
+ ): boolean => {
+ return mockedFunction.getCalls().some(call => {
+ return regex.test(call.args.toString());
+ });
+ };
+
+ it('prints detected resources and debug messages to the logger', async () => {
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ // This test depends on the env detector to be functioning as intended
+ const mockedLoggerMethod = Sinon.fake();
+ await sdk.detectResources({
+ logger: {
+ debug: mockedLoggerMethod,
+ info: Sinon.fake(),
+ warn: Sinon.fake(),
+ error: Sinon.fake(),
+ },
+ });
+
+ // Test for AWS and GCP Detector failure
+ assert.ok(
+ callArgsContains(
+ mockedLoggerMethod,
+ 'GcpDetector failed: GCP Metadata unavailable.'
+ )
+ );
+ assert.ok(
+ callArgsContains(
+ mockedLoggerMethod,
+ 'AwsEc2Detector failed: Nock: Disallowed net connect for "169.254.169.254:80/latest/api/token"'
+ )
+ );
+ // Test that the Env Detector successfully found its resource and populated it with the right values.
+ assert.ok(
+ callArgsContains(mockedLoggerMethod, 'EnvDetector found resource.')
+ );
+ // Regex formatting accounts for whitespace variations in util.inspect output over different node versions
+ assert.ok(
+ callArgsMatches(
+ mockedLoggerMethod,
+ /{\s+'service\.instance\.id':\s+'627cc493',\s+'service\.name':\s+'my-service',\s+'service\.namespace':\s+'default',\s+'service\.version':\s+'0\.0\.1'\s+}\s*/
+ )
+ );
+ });
+
+ describe('with missing environment variable', () => {
+ beforeEach(() => {
+ delete process.env.OTEL_RESOURCE_ATTRIBUTES;
+ });
+
+ it('prints correct error messages when EnvDetector has no env variable', async () => {
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ const mockedLoggerMethod = Sinon.fake();
+ await sdk.detectResources({
+ logger: {
+ debug: mockedLoggerMethod,
+ info: Sinon.fake(),
+ warn: Sinon.fake(),
+ error: Sinon.fake(),
+ },
+ });
+
+ assert.ok(
+ callArgsContains(
+ mockedLoggerMethod,
+ 'EnvDetector failed: Environment variable "OTEL_RESOURCE_ATTRIBUTES" is missing.'
+ )
+ );
+ });
+ });
+
+ describe('with a faulty environment variable', () => {
+ beforeEach(() => {
+ process.env.OTEL_RESOURCE_ATTRIBUTES = 'bad=~attribute';
+ });
+
+ it('prints correct error messages when EnvDetector has an invalid variable', async () => {
+ const sdk = new NodeSDK({
+ autoDetectResources: true,
+ });
+ const mockedLoggerMethod = Sinon.fake();
+ await sdk.detectResources({
+ logger: {
+ debug: mockedLoggerMethod,
+ info: Sinon.fake(),
+ warn: Sinon.fake(),
+ error: Sinon.fake(),
+ },
+ });
+
+ assert.ok(
+ callArgsContains(
+ mockedLoggerMethod,
+ 'EnvDetector failed: Attribute value should be a ASCII string with a length not exceed 255 characters.'
+ )
+ );
+ });
+ });
+ });
+ });
});