Wednesday, September 3, 2025

Streaming CloudWatch Logs into OpenSearch Service | Overview.

Streaming CloudWatch Logs into OpenSearch Service - Overview. 

Scope:

  • Intro,
  • The Concept of OpenSearch Patterns in the Context of CloudWatch Logs,
  • OpenSearch relies on,
  • Common OpenSearch Pattern Techniques for CloudWatch Logs,
  • Sample Apache Access Log in CloudWatch Logs,
  • Sample Apache Access Log In OpenSearch pipeline,
  • Best Practices,
  • Insights. 

Intro:

    • To stream Amazon CloudWatch Logs into OpenSearch Service, twtech can utilize a direct subscription filter or an intermediary AWS Lambda function
    • The subscription filter sends a real-time feed of log events to a destination, which can then ingest the data into twtech OpenSearch domain.

The Concept of OpenSearch Patterns in the Context of CloudWatch Logs

  • When twtech streams CloudWatch Logs into Amazon OpenSearch Service (AOS) or OpenSearch self-managed, it often need a way to structure, parse, and query logs

NB: 

    • Raw log data is often unstructured (JSON, plaintext, multiline errors),

OpenSearch relies on:

    • Ingestion pipelines (via OpenSearch Ingest Pipelines, Logstash, Fluent Bit, or Kinesis Data Firehose)
    • Mappings & Index Templates (to define field types)
    • Patterns (such as Grok patterns, regex, or JSON extraction)

  • This pattern is used to turn raw log lines into structured fields that twtech can query, visualize (e.g., Kibana dashboards, OpenSearch Dashboards), or alert on.

Common OpenSearch Pattern Techniques for CloudWatch Logs

1. JSON Logs

If twtech-app logs are already in JSON (common with Lambda, ECS, EKS, structured logging):

  • CloudWatch Firehose OpenSearch can keep logs as JSON.
  • Use an index template in OpenSearch to define field mappings.
  • Example query in OpenSearch Dashboards:

{

  "query": {

    "match": { "level": "ERROR" }

  }

}

✅ Best for modern microservices logging (fast parsing, structured search).

2. Grok Patterns (Regex-like for Logs)

For plaintext logs (e.g., Apache, NGINX, syslog), use Grok patterns to extract fields.

Sample Apache Access Log in CloudWatch Logs

127.0.0.1 - frank [10/Oct/2025:13:55:36 -0700] "GET /index.html HTTP/1.0" 200 2326

Sample Apache Access Log In OpenSearch pipeline:

processors:

  - grok:

      field: "message"

      patterns:

        - '%{IPORHOST:clientip} %{USERNAME:ident} %{USERNAME:auth} \[%{HTTPDATE:timestamp}\] "%{WORD:method} %{DATA:request} HTTP/%{NUMBER:httpversion}" %{NUMBER:status} %{NUMBER:bytes}'

This extracts:

    • clientip = 127.0.0.1
    • method = GET
    • request = /index.html
    • status = 200

✅ Great for classic log formats, but can be slower for very high-volume logs.

3. Regex & Scripted Fields

For custom formats, twtech can use regex processors:

processors:

  - dissect:

      field: "message"

      pattern: "%{clientip} - %{user} [%{timestamp}] \"%{method} %{url} HTTP/%{version}\" %{status} %{size}"

Or 

use Painless scripts to enrich data (e.g., convert epoch timestamp).

4. Kinesis Data Firehose Transformations

When streaming CloudWatch Logs via Firehose to OpenSearch:

  • Firehose supports Lambda transformations.
  • twtech can pre-parse logs into structured JSON before ingestion.
  • Example: Convert multi-line Java stack traces into structured error logs.

5. Index Naming & Partitioning Patterns

Patterns aren’t just about parsing logs — also about how you organize them:

  • logs-<service>-<env>-YYYY.MM.DD e.g., logs-app1-prod-2025.09.03
  • Separate indices by log type (app, access, error, security).
  • Use ILM (Index Lifecycle Management) or ISM (Index State Management in OpenSearch) to roll over and archive logs efficiently.

6. Visualization & Search Patterns in OpenSearch Dashboards

Once logs are structured:

  • Saved searches e.g., status:[400 TO 599] for errors
  • Aggregations top 10 error endpoints
  • Dashboards latency percentiles, error trends, security alerts
  • Alerting plugin trigger notifications (Slack, SNS, PagerDuty)

 Best Practices 

  1. Prefer structured logging (JSON) over parsing plaintext → faster queries, lower ingestion cost.
  2. Use Grok sparingly regex is powerful but CPU-expensive at scale.
  3. Normalize timestamps early (epoch, RFC3339) makes queries & time filters consistent.
  4. Index wisely avoid dumping everything into one index. Use index patterns per environment/service.
  5. Retention strategy hot (7–30 days) vs warm (archival in S3 via snapshot).
  6. Security CloudWatch Kinesis OpenSearch should use IAM roles and fine-grained access control.

