data "aws_caller_identity" "current" {
}

data "datadog_role" "datadog_admin_role" {
  filter = "Datadog Admin Role"
}

# Datadog Lambda timeboard
resource "datadog_dashboard" "datadog_lambda" {
  title            = "${var.environment}-${var.service_name} timeboard"
  description      = "Default terraformed timeboard for Lambda"
  restricted_roles = [data.datadog_role.datadog_admin_role.id]
  layout_type      = "ordered"

  template_variable {
    defaults = [var.environment]
    name    = var.service_name
    prefix  = "environment"
  }

  # Lambda Invocations (Measures the number of times a function is invoked in response to an event or invocation API call)
  widget {
    timeseries_definition {
      title       = "Lambda Invocations"
      show_legend = true

      request {
        q            = "sum:aws.lambda.invocations{environment:${var.environment},service_name:${var.service_name}}.as_count()"
        display_type = "bars"
      }
    }
  }

  # Lambda Throttles (Measures the number of Lambda function invocation attempts that were throttled due to invocation rates exceeding the customer's concurrent limits)
  widget {
    timeseries_definition {
      title       = "Lambda Throttles"
      show_legend = true

      request {
        q            = "sum:aws.lambda.throttles{environment:${var.environment},service_name:${var.service_name}}.as_count()"
        display_type = "bars"
      }
    }
  }

  # Lambda Errors Area Graph (Measures the number of invocations in graph that failed due to errors in the function (response code 4XX))
  widget {
    timeseries_definition {
      title       = "Lambda Errors"
      show_legend = true

      request {
        q            = "sum:aws.lambda.errors{environment:${var.environment},service_name:${var.service_name}}.as_count()"
        display_type = "area"
      }
    }
  }

  # Lambda Errors Query Value (Measures the number of invocations in value that failed due to errors in the function (response code 4XX))
  widget {
    query_value_definition {
      title     = "Lambda Errors"
      autoscale = true

      request {
        q = "sum:aws.lambda.errors{environment:${var.environment},service_name:${var.service_name}}.as_count()"
      }
    }
  }

  # Lambda Duration Maximum (Measures the maximum elapsed wall clock time from when the function code starts executing as a result of an invocation to when it stops executing)
  widget {
    timeseries_definition {
      title = "Lambda Duration Maximum"

      request {
        q            = "sum:aws.lambda.duration.maximum{environment:${var.environment},service_name:${var.service_name}}.as_count()"
        display_type = "bars"
      }
    }
  }

  # Lambda Duration Minimum (Measures the minimum elapsed wall clock time from when the function code starts executing as a result of an invocation to when it stops executing)
  widget {
    timeseries_definition {
      title = "Lambda Duration Minimum"

      request {
        q            = "sum:aws.lambda.duration.minimum{environment:${var.environment},service_name:${var.service_name}}.as_count()"
        display_type = "bars"
      }
    }
  }

  # Lambda Duration Sum (Measures the total execution time of the lambda function executing)
  widget {
    query_value_definition {
      title     = "Lambda Duration Sum"
      autoscale = true

      request {
        q = "sum:aws.lambda.duration.sum{environment:${var.environment},service_name:${var.service_name}}.as_count()"
      }
    }
  }

  # Lambda Timeout (Measures the amount of allowed execution time for the function before the Lambda runtime stops it)
  widget {
    timeseries_definition {
      title = "Lambda Timeout"

      request {
        q            = "sum:aws.lambda.timeout{environment:${var.environment},service_name:${var.service_name}}.as_count()"
        display_type = "bars"
      }
    }
  }

  # Lambda Max memory used (Measures the maximum amount of memory (mb) used by the function)
  widget {
    timeseries_definition {
      title = "Lambda Max Memory Used"

      request {
        q            = "max:aws.lambda.enhanced.max_memory_used{environment:${var.environment},service_name:${var.service_name}}"
        display_type = "bars"
      }
    }
  }

  tags = local.dashboard_tags
}

resource "datadog_monitor" "lambda_errors_monitor" {
  count              = var.lambda_error_monitor_enabled ? 1 : 0
  name               = "${var.environment}-${var.service_name}-error-monitor"
  type               = "metric alert"
  message            = "Monitor triggered. Notify: ${var.notification_endpoints}"
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "sum(last_15m):default(avg:aws.lambda.errors{environment:${var.environment},service_name:${var.service_name}}.as_count(), 0) ${var.lambda_error_critical_operator} ${var.lambda_error_critical_number}"

  monitor_thresholds {
    ok                = var.lambda_error_ok_number
    warning           = var.lambda_error_warning_number
    warning_recovery  = var.lambda_error_warning_recovery_number
    critical          = var.lambda_error_critical_number
    critical_recovery = var.lambda_error_critical_recovery_number
  }

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

  tags = local.tags
}

