Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resource auto detection logging #1211

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,63 @@
import { Resource } from '../../Resource';
import { envDetector, awsEc2Detector, gcpDetector } from './detectors';
import { Detector } from '../../types';
import { ResourceDetectionConfig } from '../../config';
import { Logger } from '@opentelemetry/api';
import * as util from 'util';

const DETECTORS: Array<Detector> = [envDetector, awsEc2Detector, gcpDetector];

/**
* Runs all resource detectors and returns the results merged into a single
* Resource.
*
* @param config Configuration object for resource detection
*/
export const detectResources = async (): Promise<Resource> => {
export const detectResources = async (
config: ResourceDetectionConfig = {}
): Promise<Resource> => {
const resources: Array<Resource> = await Promise.all(
DETECTORS.map(d => {
try {
return d.detect();
return d.detect(config);
} catch {
return Resource.empty();
}
})
);
logResources(config.logger, resources);
adamegyed marked this conversation as resolved.
Show resolved Hide resolved
return resources.reduce(
(acc, resource) => acc.merge(resource),
Resource.createTelemetrySDKResource()
);
};

/**
* Writes debug information about the detected resources to the logger defined in the resource detection config, if one is provided.
*
* @param logger The logger to write the debug information to.
* @param resources The array of resources that should be logged. Empty entried will be ignored.
*/
const logResources = (
logger: Logger | undefined,
adamegyed marked this conversation as resolved.
Show resolved Hide resolved
resources: Array<Resource>
) => {
if (logger) {
adamegyed marked this conversation as resolved.
Show resolved Hide resolved
resources.forEach((resource, index) => {
adamegyed marked this conversation as resolved.
Show resolved Hide resolved
// Only print populated resources
adamegyed marked this conversation as resolved.
Show resolved Hide resolved
if (Object.keys(resource.labels).length > 0) {
const resourceDebugString = util.inspect(resource.labels, {
depth: 2,
breakLength: Infinity,
sorted: true,
compact: false,
});
const detectorName = DETECTORS[index].constructor
? DETECTORS[index].constructor.name
: 'Unknown detector';
logger.debug(`${detectorName} found resource.`);
logger.debug(resourceDebugString);
}
});
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import * as http from 'http';
import { Resource } from '../../../Resource';
import { CLOUD_RESOURCE, HOST_RESOURCE } from '../../../constants';
import { Detector } from '../../../types';
import { ResourceDetectionConfig } from '../../../config';

/**
* The AwsEc2Detector can be used to detect if a process is running in AWS EC2
Expand All @@ -39,7 +40,7 @@ class AwsEc2Detector implements Detector {
* empty {@link Resource} if the connection or parsing of the identity
* document fails.
*/
async detect(): Promise<Resource> {
async detect(config: ResourceDetectionConfig = {}): Promise<Resource> {
try {
const {
accountId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import { Resource } from '../../../Resource';
import { Detector, ResourceLabels } from '../../../types';
import { ResourceDetectionConfig } from '../../../config';

/**
* EnvDetector can be used to detect the presence of and create a Resource
Expand Down Expand Up @@ -46,7 +47,7 @@ class EnvDetector implements Detector {
* OTEL_RESOURCE_LABELS environment variable. Note this is an async function
* to conform to the Detector interface.
*/
async detect(): Promise<Resource> {
async detect(config: ResourceDetectionConfig = {}): Promise<Resource> {
try {
const labelString = process.env.OTEL_RESOURCE_LABELS;
if (!labelString) return Resource.empty();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ import {
K8S_RESOURCE,
CONTAINER_RESOURCE,
} from '../../../constants';
import { ResourceDetectionConfig } from '../../../config';

/**
* The GcpDetector can be used to detect if a process is running in the Google
* Cloud Platofrm and return a {@link Resource} populated with metadata about
* the instance. Returns an empty Resource if detection fails.
*/
class GcpDetector implements Detector {
async detect(): Promise<Resource> {
async detect(config: ResourceDetectionConfig = {}): Promise<Resource> {
if (!(await gcpMetadata.isAvailable())) return Resource.empty();

const [projectId, instanceId, zoneId, clusterName] = await Promise.all([
Expand Down
3 changes: 2 additions & 1 deletion packages/opentelemetry-resources/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/

import { Resource } from './Resource';
import { ResourceDetectionConfig } from './config';

/** Interface for Resource labels */
export interface ResourceLabels {
Expand All @@ -26,5 +27,5 @@ export interface ResourceLabels {
* a detector returns a Promise containing a Resource.
*/
export interface Detector {
detect(): Promise<Resource>;
detect(config?: ResourceDetectionConfig): Promise<Resource>;
}
23 changes: 23 additions & 0 deletions packages/opentelemetry-resources/test/detect-resources.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import * as nock from 'nock';
import * as sinon from 'sinon';
import * as assert from 'assert';
import { URL } from 'url';
import { Resource, detectResources } from '../src';
import { awsEc2Detector } from '../src/platform/node/detectors';
Expand Down Expand Up @@ -162,4 +163,26 @@ describe('detectResources', async () => {
stub.restore();
});
});

describe('with a debug logger', () => {
it('prints detected resources 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(),
},
});

assert.deepStrictEqual(mockedLoggerMethod.getCall(0).args, [
'EnvDetector found resource.',
]);
assert.deepStrictEqual(mockedLoggerMethod.getCall(1).args, [
"{\n 'service.instance.id': '627cc493',\n 'service.name': 'my-service',\n 'service.namespace': 'default',\n 'service.version': '0.0.1'\n}",
]);
});
});
});