Skip to content

Commit 4fac1ca

Browse files
authored
CFn: Add Lambda Function LoggingConfig (#12480)
1 parent 97bc2c7 commit 4fac1ca

File tree

6 files changed

+259
-8
lines changed

6 files changed

+259
-8
lines changed

localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,13 @@ class Code(TypedDict):
9999
ZipFile: Optional[str]
100100

101101

102+
class LoggingConfig(TypedDict):
103+
ApplicationLogLevel: Optional[str]
104+
LogFormat: Optional[str]
105+
LogGroup: Optional[str]
106+
SystemLogLevel: Optional[str]
107+
108+
102109
class Environment(TypedDict):
103110
Variables: Optional[dict]
104111

@@ -333,11 +340,22 @@ def create(
333340
- ec2:DescribeSecurityGroups
334341
- ec2:DescribeSubnets
335342
- ec2:DescribeVpcs
343+
- elasticfilesystem:DescribeMountTargets
344+
- kms:CreateGrant
336345
- kms:Decrypt
346+
- kms:Encrypt
347+
- kms:GenerateDataKey
337348
- lambda:GetCodeSigningConfig
338349
- lambda:GetFunctionCodeSigningConfig
350+
- lambda:GetLayerVersion
339351
- lambda:GetRuntimeManagementConfig
340352
- lambda:PutRuntimeManagementConfig
353+
- lambda:TagResource
354+
- lambda:GetPolicy
355+
- lambda:AddPermission
356+
- lambda:RemovePermission
357+
- lambda:GetResourcePolicy
358+
- lambda:PutResourcePolicy
341359
342360
"""
343361
model = request.desired_state
@@ -368,6 +386,7 @@ def create(
368386
"Timeout",
369387
"TracingConfig",
370388
"VpcConfig",
389+
"LoggingConfig",
371390
],
372391
)
373392
if "Timeout" in kwargs:
@@ -481,13 +500,22 @@ def update(
481500
- ec2:DescribeSecurityGroups
482501
- ec2:DescribeSubnets
483502
- ec2:DescribeVpcs
503+
- elasticfilesystem:DescribeMountTargets
504+
- kms:CreateGrant
484505
- kms:Decrypt
506+
- kms:GenerateDataKey
507+
- lambda:GetRuntimeManagementConfig
508+
- lambda:PutRuntimeManagementConfig
485509
- lambda:PutFunctionCodeSigningConfig
486510
- lambda:DeleteFunctionCodeSigningConfig
487511
- lambda:GetCodeSigningConfig
488512
- lambda:GetFunctionCodeSigningConfig
489-
- lambda:GetRuntimeManagementConfig
490-
- lambda:PutRuntimeManagementConfig
513+
- lambda:GetPolicy
514+
- lambda:AddPermission
515+
- lambda:RemovePermission
516+
- lambda:GetResourcePolicy
517+
- lambda:PutResourcePolicy
518+
- lambda:DeleteResourcePolicy
491519
"""
492520
client = request.aws_client_factory.lambda_
493521

@@ -512,6 +540,7 @@ def update(
512540
"Timeout",
513541
"TracingConfig",
514542
"VpcConfig",
543+
"LoggingConfig",
515544
]
516545
update_config_props = util.select_attributes(request.desired_state, config_keys)
517546
function_name = request.previous_state["FunctionName"]

localstack-core/localstack/services/lambda_/resource_providers/aws_lambda_function.schema.json

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
{
2+
"tagging": {
3+
"taggable": true,
4+
"tagOnCreate": true,
5+
"tagUpdatable": true,
6+
"tagProperty": "/properties/Tags",
7+
"cloudFormationSystemTags": true
8+
},
29
"handlers": {
310
"read": {
411
"permissions": [
@@ -17,11 +24,22 @@
1724
"ec2:DescribeSecurityGroups",
1825
"ec2:DescribeSubnets",
1926
"ec2:DescribeVpcs",
27+
"elasticfilesystem:DescribeMountTargets",
28+
"kms:CreateGrant",
2029
"kms:Decrypt",
30+
"kms:Encrypt",
31+
"kms:GenerateDataKey",
2132
"lambda:GetCodeSigningConfig",
2233
"lambda:GetFunctionCodeSigningConfig",
34+
"lambda:GetLayerVersion",
2335
"lambda:GetRuntimeManagementConfig",
24-
"lambda:PutRuntimeManagementConfig"
36+
"lambda:PutRuntimeManagementConfig",
37+
"lambda:TagResource",
38+
"lambda:GetPolicy",
39+
"lambda:AddPermission",
40+
"lambda:RemovePermission",
41+
"lambda:GetResourcePolicy",
42+
"lambda:PutResourcePolicy"
2543
]
2644
},
2745
"update": {
@@ -40,13 +58,22 @@
4058
"ec2:DescribeSecurityGroups",
4159
"ec2:DescribeSubnets",
4260
"ec2:DescribeVpcs",
61+
"elasticfilesystem:DescribeMountTargets",
62+
"kms:CreateGrant",
4363
"kms:Decrypt",
64+
"kms:GenerateDataKey",
65+
"lambda:GetRuntimeManagementConfig",
66+
"lambda:PutRuntimeManagementConfig",
4467
"lambda:PutFunctionCodeSigningConfig",
4568
"lambda:DeleteFunctionCodeSigningConfig",
4669
"lambda:GetCodeSigningConfig",
4770
"lambda:GetFunctionCodeSigningConfig",
48-
"lambda:GetRuntimeManagementConfig",
49-
"lambda:PutRuntimeManagementConfig"
71+
"lambda:GetPolicy",
72+
"lambda:AddPermission",
73+
"lambda:RemovePermission",
74+
"lambda:GetResourcePolicy",
75+
"lambda:PutResourcePolicy",
76+
"lambda:DeleteResourcePolicy"
5077
]
5178
},
5279
"list": {
@@ -63,13 +90,15 @@
6390
},
6491
"typeName": "AWS::Lambda::Function",
6592
"readOnlyProperties": [
66-
"/properties/Arn",
6793
"/properties/SnapStartResponse",
6894
"/properties/SnapStartResponse/ApplyOn",
69-
"/properties/SnapStartResponse/OptimizationStatus"
95+
"/properties/SnapStartResponse/OptimizationStatus",
96+
"/properties/Arn"
7097
],
71-
"description": "Resource Type definition for AWS::Lambda::Function",
98+
"description": "Resource Type definition for AWS::Lambda::Function in region",
7299
"writeOnlyProperties": [
100+
"/properties/SnapStart",
101+
"/properties/SnapStart/ApplyOn",
73102
"/properties/Code",
74103
"/properties/Code/ImageUri",
75104
"/properties/Code/S3Bucket",
@@ -133,6 +162,10 @@
133162
"additionalProperties": false,
134163
"type": "object",
135164
"properties": {
165+
"Ipv6AllowedForDualStack": {
166+
"description": "A boolean indicating whether IPv6 protocols will be allowed for dual stack subnets",
167+
"type": "boolean"
168+
},
136169
"SecurityGroupIds": {
137170
"maxItems": 5,
138171
"uniqueItems": false,
@@ -261,6 +294,49 @@
261294
}
262295
}
263296
},
297+
"LoggingConfig": {
298+
"description": "The function's logging configuration.",
299+
"additionalProperties": false,
300+
"type": "object",
301+
"properties": {
302+
"LogFormat": {
303+
"description": "Log delivery format for the lambda function",
304+
"type": "string",
305+
"enum": [
306+
"Text",
307+
"JSON"
308+
]
309+
},
310+
"ApplicationLogLevel": {
311+
"description": "Application log granularity level, can only be used when LogFormat is set to JSON",
312+
"type": "string",
313+
"enum": [
314+
"TRACE",
315+
"DEBUG",
316+
"INFO",
317+
"WARN",
318+
"ERROR",
319+
"FATAL"
320+
]
321+
},
322+
"LogGroup": {
323+
"minLength": 1,
324+
"pattern": "[\\.\\-_/#A-Za-z0-9]+",
325+
"description": "The log group name.",
326+
"type": "string",
327+
"maxLength": 512
328+
},
329+
"SystemLogLevel": {
330+
"description": "System log granularity level, can only be used when LogFormat is set to JSON",
331+
"type": "string",
332+
"enum": [
333+
"DEBUG",
334+
"INFO",
335+
"WARN"
336+
]
337+
}
338+
}
339+
},
264340
"Environment": {
265341
"description": "A function's environment variable settings.",
266342
"additionalProperties": false,
@@ -457,6 +533,10 @@
457533
"description": "The Amazon Resource Name (ARN) of the function's execution role.",
458534
"type": "string"
459535
},
536+
"LoggingConfig": {
537+
"description": "The logging configuration of your function",
538+
"$ref": "#/definitions/LoggingConfig"
539+
},
460540
"Environment": {
461541
"description": "Environment variables that are accessible from function code during execution.",
462542
"$ref": "#/definitions/Environment"

tests/aws/services/cloudformation/resources/test_lambda.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,38 @@ def test_lambda_alias(deploy_cfn_template, snapshot, aws_client):
253253
snapshot.match("Alias", alias)
254254

255255

256+
@markers.aws.validated
257+
def test_lambda_logging_config(deploy_cfn_template, snapshot, aws_client):
258+
function_name = f"function{short_uid()}"
259+
260+
snapshot.add_transformer(snapshot.transform.cloudformation_api())
261+
snapshot.add_transformer(SortingTransformer("StackResources", lambda x: x["LogicalResourceId"]))
262+
snapshot.add_transformer(
263+
snapshot.transform.key_value("LogicalResourceId", reference_replacement=False)
264+
)
265+
snapshot.add_transformer(
266+
snapshot.transform.key_value("PhysicalResourceId", reference_replacement=False)
267+
)
268+
snapshot.add_transformer(snapshot.transform.regex(function_name, "<function-name>"))
269+
270+
deployment = deploy_cfn_template(
271+
template_path=os.path.join(
272+
os.path.dirname(__file__), "../../../templates/cfn_lambda_logging_config.yaml"
273+
),
274+
parameters={"FunctionName": function_name},
275+
)
276+
277+
description = aws_client.cloudformation.describe_stack_resources(
278+
StackName=deployment.stack_name
279+
)
280+
snapshot.match("stack_resource_descriptions", description)
281+
282+
logging_config = aws_client.lambda_.get_function(FunctionName=function_name)["Configuration"][
283+
"LoggingConfig"
284+
]
285+
snapshot.match("logging_config", logging_config)
286+
287+
256288
@pytest.mark.skipif(
257289
not in_default_partition(), reason="Test not applicable in non-default partitions"
258290
)

tests/aws/services/cloudformation/resources/test_lambda.snapshot.json

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,5 +1606,60 @@
16061606
"LayerVersionRef": "arn:<partition>:lambda:<region>:111111111111:layer:<layer-name:1>:1"
16071607
}
16081608
}
1609+
},
1610+
"tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_logging_config": {
1611+
"recorded-date": "08-04-2025, 12:10:56",
1612+
"recorded-content": {
1613+
"stack_resource_descriptions": {
1614+
"StackResources": [
1615+
{
1616+
"DriftInformation": {
1617+
"StackResourceDriftStatus": "NOT_CHECKED"
1618+
},
1619+
"LogicalResourceId": "logical-resource-id",
1620+
"PhysicalResourceId": "physical-resource-id",
1621+
"ResourceStatus": "CREATE_COMPLETE",
1622+
"ResourceType": "AWS::Lambda::Function",
1623+
"StackId": "arn:<partition>:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:1>",
1624+
"StackName": "<stack-name:1>",
1625+
"Timestamp": "timestamp"
1626+
},
1627+
{
1628+
"DriftInformation": {
1629+
"StackResourceDriftStatus": "NOT_CHECKED"
1630+
},
1631+
"LogicalResourceId": "logical-resource-id",
1632+
"PhysicalResourceId": "physical-resource-id",
1633+
"ResourceStatus": "CREATE_COMPLETE",
1634+
"ResourceType": "AWS::IAM::Role",
1635+
"StackId": "arn:<partition>:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:1>",
1636+
"StackName": "<stack-name:1>",
1637+
"Timestamp": "timestamp"
1638+
},
1639+
{
1640+
"DriftInformation": {
1641+
"StackResourceDriftStatus": "NOT_CHECKED"
1642+
},
1643+
"LogicalResourceId": "logical-resource-id",
1644+
"PhysicalResourceId": "physical-resource-id",
1645+
"ResourceStatus": "CREATE_COMPLETE",
1646+
"ResourceType": "AWS::Lambda::Version",
1647+
"StackId": "arn:<partition>:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:1>",
1648+
"StackName": "<stack-name:1>",
1649+
"Timestamp": "timestamp"
1650+
}
1651+
],
1652+
"ResponseMetadata": {
1653+
"HTTPHeaders": {},
1654+
"HTTPStatusCode": 200
1655+
}
1656+
},
1657+
"logging_config": {
1658+
"ApplicationLogLevel": "INFO",
1659+
"LogFormat": "JSON",
1660+
"LogGroup": "/aws/lambda/<function-name>",
1661+
"SystemLogLevel": "INFO"
1662+
}
1663+
}
16091664
}
16101665
}

