From 11fb3095bcd72aad74c98fb652e12e84c9f5e79f Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Thu, 20 Feb 2020 08:56:44 -0800 Subject: [PATCH 1/6] Allow overriding environment and provide LocalEnvironment - adds LocalEnvironment - renames LambdaSink to ConsoleSink - short-circuits environment discovery if override is specified - adds environment override --- .../EnvironmentConfigurationProvider.ts | 12 +++ src/config/IConfiguration.ts | 12 +++ .../EnvironmentConfigurationProvider.test.ts | 36 +++++++ src/environment/EnvironmentDetector.ts | 41 ++++++- src/environment/Environments.ts | 9 ++ src/environment/LambdaEnvironment.ts | 4 +- src/environment/LocalEnvironment.ts | 62 +++++++++++ .../__tests__/LambdaEnvironment.test.ts | 4 +- .../__tests__/LocalEnvironment.test.ts | 101 ++++++++++++++++++ src/index.ts | 2 +- src/sinks/{LambdaSink.ts => ConsoleSink.ts} | 4 +- ...LambdaSink.test.ts => ConsoleSink.test.ts} | 4 +- 12 files changed, 277 insertions(+), 14 deletions(-) create mode 100644 src/environment/Environments.ts create mode 100644 src/environment/LocalEnvironment.ts create mode 100644 src/environment/__tests__/LocalEnvironment.test.ts rename src/sinks/{LambdaSink.ts => ConsoleSink.ts} (93%) rename src/sinks/__tests__/{LambdaSink.test.ts => ConsoleSink.test.ts} (83%) diff --git a/src/config/EnvironmentConfigurationProvider.ts b/src/config/EnvironmentConfigurationProvider.ts index f3b0f43..3e8e6ca 100644 --- a/src/config/EnvironmentConfigurationProvider.ts +++ b/src/config/EnvironmentConfigurationProvider.ts @@ -14,6 +14,7 @@ */ import { IConfiguration } from './IConfiguration'; +import Environments from "../environment/Environments"; const ENV_VAR_PREFIX = 'AWS_EMF'; @@ -24,6 +25,7 @@ enum ConfigKeys { SERVICE_NAME = 'SERVICE_NAME', SERVICE_TYPE = 'SERVICE_TYPE', AGENT_ENDPOINT = 'AGENT_ENDPOINT', + ENVIRONMENT_OVERRIDE = 'ENVIRONMENT' } export class EnvironmentConfigurationProvider { @@ -37,6 +39,7 @@ export class EnvironmentConfigurationProvider { this.getEnvVariable(ConfigKeys.SERVICE_NAME) || this.getEnvVariableWithoutPrefix(ConfigKeys.SERVICE_NAME), serviceType: this.getEnvVariable(ConfigKeys.SERVICE_TYPE) || this.getEnvVariableWithoutPrefix(ConfigKeys.SERVICE_TYPE), + environmentOverride: this.getEnvironmentOverride() }; } @@ -52,4 +55,13 @@ export class EnvironmentConfigurationProvider { const configValue = this.getEnvVariable(configKey); return !configValue ? fallback : configValue.toLowerCase() === 'true'; } + + getEnvironmentOverride(): Environments { + const overrideValue = this.getEnvVariable(ConfigKeys.ENVIRONMENT_OVERRIDE); + const environment = Environments[overrideValue as keyof typeof Environments]; + if (environment === undefined) { + return Environments.Unknown; + } + return environment; + } } diff --git a/src/config/IConfiguration.ts b/src/config/IConfiguration.ts index adc8abd..a8083af 100644 --- a/src/config/IConfiguration.ts +++ b/src/config/IConfiguration.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import Environments from "../environment/Environments"; + export interface IConfiguration { /** * Whether or not internal logging should be enabled. @@ -45,4 +47,14 @@ export interface IConfiguration { * The endpoint to use to connect to the CloudWatch Agent */ agentEndpoint: string | undefined; + + /** + * Environment override. This will short circuit auto-environment detection. + * Valid values include: + * - Local: no decoration and sends over stdout + * - Lambda: decorates logs with Lambda metadata and sends over stdout + * - Agent: no decoration and sends over TCP + * - EC2: decorates logs with EC2 metadata and sends over TCP + */ + environmentOverride: Environments | undefined; } diff --git a/src/config/__tests__/EnvironmentConfigurationProvider.test.ts b/src/config/__tests__/EnvironmentConfigurationProvider.test.ts index 461c24d..8882abc 100644 --- a/src/config/__tests__/EnvironmentConfigurationProvider.test.ts +++ b/src/config/__tests__/EnvironmentConfigurationProvider.test.ts @@ -1,4 +1,5 @@ import * as faker from 'faker'; +import Environments from '../../environment/Environments'; beforeEach(() => { jest.resetModules(); @@ -171,3 +172,38 @@ test('can set agent endpoint from environment', () => { const result = config.agentEndpoint; expect(result).toBe(expectedValue); }); + +test('can set environment override from environment', () => { + // arrange + const expectedValue = "Local" + process.env.AWS_EMF_ENVIRONMENT = expectedValue; + + // act + const config = getConfig(); + + // assert + const result = config.environmentOverride; + expect(result).toBe(Environments.Local); +}); + +test('if environment override is not set, default to unknown', () => { + // arrange + process.env.AWS_EMF_ENVIRONMENT = ""; + // act + const config = getConfig(); + + // assert + const result = config.environmentOverride; + expect(result).toBe(Environments.Unknown); +}); + +test('if environment override cannot be parsed, default to unknown', () => { + // arrange + process.env.AWS_EMF_ENVIRONMENT = faker.random.alphaNumeric(); + // act + const config = getConfig(); + + // assert + const result = config.environmentOverride; + expect(result).toBe(Environments.Unknown); +}); diff --git a/src/environment/EnvironmentDetector.ts b/src/environment/EnvironmentDetector.ts index dd3ac3f..36cec4b 100644 --- a/src/environment/EnvironmentDetector.ts +++ b/src/environment/EnvironmentDetector.ts @@ -18,18 +18,37 @@ import { DefaultEnvironment } from './DefaultEnvironment'; import { EC2Environment } from './EC2Environment'; import { IEnvironment } from './IEnvironment'; import { LambdaEnvironment } from './LambdaEnvironment'; +import config from '../config/Configuration'; +import Environments from './Environments'; +import { LocalEnvironment } from './LocalEnvironment'; type EnvironmentProvider = () => Promise; -const environments = [new LambdaEnvironment(), new EC2Environment()]; +const lambdaEnvironment = new LambdaEnvironment(); +const ec2Environment = new EC2Environment(); const defaultEnvironment = new DefaultEnvironment(); +const environments = [lambdaEnvironment, ec2Environment]; -let environment: IEnvironment | undefined; -const resolveEnvironment: EnvironmentProvider = async (): Promise => { - if (environment) { - return environment; +let environment : IEnvironment | undefined = defaultEnvironment; + +const getEnvironmentFromOverride = (): IEnvironment => { + // short-circuit environment detection and use override + switch (config.environmentOverride) { + case Environments.Agent: + return defaultEnvironment; + case Environments.EC2: + return ec2Environment; + case Environments.Lambda: + return lambdaEnvironment; + case Environments.Local: + return new LocalEnvironment(); + case Environments.Unknown: + default: + return defaultEnvironment; } +} +const discoverEnvironment = async (): Promise => { for (const envUnderTest of environments) { LOG(`Testing: ${envUnderTest.constructor.name}`); @@ -50,6 +69,18 @@ const resolveEnvironment: EnvironmentProvider = async (): Promise environment = defaultEnvironment; } + return environment; +} + +const resolveEnvironment: EnvironmentProvider = async (): Promise => { + if (environment) { + return environment; + } + + environment = (config.environmentOverride) + ? getEnvironmentFromOverride() + : await discoverEnvironment(); + LOG(`Using Environment: ${environment.constructor.name}`); return environment; diff --git a/src/environment/Environments.ts b/src/environment/Environments.ts new file mode 100644 index 0000000..5462782 --- /dev/null +++ b/src/environment/Environments.ts @@ -0,0 +1,9 @@ +enum Environments { + Local = "Local", + Lambda = "Lambda", + Agent = "Agent", + EC2 = "EC2", + Unknown = "" +}; + +export default Environments; \ No newline at end of file diff --git a/src/environment/LambdaEnvironment.ts b/src/environment/LambdaEnvironment.ts index ca87c2c..e53e98f 100644 --- a/src/environment/LambdaEnvironment.ts +++ b/src/environment/LambdaEnvironment.ts @@ -14,7 +14,7 @@ */ import { MetricsContext } from '../logger/MetricsContext'; -import { LambdaSink } from '../sinks/LambdaSink'; +import { ConsoleSink } from '../sinks/ConsoleSink'; import { ISink } from '../sinks/Sink'; import { IEnvironment } from './IEnvironment'; @@ -51,7 +51,7 @@ export class LambdaEnvironment implements IEnvironment { public getSink(): ISink { if (!this.sink) { - this.sink = new LambdaSink(); + this.sink = new ConsoleSink(); } return this.sink; } diff --git a/src/environment/LocalEnvironment.ts b/src/environment/LocalEnvironment.ts new file mode 100644 index 0000000..cc66f56 --- /dev/null +++ b/src/environment/LocalEnvironment.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. + * 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. + */ + +import config from '../config/Configuration'; +import { ISink } from '../sinks/Sink'; +import { LOG } from '../utils/Logger'; +import { IEnvironment } from './IEnvironment'; +import { ConsoleSink } from '../sinks/ConsoleSink'; + +export class LocalEnvironment implements IEnvironment { + private sink: ISink | undefined; + + public probe(): Promise { + // probe is not intended to be used in the LocalEnvironment + // To use the local environment you should set the environment + // override + return Promise.resolve(false); + } + + public getName(): string { + if (!config.serviceName) { + LOG('Unknown ServiceName.'); + return 'Unknown'; + } + return config.serviceName; + } + + public getType(): string { + if (!config.serviceType) { + LOG('Unknown ServiceType.'); + return 'Unknown'; + } + return config.serviceType; + } + + public getLogGroupName(): string { + return config.logGroupName ? config.logGroupName : `${this.getName()}-metrics`; + } + + public configureContext(): void { + // no-op + } + + public getSink(): ISink { + if (!this.sink) { + this.sink = new ConsoleSink(); + } + return this.sink; + } +} diff --git a/src/environment/__tests__/LambdaEnvironment.test.ts b/src/environment/__tests__/LambdaEnvironment.test.ts index 2c3e2c4..f9e6dff 100644 --- a/src/environment/__tests__/LambdaEnvironment.test.ts +++ b/src/environment/__tests__/LambdaEnvironment.test.ts @@ -51,9 +51,9 @@ test('getLogGroupName() returns function name', () => { expect(result).toBe(expectedName); }); -test('createSink() creates a LambdaSink', () => { +test('createSink() creates a ConsoleSink', () => { // arrange - const expectedSink = 'LambdaSink'; + const expectedSink = 'ConsoleSink'; const env = new LambdaEnvironment(); // act diff --git a/src/environment/__tests__/LocalEnvironment.test.ts b/src/environment/__tests__/LocalEnvironment.test.ts new file mode 100644 index 0000000..09410e1 --- /dev/null +++ b/src/environment/__tests__/LocalEnvironment.test.ts @@ -0,0 +1,101 @@ +import * as faker from 'faker'; +import config from '../../config/Configuration'; +import { LocalEnvironment } from '../LocalEnvironment'; + +test('probe() always returns false', async () => { + // arrange + const env = new LocalEnvironment(); + + // act + const result = await env.probe(); + + // assert + expect(result).toBe(false); +}); + +test('getName() returns "Unknown" if not specified', () => { + // arrange + const env = new LocalEnvironment(); + + // act + const result = env.getName(); + + // assert + expect(result).toBe('Unknown'); +}); + +test('getType() returns "Unknown" if not specified', () => { + // arrange + const env = new LocalEnvironment(); + + // act + const result = env.getType(); + + // assert + expect(result).toBe('Unknown'); +}); + +test('getName() returns name if configured', () => { + // arrange + const expectedName = faker.random.word(); + config.serviceName = expectedName; + const env = new LocalEnvironment(); + + // act + const result = env.getName(); + + // assert + expect(result).toBe(expectedName); +}); + +test('getType() returns type if configured', () => { + // arrange + const expectedType = faker.random.word(); + config.serviceType = expectedType; + const env = new LocalEnvironment(); + + // act + const result = env.getType(); + + // assert + expect(result).toBe(expectedType); +}); + +test('getLogGroupName() returns logGroup if configured', () => { + // arrange + const name = faker.random.word(); + config.logGroupName = name; + const env = new LocalEnvironment(); + + // act + const result = env.getLogGroupName(); + + // assert + expect(result).toBe(name); +}); + +test('getLogGroupName() returns -metrics if not configured', () => { + // arrange + const serviceName = faker.random.word(); + config.logGroupName = undefined; + config.serviceName = serviceName; + const env = new LocalEnvironment(); + + // act + const result = env.getLogGroupName(); + + // assert + expect(result).toBe(`${serviceName}-metrics`); +}); + +test('getSink() creates a ConsoleSink', () => { + // arrange + const expectedSink = 'ConsoleSink'; + const env = new LocalEnvironment(); + + // act + const sink = env.getSink(); + + // assert + expect(sink.name).toBe(expectedSink); +}); diff --git a/src/index.ts b/src/index.ts index d6f0bb9..883c260 100644 --- a/src/index.ts +++ b/src/index.ts @@ -14,7 +14,7 @@ */ export { MetricsLogger } from './logger/MetricsLogger'; -export { LambdaSink } from './sinks/LambdaSink'; +export { ConsoleSink as LocalSink } from './sinks/ConsoleSink'; export { AgentSink } from './sinks/AgentSink'; export { metricScope } from './logger/MetricScope'; export { createMetricsLogger } from './logger/MetricsLoggerFactory'; diff --git a/src/sinks/LambdaSink.ts b/src/sinks/ConsoleSink.ts similarity index 93% rename from src/sinks/LambdaSink.ts rename to src/sinks/ConsoleSink.ts index ff981bc..59468de 100644 --- a/src/sinks/LambdaSink.ts +++ b/src/sinks/ConsoleSink.ts @@ -22,8 +22,8 @@ import { ISink } from './Sink'; * A sink that flushes log data to stdout. * This is the preferred sink for Lambda functions. */ -export class LambdaSink implements ISink { - public readonly name: string = 'LambdaSink'; +export class ConsoleSink implements ISink { + public readonly name: string = 'ConsoleSink'; private serializer: ISerializer; diff --git a/src/sinks/__tests__/LambdaSink.test.ts b/src/sinks/__tests__/ConsoleSink.test.ts similarity index 83% rename from src/sinks/__tests__/LambdaSink.test.ts rename to src/sinks/__tests__/ConsoleSink.test.ts index 33f8350..00a3454 100644 --- a/src/sinks/__tests__/LambdaSink.test.ts +++ b/src/sinks/__tests__/ConsoleSink.test.ts @@ -1,6 +1,6 @@ import * as faker from 'faker'; import { MetricsContext } from '../../logger/MetricsContext'; -import { LambdaSink } from '../LambdaSink'; +import { ConsoleSink } from '../ConsoleSink'; beforeEach(() => { console.log = jest.fn(); @@ -13,7 +13,7 @@ test('accept serializes and writes result to stdout', () => { serialize: jest.fn(() => expected), }; - const sink = new LambdaSink(serializer); + const sink = new ConsoleSink(serializer); // act sink.accept(MetricsContext.empty()); From c75318243d30f8928069ea6a95fbc7a196488c4e Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Fri, 21 Feb 2020 21:04:14 -0800 Subject: [PATCH 2/6] ensure environment resolution only happens once --- src/environment/EnvironmentDetector.ts | 45 ++++++++++--------- .../__tests__/EnvironmentDetector.test.ts | 8 ++-- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/environment/EnvironmentDetector.ts b/src/environment/EnvironmentDetector.ts index 36cec4b..e3b8269 100644 --- a/src/environment/EnvironmentDetector.ts +++ b/src/environment/EnvironmentDetector.ts @@ -52,46 +52,47 @@ const discoverEnvironment = async (): Promise => { for (const envUnderTest of environments) { LOG(`Testing: ${envUnderTest.constructor.name}`); - let isEnvironment = false; try { - isEnvironment = await envUnderTest.probe(); + if (await envUnderTest.probe()) { + return envUnderTest; + } } catch (e) { LOG(`Failed probe: ${envUnderTest.constructor.name}`); } - - if (isEnvironment) { - environment = envUnderTest; - break; - } - } - - if (!environment) { - environment = defaultEnvironment; } - - return environment; + return defaultEnvironment; } -const resolveEnvironment: EnvironmentProvider = async (): Promise => { +const _resolveEnvironment: EnvironmentProvider = async (): Promise => { + console.log('resolvingenvion') if (environment) { return environment; } - environment = (config.environmentOverride) - ? getEnvironmentFromOverride() - : await discoverEnvironment(); + let detectedEnvironment = undefined; + if (config.environmentOverride) { + detectedEnvironment = getEnvironmentFromOverride(); + } - LOG(`Using Environment: ${environment.constructor.name}`); - + detectedEnvironment = await discoverEnvironment(); + environment = detectedEnvironment; // eslint-disable-line require-atomic-updates return environment; }; -const resetEnvironment = (): void => (environment = undefined); + // pro-actively begin resolving the environment // this will allow us to kick off any async tasks // at module load time to reduce any blocking that // may occur on the initial flush() -resolveEnvironment(); +const environmentPromise = _resolveEnvironment(); +const resolveEnvironment: EnvironmentProvider = async (): Promise => { + return environmentPromise; +}; + +const cleanResolveEnvironment = async (): Promise => { + environment = undefined; + return await _resolveEnvironment(); +}; -export { EnvironmentProvider, resolveEnvironment, resetEnvironment }; +export { EnvironmentProvider, resolveEnvironment, cleanResolveEnvironment }; diff --git a/src/environment/__tests__/EnvironmentDetector.test.ts b/src/environment/__tests__/EnvironmentDetector.test.ts index f6af77e..24a0a4f 100644 --- a/src/environment/__tests__/EnvironmentDetector.test.ts +++ b/src/environment/__tests__/EnvironmentDetector.test.ts @@ -1,10 +1,8 @@ import * as faker from 'faker'; -import { resetEnvironment, resolveEnvironment } from '../EnvironmentDetector'; +import { cleanResolveEnvironment } from '../EnvironmentDetector'; beforeEach(() => { process.env = {}; - resetEnvironment(); - jest.resetModules(); }); test('resolveEnvironment() returns LambdaEnvironment if AWS_LAMBDA_FUNCTION_NAME specified', async () => { @@ -12,7 +10,7 @@ test('resolveEnvironment() returns LambdaEnvironment if AWS_LAMBDA_FUNCTION_NAME process.env.AWS_LAMBDA_FUNCTION_NAME = faker.random.word(); // act - const result = await resolveEnvironment(); + const result = await cleanResolveEnvironment(); // assert expect(result.constructor.name).toBe('LambdaEnvironment'); @@ -21,7 +19,7 @@ test('resolveEnvironment() returns LambdaEnvironment if AWS_LAMBDA_FUNCTION_NAME test('resolveEnvironment() returns DefaultEnvironment if nothing else was detected', async () => { // arrange // act - const result = await resolveEnvironment(); + const result = await cleanResolveEnvironment(); // assert expect(result.constructor.name).toBe('DefaultEnvironment'); From 3f796cc1eafb5ed314b71868439e75ab9a643d76 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Fri, 21 Feb 2020 21:16:14 -0800 Subject: [PATCH 3/6] update documentation --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/README.md b/README.md index ce7876c..d0b8c0d 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,52 @@ Configuration.logStreamName = "LogStreamName"; AWS_EMF_LOG_STREAM_NAME=LogStreamName ``` +**AgentEndpoint**: For agent-based platforms, you may optionally configure the endpoint to reach the agent on. + +Example: + +```js +// in process +const { Configuration } = require("aws-embedded-metrics"); +Configuration.agentEndpoint = "udp://127.0.0.1:1000"; + +// environment +AWS_EMF_AGENT_ENDPOINT="udp://127.0.0.1:1000" +``` + +**EnvironmentOverride**: Short circuit auto-environment detection by explicitly defining how events should be sent. + +Valid values include: + +- Local: no decoration and sends over stdout +- Lambda: decorates logs with Lambda metadata and sends over stdout +- Agent: no decoration and sends over TCP +- EC2: decorates logs with EC2 metadata and sends over TCP + +Example: + +```js +// in process +const { Configuration } = require("aws-embedded-metrics"); +Configuration.environmentOverride = "Local"; + +// environment +AWS_EMF_AGENT_ENDPOINT=Local +``` + +**EnableDebugLogging**: Enable debug logging for the library. If the library is not behaving as expected, you can set this to true to log to console. + +Example: + +```js +// in process +const { Configuration } = require("aws-embedded-metrics"); +Configuration.debuggingLoggingEnabled = true; + +// environment +AWS_EMF_ENABLE_DEBUG_LOGGING=true +``` + ## Examples Check out the [examples](https://github.com/awslabs/aws-embedded-metrics-node/tree/master/examples) directory to get started. From 731def16a91327d01357ee36eec32cc69b349223 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Fri, 21 Feb 2020 21:25:27 -0800 Subject: [PATCH 4/6] add environment detection tests and fix cache issue --- src/environment/EnvironmentDetector.ts | 9 ++++----- .../__tests__/EnvironmentDetector.test.ts | 13 +++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/environment/EnvironmentDetector.ts b/src/environment/EnvironmentDetector.ts index e3b8269..d420e04 100644 --- a/src/environment/EnvironmentDetector.ts +++ b/src/environment/EnvironmentDetector.ts @@ -64,18 +64,17 @@ const discoverEnvironment = async (): Promise => { } const _resolveEnvironment: EnvironmentProvider = async (): Promise => { - console.log('resolvingenvion') if (environment) { return environment; } - let detectedEnvironment = undefined; if (config.environmentOverride) { - detectedEnvironment = getEnvironmentFromOverride(); + LOG("Environment override supplied", config.environmentOverride); + environment = getEnvironmentFromOverride(); + return environment; } - detectedEnvironment = await discoverEnvironment(); - environment = detectedEnvironment; // eslint-disable-line require-atomic-updates + environment = await discoverEnvironment(); // eslint-disable-line require-atomic-updates return environment; }; diff --git a/src/environment/__tests__/EnvironmentDetector.test.ts b/src/environment/__tests__/EnvironmentDetector.test.ts index 24a0a4f..ef3a75a 100644 --- a/src/environment/__tests__/EnvironmentDetector.test.ts +++ b/src/environment/__tests__/EnvironmentDetector.test.ts @@ -1,5 +1,7 @@ import * as faker from 'faker'; import { cleanResolveEnvironment } from '../EnvironmentDetector'; +import config from '../../config/Configuration'; +import Environments from '../Environments'; beforeEach(() => { process.env = {}; @@ -24,3 +26,14 @@ test('resolveEnvironment() returns DefaultEnvironment if nothing else was detect // assert expect(result.constructor.name).toBe('DefaultEnvironment'); }, 10000); + +test('resolveEnvironment() honors configured override', async () => { + // arrange + config.environmentOverride = Environments.Local; + + // act + const result = await cleanResolveEnvironment(); + + // assert + expect(result.constructor.name).toBe('LocalEnvironment'); +}); \ No newline at end of file From 6fbfdf216132e47bd04bb956cde07e84ef083787 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Fri, 21 Feb 2020 21:30:09 -0800 Subject: [PATCH 5/6] if invalid environment configured, fallback to discovery --- src/environment/EnvironmentDetector.ts | 14 ++++++++++---- .../__tests__/EnvironmentDetector.test.ts | 13 +++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/environment/EnvironmentDetector.ts b/src/environment/EnvironmentDetector.ts index d420e04..769030d 100644 --- a/src/environment/EnvironmentDetector.ts +++ b/src/environment/EnvironmentDetector.ts @@ -31,7 +31,7 @@ const environments = [lambdaEnvironment, ec2Environment]; let environment : IEnvironment | undefined = defaultEnvironment; -const getEnvironmentFromOverride = (): IEnvironment => { +const getEnvironmentFromOverride = (): IEnvironment | undefined => { // short-circuit environment detection and use override switch (config.environmentOverride) { case Environments.Agent: @@ -44,7 +44,7 @@ const getEnvironmentFromOverride = (): IEnvironment => { return new LocalEnvironment(); case Environments.Unknown: default: - return defaultEnvironment; + return undefined; } } @@ -70,8 +70,14 @@ const _resolveEnvironment: EnvironmentProvider = async (): Promise if (config.environmentOverride) { LOG("Environment override supplied", config.environmentOverride); - environment = getEnvironmentFromOverride(); - return environment; + // this will be falsy if an invalid configuration value is provided + environment = getEnvironmentFromOverride() + if (environment) { + return environment; + } + else { + LOG('Invalid environment provided. Falling back to auto-discovery.', config.environmentOverride); + } } environment = await discoverEnvironment(); // eslint-disable-line require-atomic-updates diff --git a/src/environment/__tests__/EnvironmentDetector.test.ts b/src/environment/__tests__/EnvironmentDetector.test.ts index ef3a75a..d68fb93 100644 --- a/src/environment/__tests__/EnvironmentDetector.test.ts +++ b/src/environment/__tests__/EnvironmentDetector.test.ts @@ -36,4 +36,17 @@ test('resolveEnvironment() honors configured override', async () => { // assert expect(result.constructor.name).toBe('LocalEnvironment'); +}); + +test('resolveEnvironment() ignores invalid override and falls back to discovery', async () => { + // arrange + // @ts-ignore + config.environmentOverride = "Invalid"; + process.env.AWS_LAMBDA_FUNCTION_NAME = faker.random.word(); + + // act + const result = await cleanResolveEnvironment(); + + // assert + expect(result.constructor.name).toBe('LambdaEnvironment'); }); \ No newline at end of file From 408faef4e9d995e72ffaf5e7ab0c84864f55f9f6 Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sat, 22 Feb 2020 09:28:03 -0800 Subject: [PATCH 6/6] docs(readme): add link to configuration section --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0b8c0d..6e9ea7d 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Generate CloudWatch Metrics embedded within structured log events. The embedded * [Installation](#installation) * [Usage](#usage) * [API](#api) +* [Configuration](#configuration) * [Examples](#examples) * [Development](#development) @@ -193,7 +194,7 @@ setNamespace("MyApplication"); Flushes the current MetricsContext to the configured sink and resets all properties, dimensions and metric values. The namespace and default dimensions will be preserved across flushes. -### Configuration +## Configuration All configuration values can be set using environment variables with the prefix (`AWS_EMF_`). Configuration should be performed as close to application start up as possible.