Skip to content

Commit 167dced

Browse files
authored
feat(detector-aws): add sync version for all detectors (#2376)
1 parent 8b32219 commit 167dced

22 files changed

+2108
-769
lines changed

detectors/node/opentelemetry-resource-detector-aws/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
},
5757
"dependencies": {
5858
"@opentelemetry/core": "^1.0.0",
59-
"@opentelemetry/resources": "^1.0.0",
59+
"@opentelemetry/resources": "^1.10.0",
6060
"@opentelemetry/semantic-conventions": "^1.22.0"
6161
},
6262
"homepage": "https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/detectors/node/opentelemetry-resource-detector-aws#readme"

detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsBeanstalkDetector.ts

Lines changed: 7 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,13 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { diag } from '@opentelemetry/api';
1817
import {
1918
Detector,
20-
Resource,
19+
IResource,
2120
ResourceDetectionConfig,
2221
} from '@opentelemetry/resources';
23-
import {
24-
SEMRESATTRS_CLOUD_PROVIDER,
25-
SEMRESATTRS_CLOUD_PLATFORM,
26-
SEMRESATTRS_SERVICE_NAME,
27-
SEMRESATTRS_SERVICE_NAMESPACE,
28-
SEMRESATTRS_SERVICE_VERSION,
29-
SEMRESATTRS_SERVICE_INSTANCE_ID,
30-
CLOUDPROVIDERVALUES_AWS,
31-
CLOUDPLATFORMVALUES_AWS_ELASTIC_BEANSTALK,
32-
} from '@opentelemetry/semantic-conventions';
33-
import * as fs from 'fs';
34-
import * as util from 'util';
22+
23+
import { awsBeanstalkDetectorSync } from './AwsBeanstalkDetectorSync';
3524

3625
/**
3726
* The AwsBeanstalkDetector can be used to detect if a process is running in AWS Elastic
@@ -40,51 +29,13 @@ import * as util from 'util';
4029
*
4130
* See https://docs.amazonaws.cn/en_us/xray/latest/devguide/xray-guide.pdf
4231
* for more details about detecting information of Elastic Beanstalk plugins
32+
*
33+
* @deprecated Use {@link AwsBeanstalkDetectorSync} class instead.
4334
*/
4435

