diff --git a/samcli/commands/local/lib/local_lambda.py b/samcli/commands/local/lib/local_lambda.py index d0d1446b5c..14f7578187 100644 --- a/samcli/commands/local/lib/local_lambda.py +++ b/samcli/commands/local/lib/local_lambda.py @@ -296,6 +296,7 @@ def _make_env_vars(self, function: Function) -> EnvironmentVariables: function.memory, function.timeout, function.handler, + function.logging_config, variables=variables, shell_env_values=shell_env, override_values=overrides, diff --git a/samcli/lib/providers/provider.py b/samcli/lib/providers/provider.py index b2be6677af..0709e96b0a 100644 --- a/samcli/lib/providers/provider.py +++ b/samcli/lib/providers/provider.py @@ -111,6 +111,8 @@ class Function(NamedTuple): stack_path: str = "" # Configuration for runtime management. Includes the fields `UpdateRuntimeOn` and `RuntimeVersionArn` (optional). runtime_management_config: Optional[Dict] = None + # LoggingConfig for Advanced logging + logging_config: Optional[Dict] = None @property def full_path(self) -> str: diff --git a/samcli/lib/providers/sam_function_provider.py b/samcli/lib/providers/sam_function_provider.py index b7adfa597a..fde30ba502 100644 --- a/samcli/lib/providers/sam_function_provider.py +++ b/samcli/lib/providers/sam_function_provider.py @@ -473,6 +473,7 @@ def _build_function_configuration( function_url_config=resource_properties.get("FunctionUrlConfig"), runtime_management_config=resource_properties.get("RuntimeManagementConfig"), function_build_info=function_build_info, + logging_config=resource_properties.get("LoggingConfig"), ) @staticmethod diff --git a/samcli/local/lambdafn/env_vars.py b/samcli/local/lambdafn/env_vars.py index 4aefb76bef..ebf52ce5be 100644 --- a/samcli/local/lambdafn/env_vars.py +++ b/samcli/local/lambdafn/env_vars.py @@ -44,6 +44,7 @@ def __init__( function_memory=None, function_timeout=None, function_handler=None, + function_logging_config=None, variables=None, shell_env_values=None, override_values=None, @@ -58,6 +59,7 @@ def __init__( :param integer function_memory: Memory size of the function in megabytes :param integer function_timeout: Function's timeout in seconds :param string function_handler: Handler of the function + :param string function_logging_config: Logging Config for the function :param dict variables: Optional. Dict whose key is the environment variable names and value is the default values for the variable. :param dict shell_env_values: Optional. Dict containing values for the variables grabbed from the shell's @@ -79,6 +81,7 @@ def __init__( self.shell_env_values = shell_env_values or {} self.override_values = override_values or {} self.aws_creds = aws_creds or {} + self.logging_config = function_logging_config or {} def resolve(self): """ @@ -179,6 +182,17 @@ def _get_aws_variables(self): if self.aws_creds.get("sessiontoken"): result["AWS_SESSION_TOKEN"] = self.aws_creds.get("sessiontoken") + # Add the ApplicationLogLevel as a env variable and also update the function's LogGroup name + log_group = self.logging_config.get("LogGroup") + if log_group: + result["AWS_LAMBDA_LOG_GROUP_NAME"] = log_group + + log_format = self.logging_config.get("LogFormat") + if log_format: + result["AWS_LAMBDA_LOG_FORMAT"] = log_format + if log_format == "JSON": + result["AWS_LAMBDA_LOG_LEVEL"] = self.logging_config.get("ApplicationLogLevel", "INFO") + return result def _stringify_value(self, value): diff --git a/tests/unit/commands/local/lib/test_local_lambda.py b/tests/unit/commands/local/lib/test_local_lambda.py index dc5f4384bd..384771f753 100644 --- a/tests/unit/commands/local/lib/test_local_lambda.py +++ b/tests/unit/commands/local/lib/test_local_lambda.py @@ -253,6 +253,7 @@ def test_must_work_with_override_values( function_url_config=None, runtime_management_config=None, function_build_info=FunctionBuildInfo.BuildableZip, + logging_config={"LogFormat": "JSON"}, ) self.local_lambda.env_vars_values = env_vars_values @@ -264,6 +265,7 @@ def test_must_work_with_override_values( function.memory, function.timeout, function.handler, + function.logging_config, variables={"var1": "value1"}, shell_env_values=os_environ, override_values=expected_override_value, @@ -362,6 +364,7 @@ def test_must_work_with_invalid_environment_variable(self, environment_variable, function.memory, function.timeout, function.handler, + None, variables=None, shell_env_values=os_environ, override_values={}, diff --git a/tests/unit/local/lambdafn/test_env_vars.py b/tests/unit/local/lambdafn/test_env_vars.py index c0babe5fe5..f831bfe61a 100644 --- a/tests/unit/local/lambdafn/test_env_vars.py +++ b/tests/unit/local/lambdafn/test_env_vars.py @@ -13,15 +13,18 @@ def test_must_initialize_with_empty_values(self): memory = 123 timeout = 10 handler = "handler" + logging_config = {"logFormat": "JSON"} environ = EnvironmentVariables() environ.memory = memory environ.timeout = timeout environ.handler = handler + environ.logging_config = logging_config self.assertEqual(environ.memory, memory) self.assertEqual(environ.timeout, timeout) self.assertEqual(environ.handler, handler) + self.assertEqual(environ.logging_config, logging_config) def test_must_initialize_values_with_required_values(self): memory = 123 @@ -332,6 +335,101 @@ def test_must_work_with_partial_aws_creds(self): environ = EnvironmentVariables(self.name, self.memory, self.timeout, self.handler, aws_creds=creds) self.assertEqual(expected, environ._get_aws_variables()) + def test_must_work_with_text_logformat(self): + expected = { + "AWS_SAM_LOCAL": "true", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_TIMEOUT": "123", + "AWS_LAMBDA_FUNCTION_HANDLER": "handler", + "AWS_LAMBDA_FUNCTION_NAME": self.name, + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_LOG_GROUP_NAME": f"aws/lambda/{self.name}", + "AWS_LAMBDA_LOG_STREAM_NAME": "$LATEST", + "AWS_ACCOUNT_ID": "123456789012", + # Default values assigned to these variables + "AWS_REGION": "us-east-1", + "AWS_DEFAULT_REGION": "us-east-1", + "AWS_ACCESS_KEY_ID": "defaultkey", + "AWS_SECRET_ACCESS_KEY": "defaultsecret", + "AWS_LAMBDA_LOG_FORMAT": "Text", + } + + logging_config = {"LogFormat": "Text"} + environ = EnvironmentVariables(self.name, self.memory, self.timeout, self.handler, logging_config) + self.assertEqual(expected, environ._get_aws_variables()) + + def test_must_work_with_default_json_logging_config(self): + expected = { + "AWS_SAM_LOCAL": "true", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_TIMEOUT": "123", + "AWS_LAMBDA_FUNCTION_HANDLER": "handler", + "AWS_LAMBDA_FUNCTION_NAME": self.name, + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_LOG_GROUP_NAME": f"aws/lambda/{self.name}", + "AWS_LAMBDA_LOG_STREAM_NAME": "$LATEST", + "AWS_ACCOUNT_ID": "123456789012", + # Default values assigned to these variables + "AWS_REGION": "us-east-1", + "AWS_DEFAULT_REGION": "us-east-1", + "AWS_ACCESS_KEY_ID": "defaultkey", + "AWS_SECRET_ACCESS_KEY": "defaultsecret", + "AWS_LAMBDA_LOG_LEVEL": "INFO", + "AWS_LAMBDA_LOG_FORMAT": "JSON", + } + + logging_config = {"LogFormat": "JSON"} + environ = EnvironmentVariables(self.name, self.memory, self.timeout, self.handler, logging_config) + self.assertEqual(expected, environ._get_aws_variables()) + + def test_must_work_with_set_application_log_level(self): + expected = { + "AWS_SAM_LOCAL": "true", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_TIMEOUT": "123", + "AWS_LAMBDA_FUNCTION_HANDLER": "handler", + "AWS_LAMBDA_FUNCTION_NAME": self.name, + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_LOG_GROUP_NAME": f"aws/lambda/{self.name}", + "AWS_LAMBDA_LOG_STREAM_NAME": "$LATEST", + "AWS_ACCOUNT_ID": "123456789012", + # Default values assigned to these variables + "AWS_REGION": "us-east-1", + "AWS_DEFAULT_REGION": "us-east-1", + "AWS_ACCESS_KEY_ID": "defaultkey", + "AWS_SECRET_ACCESS_KEY": "defaultsecret", + "AWS_LAMBDA_LOG_LEVEL": "TRACE", + "AWS_LAMBDA_LOG_FORMAT": "JSON", + } + + logging_config = {"LogFormat": "JSON", "ApplicationLogLevel": "TRACE"} + environ = EnvironmentVariables(self.name, self.memory, self.timeout, self.handler, logging_config) + self.assertEqual(expected, environ._get_aws_variables()) + + def test_must_work_with_custom_log_group_name(self): + expected = { + "AWS_SAM_LOCAL": "true", + "AWS_LAMBDA_FUNCTION_MEMORY_SIZE": "1024", + "AWS_LAMBDA_FUNCTION_TIMEOUT": "123", + "AWS_LAMBDA_FUNCTION_HANDLER": "handler", + "AWS_LAMBDA_FUNCTION_NAME": self.name, + "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", + "AWS_LAMBDA_LOG_GROUP_NAME": "myCustomLogGroup", + "AWS_LAMBDA_LOG_STREAM_NAME": "$LATEST", + "AWS_ACCOUNT_ID": "123456789012", + # Default values assigned to these variables + "AWS_REGION": "us-east-1", + "AWS_DEFAULT_REGION": "us-east-1", + "AWS_ACCESS_KEY_ID": "defaultkey", + "AWS_SECRET_ACCESS_KEY": "defaultsecret", + "AWS_LAMBDA_LOG_LEVEL": "TRACE", + "AWS_LAMBDA_LOG_FORMAT": "JSON", + } + + logging_config = {"LogFormat": "JSON", "ApplicationLogLevel": "TRACE", "LogGroup": "myCustomLogGroup"} + environ = EnvironmentVariables(self.name, self.memory, self.timeout, self.handler, logging_config) + self.assertEqual(expected, environ._get_aws_variables()) + class TestEnvironmentVariables_stringify_value(TestCase): def setUp(self):