tests/aws/services/cloudformation/resources/test_lambda.validation.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
"tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_layer_crud": {
4242
"last_validated_date": "2024-12-20T18:23:31+00:00"
4343
},
44+
"tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_logging_config": {
45+
"last_validated_date": "2025-04-08T12:12:01+00:00"
46+
},
4447
"tests/aws/services/cloudformation/resources/test_lambda.py::test_lambda_version": {
4548
"last_validated_date": "2024-04-09T07:21:37+00:00"
4649
},
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
AWSTemplateFormatVersion: 2010-09-09
2+
3+
Parameters:
4+
FunctionName:
5+
Type: String
6+
7+
Resources:
8+
MyFnServiceRole:
9+
Type: AWS::IAM::Role
10+
Properties:
11+
AssumeRolePolicyDocument:
12+
Statement:
13+
- Action: sts:AssumeRole
14+
Effect: Allow
15+
Principal:
16+
Service: lambda.amazonaws.com
17+
Version: "2012-10-17"
18+
ManagedPolicyArns:
19+
- Fn::Join:
20+
- ""
21+
- - "arn:"
22+
- Ref: AWS::Partition
23+
- :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
24+
25+
LambdaFunction:
26+
Type: AWS::Lambda::Function
27+
Properties:
28+
FunctionName: !Ref FunctionName
29+
Code:
30+
ZipFile: |
31+
def handler(event, context):
32+
return {
33+
statusCode: 200,
34+
body: "Hello, World!"
35+
}
36+
Role:
37+
Fn::GetAtt:
38+
- MyFnServiceRole
39+
- Arn
40+
Handler: index.handler
41+
Runtime: python3.12
42+
LoggingConfig:
43+
LogFormat: JSON
44+
DependsOn:
45+
- MyFnServiceRole
46+
47+
Version:
48+
Type: AWS::Lambda::Version
49+
Properties:
50+
FunctionName: !Ref LambdaFunction
51+
Description: v1
52+

0 commit comments

Comments
 (0)