CloudWatch Logs Insights Queries

Prerequisites

  • AWS account with appropriate permissions
  • Terraform >= 1.0
  • Log group with log data

Step 1: Create the Log Group

module "app_logs" {
  source  = "registry.patterneddesigns.ca/essentials/cloudwatch-logs/aws"
  version = "1.3.0"

  log_group_name    = "/app/demo"
  retention_in_days = 30
}

Step 2: Create Saved Queries

resource "aws_cloudwatch_query_definition" "recent_errors" {
  name = "Recent Errors"

  log_group_names = [module.app_logs.log_group_name]

  query_string = <<-EOT
    fields @timestamp, @message, @logStream
    | filter @message like /ERROR/
    | sort @timestamp desc
    | limit 100
  EOT
}

resource "aws_cloudwatch_query_definition" "request_latency" {
  name = "Request Latency Stats"

  log_group_names = [module.app_logs.log_group_name]

  query_string = <<-EOT
    fields @timestamp, @message
    | parse @message /latency=(?<latency>\d+)ms/
    | stats avg(latency) as avg_latency,
            max(latency) as max_latency,
            min(latency) as min_latency,
            pct(latency, 95) as p95_latency
      by bin(5m)
  EOT
}

resource "aws_cloudwatch_query_definition" "error_breakdown" {
  name = "Error Type Breakdown"

  log_group_names = [module.app_logs.log_group_name]

  query_string = <<-EOT
    fields @timestamp, @message
    | filter @message like /ERROR/
    | parse @message /ERROR: (?<error_type>\w+)/
    | stats count(*) as count by error_type
    | sort count desc
  EOT
}

Step 3: Query Via AWS CLI

Run queries from the command line:

# Start a query
aws logs start-query \
  --log-group-name "/app/demo" \
  --start-time $(date -d '1 hour ago' +%s) \
  --end-time $(date +%s) \
  --query-string 'fields @timestamp, @message | filter @message like /ERROR/ | limit 20'

# Get query results (use query-id from previous command)
aws logs get-query-results --query-id "your-query-id"

Step 4: Create Dashboard Widget

resource "aws_cloudwatch_dashboard" "main" {
  dashboard_name = "application-logs"

  dashboard_body = jsonencode({
    widgets = [
      {
        type   = "log"
        x      = 0
        y      = 0
        width  = 24
        height = 6
        properties = {
          query  = "SOURCE '${module.app_logs.log_group_name}' | fields @timestamp, @message | filter @message like /ERROR/ | sort @timestamp desc | limit 50"
          region = data.aws_region.current.name
          title  = "Recent Errors"
        }
      }
    ]
  })
}