locals {
  # There is a Cloudwatch metric for aws.rds.freeable_memory but we calculate this using the enhanced metrics instead as these are published in realtime
  exclusion_filters = join(",", [for filter in var.excluded_identifiers : "!dbinstanceidentifier:${filter}"])
  free_memory_query = join(" + ", [
    for metric in ["aws.rds.memory.free", "aws.rds.memory.cached", "aws.rds.memory.buffers"] :
    "max:${metric}{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier}"
  ])
  total_memory_query = "max:aws.rds.memory.total{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier}"
  event_types = join(" OR ", var.event_notification_monitor_event_types)
}

resource "datadog_monitor" "uptime_monitor" {
  count = var.uptime_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS uptime monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "RDS uptime is not being reported for {{dbinstanceidentifier.name}}."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "RDS uptime is still not being reported for {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  # Use enhanced metric aws.rds.uptime instead of Cloudwatch metric aws.rds.engine_uptime for realtime data
  query = "min(${var.measurement_interval_uptime}):avg:aws.rds.uptime{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier} <= 0"

  monitor_thresholds {
    critical = "0"
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true
  no_data_timeframe   = var.no_data_timeframe_uptime

  tags = local.tags
}

resource "datadog_monitor" "cpu_monitor" {
  count = var.cpu_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS CPU monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "High CPU utilization on {{dbinstanceidentifier.name}}."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "CPU utilization is still high on {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  # Use enhanced metrics aws.rds.cpuutilization.total instead of Cloudwatch metrics aws.rds.cpuutilization for realtime data
  query = "avg(${var.measurement_interval_cpu}):max:aws.rds.cpuutilization.total{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier} > ${var.critical_number_cpu}"

  monitor_thresholds {
    ok                = var.ok_number_cpu
    warning           = var.warning_number_cpu
    warning_recovery  = var.warning_recovery_number_cpu
    critical          = var.critical_number_cpu
    critical_recovery = var.critical_recovery_number_cpu
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true

  tags = local.tags
}

resource "datadog_monitor" "memory_monitor" {
  count = var.memory_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS memory monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "High memory utilization on {{dbinstanceidentifier.name}}."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Memory utilization is still high on {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.measurement_interval_memory}):100 * (1 - ((${local.free_memory_query}) / (${local.total_memory_query}))) > ${var.critical_number_memory}"

  monitor_thresholds {
    ok                = var.ok_number_memory
    warning           = var.warning_number_memory
    warning_recovery  = var.warning_recovery_number_memory
    critical          = var.critical_number_memory
    critical_recovery = var.critical_recovery_number_memory
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true

  tags = local.tags
}

resource "datadog_monitor" "disk_utilization_monitor" {
  count = var.disk_utilization_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS disk utilization monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "Disk space is low on {{dbinstanceidentifier.name}}."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Disk space remains low on {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.measurement_interval_disk_utilization}):max:aws.rds.filesystem.usedPercent{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier} > ${var.critical_number_disk_utilization}"

  monitor_thresholds {
    ok                = var.ok_number_disk_utilization
    warning           = var.warning_number_disk_utilization
    warning_recovery  = var.warning_recovery_number_disk_utilization
    critical          = var.critical_number_disk_utilization
    critical_recovery = var.critical_recovery_number_disk_utilization
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true

  tags = local.tags
}

resource "datadog_monitor" "replication_lag_monitor" {
  count = var.replication_lag_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS replication lag monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "Replication lag is high in Aurora cluster ${var.environment}-${var.service_name}."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Replication lag remains high in Aurora cluster ${var.environment}-${var.service_name}. Escalation to ${var.escalation_notification_endpoints}"

  query = "max(${var.measurement_interval_replication_lag}):max:aws.rds.aurora_replica_lag_maximum{environment:${var.environment},service_name:${var.service_name}} > ${var.critical_number_replication_lag}"

  monitor_thresholds {
    ok                = var.ok_number_replication_lag
    warning           = var.warning_number_replication_lag
    warning_recovery  = var.warning_recovery_number_replication_lag
    critical          = var.critical_number_replication_lag
    critical_recovery = var.critical_recovery_number_replication_lag
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true
  # Configure evaluation delay because this uses a standard RDS Cloudwatch metric, and there is no equivalent enhanced metric.
  evaluation_delay = var.evaluation_delay

  tags = local.tags
}

resource "datadog_monitor" "mysql_availability_monitor" {
  count = var.availability_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS availability monitor"
  type  = "service check"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "MySQL is not available on {{dbinstanceidentifier.name}}. Monitor triggered."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "MySQL is still not available on {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  query = "\"mysql.can_connect\".over(\"environment:${var.environment}\",\"service_name:${var.service_name}\",\"${local.exclusion_filters}\").by(\"dbinstanceidentifier\").last(${max(var.ok_number_availability, var.critical_number_availability) + 1}).count_by_status()"

  monitor_thresholds {
    ok       = var.ok_number_availability
    critical = var.critical_number_availability
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true

  tags = local.tags
}

resource "datadog_monitor" "connections_monitor" {
  count = var.connections_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS connections monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "High connection utilization on {{dbinstanceidentifier.name}}."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Connection utilization is still high on {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.measurement_interval_connections}):100 * ( max:mysql.performance.threads_connected{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier} / max:mysql.net.max_connections_available{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier} ) > ${var.critical_number_connections}"

  monitor_thresholds {
    ok                = var.ok_number_connections
    warning           = var.warning_number_connections
    warning_recovery  = var.warning_recovery_number_connections
    critical          = var.critical_number_connections
    critical_recovery = var.critical_recovery_number_connections
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true

  tags = local.tags
}

resource "datadog_monitor" "mysql_slow_queries_monitor" {
  count = var.slow_queries_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS MySQL slow queries monitor"
  type  = "metric alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "High number of slow queries on {{dbinstanceidentifier.name}}. Monitor triggered."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Slow query rate is still high on {{dbinstanceidentifier.name}}. Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.measurement_interval_slow_queries}):mysql.performance.slow_queries{environment:${var.environment},service_name:${var.service_name},${local.exclusion_filters}} by {dbinstanceidentifier} > ${var.critical_number_slow_queries}"

  monitor_thresholds {
    ok                = var.ok_number_slow_queries
    warning           = var.warning_number_slow_queries
    warning_recovery  = var.warning_recovery_number_slow_queries
    critical          = var.critical_number_slow_queries
    critical_recovery = var.critical_recovery_number_slow_queries
  }

  include_tags        = true
  notify_no_data      = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true

  tags = local.tags
}

resource "datadog_monitor" "mysql_event_notification_monitor" {
  count = var.event_notification_monitor_enabled ? 1 : 0
  name  = "${var.environment}-${var.service_name} RDS event notification monitor"
  type  = "event-v2 alert"
  message = templatefile("${path.module}/templates/notifications.tftpl", {
    message                        = "RDS event: {{event.id}} \n{{event.title}} \n{{event.text}} \n{{event.host.name}}. \nMonitor triggered."
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "RDS event: {{event.id}} \n{{event.title}} \n{{event.text}} \n{{event.host.name}}. \nMonitor triggered."

  query = "events(\"source:amazon_rds event_type:(${local.event_types}) -event_source:(db-cluster-snapshot OR db-snapshot) name:${var.environment}-${var.service_name}-?\").rollup(\"count\").last(\"${var.measurement_interval_events}\") >= ${var.critical_number_events}"

  monitor_thresholds {
    ok                = var.ok_number_events
    warning           = var.warning_number_events
    critical          = var.critical_number_events
  }

  include_tags        = true
  notify_audit        = false
  renotify_interval   = 60
  timeout_h           = 0
  require_full_window = true
  on_missing_data     = "default"

  tags = local.tags
}
