feat: added AWS Beanstalk Plugins Resource Detector (#1385)
Co-authored-by: Daniel Dyla <dyladan@users.noreply.github.com>
This commit is contained in:
parent
b2eedfb04d
commit
2a8555f71b
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* 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,
|
||||
SERVICE_RESOURCE,
|
||||
ResourceDetectionConfigWithLogger,
|
||||
} from '@opentelemetry/resources';
|
||||
import * as fs from 'fs';
|
||||
import * as util from 'util';
|
||||
|
||||
/**
|
||||
* The AwsBeanstalkDetector can be used to detect if a process is running in AWS Elastic
|
||||
* Beanstalk and return a {@link Resource} populated with data about the beanstalk
|
||||
* plugins of AWS X-Ray. Returns an empty Resource if detection fails.
|
||||
*
|
||||
* See https://docs.amazonaws.cn/en_us/xray/latest/devguide/xray-guide.pdf
|
||||
* for more details about detecting information of Elastic Beanstalk plugins
|
||||
*/
|
||||
|
||||
const DEFAULT_BEANSTALK_CONF_PATH =
|
||||
'/var/elasticbeanstalk/xray/environment.conf';
|
||||
const WIN_OS_BEANSTALK_CONF_PATH =
|
||||
'C:\\Program Files\\Amazon\\XRay\\environment.conf';
|
||||
|
||||
export class AwsBeanstalkDetector implements Detector {
|
||||
BEANSTALK_CONF_PATH: string;
|
||||
private static readFileAsync = util.promisify(fs.readFile);
|
||||
private static fileAccessAsync = util.promisify(fs.access);
|
||||
|
||||
constructor() {
|
||||
if (process.platform === 'win32') {
|
||||
this.BEANSTALK_CONF_PATH = WIN_OS_BEANSTALK_CONF_PATH;
|
||||
} else {
|
||||
this.BEANSTALK_CONF_PATH = DEFAULT_BEANSTALK_CONF_PATH;
|
||||
}
|
||||
}
|
||||
|
||||
async detect(config: ResourceDetectionConfigWithLogger): Promise<Resource> {
|
||||
try {
|
||||
await AwsBeanstalkDetector.fileAccessAsync(
|
||||
this.BEANSTALK_CONF_PATH,
|
||||
fs.constants.R_OK
|
||||
);
|
||||
|
||||
const rawData = await AwsBeanstalkDetector.readFileAsync(
|
||||
this.BEANSTALK_CONF_PATH,
|
||||
'utf8'
|
||||
);
|
||||
const parsedData = JSON.parse(rawData);
|
||||
|
||||
return new Resource({
|
||||
[SERVICE_RESOURCE.NAME]: 'elastic_beanstalk',
|
||||
[SERVICE_RESOURCE.NAMESPACE]: parsedData.environment_name,
|
||||
[SERVICE_RESOURCE.VERSION]: parsedData.version_label,
|
||||
[SERVICE_RESOURCE.INSTANCE_ID]: parsedData.deployment_id,
|
||||
});
|
||||
} catch (e) {
|
||||
config.logger.debug(`AwsBeanstalkDetector failed: ${e.message}`);
|
||||
return Resource.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const awsBeanstalkDetector = new AwsBeanstalkDetector();
|
||||
|
|
@ -15,3 +15,4 @@
|
|||
*/
|
||||
|
||||
export * from './AwsEc2Detector';
|
||||
export * from './AwsBeanstalkDetector';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as sinon from 'sinon';
|
||||
import { awsBeanstalkDetector, AwsBeanstalkDetector } from '../../src';
|
||||
import {
|
||||
assertEmptyResource,
|
||||
assertServiceResource,
|
||||
} from '@opentelemetry/resources/test/util/resource-assertions';
|
||||
import { NoopLogger } from '@opentelemetry/core';
|
||||
|
||||
describe('BeanstalkResourceDetector', () => {
|
||||
const err = new Error('failed to read config file');
|
||||
const data = {
|
||||
version_label: 'app-5a56-170119_190650-stage-170119_190650',
|
||||
deployment_id: '32',
|
||||
environment_name: 'scorekeep',
|
||||
};
|
||||
const noisyData = {
|
||||
noise: 'noise',
|
||||
version_label: 'app-5a56-170119_190650-stage-170119_190650',
|
||||
deployment_id: '32',
|
||||
environment_name: 'scorekeep',
|
||||
};
|
||||
|
||||
let readStub, fileStub;
|
||||
let sandbox: sinon.SinonSandbox;
|
||||
|
||||
beforeEach(() => {
|
||||
sandbox = sinon.createSandbox();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
it('should successfully return resource data', async () => {
|
||||
fileStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'fileAccessAsync' as any)
|
||||
.resolves();
|
||||
readStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'readFileAsync' as any)
|
||||
.resolves(JSON.stringify(data));
|
||||
sandbox.stub(JSON, 'parse').returns(data);
|
||||
|
||||
const resource = await awsBeanstalkDetector.detect({
|
||||
logger: new NoopLogger(),
|
||||
});
|
||||
|
||||
sandbox.assert.calledOnce(fileStub);
|
||||
sandbox.assert.calledOnce(readStub);
|
||||
assert.ok(resource);
|
||||
assertServiceResource(resource, {
|
||||
name: 'elastic_beanstalk',
|
||||
namespace: 'scorekeep',
|
||||
version: 'app-5a56-170119_190650-stage-170119_190650',
|
||||
instanceId: '32',
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully return resource data with noise', async () => {
|
||||
fileStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'fileAccessAsync' as any)
|
||||
.resolves();
|
||||
readStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'readFileAsync' as any)
|
||||
.resolves(JSON.stringify(noisyData));
|
||||
sandbox.stub(JSON, 'parse').returns(noisyData);
|
||||
|
||||
const resource = await awsBeanstalkDetector.detect({
|
||||
logger: new NoopLogger(),
|
||||
});
|
||||
|
||||
sandbox.assert.calledOnce(fileStub);
|
||||
sandbox.assert.calledOnce(readStub);
|
||||
assert.ok(resource);
|
||||
assertServiceResource(resource, {
|
||||
name: 'elastic_beanstalk',
|
||||
namespace: 'scorekeep',
|
||||
version: 'app-5a56-170119_190650-stage-170119_190650',
|
||||
instanceId: '32',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return empty resource when failing to read file', async () => {
|
||||
fileStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'fileAccessAsync' as any)
|
||||
.resolves();
|
||||
readStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'readFileAsync' as any)
|
||||
.rejects(err);
|
||||
|
||||
const resource = await awsBeanstalkDetector.detect({
|
||||
logger: new NoopLogger(),
|
||||
});
|
||||
|
||||
sandbox.assert.calledOnce(fileStub);
|
||||
sandbox.assert.calledOnce(readStub);
|
||||
assert.ok(resource);
|
||||
assertEmptyResource(resource);
|
||||
});
|
||||
|
||||
it('should return empty resource when config file does not exist', async () => {
|
||||
fileStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'fileAccessAsync' as any)
|
||||
.rejects(err);
|
||||
readStub = sandbox
|
||||
.stub(AwsBeanstalkDetector, 'readFileAsync' as any)
|
||||
.resolves(JSON.stringify(data));
|
||||
|
||||
const resource = await awsBeanstalkDetector.detect({
|
||||
logger: new NoopLogger(),
|
||||
});
|
||||
|
||||
sandbox.assert.calledOnce(fileStub);
|
||||
sandbox.assert.notCalled(readStub);
|
||||
assert.ok(resource);
|
||||
assertEmptyResource(resource);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue