A high-performance Go-based AWS Lambda application that parses and converts AWS access logs into OpenTelemetry (OTLP) log records, exporting them via HTTP to any OTLP-compatible backend (e.g., SigNoz, OpenTelemetry Collector, Coralogix, Datadog).
Documentation • Roadmap • Ask DeepWiki
This Lambda function is triggered via Amazon SQS, which receives S3 ObjectCreated events (either directly or via Amazon EventBridge) when log files are written to S3. It streams, uncompresses, parses, and transforms access logs into semantic OpenTelemetry LogRecord batches grouped by target resource ARN/ID.
- Application Load Balancer (ALB): Standard access logs (
.log,.log.gz). - Network Load Balancer (NLB): TLS and TCP connection logs (
.log,.log.gz). - AWS WAF: Web Application Firewall JSON logs (
.json,.gz). - CloudFront: Standard access logs (
.gz) and columnar Parquet logs (.parquet).
otel-aws-log-processor/
├── cmd/
│ └── lambda/ # AWS Lambda entrypoint (SQS event consumer)
├── pkg/
│ ├── events/ # S3 and EventBridge SQS event parsing
│ ├── model/ # OpenTelemetry JSON data models
│ ├── parser/ # Dedicated log parsers (ALB, NLB, WAF, CloudFront)
│ ├── processor/ # File-matching registry and LogAdapter conversions
│ ├── sender/ # OTLP HTTP batching and retry client
│ └── utils/ # Helpers (AWS trace IDs, URLs, env vars, time)
├── .github/
│ ├── dependabot.yml # Automated dependency updates
│ └── workflows/ # Reusable CI/CD, release, and PR workflows
├── .goreleaser.yaml # Multi-architecture binary and Lambda zip packaging
├── Dockerfile # Multi-stage container build for provided.al2023
└── Makefile # Standardized build and test targets
- ⚡ High Throughput & Memory Efficient: Streams S3 log objects line-by-line without buffering large compressed files into memory.
- 🔄 Semantic Resource Batching: Automatically groups log records by cloud resource ID (e.g., ALB ARN, CloudFront Distribution ID) prior to HTTP dispatch to maintain semantic resource scoping in OTLP backends.
- 🛡️ Reliable Delivery & Concurrency: Leverages SQS concurrency controls with configurable HTTP retry backoff and batch size limits.
- 📦 Multi-Architecture Builds: Native builds for ARM64 (
provided.al2023) and AMD64.
The Lambda handler is configured entirely via environment variables:
| Variable | Description | Default |
|---|---|---|
OTLP_HTTP_LOGS_ENDPOINT |
HTTP destination endpoint for OTLP logs | http://localhost:4318/v1/logs |
BASIC_AUTH_USERNAME |
Basic authentication username (optional) | "" |
BASIC_AUTH_PASSWORD |
Basic authentication password (optional) | "" |
MAX_BATCH_SIZE |
Max log records per OTLP HTTP batch request | 500 |
MAX_RETRIES |
Number of retry attempts on failed HTTP requests | 3 |
MAX_CONCURRENT |
Concurrency limit for file processing & HTTP sending | 10 |
ENVIRONMENT |
Environment name (development, staging, production, etc.) |
production |
DIVMORA_LICENSE_KEY |
Commercial Ed25519 license token (required for production) | "" |
DIVMORA_LICENSE_MODE |
Production enforcement mode (warn non-blocking or strict) |
warn |
Deploy the Lambda function with the following least-privilege IAM policy:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3LogBucketAccess",
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::<your-aws-logs-bucket>/*"
},
{
"Sid": "SQSTriggerAccess",
"Effect": "Allow",
"Action": [
"sqs:ReceiveMessage",
"sqs:DeleteMessage",
"sqs:GetQueueAttributes"
],
"Resource": "arn:aws:sqs:<region>:<account-id>:<your-log-events-queue>"
},
{
"Sid": "CloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}To build the Lambda deployment package for AWS Lambda (provided.al2023, ARM64):
make lambda-packageThis compiles a stripped bootstrap binary and packages it into lambda.zip.
aws lambda create-function \
--function-name otel-aws-log-processor \
--runtime provided.al2023 \
--handler bootstrap \
--zip-file fileb://lambda.zip \
--role arn:aws:iam::<ACCOUNT_ID>:role/<lambda-execution-role> \
--architectures arm64 \
--timeout 300 \
--memory-size 512 \
--environment "Variables={OTLP_HTTP_LOGS_ENDPOINT=https://ingest.your-observability.com/v1/logs,MAX_BATCH_SIZE=500}"aws lambda create-event-source-mapping \
--function-name otel-aws-log-processor \
--event-source-arn arn:aws:sqs:<REGION>:<ACCOUNT_ID>:<queue-name> \
--batch-size 10Production-ready AWS CloudFormation templates with automated SQS Ingestion Queue, Dead Letter Queue (DLQ), IAM least-privilege execution roles, CloudWatch alarms, and AWS Secrets Manager integration are maintained in the divmora/cloudformation-templates repository.
- Go 1.26+: golang.org
- Make: Build automation
- Docker: Containerization and multi-arch builds
# Build binary locally
make build
# Run all unit tests
make test
# Run unit tests with code coverage analysis
make test-coverage
# Format source code
make fmt
# Run linter
make lint
# Package AWS Lambda zip
make lambda-package
# Build local Docker image
make docker-build
# Preview documentation locally
make docs-serveWe welcome contributions from the community! Please review our community documents:
- Contributing Guide: Guidelines for local setup, pull requests, and conventional commits.
- Code of Conduct: Community standards and expectations.
- Security Policy: Vulnerability disclosure guidelines and SLA.
This project is licensed under the Business Source License 1.1 (BSL 1.1) - see the LICENSE file for details.
- Non-Production Use: 100% free of charge for local development, staging, QA, testing, CI/CD automated validation, and proof-of-concept evaluation. Simply set
ENVIRONMENT=developmentorstaging. - Change Date Conversion: Automatically converts to the permissive Apache License, Version 2.0 exactly three (3) years after each release.
- Production Deployments: Production use requires a valid commercial license (EULA) from DIVMORA Technologies.
For container and serverless AWS Lambda deployments, supply your cryptographic license token via the DIVMORA_LICENSE_KEY environment variable in your Lambda function configuration or Terraform module:
export DIVMORA_LICENSE_KEY="DIV1.<payload>.<signature>"Alternatively, mount a license file and point to its location using DIVMORA_LICENSE_FILE=/path/to/license.key.
| Mode | Behavior |
|---|---|
DIVMORA_LICENSE_MODE=warn (Default) |
Emits structured warnings and stamps divmora.license.status=unlicensed_production_alert in OTel telemetry and CloudWatch EMF without dropping logs or disrupting production pipelines. |
DIVMORA_LICENSE_MODE=strict |
Strictly enforces licensing compliance, rejecting invocations if unverified or expired past the 14-day grace period. |
Install the official DIVMORA licensing toolkit CLI:
go install github.com/divmora/license-go/cmd/license-cli@v1.0.0Inspect and verify license tokens and quotas:
# Inspect commercial license claims:
license-cli inspect -license /path/to/license.key
# Check license status & quota consumption:
license-cli status -license /path/to/license.key -usage "max_streams=5"For enterprise licensing, custom SLAs, and commercial inquiries, please contact licensing@divmora.com or visit divmora.com.
