diff --git a/aws_embedded_metrics/environment/default_environment.py b/aws_embedded_metrics/environment/default_environment.py index 8f9e3f4..c4a16af 100644 --- a/aws_embedded_metrics/environment/default_environment.py +++ b/aws_embedded_metrics/environment/default_environment.py @@ -14,6 +14,7 @@ from aws_embedded_metrics.config import get_config 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.agent_sink import AgentSink from typing import Optional @@ -22,7 +23,7 @@ class DefaultEnvironment(Environment): def __init__(self) -> None: - self.sink: Optional[AgentSink] = None + self.sink: Optional[Sink] = None async def probe(self) -> bool: return True @@ -39,7 +40,7 @@ def get_log_group_name(self) -> str: def configure_context(self, context: MetricsContext) -> None: pass - def get_sink(self) -> AgentSink: + def get_sink(self) -> Sink: if self.sink is None: self.sink = AgentSink(self.get_log_group_name(), Config.log_stream_name) return self.sink diff --git a/aws_embedded_metrics/environment/environment_detector.py b/aws_embedded_metrics/environment/environment_detector.py index d051c02..9b3d320 100644 --- a/aws_embedded_metrics/environment/environment_detector.py +++ b/aws_embedded_metrics/environment/environment_detector.py @@ -16,6 +16,7 @@ from aws_embedded_metrics.environment import Environment from aws_embedded_metrics.environment.default_environment import DefaultEnvironment from aws_embedded_metrics.environment.lambda_environment import LambdaEnvironment +from aws_embedded_metrics.environment.local_environment import LocalEnvironment from aws_embedded_metrics.environment.ec2_environment import EC2Environment from typing import Optional @@ -24,6 +25,7 @@ lambda_environment = LambdaEnvironment() ec2_environment = EC2Environment() default_environment = DefaultEnvironment() +local_environment = LocalEnvironment() environments = [lambda_environment, ec2_environment] Config = config.get_config() @@ -45,6 +47,8 @@ async def resolve_environment() -> Environment: EnvironmentCache.environment = ec2_environment elif lower_configured_enviroment == "default": EnvironmentCache.environment = default_environment + elif lower_configured_enviroment == "local": + EnvironmentCache.environment = local_environment else: log.info("Failed to understand environment override: %s", Config.environment) if EnvironmentCache.environment is not None: diff --git a/aws_embedded_metrics/environment/lambda_environment.py b/aws_embedded_metrics/environment/lambda_environment.py index 8e52078..14635cd 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.stdout_sink import StdoutSink import os @@ -24,7 +24,7 @@ def get_env(key: str) -> str: return "" -sink = LambdaSink() +sink = StdoutSink() 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..a6a5e55 --- /dev/null +++ b/aws_embedded_metrics/environment/local_environment.py @@ -0,0 +1,46 @@ +# 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.config import get_config +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.stdout_sink import StdoutSink +from typing import Optional + +Config = get_config() + + +class LocalEnvironment(Environment): + def __init__(self) -> None: + self.sink: Optional[Sink] = None + + async def probe(self) -> bool: + return False + + def get_name(self) -> str: + return Config.service_name or "Unknown" + + def get_type(self) -> str: + return Config.service_type or "Unknown" + + 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: + if self.sink is None: + self.sink = StdoutSink() + return self.sink diff --git a/aws_embedded_metrics/sinks/lambda_sink.py b/aws_embedded_metrics/sinks/stdout_sink.py similarity index 89% rename from aws_embedded_metrics/sinks/lambda_sink.py rename to aws_embedded_metrics/sinks/stdout_sink.py index 54e390b..4004938 100644 --- a/aws_embedded_metrics/sinks/lambda_sink.py +++ b/aws_embedded_metrics/sinks/stdout_sink.py @@ -17,14 +17,15 @@ from aws_embedded_metrics.serializers.log_serializer import LogSerializer -class LambdaSink(Sink): +class StdoutSink(Sink): def __init__(self, serializer: Serializer = LogSerializer()): self.serializer = serializer def accept(self, context: MetricsContext) -> None: for serialized_content in self.serializer.serialize(context): - print(serialized_content) + if serialized_content: + print(serialized_content) @staticmethod def name() -> str: - return "LambdaSink" + return "StdoutSink" diff --git a/tests/environment/test_lambda_environment.py b/tests/environment/test_lambda_environment.py index e9e76bd..b7925ec 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.stdout_sink import StdoutSink import pytest from faker import Faker @@ -65,4 +65,4 @@ def test_create_sink_creates_LambdaSink(): result = env.get_sink() # assert - assert isinstance(result, LambdaSink) + assert isinstance(result, StdoutSink) diff --git a/tests/environment/test_local_environment.py b/tests/environment/test_local_environment.py new file mode 100644 index 0000000..fbf063f --- /dev/null +++ b/tests/environment/test_local_environment.py @@ -0,0 +1,108 @@ +from aws_embedded_metrics import config +from aws_embedded_metrics.environment.local_environment import LocalEnvironment +from aws_embedded_metrics.sinks.stdout_sink import StdoutSink +import pytest +from faker import Faker + +Config = config.get_config() +fake = Faker() + + +@pytest.mark.asyncio +async def test_probe_always_returns_false(): + # arrange + env = LocalEnvironment() + + # act + result = await env.probe() + + # assert + assert result is False + + +def test_get_name_returns_unknown_if_not_specified(): + # arrange + env = LocalEnvironment() + Config.service_name = None + + # act + result = env.get_name() + + # assert + assert result == "Unknown" + + +def test_get_type_returns_unknown_if_not_specified(): + # arrange + env = LocalEnvironment() + Config.service_type = None + + # act + result = env.get_type() + + # assert + assert result == "Unknown" + + +def test_get_name_returns_name_if_configured(): + # arrange + expected_name = fake.word() + env = LocalEnvironment() + Config.service_name = expected_name + + # act + result = env.get_name() + + # assert + assert result == expected_name + + +def test__get_type__returns_type_if_configured(): + # arrange + expected_type = fake.word() + env = LocalEnvironment() + Config.service_type = expected_type + + # act + result = env.get_type() + + # assert + assert result == expected_type + + +def test__get_log_group_name__returns_log_group_if_configured(): + # arrange + expected = fake.word() + env = LocalEnvironment() + Config.log_group_name = expected + + # act + result = env.get_log_group_name() + + # assert + assert result == expected + + +def test__get_log_group_name__returns_service_name_metrics_if_not_configured(): + # arrange + expected = fake.word() + env = LocalEnvironment() + Config.service_name = expected + Config.log_group_name = None + + # act + result = env.get_log_group_name() + + # assert + assert result == f"{expected}-metrics" + + +def test__get_sink__returns_stdout_sink(): + # arrange + env = LocalEnvironment() + + # act + result = env.get_sink() + + # assert + assert isinstance(result, StdoutSink) diff --git a/tests/sinks/test_lambda_sink.py b/tests/sinks/test_stdout_sink.py similarity index 78% rename from tests/sinks/test_lambda_sink.py rename to tests/sinks/test_stdout_sink.py index 79aeb84..b0be62a 100644 --- a/tests/sinks/test_lambda_sink.py +++ b/tests/sinks/test_stdout_sink.py @@ -1,7 +1,7 @@ from importlib import reload from aws_embedded_metrics import config -from aws_embedded_metrics.sinks.lambda_sink import LambdaSink +from aws_embedded_metrics.sinks.stdout_sink import StdoutSink from aws_embedded_metrics.logger.metrics_context import MetricsContext from faker import Faker from unittest.mock import patch @@ -14,9 +14,10 @@ def test_accept_writes_to_stdout(capfd): # arrange reload(config) - sink = LambdaSink() + sink = StdoutSink() context = MetricsContext.empty() context.meta["Timestamp"] = 1 + context.put_metric("Dummy", 1) # act sink.accept(context) @@ -25,7 +26,8 @@ def test_accept_writes_to_stdout(capfd): out, err = capfd.readouterr() assert ( out - == '{"_aws": {"Timestamp": 1, "CloudWatchMetrics": [{"Dimensions": [], "Metrics": [], "Namespace": "aws-embedded-metrics"}]}}\n' + == '{"_aws": {"Timestamp": 1, "CloudWatchMetrics": [{"Dimensions": [], "Metrics": [{"Name": "Dummy", "Unit": "None"}], ' + '"Namespace": "aws-embedded-metrics"}]}, "Dummy": 1}\n' ) @@ -34,7 +36,7 @@ def test_accept_writes_multiple_messages_to_stdout(mock_serializer, capfd): # arrange expected_messages = [fake.word() for _ in range(10)] mock_serializer.serialize.return_value = expected_messages - sink = LambdaSink(serializer=mock_serializer) + sink = StdoutSink(serializer=mock_serializer) context = MetricsContext.empty() context.meta["Timestamp"] = 1