data "aws_caller_identity" "current" {
}

resource "datadog_monitor" "elasticache_memory_pressure_monitor" {
  name = "${var.environment}-${var.service_name}-memory-pressure"
  type = "metric alert"

  evaluation_delay    = var.evaluation_delay
  include_tags        = true
  notify_audit        = false
  notify_no_data      = false
  renotify_interval   = 60
  require_full_window = false
  new_group_delay     = 60
  notify_by = [
    "cachenodeid"
  ]

  message = templatefile("${path.module}/templates/notifications.tftpl", {
    description                    = "The `SwapUsage` metric is greater than the `FreeableMemory` metric"
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "max(${var.memory_pressure_evaluation_window}):sum:aws.elasticache.freeable_memory{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.weighted() - sum:aws.elasticache.swap_usage{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.weighted() <= ${var.memory_pressure_critical_number}"

  monitor_thresholds {
    critical          = var.memory_pressure_critical_number
  }

  tags = local.tags
}

resource "datadog_monitor" "elasticache_redis_evictions_monitor" {
  count = local.is_redis ? var.evictions_monitor_enabled ? 1 : 0 : 0
  name  = "${var.environment}-${var.service_name}-evictions"
  type  = "metric alert"

  evaluation_delay    = var.evaluation_delay
  include_tags        = true
  notify_audit        = false
  notify_no_data      = false
  renotify_interval   = 60
  require_full_window = false
  new_group_delay     = 60

  message = templatefile("${path.module}/templates/notifications.tftpl", {
    description                    = "Evictions monitor triggered when DB memory usage reaches 100%"
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.evictions_evaluation_window}):anomalies(sum:aws.elasticache.evictions{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid}.as_count(), '${var.evictions_anomaly_algorithm}', ${var.evictions_anomaly_deviations}, direction='${var.evictions_anomaly_direction}', interval=${var.evictions_anomaly_rollup_interval}, alert_window='${var.evictions_anomaly_alert_window}', count_default_zero='${var.evictions_anomaly_count_default_zero}') ${var.evictions_anomaly_operator} ${var.evictions_critical_number}"

  monitor_thresholds {
    critical          = var.evictions_critical_number
    critical_recovery = var.evictions_critical_recovery_number
    warning           = var.evictions_warning_number
    warning_recovery  = var.evictions_warning_recovery_number
  }

  tags = local.tags
}


resource "datadog_monitor" "elasticache_cpu_utilization_monitor" {
  name = "${var.environment}-${var.service_name}-cpu-utilization"
  type = "metric alert"

  evaluation_delay    = var.evaluation_delay
  include_tags        = true
  notify_audit        = false
  notify_no_data      = false
  renotify_interval   = 60
  require_full_window = false
  new_group_delay     = 60
  notify_by = [
    "cachenodeid"
  ]

  message = templatefile("${path.module}/templates/notifications.tftpl", {
    description                    = "Cache CPU utilization monitor triggered on {{cachenodeid.name}}"
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.cpu_utilization_evaluation_window}):avg:aws.elasticache.cpuutilization{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid} > ${var.cpu_utilization_critical_number}"

  monitor_thresholds {
    critical          = var.cpu_utilization_critical_number
    critical_recovery = var.cpu_utilization_critical_recovery_number
  }

  tags = local.tags
}


resource "datadog_monitor" "elasticache_redis_database_memory_usage_percentage" {
  count = local.is_redis ? var.database_memory_usage_percentage_monitor_enabled ? 1 : 0 : 0
  name  = "${var.environment}-${var.service_name}-database-memory-usage-percentage"
  type  = "metric alert"

  evaluation_delay    = var.evaluation_delay
  include_tags        = true
  notify_audit        = false
  notify_no_data      = false
  renotify_interval   = 60
  require_full_window = false
  new_group_delay     = 60

  message = templatefile("${path.module}/templates/notifications.tftpl", {
    description                    = "Database memory usage percentage triggered"
    notification_endpoints         = var.notification_endpoints
    alert_notification_endpoints   = var.alert_notification_endpoints
    no_data_notification_endpoints = var.no_data_notification_endpoints
  })
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "avg(${var.database_memory_usage_percentage_evaluation_window}):sum:aws.elasticache.database_memory_usage_percentage{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid}.weighted() >= ${var.database_memory_usage_percentage_critical_number}"

  monitor_thresholds {
    critical          = var.database_memory_usage_percentage_critical_number
    critical_recovery = var.database_memory_usage_percentage_critical_recovery_number
    warning           = var.database_memory_usage_percentage_warning_number
    warning_recovery  = var.database_memory_usage_percentage_warning_recovery_number
  }

  tags = local.tags
}

resource "datadog_dashboard" "elasticache_redis_dashboard" {
  count       = local.is_redis ? 1 : 0
  title       = "${var.environment}-${var.service_name} Redis Dashboard"
  description = "Managed by Terraform"
  tags        = local.dashboard_tags
  layout_type = "ordered"
  reflow_type = "fixed"

  #### Overview Group Widget (START)
  widget {
    group_definition {
      layout_type = "ordered"
      title       = "Overview"
      show_title  = true

      widget {
        manage_status_definition {
          title               = "Monitors"
          display_format      = "countsAndList"
          color_preference    = "text"
          hide_zero_counts    = true
          query               = "${var.environment}-${var.service_name} AND tag:(environment:${var.environment})"
          sort                = "status,asc"
          summary_type        = "monitors"
          show_last_triggered = false
          show_priority       = false
        }
        widget_layout {
          x      = 0
          y      = 0
          width  = 4
          height = 4
        }
      }

      widget {
        check_status_definition {
          title       = "Is AWS Elasticache Up?"
          title_size  = 13
          title_align = "center"
          check       = "aws.status"
          grouping    = "cluster"
          group_by    = ["service", "region"]
          tags = [
            "service:elasticache"
          ]
        }
        widget_layout {
          x      = 4
          y      = 0
          width  = 2
          height = 2
        }
      }

      widget {
        query_value_definition {
          title       = "AVG Cache Hit Rate"
          title_size  = 16
          title_align = "left"
          autoscale   = false
          custom_unit = "%"
          text_align  = "center"
          precision   = 1
          request {
            conditional_formats {
              comparator = "<"
              value      = 50
              palette    = "red_on_white"
            }
            conditional_formats {
              comparator = "<"
              value      = 80
              palette    = "yellow_on_white"
            }
            conditional_formats {
              comparator = ">="
              value      = 80
              palette    = "green_on_white"
            }

            query {
              metric_query {
                name  = "cache_hits"
                query = "avg:aws.elasticache.cache_hits{environment:${var.environment}, service_name:${var.service_name}}.as_count()"
              }
            }
            query {
              metric_query {
                name  = "cache_misses"
                query = "avg:aws.elasticache.cache_misses{environment:${var.environment}, service_name:${var.service_name}}.as_count()"
              }
            }
            formula {
              formula_expression = "100 * (cache_hits) / (cache_hits + cache_misses)"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 0
          width  = 2
          height = 2
        }

      }

      widget {
        query_value_definition {
          title       = "Max Swap Usage"
          title_size  = 16
          title_align = "left"
          autoscale   = true
          text_align  = "center"
          precision   = 1
          request {
            conditional_formats {
              comparator = "<"
              value      = 40000000
              palette    = "green_on_white"
            }
            conditional_formats {
              comparator = ">="
              value      = 40000000
              palette    = "red_on_white"
            }
            query {
              metric_query {
                name       = "swap_usage"
                query      = "max:aws.elasticache.swap_usage{environment:${var.environment}, service_name:${var.service_name}}"
                aggregator = "max"
              }
            }
            formula {
              formula_expression = "swap_usage"
            }
          }
        }
        widget_layout {
          x      = 4
          y      = 2
          width  = 2
          height = 2
        }
      }

      widget {
        query_value_definition {
          title       = "Database Memory Usage Percentage"
          title_size  = 16
          title_align = "left"
          autoscale   = true
          precision   = 2
          request {
            conditional_formats {
              comparator = "<="
              value      = 50
              palette    = "green_on_white"
            }
            conditional_formats {
              comparator = "<="
              value      = 80
              palette    = "yellow_on_white"
            }
            conditional_formats {
              comparator = "<="
              value      = 90
              palette    = "red_on_white"
            }
            query {
              metric_query {
                name  = "database_memory_usage_percentage"
                query = "avg:aws.elasticache.database_memory_usage_percentage{environment:${var.environment}, service_name:${var.service_name}}"
              }
            }
            formula {
              formula_expression = "database_memory_usage_percentage"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 2
          width  = 2
          height = 2
        }
      }
    }
    widget_layout {
      x      = 0
      y      = 0
      width  = 8
      height = 5
    }
  }
  #### Overview Group Widget (END)

  #### Elasticache Events Widget (START)
  widget {
    list_stream_definition {
      title = "Elasticache Events"
      request {
        query {
          data_source  = "event_stream"
          event_size   = "s"
          query_string = "source:amazon_elasticache application_family:${var.application_family} environment:${var.environment} service_name:${var.service_name}"
        }
        columns {
          field = "source"
          width = "auto"
        }
        columns {
          field = "message"
          width = "auto"
        }
        columns {
          field = "date"
          width = "auto"
        }
        response_format = "event_list"
      }
    }
    widget_layout {
      x      = 8
      y      = 0
      width  = 4
      height = 5
    }
  }
  #### Elasticache Events Widget (END)

  #### Throughtput and Performance Group Widget (START)
  widget {
    group_definition {
      title            = "Throughtput and Performance"
      layout_type      = "ordered"
      background_color = "vivid_blue"

      widget {
        timeseries_definition {
          title          = "Get Commands by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            query {
              metric_query {
                name  = "get_type_cmds"
                query = "sum:aws.elasticache.get_type_cmds{environment:${var.environment}, service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.as_rate()"
              }
            }
            formula {
              formula_expression = "get_type_cmds"
            }
            style {
              palette = "green"
            }
            display_type = "line"
          }
        }
        widget_layout {
          x      = 0
          y      = 0
          width  = 6
          height = 3
        }
      }

      widget {
        timeseries_definition {
          title          = "Cache Hit Rate by Cluster"
          title_size     = 16
          title_align    = "left"
          show_legend    = true
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            display_type = "line"
            style {
              palette    = "dog_classic"
              line_type  = "solid"
              line_width = "normal"
            }
            query {
              metric_query {

                name  = "cache_hit_rate"
                query = "max:aws.elasticache.cache_hit_rate{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid}"
              }
            }
            formula {
              formula_expression = "cache_hit_rate"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 0
          width  = 6
          height = 3
        }
      }

      widget {
        timeseries_definition {
          title          = "Set commands by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]

          request {
            display_type = "line"
            style {
              palette = "purple"
            }
            query {
              metric_query {
                name  = "set_type_cmds"
                query = "sum:aws.elasticache.set_type_cmds{environment:${var.environment}, service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.as_rate()"
              }
            }
            formula {
              formula_expression = "set_type_cmds"
            }
          }
        }
        widget_layout {
          x      = 0
          y      = 3
          width  = 6
          height = 3
        }
      }

      widget {
        timeseries_definition {
          title          = "Current Connections by Cluster"
          title_size     = 16
          title_align    = "left"
          show_legend    = true
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            display_type = "line"
            style {
              palette    = "dog_classic"
              line_type  = "solid"
              line_width = "normal"
            }
            query {
              metric_query {
                name  = "current_connections"
                query = "sum:aws.elasticache.curr_connections{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid}.weighted()"
              }
            }
            formula {
              formula_expression = "current_connections"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 3
          width  = 6
          height = 3
        }
      }
    }
    widget_layout {
      x      = 0
      y      = 5
      width  = 12
      height = 7
    }
  }
  #### Throughtput and Performance Group Widget (END)

  #### Memory Group Widget (START)
  widget {
    group_definition {
      title            = "Memory"
      layout_type      = "ordered"
      background_color = "orange"

      widget {
        timeseries_definition {
          title          = "% DB Memory Usage by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]

          request {
            display_type = "line"
            style {
              palette = "dog_classic"
            }
            query {
              metric_query {
                name  = "database_memory_usage_percentage"
                query = "sum:aws.elasticache.database_memory_usage_percentage{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.weighted()"
              }
            }
            formula {
              formula_expression = "database_memory_usage_percentage"
            }
          }
        }
        widget_layout {
          x      = 0
          y      = 0
          width  = 6
          height = 3
        }
      }

      widget {
        timeseries_definition {
          title          = "Evictions by Cluster"
          title_size     = 16
          title_align    = "left"
          show_legend    = true
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]

          request {
            display_type = "line"
            style {
              palette    = "dog_classic"
              line_type  = "solid"
              line_width = "normal"
            }
            query {
              metric_query {
                name  = "evictions"
                query = "sum:aws.elasticache.evictions{environment:${var.environment}, service_name:${var.service_name}} by {cacheclusterid}.as_count()"
              }
            }
            formula {
              formula_expression = "evictions"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 0
          width  = 6
          height = 3
        }
      }

      widget {
        timeseries_definition {
          title          = "Available System Memory by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            display_type = "line"
            style {
              palette = "dog_classic"
            }
            query {
              metric_query {
                name  = "freeable_memory"
                query = "avg:aws.elasticache.freeable_memory{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}"
              }
            }
            formula {
              formula_expression = "freeable_memory"
            }
          }
        }
        widget_layout {
          x      = 0
          y      = 3
          width  = 6
          height = 3
        }
      }

      widget {
        timeseries_definition {
          title          = "Swap Usage by Cluster"
          title_size     = 16
          title_align    = "left"
          show_legend    = true
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            query {
              metric_query {
                name  = "swap_usage"
                query = "avg:aws.elasticache.swap_usage{environment:${var.environment} , service_name:${var.service_name}} by {cacheclusterid}"
              }
            }
            formula {
              formula_expression = "swap_usage"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 3
          width  = 6
          height = 3
        }
      }
    }
    widget_layout {
      x               = 0
      y               = 12
      width           = 12
      height          = 7
      is_column_break = true
    }
  }
  #### Memory Group Widget (END)

  #### Other Host-Level Metrics Group Widget (START)
  widget {
    group_definition {
      title            = "Other Host-Level Metrics"
      layout_type      = "ordered"
      background_color = "green"

      widget {
        timeseries_definition {
          title          = "Outgoing Network Bytes by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            display_type = "line"
            style {
              palette = "orange"
            }
            query {
              metric_query {
                name  = "network_bytes_out"
                query = "avg:aws.elasticache.network_bytes_out{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.as_rate()"
              }
            }
            formula {
              formula_expression = "network_bytes_out"
            }
          }
        }
        widget_layout {
          x      = 0
          y      = 0
          width  = 6
          height = 2
        }
      }
      widget {
        timeseries_definition {
          title          = "CPU Utilization by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]

          request {
            display_type = "line"
            style {
              palette = "warm"
            }
            query {
              metric_query {
                name  = "cpuutil"
                query = "avg:aws.elasticache.cpuutilization{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}"
              }
            }
            formula {
              formula_expression = "cpuutil"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 0
          width  = 6
          height = 2
        }
      }

      widget {
        timeseries_definition {
          title          = "Incoming Network Bytes by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]
          request {
            display_type = "line"
            style {
              palette = "blue"
            }
            query {
              metric_query {
                name  = "network_bytes_in"
                query = "avg:aws.elasticache.network_bytes_in{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}.as_rate()"
              }
            }
            formula {
              formula_expression = "network_bytes_in"
            }
          }
        }
        widget_layout {
          x      = 0
          y      = 2
          width  = 6
          height = 2
        }
      }

      widget {
        timeseries_definition {
          title          = "Replication Lag by Node"
          title_size     = 16
          title_align    = "left"
          show_legend    = false
          legend_layout  = "auto"
          legend_columns = ["avg", "min", "max", "value", "sum"]

          request {
            display_type = "line"
            style {
              palette = "warm"
            }
            query {
              metric_query {
                name  = "lag"
                query = "avg:aws.elasticache.replication_lag{environment:${var.environment},service_name:${var.service_name}} by {cacheclusterid,cachenodeid}"
              }
            }
            formula {
              formula_expression = "lag"
            }
          }
        }
        widget_layout {
          x      = 6
          y      = 2
          width  = 6
          height = 2
        }
      }
    }
    widget_layout {
      x      = 0
      y      = 19
      width  = 12
      height = 5
    }
  }
  #### Other Host-Level Metrics Group Widget (END)
}


resource "datadog_dashboard" "elasticache_memcached_dashboard" {
  count       = local.is_memcached ? 1 : 0
  title       = "${var.environment}-${var.service_name} Memcached Dashboard"
  description = "Managed by Terraform"
  tags        = local.dashboard_tags
  layout_type = "ordered"
  reflow_type = "fixed"
}
