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 './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