Repository: terraform-ibm-modules/terraform-ibm-cloud-logs
Pull request #3: Migrate code from observability-instances
Author: login: kierramarie
Labels: name: released
Created: 2025-03-11T15:46:26Z | Merged: 2025-03-12T13:41:55Z

### Description

Cloud logs code from the observabilities-instances repo has been moved here and examples for this module created. 

### Release required?
<!--- Identify the type of release. For information about the changes in a semantic versioning release, see [Release versioning](https://terraform-ibm-modules.github.io/documentation/#/versioning). --->

- [ ] No release
- [ ] Patch release (`x.x.X`)
- [ ] Minor release (`x.X.x`)
- [ ] Major release (`X.x.x`)

##### Release notes content

<!--- If a release is required, replace this text with information that users need to know about the release. Write the release notes to help users understand the changes, and include information about how to update from the previous version.

Your notes help the merger write the commit message for the PR that is published in the release notes for the module. --->

### Run the pipeline

If the CI pipeline doesn't run when you create the PR, the PR requires a user with GitHub collaborators access to run the pipeline.

Run the CI pipeline when the PR is ready for review and you expect tests to pass. Add a comment to the PR with the following text:

```
/run pipeline
```

### Checklist for reviewers

- [ ] If relevant, a test for the change is included or updated with this PR.
- [ ] If relevant, documentation for the change is included or updated with this PR.

### For mergers

- Use a conventional commit message to set the release level. Follow the [guidelines](https://terraform-ibm-modules.github.io/documentation/#/merging.md).
- Include information that users need to know about the PR in the commit message. The commit message becomes part of the GitHub release notes.
- Use the **Squash and merge** option.



Diff:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index d545b87..ccea4e3 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1,2 +1,2 @@
 # Primary owner should be listed first in list of global owners, followed by any secondary owners
-*       @ocofaigh @daniel-butler-irl
+*       @kierramarie @ocofaigh
diff --git a/.github/settings.yml b/.github/settings.yml
index 18e7e09..d178adf 100644
--- a/.github/settings.yml
+++ b/.github/settings.yml
@@ -22,7 +22,7 @@ repository:
 
   # Uncomment this description property
   # and update the description to the current repo description.
-  # description: ""
+  description: "This module supports configuring an IBM Cloud Logs instance, log routing tenants to enable platform logs and cloud logs policies."
 
   # Use a comma-separated list of topics to set on the repo (ensure not to use any caps in the topic string).
   topics: terraform, ibm-cloud, terraform-module, core-team, cloud-logs, logging, logs, observability
diff --git a/.secrets.baseline b/.secrets.baseline
index 0a4efa4..9d13462 100644
--- a/.secrets.baseline
+++ b/.secrets.baseline
@@ -3,7 +3,7 @@
     "files": "go.sum|^.secrets.baseline$",
     "lines": null
   },
-  "generated_at": "2024-11-22T17:36:38Z",
+  "generated_at": "2025-03-10T19:32:13Z",
   "plugins_used": [
     {
       "name": "AWSKeyDetector"
@@ -76,18 +76,7 @@
       "name": "TwilioKeyDetector"
     }
   ],
-  "results": {
-    "README.md": [
-      {
-        "hashed_secret": "ff9ee043d85595eb255c05dfe32ece02a53efbb2",
-        "is_secret": false,
-        "is_verified": false,
-        "line_number": 74,
-        "type": "Secret Keyword",
-        "verified_result": null
-      }
-    ]
-  },
+  "results": {},
   "version": "0.13.1+ibm.62.dss",
   "word_list": {
     "file": null,
diff --git a/README.md b/README.md
index 0ec97c8..eb92c7b 100644
--- a/README.md
+++ b/README.md
@@ -1,162 +1,145 @@
-<!-- Update this title with a descriptive name. Use sentence case. -->
-# Terraform modules template project
+# IBM Cloud Logs module
 
-<!--
-Update status and "latest release" badges:
-  1. For the status options, see https://terraform-ibm-modules.github.io/documentation/#/badge-status
-  2. Update the "latest release" badge to point to the correct module's repo. Replace "terraform-ibm-module-template" in two places.
--->
-[![Incubating (Not yet consumable)](https://img.shields.io/badge/status-Incubating%20(Not%20yet%20consumable)-red)](https://terraform-ibm-modules.github.io/documentation/#/badge-status)
-[![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-cloud-logs?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-cloud-logs/releases/latest)
-[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
-[![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/)
-[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
+This module supports configuring an IBM Cloud Logs instance, log routing tenants to enable platform logs and cloud logs policies.
 
-<!--
-Add a description of modules in this repo.
-Expand on the repo short description in the .github/settings.yml file.
+## Usage
 
-For information, see "Module names and descriptions" at
-https://terraform-ibm-modules.github.io/documentation/#/implementation-guidelines?id=module-names-and-descriptions
--->
-
-TODO: Replace this with a description of the modules in this repo.
-
-
-<!-- The following content is automatically populated by the pre-commit hook -->
-<!-- BEGIN OVERVIEW HOOK -->
-## Overview
-* [terraform-ibm-cloud-logs](#terraform-ibm-cloud-logs)
-* [Examples](./examples)
-    * [Advanced example](./examples/advanced)
-    * [Basic example](./examples/basic)
-* [Contributing](#contributing)
-<!-- END OVERVIEW HOOK -->
-
-
-<!--
-If this repo contains any reference architectures, uncomment the heading below and link to them.
-(Usually in the `/reference-architectures` directory.)
-See "Reference architecture" in the public documentation at
-https://terraform-ibm-modules.github.io/documentation/#/implementation-guidelines?id=reference-architecture
--->
-<!-- ## Reference architectures -->
-
-
-<!-- Replace this heading with the name of the root level module (the repo name) -->
-## terraform-ibm-cloud-logs
-
-### Usage
-
-<!--
-Add an example of the use of the module in the following code block.
-
-Use real values instead of "var.<var_name>" or other placeholder values
-unless real values don't help users know what to change.
--->
+To provision Cloud Logs instance
 
 ```hcl
+# Locals
+locals {
+  region      = "us-south"
+}
+
+# Required providers
 terraform {
-  required_version = ">= 1.9.0"
+  required_version = ">= 1.0.0"
   required_providers {
     ibm = {
-      source  = "IBM-Cloud/ibm"
-      version = "X.Y.Z"  # Lock into a provider version that satisfies the module constraints
+      source  = "ibm-cloud/ibm"
+      version = "X.Y.Z" # lock into a supported provider version
     }
   }
 }
-
-locals {
-    region = "us-south"
-}
-
 provider "ibm" {
-  ibmcloud_api_key = "XXXXXXXXXX"  # replace with apikey value
+  ibmcloud_api_key = XXXXXXXXXXXX  # pragma: allowlist secret
   region           = local.region
 }
 
-module "module_template" {
-  source            = "terraform-ibm-modules/<replace>/ibm"
+# IBM Cloud Logs
+module "cloud_logs" {
+  source            = "terraform-ibm-modules/observability-instances/ibm//modules/cloud_logs"
   version           = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release
+  resource_group_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX"
   region            = local.region
-  name              = "instance-name"
-  resource_group_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" # Replace with the actual ID of resource group to use
+  data_storage = {
+    # logs and metrics buckets must be different
+    logs_data = {
+      enabled         = true
+      bucket_crn      = "crn:v1:bluemix:public:cloud-object-storage:global:a/......"
+      bucket_endpoint = "s3.direct.us-south.cloud-object-storage.appdomain.cloud"
+    },
+    metrics_data = {
+      enabled         = true
+      bucket_crn      = "crn:v1:bluemix:public:cloud-object-storage:global:a/......"
+      bucket_endpoint = "s3.direct.us-south.cloud-object-storage.appdomain.cloud"
+    }
+  }
+  # Create policies
+  policies = [{
+    logs_policy_name        = "logs_policy_name"
+    logs_policy_priority    = "type_medium"
+    application_rule = [{
+      name         = "test-system-app"
+      rule_type_id = "start_with"
+    }]
+    subsystem_rule = [{
+      name         = "test-sub-system"
+      rule_type_id = "start_with"
+    }]
+    log_rules = [{
+      severities = ["info", "debug"]
+    }]
+  }]
 }
 ```
 
-### Required access policies
+### Required IAM access policies
 
-<!-- PERMISSIONS REQUIRED TO RUN MODULE
-If this module requires permissions, uncomment the following block and update
-the sample permissions, following the format.
-Replace the 'Sample IBM Cloud' service and roles with applicable values.
-The required information can usually be found in the services official
-IBM Cloud documentation.
-To view all available service permissions, you can go in the
-console at Manage > Access (IAM) > Access groups and click into an existing group
-(or create a new one) and in the 'Access' tab click 'Assign access'.
--->
-
-<!--
-You need the following permissions to run this module:
+You need the following permissions to run this module.
 
 - Service
     - **Resource group only**
         - `Viewer` access on the specific resource group
-    - **Sample IBM Cloud** service
+    - **Cloud Logs**
         - `Editor` platform access
         - `Manager` service access
--->
-
-<!-- NO PERMISSIONS FOR MODULE
-If no permissions are required for the module, uncomment the following
-statement instead the previous block.
--->
-
-<!-- No permissions are needed to run this module.-->
-
+    - **IBM Cloud Logs Routing** (Required if creating tenants, which are required to enable platform logs)
+        - `Editor` platform access
+        - `Manager` service access
+    - **Tagging service** (Required if attaching access tags to the ICL instance)
+        - `Editor` platform access
 
-<!-- The following content is automatically populated by the pre-commit hook -->
 <!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
 ### Requirements
 
 | Name | Version |
 |------|---------|
 | <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.9.0 |
-| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.71.2, < 2.0.0 |
+| <a name="requirement_ibm"></a> [ibm](#requirement\_ibm) | >= 1.76.1, < 2.0.0 |
+| <a name="requirement_random"></a> [random](#requirement\_random) | >= 3.5.1, < 4.0.0 |
+| <a name="requirement_time"></a> [time](#requirement\_time) | >= 0.9.1, < 1.0.0 |
 
 ### Modules
 
-No modules.
+| Name | Source | Version |
+|------|--------|---------|
+| <a name="module_cos_bucket_crn_parser"></a> [cos\_bucket\_crn\_parser](#module\_cos\_bucket\_crn\_parser) | terraform-ibm-modules/common-utilities/ibm//modules/crn-parser | 1.1.0 |
 
 ### Resources
 
 | Name | Type |
 |------|------|
-| [ibm_resource_instance.cos_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource |
+| [ibm_iam_authorization_policy.cos_policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
+| [ibm_iam_authorization_policy.en_policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
+| [ibm_iam_authorization_policy.logs_routing_policy](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/iam_authorization_policy) | resource |
+| [ibm_logs_outgoing_webhook.en_integration](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/logs_outgoing_webhook) | resource |
+| [ibm_logs_policy.logs_policies](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/logs_policy) | resource |
+| [ibm_logs_router_tenant.logs_router_tenant_instances](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/logs_router_tenant) | resource |
+| [ibm_resource_instance.cloud_logs](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_instance) | resource |
+| [ibm_resource_tag.cloud_logs_tag](https://registry.terraform.io/providers/ibm-cloud/ibm/latest/docs/resources/resource_tag) | resource |
+| [random_string.random_tenant_suffix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource |
+| [time_sleep.wait_for_cos_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource |
+| [time_sleep.wait_for_en_authorization_policy](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource |
 
 ### Inputs
 
 | Name | Description | Type | Default | Required |
 |------|-------------|------|---------|:--------:|
-| <a name="input_name"></a> [name](#input\_name) | A descriptive name used to identify the resource instance. | `string` | n/a | yes |
-| <a name="input_plan"></a> [plan](#input\_plan) | The name of the plan type supported by service. | `string` | `"standard"` | no |
-| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | The ID of the resource group where you want to create the service. | `string` | n/a | yes |
-| <a name="input_resource_tags"></a> [resource\_tags](#input\_resource\_tags) | List of resource tag to associate with the instance. | `list(string)` | `[]` | no |
+| <a name="input_access_tags"></a> [access\_tags](#input\_access\_tags) | A list of access tags to apply to the IBM Cloud Logs instance created by the module. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial. | `list(string)` | `[]` | no |
+| <a name="input_data_storage"></a> [data\_storage](#input\_data\_storage) | A logs data bucket and a metrics bucket in IBM Cloud Object Storage to store your IBM Cloud Logs data for long term storage, search, analysis and alerting. | <pre>object({<br/>    logs_data = optional(object({<br/>      enabled              = optional(bool, false)<br/>      bucket_crn           = optional(string)<br/>      bucket_endpoint      = optional(string)<br/>      skip_cos_auth_policy = optional(bool, false)<br/>    }), {})<br/>    metrics_data = optional(object({<br/>      enabled              = optional(bool, false)<br/>      bucket_crn           = optional(string)<br/>      bucket_endpoint      = optional(string)<br/>      skip_cos_auth_policy = optional(bool, false)<br/>    }), {})<br/>    }<br/>  )</pre> | <pre>{<br/>  "logs_data": null,<br/>  "metrics_data": null<br/>}</pre> | no |
+| <a name="input_existing_event_notifications_instances"></a> [existing\_event\_notifications\_instances](#input\_existing\_event\_notifications\_instances) | List of Event Notifications instance details for routing critical events that occur in your IBM Cloud Logs. | <pre>list(object({<br/>    en_instance_id      = string<br/>    en_region           = string<br/>    en_integration_name = optional(string)<br/>    skip_en_auth_policy = optional(bool, false)<br/>  }))</pre> | `[]` | no |
+| <a name="input_instance_name"></a> [instance\_name](#input\_instance\_name) | The name of the IBM Cloud Logs instance to create. Defaults to 'cloud-logs-<region>' | `string` | `null` | no |
+| <a name="input_logs_routing_tenant_regions"></a> [logs\_routing\_tenant\_regions](#input\_logs\_routing\_tenant\_regions) | Pass a list of regions to create a tenant for that is targetted to the Cloud Logs instance created by this module. To manage platform logs that are generated by IBM Cloud® services in a region of IBM Cloud, you must create a tenant in each region that you operate. Leave the list empty if you don't want to create any tenants. NOTE: You can only have 1 tenant per region in an account. | `list(any)` | `[]` | no |
+| <a name="input_plan"></a> [plan](#input\_plan) | The IBM Cloud Logs plan to provision. Available: standard | `string` | `"standard"` | no |
+| <a name="input_policies"></a> [policies](#input\_policies) | Configuration of Cloud Logs policies. | <pre>list(object({<br/>    logs_policy_name        = string<br/>    logs_policy_description = optional(string, null)<br/>    logs_policy_priority    = string<br/>    application_rule = optional(list(object({<br/>      name         = string<br/>      rule_type_id = string<br/>    })))<br/>    subsystem_rule = optional(list(object({<br/>      name         = string<br/>      rule_type_id = string<br/>    })))<br/>    log_rules = optional(list(object({<br/>      severities = list(string)<br/>    })))<br/>    archive_retention = optional(list(object({<br/>      id = string<br/>    })))<br/>  }))</pre> | `[]` | no |
+| <a name="input_region"></a> [region](#input\_region) | The IBM Cloud region where Cloud logs instance will be created. | `string` | `"us-south"` | no |
+| <a name="input_resource_group_id"></a> [resource\_group\_id](#input\_resource\_group\_id) | The id of the IBM Cloud resource group where the instance will be created. | `string` | `null` | no |
+| <a name="input_resource_tags"></a> [resource\_tags](#input\_resource\_tags) | Tags associated with the IBM Cloud Logs instance (Optional, array of strings). | `list(string)` | `[]` | no |
+| <a name="input_retention_period"></a> [retention\_period](#input\_retention\_period) | The number of days IBM Cloud Logs will retain the logs data in Priority insights. Allowed values: 7, 14, 30, 60, 90. | `number` | `7` | no |
+| <a name="input_service_endpoints"></a> [service\_endpoints](#input\_service\_endpoints) | The type of the service endpoint that will be set for the IBM Cloud Logs instance. Allowed values: public-and-private. | `string` | `"public-and-private"` | no |
+| <a name="input_skip_logs_routing_auth_policy"></a> [skip\_logs\_routing\_auth\_policy](#input\_skip\_logs\_routing\_auth\_policy) | Whether to create an IAM authorization policy that permits the Logs Routing server 'Sender' access to the IBM Cloud Logs instance created by this module. | `bool` | `false` | no |
 
 ### Outputs
 
 | Name | Description |
 |------|-------------|
-| <a name="output_account_id"></a> [account\_id](#output\_account\_id) | An alpha-numeric value identifying the account ID. |
-| <a name="output_crn"></a> [crn](#output\_crn) | The CRN of the resource instance. |
-| <a name="output_guid"></a> [guid](#output\_guid) | The GUID of the resource instance. |
-| <a name="output_id"></a> [id](#output\_id) | The unique identifier of the resource instance. |
+| <a name="output_crn"></a> [crn](#output\_crn) | The CRN of the provisioned Cloud Logs instance. |
+| <a name="output_guid"></a> [guid](#output\_guid) | The guid of the provisioned Cloud Logs instance. |
+| <a name="output_ingress_endpoint"></a> [ingress\_endpoint](#output\_ingress\_endpoint) | The public ingress endpoint of the provisioned Cloud Logs instance. |
+| <a name="output_ingress_private_endpoint"></a> [ingress\_private\_endpoint](#output\_ingress\_private\_endpoint) | The private ingress endpoint of the provisioned Cloud Logs instance. |
+| <a name="output_logs_policies_details"></a> [logs\_policies\_details](#output\_logs\_policies\_details) | The details of the Cloud logs policies created. |
+| <a name="output_name"></a> [name](#output\_name) | The name of the provisioned Cloud Logs instance. |
+| <a name="output_resource_group_id"></a> [resource\_group\_id](#output\_resource\_group\_id) | The resource group where Cloud Logs instance resides. |
 <!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
-
-<!-- Leave this section as is so that your module has a link to local development environment set-up steps for contributors to follow -->
-## Contributing
-
-You can report issues and request features for this module in GitHub issues in the module repo. See [Report an issue or request a feature](https://github.com/terraform-ibm-modules/.github/blob/main/.github/SUPPORT.md).
-
-To set up your local development environment, see [Local development setup](https://terraform-ibm-modules.github.io/documentation/#/local-dev-setup) in the project documentation.
diff --git a/examples/advanced/README.md b/examples/advanced/README.md
index d52511a..05ad8b6 100644
--- a/examples/advanced/README.md
+++ b/examples/advanced/README.md
@@ -2,3 +2,10 @@
 
 <!-- There is a pre-commit hook that will take the title of each example add include it in the repos main README.md  -->
 <!-- Add text below should describe exactly what resources are provisioned / configured by the example  -->
+
+Example that configures:
+
+- COS instance and KMS encrypted COS buckets
+- Cloud Logs with Event Notifications integration
+- Cloud Logs policies
+- Key Protect instance and root key
diff --git a/examples/advanced/main.tf b/examples/advanced/main.tf
index 29e4104..7a552db 100644
--- a/examples/advanced/main.tf
+++ b/examples/advanced/main.tf
@@ -10,23 +10,163 @@ module "resource_group" {
   existing_resource_group_name = var.resource_group
 }
 
+##############################################################################
+# Key Protect Instance + Key (used to encrypt bucket)
+##############################################################################
+
+locals {
+  key_ring_name = "${var.prefix}-cloud-logs"
+  key_name      = "${var.prefix}-cloud-logs-key"
+}
+
+module "key_protect" {
+  source            = "terraform-ibm-modules/kms-all-inclusive/ibm"
+  version           = "4.20.0"
+  resource_group_id = module.resource_group.resource_group_id
+  region            = var.region
+  resource_tags     = var.resource_tags
+  keys = [
+    {
+      key_ring_name = local.key_ring_name
+      keys = [
+        {
+          key_name = local.key_name
+        }
+      ]
+    }
+  ]
+  key_protect_instance_name = "${var.prefix}-kp"
+}
+
+##############################################################################
+# Event Notification
+##############################################################################
+
+module "event_notification_1" {
+  source            = "terraform-ibm-modules/event-notifications/ibm"
+  version           = "1.18.8"
+  resource_group_id = module.resource_group.resource_group_id
+  name              = "${var.prefix}-en-1"
+  tags              = var.resource_tags
+  plan              = "standard"
+  service_endpoints = "public"
+  region            = var.region
+}
+
+module "event_notification_2" {
+  source            = "terraform-ibm-modules/event-notifications/ibm"
+  version           = "1.18.8"
+  resource_group_id = module.resource_group.resource_group_id
+  name              = "${var.prefix}-en-2"
+  tags              = var.resource_tags
+  plan              = "standard"
+  service_endpoints = "public"
+  region            = var.region
+}
+
+##############################################################################
+# COS instance + buckets
+##############################################################################
+
+module "cos" {
+  source            = "terraform-ibm-modules/cos/ibm"
+  version           = "8.19.5"
+  resource_group_id = module.resource_group.resource_group_id
+  cos_instance_name = "${var.prefix}-cos"
+  cos_tags          = var.resource_tags
+  create_cos_bucket = false
+}
+
+locals {
+  logs_bucket_name    = "${var.prefix}-logs-data"
+  metrics_bucket_name = "${var.prefix}-metrics-data"
+}
+
+module "buckets" {
+  source  = "terraform-ibm-modules/cos/ibm//modules/buckets"
+  version = "8.19.5"
+  bucket_configs = [
+    {
+      bucket_name                   = local.logs_bucket_name
+      kms_encryption_enabled        = true
+      region_location               = var.region
+      resource_instance_id          = module.cos.cos_instance_id
+      kms_guid                      = module.key_protect.kms_guid
+      kms_key_crn                   = module.key_protect.keys["${local.key_ring_name}.${local.key_name}"].crn
+      skip_iam_authorization_policy = false
+    },
+    {
+      bucket_name                   = local.metrics_bucket_name
+      kms_encryption_enabled        = true
+      region_location               = var.region
+      resource_instance_id          = module.cos.cos_instance_id
+      kms_guid                      = module.key_protect.kms_guid
+      kms_key_crn                   = module.key_protect.keys["${local.key_ring_name}.${local.key_name}"].crn
+      skip_iam_authorization_policy = true # Auth policy created in first bucket
+    }
+  ]
+}
+
 ########################################################################################################################
-# COS
+# Cloud Logs
 ########################################################################################################################
 
 #
 # Developer tips:
 #   - Call the local module / modules in the example to show how they can be consumed
-#   - Include the actual module source as a code comment like below so consumers know how to consume from correct location
+#   - include the actual module source as a code comment like below so consumers know how to consume from correct location
 #
 
-module "cos" {
-  source = "../.."
-  # remove the above line and uncomment the below 2 lines to consume the module from the registry
-  # source            = "terraform-ibm-modules/<replace>/ibm"
-  # version           = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release
-  name              = "${var.prefix}-cos"
+locals {
+  cloud_logs_instance_name = "${var.prefix}-cloud-logs"
+}
+
+module "cloud_logs" {
+  source = "../../"
+  # delete line above and use below syntax to pull module source from hashicorp when consuming this module
+  # source    = "terraform-ibm-modules/cloud-logs/ibm"
+  # version   = "X.Y.Z" # Replace "X.X.X" with a release version to lock into a specific release
   resource_group_id = module.resource_group.resource_group_id
+  region            = var.region
+  instance_name     = local.cloud_logs_instance_name
   resource_tags     = var.resource_tags
-  plan              = "cos-one-rate-plan"
+  access_tags       = var.access_tags
+  data_storage = {
+    # logs and metrics buckets must be different
+    logs_data = {
+      enabled         = true
+      bucket_crn      = module.buckets.buckets[local.logs_bucket_name].bucket_crn
+      bucket_endpoint = module.buckets.buckets[local.logs_bucket_name].s3_endpoint_direct
+    },
+    metrics_data = {
+      enabled         = true
+      bucket_crn      = module.buckets.buckets[local.metrics_bucket_name].bucket_crn
+      bucket_endpoint = module.buckets.buckets[local.metrics_bucket_name].s3_endpoint_direct
+    }
+  }
+  policies = [{
+    logs_policy_name     = "${var.prefix}-logs-policy-1"
+    logs_policy_priority = "type_low"
+    application_rule = [{
+      name         = "test-system-app"
+      rule_type_id = "start_with"
+    }]
+    log_rules = [{
+      severities = ["info", "debug"]
+    }]
+    subsystem_rule = [{
+      name         = "test-sub-system"
+      rule_type_id = "start_with"
+    }]
+  }]
+  existing_event_notifications_instances = [{
+    en_instance_id      = module.event_notification_1.guid
+    en_region           = var.region
+    en_integration_name = "${var.prefix}-en-1"
+    },
+    {
+      en_instance_id      = module.event_notification_2.guid
+      en_region           = var.region
+      en_integration_name = "${var.prefix}-en-2"
+  }]
 }
diff --git a/examples/advanced/outputs.tf b/examples/advanced/outputs.tf
index 316751f..9e63056 100644
--- a/examples/advanced/outputs.tf
+++ b/examples/advanced/outputs.tf
@@ -7,32 +7,67 @@
 #   - Include all relevant outputs from the modules being called in the example
 #
 
-output "account_id" {
-  description = "An alpha-numeric value identifying the account ID."
-  value       = module.cos.account_id
+output "cloud_logs_crn" {
+  value       = module.cloud_logs.crn
+  description = "The id of the provisioned Cloud Logs instance."
 }
 
-output "guid" {
-  description = "The GUID of the resource instance."
-  value       = module.cos.account_id
+output "cloud_logs_guid" {
+  value       = module.cloud_logs.guid
+  description = "The guid of the provisioned Cloud Logs instance."
 }
 
-output "id" {
-  description = "The unique identifier of the resource instance."
-  value       = module.cos.id
+output "cloud_logs_name" {
+  value       = module.cloud_logs.name
+  description = "The name of the provisioned Cloud Logs instance."
 }
 
-output "crn" {
-  description = "The CRN of the resource instance."
-  value       = module.cos.crn
+output "resource_group_id" {
+  value       = module.cloud_logs.resource_group_id
+  description = "The resource group where Cloud Logs instance resides."
 }
 
-output "resource_group_name" {
-  description = "Resource group name."
-  value       = module.resource_group.resource_group_name
+output "cloud_logs_ingress_endpoint" {
+  value       = module.cloud_logs.ingress_endpoint
+  description = "The public ingress endpoint of the provisioned Cloud Logs instance."
 }
 
-output "resource_group_id" {
-  description = "Resource group ID."
-  value       = module.resource_group.resource_group_id
+output "cloud_logs_ingress_private_endpoint" {
+  value       = module.cloud_logs.ingress_private_endpoint
+  description = "The private ingress endpoint of the provisioned Cloud Logs instance."
+}
+
+output "cos_crn" {
+  value       = module.cos.cos_instance_id
+  description = "The id of the provisioned Cloud Object Storage instance."
+}
+
+output "logs_bucket_crn" {
+  value       = module.buckets.buckets[local.logs_bucket_name].bucket_crn
+  description = "The id of the provisioned Cloud Object Storage bucket for logs."
+}
+
+output "logs_bucket_name" {
+  value       = local.logs_bucket_name
+  description = "The name of the provisioned Cloud Object Storage bucket for logs."
+}
+
+output "metrics_bucket_crn" {
+  value       = module.buckets.buckets[local.metrics_bucket_name].bucket_crn
+  description = "The id of the provisioned Cloud Object Storage bucket for metrics."
+}
+
+output "metrics_bucket_name" {
+  value       = local.metrics_bucket_name
+  description = "The name of the provisioned Cloud Object Storage bucket for metrics."
+}
+
+output "event_notification_1_crn" {
+  value       = module.event_notification_1.crn
+  description = "The id of the provisioned Event Notifications 1 instance."
+}
+
+output "event_notification_2_crn" {
+  value       = module.event_notification_2.crn
+  description = "The id of the provisioned Event Notifications 2 instance."
 }
diff --git a/examples/advanced/variables.tf b/examples/advanced/variables.tf
index d460364..74fafcd 100644
--- a/examples/advanced/variables.tf
+++ b/examples/advanced/variables.tf
@@ -37,3 +37,9 @@ variable "resource_tags" {
   description = "List of resource tag to associate with all resource instances created by this example."
   default     = []
 }
+
+variable "access_tags" {
+  type        = list(string)
+  description = "Optional list of access management tags to add to resources that are created."
+  default     = []
+}
diff --git a/examples/basic/README.md b/examples/basic/README.md
index e5977ae..cab6f39 100644
--- a/examples/basic/README.md
+++ b/examples/basic/README.md
@@ -8,4 +8,6 @@ The text below should describe exactly what resources are provisioned / configur
 
 An end-to-end basic example that will provision the following:
 - A new resource group if one is not passed in.
-- A new standard plan Cloud Object Storage instance using the root level module.
+- A new standard plan Cloud Object Storage instance.
+- Two Cloud Object Storage buckets.
+- A Cloud Logs instance using root module, attached to provisioned Cloud Object Storage buckets.
diff --git a/examples/basic/main.tf b/examples/basic/main.tf
index 410054a..0d6c858 100644
--- a/examples/basic/main.tf
+++ b/examples/basic/main.tf
@@ -10,8 +10,49 @@ module "resource_group" {
   existing_resource_group_name = var.resource_group
 }
 
+##############################################################################
+# COS instance
+##############################################################################
+
+module "cos" {
+  source            = "terraform-ibm-modules/cos/ibm"
+  version           = "8.19.5"
+  resource_group_id = module.resource_group.resource_group_id
+  cos_instance_name = "${var.prefix}-cos"
+  cos_tags          = var.resource_tags
+  create_cos_bucket = false
+}
+
+##############################################################################
+# COS buckets
+##############################################################################
+
+locals {
+  logs_bucket_name    = "${var.prefix}-logs-data"
+  metrics_bucket_name = "${var.prefix}-metrics-data"
+}
+
+module "buckets" {
+  source  = "terraform-ibm-modules/cos/ibm//modules/buckets"
+  version = "8.19.5"
+  bucket_configs = [
+    {
+      bucket_name            = local.logs_bucket_name
+      kms_encryption_enabled = false
+      region_location        = var.region
+      resource_instance_id   = module.cos.cos_instance_id
+    },
+    {
+      bucket_name            = local.metrics_bucket_name
+      kms_encryption_enabled = false
+      region_location        = var.region
+      resource_instance_id   = module.cos.cos_instance_id
+    }
+  ]
+}
+
 ########################################################################################################################
-# COS
+# Cloud Logs
 ########################################################################################################################
 
 #
@@ -20,12 +61,31 @@ module "resource_group" {
 #   - include the actual module source as a code comment like below so consumers know how to consume from correct location
 #
 
-module "cos" {
-  source = "../.."
-  # remove the above line and uncomment the below 2 lines to consume the module from the registry
-  # source            = "terraform-ibm-modules/<replace>/ibm"
-  # version           = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release
-  name              = "${var.prefix}-cos"
+locals {
+  cloud_logs_instance_name = "${var.prefix}-cloud-logs"
+}
+
+module "cloud_logs" {
+  source = "../../"
+  # delete line above and use below syntax to pull module source from hashicorp when consuming this module
+  # source    = "terraform-ibm-modules/cloud-logs/ibm"
+  # version   = "X.Y.Z" # Replace "X.X.X" with a release version to lock into a specific release
   resource_group_id = module.resource_group.resource_group_id
+  region            = var.region
+  instance_name     = local.cloud_logs_instance_name
   resource_tags     = var.resource_tags
+  access_tags       = var.access_tags
+  data_storage = {
+    # logs and metrics buckets must be different
+    logs_data = {
+      enabled         = true
+      bucket_crn      = module.buckets.buckets[local.logs_bucket_name].bucket_crn
+      bucket_endpoint = module.buckets.buckets[local.logs_bucket_name].s3_endpoint_direct
+    },
+    metrics_data = {
+      enabled         = true
+      bucket_crn      = module.buckets.buckets[local.metrics_bucket_name].bucket_crn
+      bucket_endpoint = module.buckets.buckets[local.metrics_bucket_name].s3_endpoint_direct
+    }
+  }
 }
diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf
index 552db48..7266d00 100644
--- a/examples/basic/outputs.tf
+++ b/examples/basic/outputs.tf
@@ -7,32 +7,57 @@
 #   - Include all relevant outputs from the modules being called in the example
 #
 
-output "account_id" {
-  description = "An alpha-numeric value identifying the account ID."
-  value       = module.cos.account_id
+output "cloud_logs_crn" {
+  value       = module.cloud_logs.crn
+  description = "The id of the provisioned Cloud Logs instance."
 }
 
-output "guid" {
-  description = "The GUID of the resource instance."
-  value       = module.cos.account_id
+output "cloud_logs_guid" {
+  value       = module.cloud_logs.guid
+  description = "The guid of the provisioned Cloud Logs instance."
 }
 
-output "id" {
-  description = "The unique identifier of the resource instance."
-  value       = module.cos.id
+output "cloud_logs_name" {
+  value       = module.cloud_logs.name
+  description = "The name of the provisioned Cloud Logs instance."
 }
 
-output "crn" {
-  description = "The CRN of the resource instance."
-  value       = module.cos.crn
+output "resource_group_id" {
+  value       = module.cloud_logs.resource_group_id
+  description = "The resource group where Cloud Logs instance resides."
 }
 
-output "resource_group_name" {
-  description = "Resource group name."
-  value       = module.resource_group.resource_group_name
+output "cloud_logs_ingress_endpoint" {
+  value       = module.cloud_logs.ingress_endpoint
+  description = "The public ingress endpoint of the provisioned Cloud Logs instance."
 }
 
-output "resource_group_id" {
-  description = "Resource group ID."
-  value       = module.resource_group.resource_group_id
+output "cloud_logs_ingress_private_endpoint" {
+  value       = module.cloud_logs.ingress_private_endpoint
+  description = "The private ingress endpoint of the provisioned Cloud Logs instance."
+}
+
+output "cos_crn" {
+  value       = module.cos.cos_instance_id
+  description = "The id of the provisioned Cloud Object Storage instance."
+}
+
+output "logs_bucket_crn" {
+  value       = module.buckets.buckets[local.logs_bucket_name].bucket_crn
+  description = "The id of the provisioned Cloud Object Storage bucket for logs."
+}
+
+output "logs_bucket_name" {
+  value       = local.logs_bucket_name
+  description = "The name of the provisioned Cloud Object Storage bucket for logs."
+}
+
+output "metrics_bucket_crn" {
+  value       = module.buckets.buckets[local.metrics_bucket_name].bucket_crn
+  description = "The id of the provisioned Cloud Object Storage bucket for metrics."
+}
+
+output "metrics_bucket_name" {
+  value       = local.metrics_bucket_name
+  description = "The name of the provisioned Cloud Object Storage bucket for metrics."
 }
diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf
index d460364..74fafcd 100644
--- a/examples/basic/variables.tf
+++ b/examples/basic/variables.tf
@@ -37,3 +37,9 @@ variable "resource_tags" {
   description = "List of resource tag to associate with all resource instances created by this example."
   default     = []
 }
+
+variable "access_tags" {
+  type        = list(string)
+  description = "Optional list of access management tags to add to resources that are created."
+  default     = []
+}
diff --git a/examples/basic/version.tf b/examples/basic/version.tf
index 401504c..bcb8b7a 100644
--- a/examples/basic/version.tf
+++ b/examples/basic/version.tf
@@ -10,7 +10,7 @@ terraform {
   required_providers {
     ibm = {
       source  = "IBM-Cloud/ibm"
-      version = "1.71.2"
+      version = "1.76.1"
     }
   }
 }
diff --git a/main.tf b/main.tf
index b6b879e..c8d3e40 100644
--- a/main.tf
+++ b/main.tf
@@ -1,13 +1,224 @@
-#
-# Developer tips:
-#   - Below code should be replaced with the code for the root level module
-#
+locals {
+  instance_name = var.instance_name != null ? var.instance_name : "cloud-logs-${var.region}"
+}
+
 
-resource "ibm_resource_instance" "cos_instance" {
-  name              = var.name
+# Cloud Logs
+resource "ibm_resource_instance" "cloud_logs" {
+  depends_on        = [time_sleep.wait_for_cos_authorization_policy]
+  name              = local.instance_name
   resource_group_id = var.resource_group_id
-  service           = "cloud-object-storage"
+  service           = "logs"
   plan              = var.plan
-  location          = "global"
   tags              = var.resource_tags
+  location          = var.region
+  parameters = {
+    "logs_bucket_crn"         = var.data_storage.logs_data.enabled ? var.data_storage.logs_data.bucket_crn : null
+    "logs_bucket_endpoint"    = var.data_storage.logs_data.enabled ? var.data_storage.logs_data.bucket_endpoint : null
+    "metrics_bucket_crn"      = var.data_storage.metrics_data.enabled ? var.data_storage.metrics_data.bucket_crn : null
+    "metrics_bucket_endpoint" = var.data_storage.metrics_data.enabled ? var.data_storage.metrics_data.bucket_endpoint : null
+    "retention_period"        = var.retention_period
+  }
+  service_endpoints = var.service_endpoints
+}
+
+resource "ibm_resource_tag" "cloud_logs_tag" {
+  count       = length(var.access_tags) == 0 ? 0 : 1
+  resource_id = ibm_resource_instance.cloud_logs.crn
+  tags        = var.access_tags
+  tag_type    = "access"
+}
+
+##############################################################################
+# Get Cloud Account ID
+##############################################################################
+
+# If logs or metrics data is enabled, parse details from it
+module "cos_bucket_crn_parser" {
+  for_each = { for index, bucket in var.data_storage : index => bucket if bucket.enabled && !bucket.skip_cos_auth_policy }
+  source   = "terraform-ibm-modules/common-utilities/ibm//modules/crn-parser"
+  version  = "1.1.0"
+  crn      = each.value.bucket_crn
+}
+
+resource "ibm_iam_authorization_policy" "cos_policy" {
+  for_each                 = { for index, bucket in var.data_storage : index => bucket if bucket.enabled && !bucket.skip_cos_auth_policy }
+  source_service_name      = "logs"
+  source_resource_group_id = var.resource_group_id
+  roles                    = ["Writer"]
+  description              = "Allow Cloud logs instances `Writer` access to the COS bucket with ID ${regex("bucket:(.*)", each.value.bucket_crn)[0]}, in the COS instance with ID ${regex(".*:(.*):bucket:.*", each.value.bucket_crn)[0]}."
+
+  resource_attributes {
+    name     = "serviceName"
+    operator = "stringEquals"
+    value    = "cloud-object-storage"
+  }
+
+  resource_attributes {
+    name     = "accountId"
+    operator = "stringEquals"
+    value    = module.cos_bucket_crn_parser[each.key].account_id
+  }
+
+  resource_attributes {
+    name     = "serviceInstance"
+    operator = "stringEquals"
+    value    = regex(".*:(.*):bucket:.*", each.value.bucket_crn)[0]
+  }
+
+  resource_attributes {
+    name     = "resourceType"
+    operator = "stringEquals"
+    value    = "bucket"
+  }
+
+  resource_attributes {
+    name     = "resource"
+    operator = "stringEquals"
+    value    = regex("bucket:(.*)", each.value.bucket_crn)[0]
+  }
+}
+
+resource "time_sleep" "wait_for_cos_authorization_policy" {
+  depends_on = [ibm_iam_authorization_policy.cos_policy]
+  # trigger once if any of the buckets create an auth policy
+  count           = anytrue([for _, bucket in var.data_storage : bucket.enabled && !bucket.skip_cos_auth_policy]) ? 1 : 0
+  create_duration = "30s"
+}
+
+##############################################################################
+# EN Integration
+##############################################################################
+
+# Create IAM Authorization Policies to allow Cloud Logs to access event notification
+resource "ibm_iam_authorization_policy" "en_policy" {
+  for_each                    = { for idx, en in var.existing_event_notifications_instances : idx => en if !en.skip_en_auth_policy }
+  source_service_name         = "logs"
+  source_resource_instance_id = ibm_resource_instance.cloud_logs.guid
+  target_service_name         = "event-notifications"
+  target_resource_instance_id = each.value.en_instance_id
+  roles                       = ["Event Source Manager", "Viewer"]
+  description                 = "Allow Cloud Logs with instance ID ${ibm_resource_instance.cloud_logs.guid} 'Event Source Manager' and 'Viewer' role access on the Event Notification instance GUID ${each.value.en_instance_id}"
+}
+
+resource "time_sleep" "wait_for_en_authorization_policy" {
+  depends_on      = [ibm_iam_authorization_policy.en_policy]
+  create_duration = "30s"
+}
+
+resource "ibm_logs_outgoing_webhook" "en_integration" {
+  depends_on  = [time_sleep.wait_for_en_authorization_policy]
+  for_each    = { for idx, en in var.existing_event_notifications_instances : idx => en }
+  instance_id = ibm_resource_instance.cloud_logs.guid
+  region      = var.region
+  name        = each.value.en_integration_name == null ? "${local.instance_name}-en-integration-${each.key}" : each.value.en_integration_name
+  type        = "ibm_event_notifications"
+
+  ibm_event_notifications {
+    event_notifications_instance_id = each.value.en_instance_id
+    region_id                       = each.value.en_region
+  }
+}
+
+##############################################################################
+# Logs Routing
+##############################################################################
+
+# Create required auth policy to allow log routing service to send logs to the cloud logs instance
+resource "ibm_iam_authorization_policy" "logs_routing_policy" {
+  count               = !var.skip_logs_routing_auth_policy ? 1 : 0
+  source_service_name = "logs-router"
+  roles               = ["Sender"]
+  description         = "Allow Logs Routing `Sender` access to the IBM Cloud Logs with ID ${ibm_resource_instance.cloud_logs.guid}."
+
+  resource_attributes {
+    name     = "serviceName"
+    operator = "stringEquals"
+    value    = "logs"
+  }
+
+  resource_attributes {
+    name     = "accountId"
+    operator = "stringEquals"
+    value    = ibm_resource_instance.cloud_logs.account_id
+  }
+
+  resource_attributes {
+    name     = "serviceInstance"
+    operator = "stringEquals"
+    value    = ibm_resource_instance.cloud_logs.guid
+  }
+}
+
+resource "random_string" "random_tenant_suffix" {
+  length  = 4
+  numeric = true
+  upper   = false
+  lower   = false
+  special = false
+}
+
+locals {
+  logs_routing_tenant_target_name = replace(substr(local.instance_name, 0, 32), "/[^a-zA-Z0-9]+$/", "")
+}
+
+resource "ibm_logs_router_tenant" "logs_router_tenant_instances" {
+  for_each = toset(var.logs_routing_tenant_regions)
+  name     = "${each.key}-${random_string.random_tenant_suffix.result}"
+  region   = each.key
+  targets {
+    log_sink_crn = ibm_resource_instance.cloud_logs.crn
+    name         = local.logs_routing_tenant_target_name
+    parameters {
+      host = ibm_resource_instance.cloud_logs.extensions.external_ingress
+      port = 443
+    }
+  }
+}
+
+##############################################################################
+# Configure Logs Policies - TCO Optimizer
+##############################################################################
+
+resource "ibm_logs_policy" "logs_policies" {
+  for_each = {
+    for policy in var.policies :
+    policy.logs_policy_name => policy
+  }
+  instance_id   = ibm_resource_instance.cloud_logs.guid
+  region        = ibm_resource_instance.cloud_logs.location
+  endpoint_type = ibm_resource_instance.cloud_logs.service_endpoints
+  name          = each.value.logs_policy_name
+  description   = each.value.logs_policy_description
+  priority      = each.value.logs_policy_priority
+
+  dynamic "application_rule" {
+    for_each = each.value.application_rule != null ? each.value.application_rule : []
+    content {
+      name         = application_rule.value["name"]
+      rule_type_id = application_rule.value["rule_type_id"]
+    }
+  }
+
+  dynamic "log_rules" {
+    for_each = each.value.log_rules
+    content {
+      severities = log_rules.value["severities"]
+    }
+  }
+
+  dynamic "subsystem_rule" {
+    for_each = each.value.subsystem_rule != null ? each.value.subsystem_rule : []
+    content {
+      name         = subsystem_rule.value["name"]
+      rule_type_id = subsystem_rule.value["rule_type_id"]
+    }
+  }
+
+  dynamic "archive_retention" {
+    for_each = each.value.archive_retention != null ? each.value.archive_retention : []
+    content {
+      id = archive_retention.value["id"]
+    }
+  }
 }
diff --git a/outputs.tf b/outputs.tf
index 1c0cf4c..dd376bb 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -1,30 +1,34 @@
-########################################################################################################################
-# Outputs
-########################################################################################################################
+output "crn" {
+  value       = ibm_resource_instance.cloud_logs.id
+  description = "The CRN of the provisioned Cloud Logs instance."
+}
+
+output "guid" {
+  value       = ibm_resource_instance.cloud_logs.guid
+  description = "The guid of the provisioned Cloud Logs instance."
+}
 
-#
-# Developer tips:
-#   - Below are some good practise sample outputs
-#   - They should be updated for outputs applicable to the module being added
-#   - Use variable validation when possible
-#
+output "name" {
+  value       = ibm_resource_instance.cloud_logs.name
+  description = "The name of the provisioned Cloud Logs instance."
+}
 
-output "account_id" {
-  description = "An alpha-numeric value identifying the account ID."
-  value       = ibm_resource_instance.cos_instance.account_id
+output "resource_group_id" {
+  value       = ibm_resource_instance.cloud_logs.resource_group_id
+  description = "The resource group where Cloud Logs instance resides."
 }
 
-output "guid" {
-  description = "The GUID of the resource instance."
-  value       = ibm_resource_instance.cos_instance.account_id
+output "ingress_endpoint" {
+  value       = ibm_resource_instance.cloud_logs.extensions.external_ingress
+  description = "The public ingress endpoint of the provisioned Cloud Logs instance."
 }
 
-output "id" {
-  description = "The unique identifier of the resource instance."
-  value       = ibm_resource_instance.cos_instance.id
+output "ingress_private_endpoint" {
+  value       = ibm_resource_instance.cloud_logs.extensions.external_ingress_private
+  description = "The private ingress endpoint of the provisioned Cloud Logs instance."
 }
 
-output "crn" {
-  description = "The CRN of the resource instance."
-  value       = ibm_resource_instance.cos_instance.crn
+output "logs_policies_details" {
+  value       = length(var.policies) > 0 ? ibm_logs_policy.logs_policies : null
+  description = "The details of the Cloud logs policies created."
 }
diff --git a/tests/pr_test.go b/tests/pr_test.go
index 8867ed0..dafbf6f 100644
--- a/tests/pr_test.go
+++ b/tests/pr_test.go
@@ -2,6 +2,7 @@
 package test
 
 import (
+	"math/rand"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -15,12 +16,22 @@ const resourceGroup = "geretain-test-resources"
 const advancedExampleDir = "examples/advanced"
 const basicExampleDir = "examples/basic"
 
+// Since Event Notifications is used in example, need to use a region it supports
+var validRegions = []string{
+	"au-syd",
+	"eu-de",
+	"eu-es",
+	"eu-gb",
+	"us-south",
+}
+
 func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions {
 	options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{
 		Testing:       t,
 		TerraformDir:  dir,
 		Prefix:        prefix,
 		ResourceGroup: resourceGroup,
+		Region:        validRegions[rand.Intn(len(validRegions))],
 	})
 	return options
 }
@@ -29,7 +40,7 @@ func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptio
 func TestRunBasicExample(t *testing.T) {
 	t.Parallel()
 
-	options := setupOptions(t, "mod-template-basic", basicExampleDir)
+	options := setupOptions(t, "icl-basic", basicExampleDir)
 
 	output, err := options.RunTestConsistency()
 	assert.Nil(t, err, "This should not have errored")
@@ -39,7 +50,7 @@ func TestRunBasicExample(t *testing.T) {
 func TestRunAdvancedExample(t *testing.T) {
 	t.Parallel()
 
-	options := setupOptions(t, "mod-template-adv", advancedExampleDir)
+	options := setupOptions(t, "icl-adv", advancedExampleDir)
 
 	output, err := options.RunTestConsistency()
 	assert.Nil(t, err, "This should not have errored")
@@ -50,7 +61,7 @@ func TestRunAdvancedExample(t *testing.T) {
 func TestRunUpgradeExample(t *testing.T) {
 	t.Parallel()
 
-	options := setupOptions(t, "mod-template-adv-upg", advancedExampleDir)
+	options := setupOptions(t, "icl-adv-upg", advancedExampleDir)
 
 	output, err := options.RunTestUpgrade()
 	if !options.UpgradeTestSkipped {
diff --git a/variables.tf b/variables.tf
index a9d9899..abcf651 100644
--- a/variables.tf
+++ b/variables.tf
@@ -1,36 +1,267 @@
-########################################################################################################################
-# Input Variables
-########################################################################################################################
+variable "region" {
+  description = "The IBM Cloud region where Cloud logs instance will be created."
+  type        = string
+  default     = "us-south"
+}
 
-#
-# Developer tips:
-#   - Below are some common module input variables
-#   - They should be updated for input variables applicable to the module being added
-#   - Use variable validation when possible
-#
+variable "resource_group_id" {
+  type        = string
+  description = "The id of the IBM Cloud resource group where the instance will be created."
+  default     = null
+}
 
-variable "name" {
+variable "instance_name" {
   type        = string
-  description = "A descriptive name used to identify the resource instance."
+  description = "The name of the IBM Cloud Logs instance to create. Defaults to 'cloud-logs-<region>'"
+  default     = null
 }
 
 variable "plan" {
   type        = string
-  description = "The name of the plan type supported by service."
+  description = "The IBM Cloud Logs plan to provision. Available: standard"
   default     = "standard"
+
   validation {
-    condition     = contains(["standard", "cos-one-rate-plan"], var.plan)
-    error_message = "The specified pricing plan is not available. The following plans are supported: 'standard', 'cos-one-rate-plan'"
+    condition = anytrue([
+      var.plan == "standard",
+    ])
+    error_message = "The plan value must be one of the following: standard."
   }
 }
 
-variable "resource_group_id" {
-  type        = string
-  description = "The ID of the resource group where you want to create the service."
+variable "resource_tags" {
+  type        = list(string)
+  description = "Tags associated with the IBM Cloud Logs instance (Optional, array of strings)."
+  default     = []
 }
 
-variable "resource_tags" {
+variable "access_tags" {
   type        = list(string)
-  description = "List of resource tag to associate with the instance."
+  description = "A list of access tags to apply to the IBM Cloud Logs instance created by the module. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial."
+  default     = []
+}
+
+variable "retention_period" {
+  type        = number
+  description = "The number of days IBM Cloud Logs will retain the logs data in Priority insights. Allowed values: 7, 14, 30, 60, 90."
+  default     = 7
+
+  validation {
+    condition     = contains([7, 14, 30, 60, 90], var.retention_period)
+    error_message = "Valid values 'retention_period' are: 7, 14, 30, 60, 90"
+  }
+}
+
+variable "data_storage" {
+  type = object({
+    logs_data = optional(object({
+      enabled              = optional(bool, false)
+      bucket_crn           = optional(string)
+      bucket_endpoint      = optional(string)
+      skip_cos_auth_policy = optional(bool, false)
+    }), {})
+    metrics_data = optional(object({
+      enabled              = optional(bool, false)
+      bucket_crn           = optional(string)
+      bucket_endpoint      = optional(string)
+      skip_cos_auth_policy = optional(bool, false)
+    }), {})
+    }
+  )
+  default = {
+    logs_data    = null,
+    metrics_data = null
+  }
+  validation {
+    condition     = (var.data_storage.logs_data.bucket_crn == null && var.data_storage.metrics_data.bucket_crn == null) || (var.data_storage.logs_data.bucket_crn != var.data_storage.metrics_data.bucket_crn)
+    error_message = "The same bucket cannot be used as both your data bucket and your metrics bucket."
+  }
+  validation {
+    error_message = "`bucket_crn` and `bucket_endpoint` must be included if logs_data `enabled` is true."
+    condition = (
+      lookup(var.data_storage.logs_data, "enabled", null) == null
+      ) || (
+      lookup(var.data_storage.logs_data, "enabled", false) == false
+      ) || (
+      lookup(var.data_storage.logs_data, "bucket_crn", null) != null &&
+      lookup(var.data_storage.logs_data, "bucket_endpoint", null) != null &&
+      lookup(var.data_storage.logs_data, "enabled", false) == true
+    )
+  }
+  validation {
+    error_message = "`bucket_crn` and `bucket_endpoint` must be included if metrics_data `enabled` is true."
+    condition = (
+      lookup(var.data_storage.metrics_data, "enabled", null) == null
+      ) || (
+      lookup(var.data_storage.metrics_data, "enabled", false) == false
+      ) || (
+      lookup(var.data_storage.metrics_data, "bucket_crn", null) != null &&
+      lookup(var.data_storage.metrics_data, "bucket_endpoint", null) != null &&
+      lookup(var.data_storage.metrics_data, "enabled", false) == true
+    )
+  }
+  description = "A logs data bucket and a metrics bucket in IBM Cloud Object Storage to store your IBM Cloud Logs data for long term storage, search, analysis and alerting."
+}
+
+variable "service_endpoints" {
+  description = "The type of the service endpoint that will be set for the IBM Cloud Logs instance. Allowed values: public-and-private."
+  type        = string
+  default     = "public-and-private"
+  validation {
+    condition     = contains(["public-and-private"], var.service_endpoints)
+    error_message = "The specified service_endpoints is not a valid selection. Allowed values: public-and-private."
+  }
+}
+
+##############################################################################
+# Event Notification
+##############################################################################
+
+variable "existing_event_notifications_instances" {
+  type = list(object({
+    en_instance_id      = string
+    en_region           = string
+    en_integration_name = optional(string)
+    skip_en_auth_policy = optional(bool, false)
+  }))
   default     = []
+  description = "List of Event Notifications instance details for routing critical events that occur in your IBM Cloud Logs."
+}
+
+##############################################################################
+# Logs Routing
+##############################################################################
+
+variable "logs_routing_tenant_regions" {
+  type        = list(any)
+  default     = []
+  description = "Pass a list of regions to create a tenant for that is targetted to the Cloud Logs instance created by this module. To manage platform logs that are generated by IBM Cloud® services in a region of IBM Cloud, you must create a tenant in each region that you operate. Leave the list empty if you don't want to create any tenants. NOTE: You can only have 1 tenant per region in an account."
+  nullable    = false
+}
+
+variable "skip_logs_routing_auth_policy" {
+  description = "Whether to create an IAM authorization policy that permits the Logs Routing server 'Sender' access to the IBM Cloud Logs instance created by this module."
+  type        = bool
+  default     = false
+}
+
+#############################################################################################################
+# Logs Policies Configuration
+#
+# logs_policy_name -The name of the IBM Cloud Logs policy to create.
+# logs_policy_description - Description of the IBM Cloud Logs policy to create.
+# logs_policy_priority - Select priority to determine the pipeline for the logs. High (priority value) sent to 'Priority insights' (TCO pipleine), Medium to 'Analyze and alert', Low to 'Store and search', Blocked are not sent to any pipeline.
+# application_rule - Define rules for matching applications to include in the policy configuration.
+# subsystem_rule - Define subsystem rules for matching applications to include in the policy configuration.
+# log_rules - Define the log severities to include in the policy configuration.
+# archive_retention - Define archive retention.
+##############################################################################################################
+
+variable "policies" {
+  type = list(object({
+    logs_policy_name        = string
+    logs_policy_description = optional(string, null)
+    logs_policy_priority    = string
+    application_rule = optional(list(object({
+      name         = string
+      rule_type_id = string
+    })))
+    subsystem_rule = optional(list(object({
+      name         = string
+      rule_type_id = string
+    })))
+    log_rules = optional(list(object({
+      severities = list(string)
+    })))
+    archive_retention = optional(list(object({
+      id = string
+    })))
+  }))
+  description = "Configuration of Cloud Logs policies."
+  default     = []
+
+  validation {
+    condition     = alltrue([for config in var.policies : (length(config.logs_policy_name) <= 4096 ? true : false)])
+    error_message = "Maximum length of logs_policy_name allowed is 4096 chars."
+  }
+
+  validation {
+    condition     = alltrue([for config in var.policies : contains(["type_unspecified", "type_block", "type_low", "type_medium", "type_high"], config.logs_policy_priority)])
+    error_message = "The specified priority for logs policy is not a valid selection. Allowed values are: type_unspecified, type_block, type_low, type_medium, type_high."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.application_rule != null ?
+          (alltrue([for rule in config.application_rule :
+          contains(["unspecified", "is", "is_not", "start_with", "includes"], rule.rule_type_id)]))
+        : true)
+    ])
+    error_message = "Identifier of application_rule 'rule_type_id' is not a valid selection. Allowed values are: unspecified, is, is_not, start_with, includes."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.application_rule != null ?
+          (alltrue([for rule in config.application_rule :
+          can(regex("^[\\p{L}\\p{N}\\p{P}\\p{Z}\\p{S}\\p{M}]+$", rule.name)) && length(rule.name) <= 4096 && length(rule.name) > 1]))
+        : true)
+    ])
+    error_message = "The name of the application_rule does not meet the required criteria."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.log_rules != null && length(config.log_rules) > 0 ? true : false)
+    ])
+    error_message = "The log_rules can not be empty and must contain at least 1 item."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.log_rules != null ?
+          (alltrue([for rule in config.log_rules :
+            alltrue([for severity in rule["severities"] :
+          contains(["unspecified", "debug", "verbose", "info", "warning", "error", "critical"], severity)])]))
+          : true
+    )])
+    error_message = "The 'severities' of log_rules is not a valid selection. Allowed values are: unspecified, debug, verbose, info, warning, error, critical."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.subsystem_rule != null ?
+          (alltrue([for rule in config.subsystem_rule :
+          contains(["unspecified", "is", "is_not", "start_with", "includes"], rule.rule_type_id)]))
+          : true
+    )])
+    error_message = "Identifier of subsystem_rule 'rule_type_id' is not a valid selection. Allowed values are: unspecified, is, is_not, start_with, includes."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.subsystem_rule != null ?
+          (alltrue([for rule in config.subsystem_rule :
+          can(regex("^[\\p{L}\\p{N}\\p{P}\\p{Z}\\p{S}\\p{M}]+$", rule.name)) && length(rule.name) <= 4096 && length(rule.name) > 1]))
+        : true)
+    ])
+    error_message = "The name of the subsytem_rule does not meet the required criteria."
+  }
+
+  validation {
+    condition = alltrue(
+      [for config in var.policies :
+        (config.archive_retention != null ?
+          (alltrue(
+            [for rule in config.archive_retention : can(regex("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", rule.id))]
+          )) : true
+    )])
+    error_message = "The id of the archive_retention does not meet the required criteria."
+  }
 }
diff --git a/version.tf b/version.tf
index e51de7f..243557b 100644
--- a/version.tf
+++ b/version.tf
@@ -1,18 +1,18 @@
 terraform {
-  # require 1.9 or later to make use of cross-object referencing for input variable validations
-  #   more info: https://www.hashicorp.com/blog/terraform-1-9-enhances-input-variable-validations
   required_version = ">= 1.9.0"
-
-  #
-  # Developer tips:
-  #   - If your module requires any terraform providers, add them the "required_providers" section below.
-  #   - Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions.
-  #
-
   required_providers {
+    # Use "greater than or equal to" range in modules
     ibm = {
-      source  = "IBM-Cloud/ibm"
-      version = ">= 1.71.2, < 2.0.0"
+      source  = "ibm-cloud/ibm"
+      version = ">= 1.76.1, < 2.0.0"
+    }
+    time = {
+      source  = "hashicorp/time"
+      version = ">= 0.9.1, < 1.0.0"
+    }
+    random = {
+      source  = "hashicorp/random"
+      version = ">= 3.5.1, < 4.0.0"
     }
   }
 }


Reviews:
user: login: ocofaigh
body: Left some comments. Can you also:
- add a description in `.github/settings.yml`
- Update the codeowners file (`.github/CODEOWNERS`)
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T18:47:24Z
user: login: ocofaigh
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-12T13:40:28Z

Review comments:
diff_hunk: @@ -1,18 +1,18 @@
 terraform {
-  # require 1.9 or later to make use of cross-object referencing for input variable validations
-  #   more info: https://www.hashicorp.com/blog/terraform-1-9-enhances-input-variable-validations
-  required_version = ">= 1.9.0"
-
-  #
-  # Developer tips:
-  #   - If your module requires any terraform providers, add them the "required_providers" section below.
-  #   - Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions.
-  #
-
+  required_version = ">= 1.0.0"
path: version.tf
user: login: ocofaigh
body: Can we use `>= 1.9.0` (as per the module template) so we can use the terraform 1.9 features
created_at: 2025-03-11T18:26:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,18 +1,18 @@
 terraform {
-  # require 1.9 or later to make use of cross-object referencing for input variable validations
-  #   more info: https://www.hashicorp.com/blog/terraform-1-9-enhances-input-variable-validations
-  required_version = ">= 1.9.0"
-
-  #
-  # Developer tips:
-  #   - If your module requires any terraform providers, add them the "required_providers" section below.
-  #   - Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions.
-  #
-
+  required_version = ">= 1.0.0"
   required_providers {
+    # Use "greater than or equal to" range in modules
     ibm = {
-      source  = "IBM-Cloud/ibm"
-      version = ">= 1.71.2, < 2.0.0"
+      source  = "ibm-cloud/ibm"
+      version = ">= 1.70.0, < 2.0.0"
path: version.tf
user: login: ocofaigh
body: Suggest to bump to this, as there was an auth policy related fix in latest version we should pick up
`>= 1.76.1, < 2.0.0`
created_at: 2025-03-11T18:26:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,36 +1,267 @@
-########################################################################################################################
-# Input Variables
-########################################################################################################################
+variable "region" {
+  description = "The IBM Cloud region where Cloud logs instance will be created."
+  type        = string
+  default     = "us-south"
+}
 
-#
-# Developer tips:
-#   - Below are some common module input variables
-#   - They should be updated for input variables applicable to the module being added
-#   - Use variable validation when possible
-#
+variable "resource_group_id" {
+  type        = string
+  description = "The id of the IBM Cloud resource group where the instance will be created."
+  default     = null
+}
 
-variable "name" {
+variable "instance_name" {
   type        = string
-  description = "A descriptive name used to identify the resource instance."
+  description = "The name of the IBM Cloud Logs instance to create. Defaults to 'cloud-logs-<region>'"
+  default     = null
 }
 
 variable "plan" {
   type        = string
-  description = "The name of the plan type supported by service."
+  description = "The IBM Cloud Logs plan to provision. Available: standard"
   default     = "standard"
+
   validation {
-    condition     = contains(["standard", "cos-one-rate-plan"], var.plan)
-    error_message = "The specified pricing plan is not available. The following plans are supported: 'standard', 'cos-one-rate-plan'"
+    condition = anytrue([
+      var.plan == "standard",
+    ])
+    error_message = "The plan value must be one of the following: standard."
   }
 }
 
-variable "resource_group_id" {
-  type        = string
-  description = "The ID of the resource group where you want to create the service."
+variable "resource_tags" {
+  type        = list(string)
+  description = "Tags associated with the IBM Cloud Logs instance (Optional, array of strings)."
+  default     = []
 }
 
-variable "resource_tags" {
+variable "access_tags" {
   type        = list(string)
-  description = "List of resource tag to associate with the instance."
+  description = "A list of access tags to apply to the IBM Cloud Logs instance created by the module. For more information, see https://cloud.ibm.com/docs/account?topic=account-access-tags-tutorial."
+  default     = []
+}
+
+variable "retention_period" {
+  type        = number
+  description = "The number of days IBM Cloud Logs will retain the logs data in Priority insights. Allowed values: 7, 14, 30, 60, 90."
+  default     = 7
+
+  validation {
+    condition     = contains([7, 14, 30, 60, 90], var.retention_period)
+    error_message = "Valid values 'retention_period' are: 7, 14, 30, 60, 90"
+  }
+}
+
+variable "data_storage" {
+  type = object({
+    logs_data = optional(object({
+      enabled              = optional(bool, false)
+      bucket_crn           = optional(string)
+      bucket_endpoint      = optional(string)
+      skip_cos_auth_policy = optional(bool, false)
+    }), {})
+    metrics_data = optional(object({
+      enabled              = optional(bool, false)
+      bucket_crn           = optional(string)
+      bucket_endpoint      = optional(string)
+      skip_cos_auth_policy = optional(bool, false)
+    }), {})
+    }
+  )
+  default = {
+    logs_data    = null,
+    metrics_data = null
+  }
+  validation {
+    condition     = (var.data_storage.logs_data.bucket_crn == null && var.data_storage.metrics_data.bucket_crn == null) || (var.data_storage.logs_data.bucket_crn != var.data_storage.metrics_data.bucket_crn)
+    error_message = "The same bucket cannot be used as both your data bucket and your metrics bucket."
+  }
+  validation {
+    error_message = "`bucket_crn` and `bucket_endpoint` must be included if logs_data `enabled` is true."
+    condition = (
+      lookup(var.data_storage.logs_data, "enabled", null) == null
+      ) || (
+      lookup(var.data_storage.logs_data, "enabled", false) == false
+      ) || (
+      lookup(var.data_storage.logs_data, "bucket_crn", null) != null &&
+      lookup(var.data_storage.logs_data, "bucket_endpoint", null) != null &&
+      lookup(var.data_storage.logs_data, "enabled", false) == true
+    )
+  }
+  validation {
+    error_message = "`bucket_crn` and `bucket_endpoint` must be included if metrics_data `enabled` is true."
+    condition = (
+      lookup(var.data_storage.metrics_data, "enabled", null) == null
+      ) || (
+      lookup(var.data_storage.metrics_data, "enabled", false) == false
+      ) || (
+      lookup(var.data_storage.metrics_data, "bucket_crn", null) != null &&
+      lookup(var.data_storage.metrics_data, "bucket_endpoint", null) != null &&
+      lookup(var.data_storage.metrics_data, "enabled", false) == true
+    )
+  }
+  description = "A logs data bucket and a metrics bucket in IBM Cloud Object Storage to store your IBM Cloud Logs data for long term storage, search, analysis and alerting."
+}
+
+variable "service_endpoints" {
+  description = "The type of the service endpoint that will be set for the IBM Cloud Logs instance. Allowed values: public-and-private."
+  type        = string
+  default     = "public-and-private"
+  validation {
+    condition     = contains(["public-and-private"], var.service_endpoints)
+    error_message = "The specified service_endpoints is not a valid selection. Allowed values: public-and-private."
+  }
+}
+
+##############################################################################
+# Event Notification
+##############################################################################
+
+variable "existing_en_instances" {
path: variables.tf
user: login: ocofaigh
body: As per our best practises defined in https://github.ibm.com/GoldenEye/issues/issues/12542 do not use short abbreviations like `en`. I know this is in the other repo now, but we should fix it here now before creating the first release of the new module. Suggest to name this `existing_event_notifications_instances`
created_at: 2025-03-11T18:41:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,30 +1,34 @@
-########################################################################################################################
-# Outputs
-########################################################################################################################
+output "crn" {
+  value       = ibm_resource_instance.cloud_logs.id
+  description = "The id of the provisioned Cloud Logs instance."
path: outputs.tf
user: login: ocofaigh
body: this needs to be update to CRN (value and descrption)
created_at: 2025-03-11T18:42:30Z
author_association: CONTRIBUTOR

PR comments:
user: login: kierramarie
created_at: 2025-03-11T15:46:51Z
body: /run pipeline
author_association: MEMBER
user: login: kierramarie
created_at: 2025-03-11T18:01:47Z
body: /run pipeline
author_association: MEMBER
user: login: kierramarie
created_at: 2025-03-11T18:24:34Z
body: /run pipeline
author_association: MEMBER
user: login: kierramarie
created_at: 2025-03-11T20:35:38Z
body: /run pipeline
author_association: MEMBER
user: login: kierramarie
created_at: 2025-03-11T20:43:28Z
body: /run pipeline
author_association: MEMBER
user: login: terraform-ibm-modules-ops
created_at: 2025-03-12T13:42:29Z
body: :tada: This PR is included in version 1.0.0 :tada:

The release is available on [GitHub release](https://github.com/terraform-ibm-modules/terraform-ibm-cloud-logs/releases/tag/v1.0.0)

Your **[semantic-release](https://github.com/semantic-release/semantic-release)** bot :package::rocket:
author_association: CONTRIBUTOR