45-
const DEFAULT_BEANSTALK_CONF_PATH =
46-
'/var/elasticbeanstalk/xray/environment.conf';
47-
const WIN_OS_BEANSTALK_CONF_PATH =
48-
'C:\\Program Files\\Amazon\\XRay\\environment.conf';
49-
5036
export class AwsBeanstalkDetector implements Detector {
51-
BEANSTALK_CONF_PATH: string;
52-
private static readFileAsync = util.promisify(fs.readFile);
53-
private static fileAccessAsync = util.promisify(fs.access);
54-
55-
constructor() {
56-
if (process.platform === 'win32') {
57-
this.BEANSTALK_CONF_PATH = WIN_OS_BEANSTALK_CONF_PATH;
58-
} else {
59-
this.BEANSTALK_CONF_PATH = DEFAULT_BEANSTALK_CONF_PATH;
60-
}
61-
}
62-
63-
async detect(_config?: ResourceDetectionConfig): Promise<Resource> {
64-
try {
65-
await AwsBeanstalkDetector.fileAccessAsync(
66-
this.BEANSTALK_CONF_PATH,
67-
fs.constants.R_OK
68-
);
69-
70-
const rawData = await AwsBeanstalkDetector.readFileAsync(
71-
this.BEANSTALK_CONF_PATH,
72-
'utf8'
73-
);
74-
const parsedData = JSON.parse(rawData);
75-
76-
return new Resource({
77-
[SEMRESATTRS_CLOUD_PROVIDER]: CLOUDPROVIDERVALUES_AWS,
78-
[SEMRESATTRS_CLOUD_PLATFORM]: CLOUDPLATFORMVALUES_AWS_ELASTIC_BEANSTALK,
79-
[SEMRESATTRS_SERVICE_NAME]: CLOUDPLATFORMVALUES_AWS_ELASTIC_BEANSTALK,
80-
[SEMRESATTRS_SERVICE_NAMESPACE]: parsedData.environment_name,
81-
[SEMRESATTRS_SERVICE_VERSION]: parsedData.version_label,
82-
[SEMRESATTRS_SERVICE_INSTANCE_ID]: parsedData.deployment_id,
83-
});
84-
} catch (e: any) {
85-
diag.debug(`AwsBeanstalkDetector failed: ${e.message}`);
86-
return Resource.empty();
87-
}
37+
detect(config?: ResourceDetectionConfig): Promise<IResource> {
38+
return Promise.resolve(awsBeanstalkDetectorSync.detect(config));
8839
}
8940
}
9041

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { diag } from '@opentelemetry/api';
18+
import {
19+
DetectorSync,
20+
IResource,
21+
Resource,
22+
ResourceAttributes,
23+
ResourceDetectionConfig,
24+
} from '@opentelemetry/resources';
25+
import {
26+
SEMRESATTRS_CLOUD_PROVIDER,
27+
SEMRESATTRS_CLOUD_PLATFORM,
28+
SEMRESATTRS_SERVICE_NAME,
29+
SEMRESATTRS_SERVICE_NAMESPACE,
30+
SEMRESATTRS_SERVICE_VERSION,
31+
SEMRESATTRS_SERVICE_INSTANCE_ID,
32+
CLOUDPROVIDERVALUES_AWS,
33+
CLOUDPLATFORMVALUES_AWS_ELASTIC_BEANSTALK,
34+
} from '@opentelemetry/semantic-conventions';
35+
import * as fs from 'fs';
36+
import * as util from 'util';
37+
38+
/**
39+
* The AwsBeanstalkDetector can be used to detect if a process is running in AWS Elastic
40+
* Beanstalk and return a {@link Resource} populated with data about the beanstalk
41+
* plugins of AWS X-Ray. Returns an empty Resource if detection fails.
42+
*
43+
* See https://docs.amazonaws.cn/en_us/xray/latest/devguide/xray-guide.pdf
44+
* for more details about detecting information of Elastic Beanstalk plugins
45+
*/
46+
47+
const DEFAULT_BEANSTALK_CONF_PATH =
48+
'/var/elasticbeanstalk/xray/environment.conf';
49+
const WIN_OS_BEANSTALK_CONF_PATH =
50+
'C:\\Program Files\\Amazon\\XRay\\environment.conf';
51+
52+
export class AwsBeanstalkDetectorSync implements DetectorSync {
53+
BEANSTALK_CONF_PATH: string;
54+
private static readFileAsync = util.promisify(fs.readFile);
55+
private static fileAccessAsync = util.promisify(fs.access);
56+
57+
constructor() {
58+
if (process.platform === 'win32') {
59+
this.BEANSTALK_CONF_PATH = WIN_OS_BEANSTALK_CONF_PATH;
60+
} else {
61+
this.BEANSTALK_CONF_PATH = DEFAULT_BEANSTALK_CONF_PATH;
62+
}
63+
}
64+
65+
detect(config?: ResourceDetectionConfig): IResource {
66+
return new Resource({}, this._getAttributes());
67+
}
68+
69+
/**
70+
* Attempts to obtain AWS Beanstalk configuration from the file
71+
* system. If file is accesible and read succesfully it returns
72+
* a promise containing a {@link ResourceAttributes}
73+
* object with instance metadata. Returns a promise containing an
74+
* empty {@link ResourceAttributes} if the file is not accesible or
75+
* fails in the reading process.
76+
*/
77+
async _getAttributes(
78+
_config?: ResourceDetectionConfig
79+
): Promise<ResourceAttributes> {
80+
try {
81+
await AwsBeanstalkDetectorSync.fileAccessAsync(
82+
this.BEANSTALK_CONF_PATH,
83+
fs.constants.R_OK
84+
);
85+
86+
const rawData = await AwsBeanstalkDetectorSync.readFileAsync(
87+
this.BEANSTALK_CONF_PATH,
88+
'utf8'
89+
);
90+
const parsedData = JSON.parse(rawData);
91+
92+
return {
93+
[SEMRESATTRS_CLOUD_PROVIDER]: CLOUDPROVIDERVALUES_AWS,
94+
[SEMRESATTRS_CLOUD_PLATFORM]: CLOUDPLATFORMVALUES_AWS_ELASTIC_BEANSTALK,
95+
[SEMRESATTRS_SERVICE_NAME]: CLOUDPLATFORMVALUES_AWS_ELASTIC_BEANSTALK,
96+
[SEMRESATTRS_SERVICE_NAMESPACE]: parsedData.environment_name,
97+
[SEMRESATTRS_SERVICE_VERSION]: parsedData.version_label,
98+
[SEMRESATTRS_SERVICE_INSTANCE_ID]: parsedData.deployment_id,
99+
};
100+
} catch (e: any) {
101+
diag.debug(`AwsBeanstalkDetectorSync failed: ${e.message}`);
102+
return {};
103+
}
104+
}
105+
}
106+
107+
export const awsBeanstalkDetectorSync = new AwsBeanstalkDetectorSync();

detectors/node/opentelemetry-resource-detector-aws/src/detectors/AwsEc2Detector.ts

Lines changed: 8 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -16,149 +16,22 @@
1616

1717
import {
1818
Detector,
19-
Resource,
19+
IResource,
2020
ResourceDetectionConfig,
2121
} from '@opentelemetry/resources';
22-
import {
23-
SEMRESATTRS_CLOUD_PROVIDER,
24-
SEMRESATTRS_CLOUD_PLATFORM,
25-
SEMRESATTRS_CLOUD_REGION,
26-
SEMRESATTRS_CLOUD_ACCOUNT_ID,
27-
SEMRESATTRS_CLOUD_AVAILABILITY_ZONE,
28-
SEMRESATTRS_HOST_ID,
29-
SEMRESATTRS_HOST_TYPE,
30-
SEMRESATTRS_HOST_NAME,
31-
CLOUDPROVIDERVALUES_AWS,
32-
CLOUDPLATFORMVALUES_AWS_EC2,
33-
} from '@opentelemetry/semantic-conventions';
34-
import * as http from 'http';
22+
23+
import { awsEc2DetectorSync } from './AwsEc2DetectorSync';
3524

3625
/**
3726
* The AwsEc2Detector can be used to detect if a process is running in AWS EC2
3827
* and return a {@link Resource} populated with metadata about the EC2
39-
* instance. Returns an empty Resource if detection fails.
28+
* instance.
29+
*
30+
* @deprecated Use {@link AwsEc2DetectorSync} class instead.
4031
*/
4132
class AwsEc2Detector implements Detector {
42-
/**
43-
* See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html
44-
* for documentation about the AWS instance identity document
45-
* and standard of IMDSv2.
46-
*/
47-
readonly AWS_IDMS_ENDPOINT = '169.254.169.254';
48-
readonly AWS_INSTANCE_TOKEN_DOCUMENT_PATH = '/latest/api/token';
49-
readonly AWS_INSTANCE_IDENTITY_DOCUMENT_PATH =
50-
'/latest/dynamic/instance-identity/document';
51-
readonly AWS_INSTANCE_HOST_DOCUMENT_PATH = '/latest/meta-data/hostname';
52-
readonly AWS_METADATA_TTL_HEADER = 'X-aws-ec2-metadata-token-ttl-seconds';
53-
readonly AWS_METADATA_TOKEN_HEADER = 'X-aws-ec2-metadata-token';
54-
readonly MILLISECOND_TIME_OUT = 5000;
55-
56-
/**
57-
* Attempts to connect and obtain an AWS instance Identity document. If the
58-
* connection is successful it returns a promise containing a {@link Resource}
59-
* populated with instance metadata. Returns a promise containing an
60-
* empty {@link Resource} if the connection or parsing of the identity
61-
* document fails.
62-
*
63-
* @param config (unused) The resource detection config
64-
*/
65-
async detect(_config?: ResourceDetectionConfig): Promise<Resource> {
66-
const token = await this._fetchToken();
67-
const { accountId, instanceId, instanceType, region, availabilityZone } =
68-
await this._fetchIdentity(token);
69-
const hostname = await this._fetchHost(token);
70-
71-
return new Resource({
72-
[SEMRESATTRS_CLOUD_PROVIDER]: CLOUDPROVIDERVALUES_AWS,
73-
[SEMRESATTRS_CLOUD_PLATFORM]: CLOUDPLATFORMVALUES_AWS_EC2,
74-
[SEMRESATTRS_CLOUD_ACCOUNT_ID]: accountId,
75-
[SEMRESATTRS_CLOUD_REGION]: region,
76-
[SEMRESATTRS_CLOUD_AVAILABILITY_ZONE]: availabilityZone,
77-
[SEMRESATTRS_HOST_ID]: instanceId,
78-
[SEMRESATTRS_HOST_TYPE]: instanceType,
79-
[SEMRESATTRS_HOST_NAME]: hostname,
80-
});
81-
}
82-
83-
private async _fetchToken(): Promise<string> {
84-
const options = {
85-
host: this.AWS_IDMS_ENDPOINT,
86-
path: this.AWS_INSTANCE_TOKEN_DOCUMENT_PATH,
87-
method: 'PUT',
88-
timeout: this.MILLISECOND_TIME_OUT,
89-
headers: {
90-
[this.AWS_METADATA_TTL_HEADER]: '60',
91-
},
92-
};
93-
return await this._fetchString(options);
94-
}
95-
96-
private async _fetchIdentity(token: string): Promise<any> {
97-
const options = {
98-
host: this.AWS_IDMS_ENDPOINT,
99-
path: this.AWS_INSTANCE_IDENTITY_DOCUMENT_PATH,
100-
method: 'GET',
101-
timeout: this.MILLISECOND_TIME_OUT,
102-
headers: {
103-
[this.AWS_METADATA_TOKEN_HEADER]: token,
104-
},
105-
};
106-
const identity = await this._fetchString(options);
107-
return JSON.parse(identity);
108-
}
109-
110-
private async _fetchHost(token: string): Promise<string> {
111-
const options = {
112-
host: this.AWS_IDMS_ENDPOINT,
113-
path: this.AWS_INSTANCE_HOST_DOCUMENT_PATH,
114-
method: 'GET',
115-
timeout: this.MILLISECOND_TIME_OUT,
116-
headers: {
117-
[this.AWS_METADATA_TOKEN_HEADER]: token,
118-
},
119-
};
120-
return await this._fetchString(options);
121-
}
122-
123-
/**
124-
* Establishes an HTTP connection to AWS instance document url.
125-
* If the application is running on an EC2 instance, we should be able
126-
* to get back a valid JSON document. Parses that document and stores
127-
* the identity properties in a local map.
128-
*/
129-
private async _fetchString(options: http.RequestOptions): Promise<string> {
130-
return new Promise((resolve, reject) => {
131-
const timeoutId = setTimeout(() => {
132-
req.abort();
133-
reject(new Error('EC2 metadata api request timed out.'));
134-
}, this.MILLISECOND_TIME_OUT);
135-
136-
const req = http.request(options, res => {
137-
clearTimeout(timeoutId);
138-
const { statusCode } = res;
139-
res.setEncoding('utf8');
140-
let rawData = '';
141-
res.on('data', chunk => (rawData += chunk));
142-
res.on('end', () => {
143-
if (statusCode && statusCode >= 200 && statusCode < 300) {
144-
try {
145-
resolve(rawData);
146-
} catch (e) {
147-
reject(e);
148-
}
149-
} else {
150-
reject(
151-
new Error('Failed to load page, status code: ' + statusCode)
152-
);
153-
}
154-
});
155-
});
156-
req.on('error', err => {
157-
clearTimeout(timeoutId);
158-
reject(err);
159-
});
160-
req.end();
161-
});
33+
detect(_config?: ResourceDetectionConfig): Promise<IResource> {
34+
return Promise.resolve(awsEc2DetectorSync.detect(_config));
16235
}
16336
}
16437

0 commit comments

Comments
 (0)