diff --git a/manifest.json b/manifest.json
index d5e40156b..0c55add2c 100644
--- a/manifest.json
+++ b/manifest.json
@@ -121,6 +121,7 @@
             "methods": [
                 "CreateLogGroup",
                 "CreateLogStream",
+                "DescribeLogGroups",
                 "DescribeLogStreams",
                 "FilterLogEvents",
                 "PutLogEvents"
diff --git a/psalm.baseline.xml b/psalm.baseline.xml
index 41a68860e..2c6785023 100644
--- a/psalm.baseline.xml
+++ b/psalm.baseline.xml
@@ -65,6 +65,14 @@
       ]]>
     
   
+  
+    
+      ]]>
+    
+  
   
     
       $items
diff --git a/src/Core/CHANGELOG.md b/src/Core/CHANGELOG.md
index f4d80a9bd..d46df2954 100644
--- a/src/Core/CHANGELOG.md
+++ b/src/Core/CHANGELOG.md
@@ -5,6 +5,7 @@
 ### Added
 
 - AWS api-change: Added `us-isob-west-1` region
+- Added `DescribeLogGroups` method
 
 ### Dependency bumped
 
diff --git a/src/Service/CloudWatchLogs/src/CloudWatchLogsClient.php b/src/Service/CloudWatchLogs/src/CloudWatchLogsClient.php
index 752305bf4..295cb43a4 100644
--- a/src/Service/CloudWatchLogs/src/CloudWatchLogsClient.php
+++ b/src/Service/CloudWatchLogs/src/CloudWatchLogsClient.php
@@ -15,9 +15,11 @@
 use AsyncAws\CloudWatchLogs\Exception\UnrecognizedClientException;
 use AsyncAws\CloudWatchLogs\Input\CreateLogGroupRequest;
 use AsyncAws\CloudWatchLogs\Input\CreateLogStreamRequest;
+use AsyncAws\CloudWatchLogs\Input\DescribeLogGroupsRequest;
 use AsyncAws\CloudWatchLogs\Input\DescribeLogStreamsRequest;
 use AsyncAws\CloudWatchLogs\Input\FilterLogEventsRequest;
 use AsyncAws\CloudWatchLogs\Input\PutLogEventsRequest;
+use AsyncAws\CloudWatchLogs\Result\DescribeLogGroupsResponse;
 use AsyncAws\CloudWatchLogs\Result\DescribeLogStreamsResponse;
 use AsyncAws\CloudWatchLogs\Result\FilterLogEventsResponse;
 use AsyncAws\CloudWatchLogs\Result\PutLogEventsResponse;
@@ -130,6 +132,50 @@ public function createLogStream($input): Result
         return new Result($response);
     }
 
