2222 InputLogEvents ,
2323 InvalidParameterException ,
2424 KmsKeyId ,
25+ ListLogGroupsRequest ,
26+ ListLogGroupsResponse ,
2527 ListTagsForResourceResponse ,
2628 ListTagsLogGroupResponse ,
2729 LogGroupClass ,
2830 LogGroupName ,
31+ LogGroupSummary ,
2932 LogsApi ,
3033 LogStreamName ,
3134 PutLogEventsResponse ,
4346from localstack .utils .aws import arns
4447from localstack .utils .aws .client_types import ServicePrincipal
4548from localstack .utils .bootstrap import is_api_enabled
46- from localstack .utils .common import is_number
49+ from localstack .utils .numbers import is_number
4750from localstack .utils .patch import patch
4851
4952LOG = logging .getLogger (__name__ )
@@ -60,8 +63,8 @@ def put_log_events(
6063 log_group_name : LogGroupName ,
6164 log_stream_name : LogStreamName ,
6265 log_events : InputLogEvents ,
63- sequence_token : SequenceToken = None ,
64- entity : Entity = None ,
66+ sequence_token : SequenceToken | None = None ,
67+ entity : Entity | None = None ,
6568 ** kwargs ,
6669 ) -> PutLogEventsResponse :
6770 logs_backend = get_moto_logs_backend (context .account_id , context .region )
@@ -97,33 +100,32 @@ def describe_log_groups(
97100 ) -> DescribeLogGroupsResponse :
98101 region_backend = get_moto_logs_backend (context .account_id , context .region )
99102
100- prefix : str = request .get ("logGroupNamePrefix" , "" )
101- pattern : str = request .get ("logGroupNamePattern" , "" )
103+ prefix : str | None = request .get ("logGroupNamePrefix" , "" )
104+ pattern : str | None = request .get ("logGroupNamePattern" , "" )
102105
103106 if pattern and prefix :
104107 raise InvalidParameterException (
105108 "LogGroup name prefix and LogGroup name pattern are mutually exclusive parameters."
106109 )
107110
108- copy_groups = copy .deepcopy (dict (region_backend .groups ))
111+ moto_groups = copy .deepcopy (dict (region_backend .groups )). values ( )
109112
110113 groups = [
111- group .to_describe_dict ()
112- for name , group in copy_groups . items ( )
114+ { "logGroupClass" : LogGroupClass . STANDARD } | group .to_describe_dict ()
115+ for group in sorted ( moto_groups , key = lambda g : g . name )
113116 if not (prefix or pattern )
114- or (prefix and name .startswith (prefix ))
115- or (pattern and pattern in name )
117+ or (prefix and group . name .startswith (prefix ))
118+ or (pattern and pattern in group . name )
116119 ]
117120
118- groups = sorted (groups , key = lambda x : x ["logGroupName" ])
119121 return DescribeLogGroupsResponse (logGroups = groups )
120122
121123 @handler ("DescribeLogStreams" , expand = False )
122124 def describe_log_streams (
123125 self , context : RequestContext , request : DescribeLogStreamsRequest
124126 ) -> DescribeLogStreamsResponse :
125- log_group_name : str = request .get ("logGroupName" )
126- log_group_identifier : str = request .get ("logGroupIdentifier" )
127+ log_group_name : str | None = request .get ("logGroupName" )
128+ log_group_identifier : str | None = request .get ("logGroupIdentifier" )
127129
128130 if log_group_identifier and log_group_name :
129131 raise CommonServiceException (
@@ -138,13 +140,29 @@ def describe_log_streams(
138140
139141 return moto .call_moto_with_request (context , request_copy )
140142
143+ @handler ("ListLogGroups" , expand = False )
144+ def list_log_groups (
145+ self , context : RequestContext , request : ListLogGroupsRequest
146+ ) -> ListLogGroupsResponse :
147+ pattern : str | None = request .get ("logGroupNamePattern" )
148+ region_backend : LogsBackend = get_moto_logs_backend (context .account_id , context .region )
149+ moto_groups = copy .deepcopy (region_backend .groups ).values ()
150+ groups = [
151+ LogGroupSummary (
152+ logGroupName = group .name , logGroupArn = group .arn , logGroupClass = LogGroupClass .STANDARD
153+ )
154+ for group in sorted (moto_groups , key = lambda g : g .name )
155+ if not pattern or pattern in group .name
156+ ]
157+ return ListLogGroupsResponse (logGroups = groups )
158+
141159 def create_log_group (
142160 self ,
143161 context : RequestContext ,
144162 log_group_name : LogGroupName ,
145- kms_key_id : KmsKeyId = None ,
146- tags : Tags = None ,
147- log_group_class : LogGroupClass = None ,
163+ kms_key_id : KmsKeyId | None = None ,
164+ tags : Tags | None = None ,
165+ log_group_class : LogGroupClass | None = None ,
148166 ** kwargs ,
149167 ) -> None :
150168 call_moto (context )
@@ -442,10 +460,9 @@ def moto_to_describe_dict(target, self):
442460 # reported race condition in https://github.com/localstack/localstack/issues/8011
443461 # making copy of "streams" dict here to avoid issues while summing up storedBytes
444462 copy_streams = copy .deepcopy (self .streams )
445- # parity tests shows that the arn ends with ":*"
446- arn = self .arn if self .arn .endswith (":*" ) else f"{ self .arn } :*"
447463 log_group = {
448- "arn" : arn ,
464+ "arn" : f"{ self .arn } :*" ,
465+ "logGroupArn" : self .arn ,
449466 "creationTime" : self .creation_time ,
450467 "logGroupName" : self .name ,
451468 "metricFilterCount" : 0 ,
0 commit comments