From 8c4663ca85dd21abf2e7f9ec8391d437c1ac988f Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sun, 29 Mar 2020 19:16:30 -0700 Subject: [PATCH 1/3] Docs: Move Configuration to top level in readme --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14d601e..8a33043 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) @@ -151,7 +152,7 @@ set_namespace("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. From b7d3e508b5e631677a07e6749f32b8e2240c81ad Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Sun, 29 Mar 2020 19:18:30 -0700 Subject: [PATCH 2/3] Add Environments enum --- aws_embedded_metrics/config/configuration.py | 4 ++++ .../config/environment_configuration_provider.py | 13 +++++++++++++ aws_embedded_metrics/environment/environments.py | 9 +++++++++ setup.py | 2 +- 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 aws_embedded_metrics/environment/environments.py diff --git a/aws_embedded_metrics/config/configuration.py b/aws_embedded_metrics/config/configuration.py index e97911c..b7be587 100644 --- a/aws_embedded_metrics/config/configuration.py +++ b/aws_embedded_metrics/config/configuration.py @@ -11,6 +11,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +from aws_embedded_metrics.environment.environments import Environments + class Configuration: def __init__( @@ -22,6 +24,7 @@ def __init__( log_stream_name: str, agent_endpoint: str, ec2_metadata_endpoint: str = None, + environment: Environments = Environments.Unknown ): self.debug_logging_enabled = debug_logging_enabled self.service_name = service_name @@ -30,3 +33,4 @@ def __init__( self.log_stream_name = log_stream_name self.agent_endpoint = agent_endpoint self.ec2_metadata_endpoint = ec2_metadata_endpoint + self.environment = environment diff --git a/aws_embedded_metrics/config/environment_configuration_provider.py b/aws_embedded_metrics/config/environment_configuration_provider.py index 42c798c..c49c37b 100644 --- a/aws_embedded_metrics/config/environment_configuration_provider.py +++ b/aws_embedded_metrics/config/environment_configuration_provider.py @@ -13,6 +13,7 @@ import os from aws_embedded_metrics.config.configuration import Configuration +from aws_embedded_metrics.environment.environments import Environments ENV_VAR_PREFIX = "AWS_EMF" @@ -23,6 +24,7 @@ LOG_STREAM_NAME = "LOG_STREAM_NAME" AGENT_ENDPOINT = "AGENT_ENDPOINT" EC2_METADATA_ENDPOINT = "EC2_METADATA_ENDPOINT" +ENVIRONMENT_OVERRIDE = "ENVIRONMENT" class EnvironmentConfigurationProvider: @@ -39,6 +41,7 @@ def get_configuration(self) -> Configuration: self.__get_env_var(LOG_STREAM_NAME), self.__get_env_var(AGENT_ENDPOINT), self.__get_env_var(EC2_METADATA_ENDPOINT), + self.__get_environment_override(), ) @staticmethod @@ -54,3 +57,13 @@ def __get_bool_env_var(key: str) -> bool: if value is None: return False return value.lower() == "true" + + @staticmethod + def __get_environment_override() -> Environments: + value = os.environ.get(f"{ENV_VAR_PREFIX}_{ENVIRONMENT_OVERRIDE}") + if value is not None and len(value) > 0: + try: + return Environments[value] + except Exception: + pass + return Environments.Unknown diff --git a/aws_embedded_metrics/environment/environments.py b/aws_embedded_metrics/environment/environments.py new file mode 100644 index 0000000..a84e46e --- /dev/null +++ b/aws_embedded_metrics/environment/environments.py @@ -0,0 +1,9 @@ +from enum import Enum + + +class Environments(Enum): + Local = 1 + Lambda = 2 + Agent = 3 + EC2 = 4 + Unknown = -1 diff --git a/setup.py b/setup.py index 345cc62..13e6ab9 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="aws-embedded-metrics", - version="1.0.1b3", + version="1.0.1b4", author="Amazon Web Services", author_email="jarnance@amazon.com", description="AWS Embedded Metrics Package", From 1ff12b4e9adf817cdd60adc20ecefb86699c571b Mon Sep 17 00:00:00 2001 From: Jared Nance Date: Mon, 30 Mar 2020 19:01:41 -0700 Subject: [PATCH 3/3] Add LocalEnvironment and rename LambdaSink to ConsoleSink --- .../environment/environment_detector.py | 32 ++++++++++- .../environment/lambda_environment.py | 4 +- .../environment/local_environment.py | 54 +++++++++++++++++++ .../sinks/{lambda_sink.py => console_sink.py} | 4 +- tests/environment/test_lambda_environment.py | 6 +-- tests/sinks/test_lambda_sink.py | 4 +- 6 files changed, 93 insertions(+), 11 deletions(-) create mode 100644 aws_embedded_metrics/environment/local_environment.py rename aws_embedded_metrics/sinks/{lambda_sink.py => console_sink.py} (95%) diff --git a/aws_embedded_metrics/environment/environment_detector.py b/aws_embedded_metrics/environment/environment_detector.py index a616d0f..9b20d0b 100644 --- a/aws_embedded_metrics/environment/environment_detector.py +++ b/aws_embedded_metrics/environment/environment_detector.py @@ -13,14 +13,36 @@ import logging from aws_embedded_metrics.environment import Environment +from aws_embedded_metrics.environment.environments import Environments from aws_embedded_metrics.environment.default_environment import DefaultEnvironment from aws_embedded_metrics.environment.lambda_environment import LambdaEnvironment from aws_embedded_metrics.environment.ec2_environment import EC2Environment +from aws_embedded_metrics.environment.local_environment import LocalEnvironment +from aws_embedded_metrics import config from typing import Optional log = logging.getLogger(__name__) -environments = [LambdaEnvironment(), EC2Environment()] +lambda_environment = LambdaEnvironment() +ec2_environment = EC2Environment() +default_environment = DefaultEnvironment() +local_environment = LocalEnvironment() + +environments = [lambda_environment, ec2_environment] +Config = config.get_config() + + +def get_environment_from_override() -> Environment: + if Config.environment == Environments.Agent: + return default_environment + if Config.environment == Environments.EC2: + return ec2_environment + if Config.environment == Environments.Lambda: + return lambda_environment + if Config.environment == Environments.Local: + return local_environment + + return default_environment class EnvironmentCache: @@ -32,6 +54,12 @@ async def resolve_environment() -> Environment: log.debug("Environment resolved from cache.") return EnvironmentCache.environment + if Config.environment is not Environments.Unknown and Config.environment is not None: + log.info("Environment override provided: %s", Config.environment) + environment_override = get_environment_from_override() + if environment_override is not None: + return environment_override + for env_under_test in environments: is_environment = False try: @@ -49,5 +77,5 @@ async def resolve_environment() -> Environment: return env_under_test log.info("No environment was detected. Using default.") - EnvironmentCache.environment = DefaultEnvironment() + EnvironmentCache.environment = default_environment return EnvironmentCache.environment diff --git a/aws_embedded_metrics/environment/lambda_environment.py b/aws_embedded_metrics/environment/lambda_environment.py index 8e52078..2e667dd 100644 --- a/aws_embedded_metrics/environment/lambda_environment.py +++ b/aws_embedded_metrics/environment/lambda_environment.py @@ -14,7 +14,7 @@ from aws_embedded_metrics.environment import Environment from aws_embedded_metrics.logger.metrics_context import MetricsContext from aws_embedded_metrics.sinks import Sink -from aws_embedded_metrics.sinks.lambda_sink import LambdaSink +from aws_embedded_metrics.sinks.console_sink import ConsoleSink import os @@ -24,7 +24,7 @@ def get_env(key: str) -> str: return "" -sink = LambdaSink() +sink = ConsoleSink() class LambdaEnvironment(Environment): diff --git a/aws_embedded_metrics/environment/local_environment.py b/aws_embedded_metrics/environment/local_environment.py new file mode 100644 index 0000000..110982b --- /dev/null +++ b/aws_embedded_metrics/environment/local_environment.py @@ -0,0 +1,54 @@ +# 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. + +from aws_embedded_metrics.environment import Environment +from aws_embedded_metrics.logger.metrics_context import MetricsContext +from aws_embedded_metrics.sinks import Sink +from aws_embedded_metrics.sinks.console_sink import ConsoleSink +from aws_embedded_metrics import config +import os + +Config = config.get_config() + + +def get_env(key: str) -> str: + if key in os.environ: + return os.environ[key] + return "" + + +sink = ConsoleSink() + + +class LocalEnvironment(Environment): + async def probe(self) -> bool: + # probe is not intended to be used in the LocalEnvironment + # To use the local environment you should set the environment + # override + return False + + def get_name(self) -> str: + return Config.service_name or "Unknown" + + def get_type(self) -> str: + return Config.service_type or "Local" + + def get_log_group_name(self) -> str: + return Config.log_group_name or f"{self.get_name()}-metrics" + + def configure_context(self, context: MetricsContext) -> None: + pass + + def get_sink(self) -> Sink: + """Create the appropriate sink for this environment.""" + return sink diff --git a/aws_embedded_metrics/sinks/lambda_sink.py b/aws_embedded_metrics/sinks/console_sink.py similarity index 95% rename from aws_embedded_metrics/sinks/lambda_sink.py rename to aws_embedded_metrics/sinks/console_sink.py index bd7727d..c0f5c2b 100644 --- a/aws_embedded_metrics/sinks/lambda_sink.py +++ b/aws_embedded_metrics/sinks/console_sink.py @@ -17,7 +17,7 @@ from aws_embedded_metrics.serializers.log_serializer import LogSerializer -class LambdaSink(Sink): +class ConsoleSink(Sink): def __init__(self, serializer: Serializer = LogSerializer()): self.serializer = serializer @@ -26,4 +26,4 @@ def accept(self, context: MetricsContext) -> None: @staticmethod def name() -> str: - return "LambdaSink" + return "ConsoleSink" diff --git a/tests/environment/test_lambda_environment.py b/tests/environment/test_lambda_environment.py index e9e76bd..2f4269e 100644 --- a/tests/environment/test_lambda_environment.py +++ b/tests/environment/test_lambda_environment.py @@ -1,6 +1,6 @@ import os from aws_embedded_metrics.environment.lambda_environment import LambdaEnvironment -from aws_embedded_metrics.sinks.lambda_sink import LambdaSink +from aws_embedded_metrics.sinks.console_sink import ConsoleSink import pytest from faker import Faker @@ -57,7 +57,7 @@ def test_get_log_group_name_returns_function_name(): assert result == expected_name -def test_create_sink_creates_LambdaSink(): +def test_create_sink_creates_ConsoleSink(): # arrange env = LambdaEnvironment() @@ -65,4 +65,4 @@ def test_create_sink_creates_LambdaSink(): result = env.get_sink() # assert - assert isinstance(result, LambdaSink) + assert isinstance(result, ConsoleSink) diff --git a/tests/sinks/test_lambda_sink.py b/tests/sinks/test_lambda_sink.py index 373cc69..36e0850 100644 --- a/tests/sinks/test_lambda_sink.py +++ b/tests/sinks/test_lambda_sink.py @@ -1,10 +1,10 @@ -from aws_embedded_metrics.sinks.lambda_sink import LambdaSink +from aws_embedded_metrics.sinks.console_sink import ConsoleSink from aws_embedded_metrics.logger.metrics_context import MetricsContext def test_accept_writes_to_stdout(capfd): # arrange - sink = LambdaSink() + sink = ConsoleSink() context = MetricsContext.empty() context.meta["Timestamp"] = 1