Final thought:
OpenSearch patterns for CloudWatch Logs are all about turning unstructured log streams into structured, queryable fields using Grok, regex, JSON parsing, and ingestion pipelines — then organizing indices smartly for performance and retention.

twtech-Insights:

  • Hands-on with a realistic CloudWatch Logs event from a Lambda function into OpenSearch with an ingestion pipeline pattern that parses & indexes.

 Step 1: Example CloudWatch Logs Event from Lambda (JSON)

When Lambda writes to CloudWatch Logs, it usually get JSON structured like this (after it’s decoded/unzipped from the CloudWatch stream):

{

  "id": "12345678901234567890123456xxxx012",

  "timestamp": 1693750xxxx000,

  "message": "{\"level\": \"ERROR\", \"function\": \"user-service\", \"requestId\": \"abc-123\", \"error\": \"UserNotFound\", \"details\": {\"userId\": \"42\"}}"

}

 Notice:

  • CloudWatch wraps the Lambda log line in a JSON object with id, timestamp, and message.
  • The message field itself is a stringified JSON log line from Lambda.

 Step 2: Target Structure in OpenSearch

  • twtech wants to parse the nested JSON string in message so OpenSearch stores fields like this:

{

  "id": "1234567890123456789012xxxx789012",

  "timestamp": "2023-09-03T00:00:00Z",

  "level": "ERROR",

  "function": "user-service",

  "requestId": "twtech-123",

  "error": "UserNotFound",

  "details.userId": "42"

}

 Step 3: OpenSearch Ingestion Pipeline

  • Here’s a sample ingest pipeline twtech defines in OpenSearch (via API or Dashboard Stack Management Ingest Pipelines):

PUT _ingest/pipeline/cloudwatch-lambda-logs

{

  "description": "twtech Parse CloudWatch Lambda JSON logs",

  "processors": [

    {

      "json": {

        "field": "message",

        "target_field": "parsed_message",

        "ignore_failure": true

      }

    },

    {

      "set": {

        "field": "level",

        "value": "{{parsed_message.level}}",

        "if": "ctx.parsed_message != null"

      }

    },

    {

      "set": {

        "field": "function",

        "value": "{{parsed_message.function}}",

        "if": "ctx.parsed_message != null"

      }

    },

    {

      "set": {

        "field": "requestId",

        "value": "{{parsed_message.requestId}}",

        "if": "ctx.parsed_message != null"

      }

    },

    {

      "set": {

        "field": "error",

        "value": "{{parsed_message.error}}",

        "if": "ctx.parsed_message != null"

      }

    },

    {

      "rename": {

        "field": "parsed_message.details.userId",

        "target_field": "userId",

        "ignore_missing": true

      }

    },

    {

      "date": {

        "field": "timestamp",

        "formats": ["UNIX_MS"]     // timestamp format in milliseconds

      }

    }

  ]

}

 Step 4: Indexing Logs with Pipeline

  • When Firehose, Fluent Bit, or Logstash pushes documents into OpenSearch, twtech configures it to use this pipeline:

POST cloudwatch-lambda-logs/_doc?pipeline=cloudwatch-lambda-logs

{

  "id": "123456789012345678901xxxx6789012",

  "timestamp": 169375xxxx000,

  "message": "{\"level\": \"ERROR\", \"function\": \"user-service\", \"requestId\": \"abc-123\", \"error\": \"UserNotFound\", \"details\": {\"userId\": \"42\"}}"

}

 Step 5: Final Indexed Document

  • After ingestion, OpenSearch stores it as:

{

  "_index": "cloudwatch-lambda-logs",

  "_id": "1234567890123456789012xxxx789012",

  "_source": {

    "id": "1234567890123456789012xxxx789012",

    "timestamp": "2023-09-03T00:00:00Z",

    "level": "ERROR",

    "function": "user-service",

    "requestId": "abc-123",

    "error": "UserNotFound",

    "userId": "42"

  }

}

At this point, twtech can run queries like:

{

  "query": {

    "match": { "error": "UserNotFound" }

  }

}

# Or 

  • Engineer may build dashboards for level: view ERROR trends.



No comments:

Post a Comment

Amazon EventBridge | Overview.

Amazon EventBridge - Overview. Scope: Intro, Core Concepts, Key Benefits, Link to official documentation, Insights. Intro: Amazon EventBridg...