resource "datadog_monitor" "lambda_invocations_monitor" {
  count              = var.lambda_invocation_monitor_enabled ? 1 : 0
  name               = "${var.environment}-${var.service_name}-invocations-monitor"
  type               = "query alert"
  message            = "Monitor triggered. Notify: ${var.notification_endpoints}"
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "sum(${var.lambda_invocation_time}):sum:aws.lambda.invocations{environment:${var.environment},service_name:${var.service_name}}.as_count() ${var.lambda_invocation_operator} ${var.critical_invocation_number}"

  monitor_thresholds {
    ok                = var.ok_invocation_number
    critical          = var.critical_invocation_number
    warning           = var.invocation_warning_number
    critical_recovery = var.critical_recovery_invocation_number
    warning_recovery  = var.invocation_warning_recovery_number
  }

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

  tags = local.tags
}


resource "datadog_monitor" "lambda_throttle_monitor" {
  count              = var.lambda_throttle_monitor_enabled ? 1 : 0
  name               = "${var.environment}-${var.service_name}-throttle-monitor"
  type               = "query alert"
  message            = "Monitor triggered. Notify: ${var.notification_endpoints}"
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "sum(${var.lambda_throttle_time}):sum:aws.lambda.throttles{environment:${var.environment},service_name:${var.service_name}}.as_count() > ${var.lambda_throttle_critical_number}"

  monitor_thresholds {
    ok                = var.lambda_throttle_ok_number
    critical          = var.lambda_throttle_critical_number
    warning           = var.lambda_throttle_warning_number
    warning_recovery  = var.lambda_throttle_warning_recovery_number
    critical_recovery = var.lambda_throttle_critical_recovery_number
  }

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

  tags = local.tags
}

resource "datadog_monitor" "lambda_anomaly_monitor" {
  count              = var.lambda_anomaly_monitor_enabled ? 1 : 0
  name               = "${var.environment}-${var.service_name}-anomaly-monitor"
  type               = "query alert"
  message            = "Monitor triggered. Notify: ${var.notification_endpoints}"
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "sum(${var.lambda_anomaly_time}):anomalies(sum:aws.lambda.duration.${var.lambda_duration_pxx}{environment:${var.environment},functionname:${var.environment}-${var.service_name}}, '${var.lambda_anomaly_algorithm}', ${var.lambda_anomaly_deviations}, direction='${var.lambda_anomaly_direction}', interval=${var.lambda_anomaly_rollup_interval}, alert_window='${var.lambda_anomaly_alert_window}', seasonality='${var.lambda_anomaly_seasonality}') ${var.lambda_anomaly_operator} ${var.lambda_anomaly_critical_number}"
  monitor_thresholds {
    ok                = var.lambda_anomaly_ok_number
    critical          = var.lambda_anomaly_critical_number
    warning           = var.lambda_anomaly_warning_number
    warning_recovery  = var.lambda_anomaly_warning_recovery_number
    critical_recovery = var.lambda_anomaly_critical_recovery_number
  }

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

  tags = local.tags
}

resource "datadog_monitor" "lambda_max_memory_used" {
  count              = var.lambda_max_memory_used_enabled ? 1 : 0
  name               = "${var.environment}-${var.service_name}-max-memory-used-monitor"
  type               = "query alert"
  message            = "Monitor triggered. Notify: ${var.notification_endpoints}"
  escalation_message = "Escalation to ${var.escalation_notification_endpoints}"

  query = "max(last_15m):( max:aws.lambda.enhanced.max_memory_used{environment:${var.environment},service_name:${var.service_name}} / max:aws.lambda.enhanced.memorysize{environment:${var.environment},service_name:${var.service_name}} ) * 100 > ${var.lambda_max_memory_usage_critical_number}"

  monitor_thresholds {
    ok                = var.lambda_max_memory_usage_ok_number
    critical          = var.lambda_max_memory_usage_critical_number
    warning           = var.lambda_max_memory_usage_warning_number
    warning_recovery  = var.lambda_max_memory_usage_warning_recovery_number
    critical_recovery = var.lambda_max_memory_usage_critical_recovery_number
  }

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

  tags = local.tags
}