+    /**
+     * Returns information about log groups. You can return all your log groups or filter the results by prefix. The results
+     * are ASCII-sorted by log group name.
+     *
+     * CloudWatch Logs doesn't support IAM policies that control access to the `DescribeLogGroups` action by using the
+     * `aws:ResourceTag/*key-name*` condition key. Other CloudWatch Logs actions do support the use of the
+     * `aws:ResourceTag/*key-name*` condition key to control access. For more information about using tags to control
+     * access, see Controlling access to Amazon Web Services resources using tags [^1].
+     *
+     * If you are using CloudWatch cross-account observability, you can use this operation in a monitoring account and view
+     * data from the linked source accounts. For more information, see CloudWatch cross-account observability [^2].
+     *
+     * [^1]: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html
+     * [^2]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Unified-Cross-Account.html
+     *
+     * @see https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogGroups.html
+     * @see https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-logs-2014-03-28.html#describeloggroups
+     *
+     * @param array{
+     *   accountIdentifiers?: string[]|null,
+     *   logGroupNamePrefix?: string|null,
+     *   logGroupNamePattern?: string|null,
+     *   nextToken?: string|null,
+     *   limit?: int|null,
+     *   includeLinkedAccounts?: bool|null,
+     *   logGroupClass?: LogGroupClass::*|null,
+     *   logGroupIdentifiers?: string[]|null,
+     *   '@region'?: string|null,
+     * }|DescribeLogGroupsRequest $input
+     *
+     * @throws InvalidParameterException
+     * @throws ServiceUnavailableException
+     */
+    public function describeLogGroups($input = []): DescribeLogGroupsResponse
+    {
+        $input = DescribeLogGroupsRequest::create($input);
+        $response = $this->getResponse($input->request(), new RequestContext(['operation' => 'DescribeLogGroups', 'region' => $input->getRegion(), 'exceptionMapping' => [
+            'InvalidParameterException' => InvalidParameterException::class,
+            'ServiceUnavailableException' => ServiceUnavailableException::class,
+        ]]));
+
+        return new DescribeLogGroupsResponse($response, $this, $input);
+    }
+
     /**
      * Lists the log streams for the specified log group. You can list all the log streams or filter the results by prefix.
      * You can also control how the results are ordered.
diff --git a/src/Service/CloudWatchLogs/src/Enum/DataProtectionStatus.php b/src/Service/CloudWatchLogs/src/Enum/DataProtectionStatus.php
new file mode 100644
index 000000000..cd80e1011
--- /dev/null
+++ b/src/Service/CloudWatchLogs/src/Enum/DataProtectionStatus.php
@@ -0,0 +1,21 @@
+ true,
+            self::ARCHIVED => true,
+            self::DELETED => true,
+            self::DISABLED => true,
+        ][$value]);
+    }
+}
diff --git a/src/Service/CloudWatchLogs/src/Enum/InheritedProperty.php b/src/Service/CloudWatchLogs/src/Enum/InheritedProperty.php
new file mode 100644
index 000000000..b37b42bbe
--- /dev/null
+++ b/src/Service/CloudWatchLogs/src/Enum/InheritedProperty.php
@@ -0,0 +1,15 @@
+ true,
+        ][$value]);
+    }
+}
diff --git a/src/Service/CloudWatchLogs/src/Input/DescribeLogGroupsRequest.php b/src/Service/CloudWatchLogs/src/Input/DescribeLogGroupsRequest.php
new file mode 100644
index 000000000..1ca2466ef
--- /dev/null
+++ b/src/Service/CloudWatchLogs/src/Input/DescribeLogGroupsRequest.php
@@ -0,0 +1,331 @@
+ `logGroupNamePrefix` and `logGroupNamePattern` are mutually exclusive. Only one of these parameters can be passed.
+     *
+     * @var string|null
+     */
+    private $logGroupNamePrefix;
+
+    /**
+     * If you specify a string for this parameter, the operation returns only log groups that have names that match the
+     * string based on a case-sensitive substring search. For example, if you specify `DataLogs`, log groups named
+     * `DataLogs`, `aws/DataLogs`, and `GroupDataLogs` would match, but `datalogs`, `Data/log/s` and `Groupdata` would not
+     * match.
+     *
+     * If you specify `logGroupNamePattern` in your request, then only `arn`, `creationTime`, and `logGroupName` are
+     * included in the response.
+     *
+     * > `logGroupNamePattern` and `logGroupNamePrefix` are mutually exclusive. Only one of these parameters can be passed.
+     *
+     * @var string|null
+     */
+    private $logGroupNamePattern;
+
+    /**
+     * The token for the next set of items to return. (You received this token from a previous call.).
+     *
+     * @var string|null
+     */
+    private $nextToken;
+
+    /**
+     * The maximum number of items returned. If you don't specify a value, the default is up to 50 items.
+     *
+     * @var int|null
+     */
+    private $limit;
+
+    /**
+     * If you are using a monitoring account, set this to `true` to have the operation return log groups in the accounts
+     * listed in `accountIdentifiers`.
+     *
+     * If this parameter is set to `true` and `accountIdentifiers` contains a null value, the operation returns all log
+     * groups in the monitoring account and all log groups in all source accounts that are linked to the monitoring account.
+     *
+     * The default for this parameter is `false`.
+     *
+     * @var bool|null
+     */
+    private $includeLinkedAccounts;
+
+    /**
+     * Use this parameter to limit the results to only those log groups in the specified log group class. If you omit this
+     * parameter, log groups of all classes can be returned.
+     *
+     * Specifies the log group class for this log group. There are three classes:
+     *
+     * - The `Standard` log class supports all CloudWatch Logs features.
+     * - The `Infrequent Access` log class supports a subset of CloudWatch Logs features and incurs lower costs.
+     * - Use the `Delivery` log class only for delivering Lambda logs to store in Amazon S3 or Amazon Data Firehose. Log
+     *   events in log groups in the Delivery class are kept in CloudWatch Logs for only one day. This log class doesn't
+     *   offer rich CloudWatch Logs capabilities such as CloudWatch Logs Insights queries.
+     *
+     * For details about the features supported by each class, see Log classes [^1]
+     *
+     * [^1]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch_Logs_Log_Classes.html
+     *
+     * @var LogGroupClass::*|null
+     */
+    private $logGroupClass;
+
+    /**
+     * Use this array to filter the list of log groups returned. If you specify this parameter, the only other filter that
+     * you can choose to specify is `includeLinkedAccounts`.
+     *
+     * If you are using this operation in a monitoring account, you can specify the ARNs of log groups in source accounts
+     * and in the monitoring account itself. If you are using this operation in an account that is not a cross-account
+     * monitoring account, you can specify only log group names in the same account as the operation.
+     *
+     * @var string[]|null
+     */
+    private $logGroupIdentifiers;
+
+    /**
+     * @param array{
+     *   accountIdentifiers?: string[]|null,
+     *   logGroupNamePrefix?: string|null,
+     *   logGroupNamePattern?: string|null,
+     *   nextToken?: string|null,
+     *   limit?: int|null,
+     *   includeLinkedAccounts?: bool|null,
+     *   logGroupClass?: LogGroupClass::*|null,
+     *   logGroupIdentifiers?: string[]|null,
+     *   '@region'?: string|null,
+     * } $input
+     */
+    public function __construct(array $input = [])
+    {
+        $this->accountIdentifiers = $input['accountIdentifiers'] ?? null;
+        $this->logGroupNamePrefix = $input['logGroupNamePrefix'] ?? null;
+        $this->logGroupNamePattern = $input['logGroupNamePattern'] ?? null;
+        $this->nextToken = $input['nextToken'] ?? null;
+        $this->limit = $input['limit'] ?? null;
+        $this->includeLinkedAccounts = $input['includeLinkedAccounts'] ?? null;
+        $this->logGroupClass = $input['logGroupClass'] ?? null;
+        $this->logGroupIdentifiers = $input['logGroupIdentifiers'] ?? null;
+        parent::__construct($input);
+    }
+
+    /**
+     * @param array{
+     *   accountIdentifiers?: string[]|null,
+     *   logGroupNamePrefix?: string|null,
+     *   logGroupNamePattern?: string|null,
+     *   nextToken?: string|null,
+     *   limit?: int|null,
+     *   includeLinkedAccounts?: bool|null,
+     *   logGroupClass?: LogGroupClass::*|null,
+     *   logGroupIdentifiers?: string[]|null,
+     *   '@region'?: string|null,
+     * }|DescribeLogGroupsRequest $input
+     */
+    public static function create($input): self
+    {
+        return $input instanceof self ? $input : new self($input);
+    }
+
+    /**
+     * @return string[]
+     */
+    public function getAccountIdentifiers(): array
+    {
+        return $this->accountIdentifiers ?? [];
+    }
+
+    public function getIncludeLinkedAccounts(): ?bool
+    {
+        return $this->includeLinkedAccounts;
+    }
+
+    public function getLimit(): ?int
+    {
+        return $this->limit;
+    }
+
+    /**
+     * @return LogGroupClass::*|null
+     */
+    public function getLogGroupClass(): ?string
+    {
+        return $this->logGroupClass;
+    }
+
+    /**
+     * @return string[]
+     */
+    public function getLogGroupIdentifiers(): array
+    {
+        return $this->logGroupIdentifiers ?? [];
+    }
+
+    public function getLogGroupNamePattern(): ?string
+    {
+        return $this->logGroupNamePattern;
+    }
+
+    public function getLogGroupNamePrefix(): ?string
+    {
+        return $this->logGroupNamePrefix;
+    }
+
+    public function getNextToken(): ?string
+    {
+        return $this->nextToken;
+    }
+
+    /**
+     * @internal
+     */
+    public function request(): Request
+    {
+        // Prepare headers
+        $headers = [
+            'Content-Type' => 'application/x-amz-json-1.1',
+            'X-Amz-Target' => 'Logs_20140328.DescribeLogGroups',
+            'Accept' => 'application/json',
+        ];
+
+        // Prepare query
+        $query = [];
+
+        // Prepare URI
+        $uriString = '/';
+
+        // Prepare Body
+        $bodyPayload = $this->requestBody();
+        $body = empty($bodyPayload) ? '{}' : json_encode($bodyPayload, 4194304);
+
+        // Return the Request
+        return new Request('POST', $uriString, $query, $headers, StreamFactory::create($body));
+    }
+
+    /**
+     * @param string[] $value
+     */
+    public function setAccountIdentifiers(array $value): self
+    {
+        $this->accountIdentifiers = $value;
+
+        return $this;
+    }
+
+    public function setIncludeLinkedAccounts(?bool $value): self
+    {
+        $this->includeLinkedAccounts = $value;
+
+        return $this;
+    }
+
+    public function setLimit(?int $value): self
+    {
+        $this->limit = $value;
+
+        return $this;
+    }
+
+    /**
+     * @param LogGroupClass::*|null $value
+     */
+    public function setLogGroupClass(?string $value): self
+    {
+        $this->logGroupClass = $value;
+
+        return $this;
+    }
+
+    /**
+     * @param string[] $value
+     */
+    public function setLogGroupIdentifiers(array $value): self
+    {
+        $this->logGroupIdentifiers = $value;
+
+        return $this;
+    }
+
+    public function setLogGroupNamePattern(?string $value): self
+    {
+        $this->logGroupNamePattern = $value;
+
+        return $this;
+    }
+
+    public function setLogGroupNamePrefix(?string $value): self
+    {
+        $this->logGroupNamePrefix = $value;
+
+        return $this;
+    }
+
+    public function setNextToken(?string $value): self
+    {
+        $this->nextToken = $value;
+
+        return $this;
+    }
+
+    private function requestBody(): array
+    {
+        $payload = [];
+        if (null !== $v = $this->accountIdentifiers) {
+            $index = -1;
+            $payload['accountIdentifiers'] = [];
+            foreach ($v as $listValue) {
+                ++$index;
+                $payload['accountIdentifiers'][$index] = $listValue;
+            }
+        }
+        if (null !== $v = $this->logGroupNamePrefix) {
+            $payload['logGroupNamePrefix'] = $v;
+        }
+        if (null !== $v = $this->logGroupNamePattern) {
+            $payload['logGroupNamePattern'] = $v;
+        }
+        if (null !== $v = $this->nextToken) {
+            $payload['nextToken'] = $v;
+        }
+        if (null !== $v = $this->limit) {
+            $payload['limit'] = $v;
+        }
+        if (null !== $v = $this->includeLinkedAccounts) {
+            $payload['includeLinkedAccounts'] = (bool) $v;
+        }
+        if (null !== $v = $this->logGroupClass) {
+            if (!LogGroupClass::exists($v)) {
+                throw new InvalidArgument(\sprintf('Invalid parameter "logGroupClass" for "%s". The value "%s" is not a valid "LogGroupClass".', __CLASS__, $v));
+            }
+            $payload['logGroupClass'] = $v;
+        }
+        if (null !== $v = $this->logGroupIdentifiers) {
+            $index = -1;
+            $payload['logGroupIdentifiers'] = [];
+            foreach ($v as $listValue) {
+                ++$index;
+                $payload['logGroupIdentifiers'][$index] = $listValue;
+            }
+        }
+
+        return $payload;
+    }
+}
diff --git a/src/Service/CloudWatchLogs/src/Result/DescribeLogGroupsResponse.php b/src/Service/CloudWatchLogs/src/Result/DescribeLogGroupsResponse.php
new file mode 100644
index 000000000..a5b4f7640
--- /dev/null
+++ b/src/Service/CloudWatchLogs/src/Result/DescribeLogGroupsResponse.php
@@ -0,0 +1,144 @@
+
+ */
+class DescribeLogGroupsResponse extends Result implements \IteratorAggregate
+{
+    /**
+     * An array of structures, where each structure contains the information about one log group.
+     *
+     * @var LogGroup[]
+     */
+    private $logGroups;
+
+    /**
+     * @var string|null
+     */
+    private $nextToken;
+
+    /**
+     * Iterates over logGroups.
+     *
+     * @return \Traversable
+     */
+    public function getIterator(): \Traversable
+    {
+        yield from $this->getLogGroups();
+    }
+
+    /**
+     * @param bool $currentPageOnly When true, iterates over items of the current page. Otherwise also fetch items in the next pages.
+     *
+     * @return iterable
+     */
+    public function getLogGroups(bool $currentPageOnly = false): iterable
+    {
+        if ($currentPageOnly) {
+            $this->initialize();
+            yield from $this->logGroups;
+
+            return;
+        }
+
+        $client = $this->awsClient;
+        if (!$client instanceof CloudWatchLogsClient) {
+            throw new InvalidArgument('missing client injected in paginated result');
+        }
+        if (!$this->input instanceof DescribeLogGroupsRequest) {
+            throw new InvalidArgument('missing last request injected in paginated result');
+        }
+        $input = clone $this->input;
+        $page = $this;
+        while (true) {
+            $page->initialize();
+            if (null !== $page->nextToken) {
+                $input->setNextToken($page->nextToken);
+
+                $this->registerPrefetch($nextPage = $client->describeLogGroups($input));
+            } else {
+                $nextPage = null;
+            }
+
+            yield from $page->logGroups;
+
+            if (null === $nextPage) {
+                break;
+            }
+
+            $this->unregisterPrefetch($nextPage);
+            $page = $nextPage;
+        }
+    }
+
+    public function getNextToken(): ?string
+    {
+        $this->initialize();
+
+        return $this->nextToken;
+    }
+
+    protected function populateResult(Response $response): void
+    {
+        $data = $response->toArray();
+
+        $this->logGroups = empty($data['logGroups']) ? [] : $this->populateResultLogGroups($data['logGroups']);
+        $this->nextToken = isset($data['nextToken']) ? (string) $data['nextToken'] : null;
+    }
+
+    /**
+     * @return list
+     */
+    private function populateResultInheritedProperties(array $json): array
+    {
+        $items = [];
+        foreach ($json as $item) {
+            $a = isset($item) ? (string) $item : null;
+            if (null !== $a) {
+                $items[] = $a;
+            }
+        }
+
+        return $items;
+    }
+
+    private function populateResultLogGroup(array $json): LogGroup
+    {
+        return new LogGroup([
+            'logGroupName' => isset($json['logGroupName']) ? (string) $json['logGroupName'] : null,
+            'creationTime' => isset($json['creationTime']) ? (int) $json['creationTime'] : null,
+            'retentionInDays' => isset($json['retentionInDays']) ? (int) $json['retentionInDays'] : null,
+            'metricFilterCount' => isset($json['metricFilterCount']) ? (int) $json['metricFilterCount'] : null,
+            'arn' => isset($json['arn']) ? (string) $json['arn'] : null,
+            'storedBytes' => isset($json['storedBytes']) ? (int) $json['storedBytes'] : null,
+            'kmsKeyId' => isset($json['kmsKeyId']) ? (string) $json['kmsKeyId'] : null,
+            'dataProtectionStatus' => isset($json['dataProtectionStatus']) ? (string) $json['dataProtectionStatus'] : null,
+            'inheritedProperties' => !isset($json['inheritedProperties']) ? null : $this->populateResultInheritedProperties($json['inheritedProperties']),
+            'logGroupClass' => isset($json['logGroupClass']) ? (string) $json['logGroupClass'] : null,
+            'logGroupArn' => isset($json['logGroupArn']) ? (string) $json['logGroupArn'] : null,
+        ]);
+    }
+
+    /**
+     * @return LogGroup[]
+     */
+    private function populateResultLogGroups(array $json): array
+    {
+        $items = [];
+        foreach ($json as $item) {
+            $items[] = $this->populateResultLogGroup($item);
+        }
+
+        return $items;
+    }
+}
diff --git a/src/Service/CloudWatchLogs/src/ValueObject/LogGroup.php b/src/Service/CloudWatchLogs/src/ValueObject/LogGroup.php
new file mode 100644
index 000000000..b895b18d3
--- /dev/null
+++ b/src/Service/CloudWatchLogs/src/ValueObject/LogGroup.php
@@ -0,0 +1,236 @@
+|null
+     */
+    private $inheritedProperties;
+
+    /**
+     * This specifies the log group class for this log group. There are three classes:
+     *
+     * - The `Standard` log class supports all CloudWatch Logs features.
+     * - The `Infrequent Access` log class supports a subset of CloudWatch Logs features and incurs lower costs.
+     * - Use the `Delivery` log class only for delivering Lambda logs to store in Amazon S3 or Amazon Data Firehose. Log
+     *   events in log groups in the Delivery class are kept in CloudWatch Logs for only one day. This log class doesn't
+     *   offer rich CloudWatch Logs capabilities such as CloudWatch Logs Insights queries.
+     *
+     * For details about the features supported by the Standard and Infrequent Access classes, see Log classes [^1]
+     *
+     * [^1]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatch_Logs_Log_Classes.html
+     *
+     * @var LogGroupClass::*|null
+     */
+    private $logGroupClass;
+
+    /**
+     * The Amazon Resource Name (ARN) of the log group. This version of the ARN doesn't include a trailing `:*` after the
+     * log group name.
+     *
+     * Use this version to refer to the ARN in the following situations:
+     *
+     * - In the `logGroupIdentifier` input field in many CloudWatch Logs APIs.
+     * - In the `resourceArn` field in tagging APIs
+     * - In IAM policies, when specifying permissions for TagResource [^1], UntagResource [^2], and ListTagsForResource
+     *   [^3].
+     *
+     * [^1]: https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_TagResource.html
+     * [^2]: https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_UntagResource.html
+     * [^3]: https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_ListTagsForResource.html
+     *
+     * @var string|null
+     */
+    private $logGroupArn;
+
+    /**
+     * @param array{
+     *   logGroupName?: string|null,
+     *   creationTime?: int|null,
+     *   retentionInDays?: int|null,
+     *   metricFilterCount?: int|null,
+     *   arn?: string|null,
+     *   storedBytes?: int|null,
+     *   kmsKeyId?: string|null,
+     *   dataProtectionStatus?: DataProtectionStatus::*|null,
+     *   inheritedProperties?: array|null,
+     *   logGroupClass?: LogGroupClass::*|null,
+     *   logGroupArn?: string|null,
+     * } $input
+     */
+    public function __construct(array $input)
+    {
+        $this->logGroupName = $input['logGroupName'] ?? null;
+        $this->creationTime = $input['creationTime'] ?? null;
+        $this->retentionInDays = $input['retentionInDays'] ?? null;
+        $this->metricFilterCount = $input['metricFilterCount'] ?? null;
+        $this->arn = $input['arn'] ?? null;
+        $this->storedBytes = $input['storedBytes'] ?? null;
+        $this->kmsKeyId = $input['kmsKeyId'] ?? null;
+        $this->dataProtectionStatus = $input['dataProtectionStatus'] ?? null;
+        $this->inheritedProperties = $input['inheritedProperties'] ?? null;
+        $this->logGroupClass = $input['logGroupClass'] ?? null;
+        $this->logGroupArn = $input['logGroupArn'] ?? null;
+    }
+
+    /**
+     * @param array{
+     *   logGroupName?: string|null,
+     *   creationTime?: int|null,
+     *   retentionInDays?: int|null,
+     *   metricFilterCount?: int|null,
+     *   arn?: string|null,
+     *   storedBytes?: int|null,
+     *   kmsKeyId?: string|null,
+     *   dataProtectionStatus?: DataProtectionStatus::*|null,
+     *   inheritedProperties?: array|null,
+     *   logGroupClass?: LogGroupClass::*|null,
+     *   logGroupArn?: string|null,
+     * }|LogGroup $input
+     */
+    public static function create($input): self
+    {
+        return $input instanceof self ? $input : new self($input);
+    }
+
+    public function getArn(): ?string
+    {
+        return $this->arn;
+    }
+
+    public function getCreationTime(): ?int
+    {
+        return $this->creationTime;
+    }
+
+    /**
+     * @return DataProtectionStatus::*|null
+     */
+    public function getDataProtectionStatus(): ?string
+    {
+        return $this->dataProtectionStatus;
+    }
+
+    /**
+     * @return list
+     */
+    public function getInheritedProperties(): array
+    {
+        return $this->inheritedProperties ?? [];
+    }
+
+    public function getKmsKeyId(): ?string
+    {
+        return $this->kmsKeyId;
+    }
+
+    public function getLogGroupArn(): ?string
+    {
+        return $this->logGroupArn;
+    }
+
+    /**
+     * @return LogGroupClass::*|null
+     */
+    public function getLogGroupClass(): ?string
+    {
+        return $this->logGroupClass;
+    }
+
+    public function getLogGroupName(): ?string
+    {
+        return $this->logGroupName;
+    }
+
+    public function getMetricFilterCount(): ?int
+    {
+        return $this->metricFilterCount;
+    }
+
+    public function getRetentionInDays(): ?int
+    {
+        return $this->retentionInDays;
+    }
+
+    public function getStoredBytes(): ?int
+    {
+        return $this->storedBytes;
+    }
+}
diff --git a/src/Service/CloudWatchLogs/tests/Integration/CloudWatchLogsClientTest.php b/src/Service/CloudWatchLogs/tests/Integration/CloudWatchLogsClientTest.php
index caad37042..59f431cf2 100644
--- a/src/Service/CloudWatchLogs/tests/Integration/CloudWatchLogsClientTest.php
+++ b/src/Service/CloudWatchLogs/tests/Integration/CloudWatchLogsClientTest.php
@@ -6,6 +6,7 @@
 use AsyncAws\CloudWatchLogs\Enum\OrderBy;
 use AsyncAws\CloudWatchLogs\Input\CreateLogGroupRequest;
 use AsyncAws\CloudWatchLogs\Input\CreateLogStreamRequest;
