private String createLogGroupAndLogStreamIfNeeded() {
        if (this.createLogGroupIfNeeded) {
            LOGGER.debug("Attempting to locate the log group [{}]", logGroupName);
            val describeLogGroupsResult = FunctionUtils.doAndHandle(
                () -> awsLogsClient.describeLogGroups(DescribeLogGroupsRequest.builder().logGroupNamePrefix(logGroupName).build()),
                throwable -> {
                    LOGGER.error(throwable.getMessage(), throwable);
                    return null;
                }).get();

            var createLogGroup = true;
            if (describeLogGroupsResult != null && describeLogGroupsResult.hasLogGroups()) {
                createLogGroup = describeLogGroupsResult.logGroups().stream().noneMatch(g -> g.logGroupName().equals(logGroupName));
            }
            if (createLogGroup) {
                try {
                    LOGGER.debug("Creating log group [{}]", logGroupName);
                    val createLogGroupRequest = CreateLogGroupRequest.builder().logGroupName(logStreamName).build();
                    awsLogsClient.createLogGroup(createLogGroupRequest);
                } catch (final Throwable throwable) {
                    LOGGER.error(throwable.getMessage(), throwable);
                }
            }
        }

        var logSequenceToken = StringUtils.EMPTY;
        var createLogStream = true;
        LOGGER.debug("Attempting to locate the log stream [{}] for group [{}]", logStreamName, logGroupName);
        val describeLogStreamsRequest = DescribeLogStreamsRequest.builder().logGroupName(logGroupName).logStreamNamePrefix(logStreamName).build();
        val describeLogStreamsResult = FunctionUtils.doAndHandle(
            () -> awsLogsClient.describeLogStreams(describeLogStreamsRequest),
            throwable -> {
                LOGGER.error(throwable.getMessage(), throwable);
                return null;
            }).get();
        if (describeLogStreamsResult != null && describeLogStreamsResult.hasLogStreams()) {
            for (val ls : describeLogStreamsResult.logStreams()) {
                if (logStreamName.equals(ls.logStreamName())) {
                    createLogStream = false;
                    logSequenceToken = ls.uploadSequenceToken();
                    LOGGER.debug("Found log stream [{}] with sequence token [{}]", logStreamName, logSequenceToken);
                    break;
                }
            }
        }

        if (createLogStream) {
            if (!this.createLogStreamIfNeeded) {
                throw new RuntimeException("Log stream does not exist, yet `createIfNeeded` is false. This will not work");
            }
            try {
                LOGGER.debug("Creating log stream [{}] for group [{}]", logStreamName, logGroupName);
                val createLogStreamRequest = CreateLogStreamRequest.builder().logGroupName(logGroupName).logStreamName(logStreamName).build();
                awsLogsClient.createLogStream(createLogStreamRequest);
            } catch (final Throwable throwable) {
                LOGGER.error(throwable.getMessage(), throwable);
            }
        }
        if (StringUtils.isBlank(logSequenceToken)) {
            LOGGER.warn("Unable to determine CloudWatch log sequence token. Log stream [{}] "
                + "likely does not exist for log group [{}], or cannot be determined.", logStreamName, logGroupName);
        }
        return logSequenceToken;
    }
Create appender cloud watch appender.

@param name                             the name
@param endpoint                         the endpoint
@param awsLogStreamName                 the aws log stream name
@param awsLogGroupName                  the aws log group name
@param awsLogStreamFlushPeriodInSeconds the aws log stream flush period in seconds
@param credentialAccessKey              the credential access key
@param credentialSecretKey              the credential secret key
@param awsLogRegionName                 the aws log region name
@param layout                           the layout
@param createIfNeeded                   whether to create resources if needed
@param createLogGroupIfNeeded           whether to create log group if needed
@param createLogStreamIfNeeded          whether to create log stream if needed
@return the cloud watch appender
support/cas-server-support-aws-cloudwatch/src/main/java/org/apereo/cas/logging/CloudWatchAppender.java