|
| 1 | +--- |
| 2 | +title: AWS Application Load Balancer Logs Integration Guide |
| 3 | +description: This guide explains how to enable Application Load Balancer access logs, store them in S3, and forward them to OpenObserve for monitoring. Supports both manual setup and automated deployment. |
| 4 | +--- |
| 5 | + |
| 6 | +# Integration with AWS Application Load Balancer |
| 7 | + |
| 8 | +This guide provides step-by-step instructions to integrate AWS Application Load Balancer (ALB) with OpenObserve. |
| 9 | + |
| 10 | +## Overview |
| 11 | + |
| 12 | +Ingest ALB access logs into OpenObserve for monitoring and troubleshooting. ALB access logs provide details such as client IPs, request paths, status codes, and processing times. Forwarding these logs to OpenObserve lets you store, search, and visualize ALB traffic to analyze usage, performance, and issues. |
| 13 | + |
| 14 | + |
| 15 | +## Integration Options |
| 16 | + |
| 17 | +You can integrate ALB logs with OpenObserve in **two ways**: |
| 18 | + |
| 19 | +1. **Manually using Console**: good for testing, learning, small environments |
| 20 | +2. **Automated Setup with CloudFormation**: best for repeatable, production-ready deployments |
| 21 | + |
| 22 | + |
| 23 | +## Manually using Console |
| 24 | +Use this flow if you want to get started step-by-step using the AWS Console. |
| 25 | + |
| 26 | + |
| 27 | +??? "Prerequisites" |
| 28 | + - AWS account with an Application Load Balancer configured and serving traffic |
| 29 | + - S3 bucket for storing ALB logs |
| 30 | + - IAM permissions to configure ALB logging and bucket policies |
| 31 | + - OpenObserve account with valid API credentials |
| 32 | + - Lambda execution role with `s3:GetObject` and `s3:ListBucket` permissions |
| 33 | + |
| 34 | + |
| 35 | +??? "Step 1: Enable ALB Access Logs" |
| 36 | + |
| 37 | + 1. In the AWS Console, open **EC2 → Load Balancers**. |
| 38 | + 2. Select your ALB → **Description → Edit attributes**. |
| 39 | + 3. Enable **Access logs** and **Connection Logs**, enter your S3 bucket name, add a prefix if needed, and save. |
| 40 | + |
| 41 | +  |
| 42 | + |
| 43 | +??? "Step 2: Verify Logs in S3" |
| 44 | + |
| 45 | + 1. Send traffic through your ALB (e.g., use `curl` on your ALB DNS name). |
| 46 | + 2. In your **S3 bucket**, confirm that `.log.gz` files appear under the prefix. |
| 47 | + |
| 48 | +  |
| 49 | + |
| 50 | + |
| 51 | +??? "Step 3: Deploy a Lambda to Forward Logs" |
| 52 | + |
| 53 | + 1. Use a Python handler that: |
| 54 | + |
| 55 | + - Reads the `.log.gz` from S3 |
| 56 | + - Parses ALB log lines |
| 57 | + - POSTs JSON logs to your OpenObserve stream |
| 58 | + |
| 59 | + Example: |
| 60 | + ```python |
| 61 | + import boto3, gzip, urllib.parse, base64, requests |
| 62 | + |
| 63 | + s3 = boto3.client('s3') |
| 64 | + |
| 65 | + OPENOBSERVE_URL = 'https://<your-openobserve>/api/<org>/<stream>/_json' |
| 66 | + OPENOBSERVE_USER = 'your_username' |
| 67 | + OPENOBSERVE_PASS = 'your_password' |
| 68 | + |
| 69 | + def parse_alb_line(line): |
| 70 | + parts = line.split() |
| 71 | + if len(parts) < 12: |
| 72 | + return None |
| 73 | + return { |
| 74 | + "type": parts[0], |
| 75 | + "time": parts[1], |
| 76 | + "elb": parts[2], |
| 77 | + "client_ip": parts[3], |
| 78 | + "target_ip": parts[4], |
| 79 | + "request_processing_time": parts[5], |
| 80 | + "backend_processing_time": parts[6], |
| 81 | + "response_processing_time": parts[7], |
| 82 | + "elb_status_code": parts[8], |
| 83 | + "backend_status_code": parts[9], |
| 84 | + "received_bytes": parts[10], |
| 85 | + "sent_bytes": parts[11], |
| 86 | + } |
| 87 | + |
| 88 | + def lambda_handler(event, context): |
| 89 | + for record in event['Records']: |
| 90 | + bucket = record['s3']['bucket']['name'] |
| 91 | + key = urllib.parse.unquote_plus(record['s3']['object']['key']) |
| 92 | + obj = s3.get_object(Bucket=bucket, Key=key) |
| 93 | + bytestream = obj['Body'].read() |
| 94 | + lines = gzip.decompress(bytestream).decode('utf-8').splitlines() |
| 95 | + |
| 96 | + logs = [parse_alb_line(l) for l in lines if parse_alb_line(l)] |
| 97 | + |
| 98 | + if logs: |
| 99 | + auth = base64.b64encode(f"{OPENOBSERVE_USER}:{OPENOBSERVE_PASS}".encode()).decode() |
| 100 | + headers = {"Authorization": f"Basic {auth}", "Content-Type": "application/json"} |
| 101 | + r = requests.post(OPENOBSERVE_URL, headers=headers, json=logs) |
| 102 | + print(f"Sent logs → Status: {r.status_code} Response: {r.text}") |
| 103 | + ``` |
| 104 | + |
| 105 | + |
| 106 | + > The Python runtime **does not include `requests`**, you must package it. If using local OpenObserve, expose with `ngrok` or run on a public IP. |
| 107 | + |
| 108 | +??? "Step 4: Attach an S3 Trigger in Lambda" |
| 109 | + |
| 110 | + - In Lambda, go to **Triggers → Add trigger**. |
| 111 | + - Select **S3**, pick your bucket. |
| 112 | + - Set **Event type** to **All object create events**. |
| 113 | + - (Optional) Add a prefix filter. |
| 114 | + - Click **Add**. |
| 115 | + |
| 116 | +  |
| 117 | + |
| 118 | +??? "Step 5: Verify" |
| 119 | + |
| 120 | + - In OpenObserve → Logs → filter your stream → logs should appear. |
| 121 | + |
| 122 | +  |
| 123 | + |
| 124 | + |
| 125 | +??? "Troubleshooting" |
| 126 | + |
| 127 | + **No logs in S3** |
| 128 | + |
| 129 | + * Confirm ALB logging is enabled. |
| 130 | + * Check the bucket policy. |
| 131 | + |
| 132 | + **Lambda permission error (`AccessDenied`)** |
| 133 | + |
| 134 | + * Add `s3:GetObject` + `s3:ListBucket` to your Lambda role. |
| 135 | + |
| 136 | + **`ImportModuleError: requests`** |
| 137 | + |
| 138 | + * Package `requests` in your `.zip`. Don’t use the inline editor. |
| 139 | + |
| 140 | + **`401 Unauthorized`** |
| 141 | + |
| 142 | + * Double-check OpenObserve username. |
| 143 | + * Verify Basic Auth: `username:password`. |
| 144 | + * Use `curl -u` to confirm credentials. |
| 145 | + * Make sure your OpenObserve is reachable from Lambda (not `localhost`). |
| 146 | + |
| 147 | +## Automated Setup using CloudFormation |
| 148 | + |
| 149 | +Use this option to automatically deploy the entire ALB → S3 → Lambda → OpenObserve pipeline using AWS CloudFormation. |
| 150 | + |
| 151 | + |
| 152 | +??? "Step 1: Download the CloudFormation Template" |
| 153 | + |
| 154 | + - Download the prebuilt CloudFormation template from: |
| 155 | + [https://github.com/openobserve/cloudformation-templates/blob/main/aws_alb/alb.yaml](https://github.com/openobserve/cloudformation-templates/blob/main/aws_alb/alb.yaml) |
| 156 | + |
| 157 | + |
| 158 | +??? "Step 2: Configure CloudFormation with Parameters" |
| 159 | + |
| 160 | + - In AWS Console → **CloudFormation** → **Create stack → With new resources (standard)**. |
| 161 | + |
| 162 | +  |
| 163 | + |
| 164 | + - Upload the `alb.yaml` template. |
| 165 | + - Enter required parameters: |
| 166 | + |
| 167 | + - **ALB name** |
| 168 | + - **Target S3 bucket** |
| 169 | + - **IAM role** |
| 170 | + - **OpenObserve credentials** (username/password or token) |
| 171 | + - **ELBAccountId** |
| 172 | +  |
| 173 | + - Click **Next** → keep defaults → **Create stack**. |
| 174 | + |
| 175 | + |
| 176 | +??? "Step 3: Validate the CloudFormation Deployment" |
| 177 | + |
| 178 | + - Once the stack is deployed, check the **CloudFormation Stacks** page and confirm the status is **CREATE_COMPLETE**. |
| 179 | + - Go to **S3** → verify the bucket was created. |
| 180 | + - Go to **Lambda** → verify the function exists. |
| 181 | + |
| 182 | +  |
| 183 | + |
| 184 | +??? "Step 4: Enable Monitoring in AWS ALB" |
| 185 | + |
| 186 | + - In AWS Console, go to **EC2 → Load Balancers**. |
| 187 | + - Select your ALB → **Edit attributes** |
| 188 | + - Enable **Access Logs / Connection Logs**. |
| 189 | + - Pick the S3 bucket created by CloudFormation. |
| 190 | + - Add your chosen prefix and save the changes |
| 191 | + |
| 192 | +  |
| 193 | + |
| 194 | + |
| 195 | +??? "Step 5: Verify Logs in OpenObserve" |
| 196 | + |
| 197 | + - Go to **OpenObserve → Logs → your ALB stream → Run Query** to see ingested logs. |
| 198 | + |
| 199 | +  |
| 200 | + |
| 201 | +??? "Trobubleshooting" |
| 202 | + |
| 203 | + **CloudFormation stack failed or stuck** |
| 204 | + |
| 205 | + - Check the **Events** tab for detailed error messages. |
| 206 | + - Common causes: bad IAM role, missing required parameters, invalid bucket names. |
| 207 | + - Fix the issue → update or redeploy the stack. |
| 208 | + |
| 209 | + **No logs in OpenObserve** |
| 210 | + |
| 211 | + - check Lambda logs, permissions, and OpenObserve credentials. |
0 commit comments