+use AsyncAws\CloudWatchLogs\Input\DescribeLogGroupsRequest;
 use AsyncAws\CloudWatchLogs\Input\DescribeLogStreamsRequest;
 use AsyncAws\CloudWatchLogs\Input\FilterLogEventsRequest;
 use AsyncAws\CloudWatchLogs\Input\PutLogEventsRequest;
@@ -46,6 +47,23 @@ public function testCreateLogStream(): void
         $result->resolve();
     }
 
+    public function testDescribeLogGroups(): void
+    {
+        $client = $this->getClient();
+
+        $input = new DescribeLogGroupsRequest([
+            'accountIdentifiers' => ['123456789012'],
+            'logGroupNamePrefix' => 'searchForNamePrefix',
+            'limit' => 1337,
+            'includeLinkedAccounts' => false,
+        ]);
+        $result = $client->describeLogGroups($input);
+
+        $result->resolve();
+        self::assertEquals(200, $result->info()['status']);
+        self::assertInstanceOf(\Generator::class, $result->getLogGroups());
+    }
+
     public function testDescribeLogStreams(): void
     {
         $client = $this->getClient();
diff --git a/src/Service/CloudWatchLogs/tests/Unit/CloudWatchLogsClientTest.php b/src/Service/CloudWatchLogs/tests/Unit/CloudWatchLogsClientTest.php
index 468ea76c9..24daf6c07 100644
--- a/src/Service/CloudWatchLogs/tests/Unit/CloudWatchLogsClientTest.php
+++ b/src/Service/CloudWatchLogs/tests/Unit/CloudWatchLogsClientTest.php
@@ -5,9 +5,11 @@
 use AsyncAws\CloudWatchLogs\CloudWatchLogsClient;
 use AsyncAws\CloudWatchLogs\Input\CreateLogGroupRequest;
 use AsyncAws\CloudWatchLogs\Input\CreateLogStreamRequest;
+use AsyncAws\CloudWatchLogs\Input\DescribeLogGroupsRequest;
 use AsyncAws\CloudWatchLogs\Input\DescribeLogStreamsRequest;
 use AsyncAws\CloudWatchLogs\Input\FilterLogEventsRequest;
 use AsyncAws\CloudWatchLogs\Input\PutLogEventsRequest;
+use AsyncAws\CloudWatchLogs\Result\DescribeLogGroupsResponse;
 use AsyncAws\CloudWatchLogs\Result\DescribeLogStreamsResponse;
 use AsyncAws\CloudWatchLogs\Result\FilterLogEventsResponse;
 use AsyncAws\CloudWatchLogs\Result\PutLogEventsResponse;
@@ -46,6 +48,18 @@ public function testCreateLogStream(): void
         self::assertFalse($result->info()['resolved']);
     }
 
+    public function testDescribeLogGroups(): void
+    {
+        $client = new CloudWatchLogsClient([], new NullProvider(), new MockHttpClient());
+
+        $input = new DescribeLogGroupsRequest([
+        ]);
+        $result = $client->describeLogGroups($input);
+
+        self::assertInstanceOf(DescribeLogGroupsResponse::class, $result);
+        self::assertFalse($result->info()['resolved']);
+    }
+
     public function testDescribeLogStreams(): void
     {
         $client = new CloudWatchLogsClient([], new NullProvider(), new MockHttpClient());
diff --git a/src/Service/CloudWatchLogs/tests/Unit/Input/DescribeLogGroupsRequestTest.php b/src/Service/CloudWatchLogs/tests/Unit/Input/DescribeLogGroupsRequestTest.php
new file mode 100644
index 000000000..88e6314ff
--- /dev/null
+++ b/src/Service/CloudWatchLogs/tests/Unit/Input/DescribeLogGroupsRequestTest.php
@@ -0,0 +1,45 @@
+ ['123456789012'],
+            'includeLinkedAccounts' => false,
+            'limit' => 1337,
+            'logGroupClass' => LogGroupClass::STANDARD,
+            'logGroupIdentifiers' => ['logGroupIdentifier1'],
+            'logGroupNamePattern' => 'my-log-group-pattern',
+            'logGroupNamePrefix' => 'my-log-group',
+        ]);
+
+        // see https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DescribeLogGroups.html
+        $expected = 'POST / HTTP/1.0
+Content-Type: application/x-amz-json-1.1
+X-AMZ-TARGET: Logs_20140328.DescribeLogGroups
+Accept: application/json
+
+{
+    "accountIdentifiers": [
+        "123456789012"
+    ],
+    "includeLinkedAccounts": false,
+    "limit": 1337,
+    "logGroupClass": "STANDARD",
+    "logGroupIdentifiers": [
+        "logGroupIdentifier1"
+    ],
+    "logGroupNamePattern": "my-log-group-pattern",
+    "logGroupNamePrefix": "my-log-group"
+}';
+
+        self::assertRequestEqualsHttpRequest($expected, $input->request());
+    }
+}
diff --git a/src/Service/CloudWatchLogs/tests/Unit/Result/DescribeLogGroupsResponseTest.php b/src/Service/CloudWatchLogs/tests/Unit/Result/DescribeLogGroupsResponseTest.php
new file mode 100644
index 000000000..01f439905
--- /dev/null
+++ b/src/Service/CloudWatchLogs/tests/Unit/Result/DescribeLogGroupsResponseTest.php
@@ -0,0 +1,56 @@
+request('POST', 'http://localhost'), $client, new NullLogger()), new CloudWatchLogsClient(), new DescribeLogGroupsRequest([]));
+
+        /** @var LogGroup[] $logGroups */
+        $logGroups = iterator_to_array($result->getLogGroups(true));
+
+        self::assertCount(2, $logGroups);
+        self::assertSame('arn:aws:logs:us-east-1:123456789012:log-group:my-log-group-1:*', $logGroups[0]->getArn());
+        self::assertSame(1393545600000, $logGroups[0]->getCreationTime());
+        self::assertSame('my-log-group-1', $logGroups[0]->getLogGroupName());
+        self::assertSame(0, $logGroups[0]->getMetricFilterCount());
+        self::assertSame(14, $logGroups[0]->getRetentionInDays());
+        self::assertSame('arn:aws:kms:us-east-1:123456789012:key/abcd1234-a123-456a-a12b-a123b4cd56ef', $logGroups[0]->getKmsKeyId());
+    }
+}