Your coding agents already write tool-audit JSON to S3 — session id, tool name, latency, token counts, tenant. Dumping that into a warehouse “someday” means you still cannot answer “which tenant burned $400 of Bedrock last night?” today. Amazon Athena runs SQL against the S3 objects (via Glue Data Catalog) so forensics and cost queries stay serverless. Distinct from CloudTrail Lake (organization CloudTrail / IAM abuse), CloudWatch Logs Insights (live log groups), and Detective (entity investigation graphs): here we query your application-level tool audit lake on S3.
⚡ TL;DR: Emit newline-delimited JSON tool audits to partitioned S3 prefixes, crawl/register with Glue, query with Athena for abuse/cost/quality joins, and keep CloudTrail Lake for IAM. Related: CloudTrail Lake IAM abuses, GuardDuty compromised credentials, ADOT multi-hop traces, Budgets + Cost Anomaly.
What belongs in the tool-audit lake
Emit one JSON object per tool invocation (or per turn summary). Keep it boring and columnar-friendly:
{
"ts": "2026-10-04T20:15:03.441Z",
"account_id": "111122223333",
"tenant_id": "acme",
"session_id": "sess_9f3a",
"agent_role": "patcher",
"prompt_version": "3",
"tool": "apply_patch",
"ok": true,
"latency_ms": 842,
"input_bytes": 12044,
"output_bytes": 220,
"bedrock_input_tokens": 4100,
"bedrock_output_tokens": 900,
"model_id": "anthropic.claude-sonnet-4-20250514-v1:0",
"repo": "acme/payments",
"pr_number": 1882,
"error_code": null,
"actor_arn": "arn:aws:sts::111122223333:assumed-role/batch-agent-job/job-1"
}
| Store | Use | Not for |
|---|---|---|
| S3 + Athena | Ad-hoc SQL, cost rollups, forensics | Sub-second product UI queries |
| CloudWatch Logs Insights | Live debugging last hours/days | Cheap year-long analytics at scale |
| CloudTrail Lake | Who called which AWS API | Your custom tool names |
| Detective | Credential compromise graphs | Token-cost by prompt_version |
| OpenSearch | Full-text / semantic scratch | Pennies-per-TB SQL scans |
❌ Only relying on CloudTrail: it will not show tool=apply_patch or prompt versions.
Land data so Athena does not hate you
Partition by date (and tenant if huge). Use JSON-SerDe or — better — convert to Parquet with a Firehose/ETL job once volume grows.
s3://coding-agent-audit-prod/
tool_invocations/
dt=2026-10-04/
tenant=acme/
part-000.gz
# ✅ agent host: append NDJSON to dated prefix (or Kinesis Firehose)
import json, gzip, io, boto3
from datetime import datetime, timezone
s3 = boto3.client("s3")
def emit_tool_audit(record: dict):
dt = datetime.now(timezone.utc).strftime("%Y-%m-%d")
tenant = record["tenant_id"]
key = f"tool_invocations/dt={dt}/tenant={tenant}/{record['session_id']}-{record['ts']}.json.gz"
buf = io.BytesIO()
with gzip.GzipFile(fileobj=buf, mode="wb") as gz:
gz.write((json.dumps(record) + "\n").encode())
s3.put_object(
Bucket="coding-agent-audit-prod",
Key=key,
Body=buf.getvalue(),
ServerSideEncryption="aws:kms",
ContentType="application/json",
)
Prefer Firehose → S3 with GZIP and period partitioning when QPS rises. Tag the bucket; block public access; Macie-scan if agents might leak secrets into fields (Macie on artifact buckets).
Glue table + Athena workgroup
-- ✅ external table over JSON (simplify types as needed)
CREATE EXTERNAL TABLE IF NOT EXISTS coding_agent.tool_invocations (
ts string,
account_id string,
tenant_id string,
session_id string,
agent_role string,
prompt_version string,
tool string,
ok boolean,
latency_ms int,
input_bytes bigint,
output_bytes bigint,
bedrock_input_tokens int,
bedrock_output_tokens int,
model_id string,
repo string,
pr_number int,
error_code string,
actor_arn string
)
PARTITIONED BY (dt string, tenant string)
ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://coding-agent-audit-prod/tool_invocations/'
TBLPROPERTIES ('has_encrypted_data'='true');
MSCK REPAIR TABLE coding_agent.tool_invocations;
-- or ALTER TABLE ... ADD PARTITION for tighter control
# ✅ Athena workgroup with enforce output location + bytes scanned cutoff
aws athena create-work-group \
--name coding-agent-forensics \
--configuration ResultConfigurationUpdates={OutputLocation=s3://athena-results-prod/coding-agent/},EnforceWorkGroupConfiguration=true,BytesScannedCutoffPerQuery=10737418240
Queries that earn their keep
-- ✅ Bedrock token burn by tenant + prompt_version (yesterday IST window ≈ UTC day)
SELECT tenant_id,
prompt_version,
COUNT(*) AS tool_calls,
SUM(bedrock_input_tokens + bedrock_output_tokens) AS tokens,
SUM(CASE WHEN ok THEN 0 ELSE 1 END) AS failures
FROM coding_agent.tool_invocations
WHERE dt = '2026-10-03'
GROUP BY 1, 2
ORDER BY tokens DESC
LIMIT 50;
-- ✅ suspicious: apply_patch spikes for one actor
SELECT actor_arn, COUNT(*) AS patches, COUNT(DISTINCT repo) AS repos
FROM coding_agent.tool_invocations
WHERE dt = '2026-10-04'
AND tool = 'apply_patch'
GROUP BY 1
HAVING COUNT(*) > 200
ORDER BY patches DESC;
-- ✅ join-quality: tool error rate by agent_role
SELECT agent_role, tool,
AVG(latency_ms) AS p_avg_ms,
AVG(CASE WHEN ok THEN 0.0 ELSE 1.0 END) AS err_rate
FROM coding_agent.tool_invocations
WHERE dt BETWEEN '2026-10-01' AND '2026-10-04'
GROUP BY 1, 2
ORDER BY err_rate DESC;
Correlate IAM oddities with CloudTrail Lake and escalate credential compromise with Detective / GuardDuty. Athena answers “what did the agent tool layer do?” — CloudTrail answers “which AWS APIs did the role call?”
Cost control for the queries themselves
| Mistake | Fix |
|---|---|
SELECT * over months |
Always filter dt; project columns |
| No workgroup cutoff | Set bytes scanned cutoff |
| Tiny gzip files | Firehose buffer or compact to Parquet |
| Results bucket open | Private + lifecycle expire 7–30d |
| Glue crawler chaos | Explicit partitions for high-churn tenants |
Convert hot partitions to Parquet/ORC when monthly scans hurt. Keep ADOT traces for hop-level latency; use Athena for fleet rollups — not as a substitute for Application Signals SLOs.
Production checklist
- [ ] NDJSON (or Parquet) tool audits to partitioned S3; KMS encrypted
- [ ] Schema stable; versions additive; document field meanings
- [ ] Glue table + repair/add partitions automated
- [ ] Athena workgroup: enforced output location + scan cutoff
- [ ] Saved queries for cost-by-tenant, patch spikes, error rates
- [ ] IAM: analysts can
athena:StartQueryExecutiononly on that workgroup - [ ] Clear split: Athena (app audits) vs CloudTrail Lake (AWS APIs) vs Detective
- [ ] Lifecycle rules on audit + results buckets
- [ ] Alert when emit pipeline lag > N minutes
FAQ
Q: Athena or OpenSearch for tool logs?
A: OpenSearch when you need full-text search and dashboards with sub-second filters. Athena when you want SQL + cheap scans over months of JSON/Parquet without running a cluster.
Q: Should every token stream go to S3?
A: No — store counts and metadata, not raw prompts/completions with secrets. If you must retain payloads, encrypt, redact, and bucket-policy deny public + cross-account by default.
Q: How does this relate to Cost Explorer?
A: Cost Explorer shows AWS service bills. Athena shows which tenant/prompt/tool drove Bedrock tokens inside your app. You need both to attribute spend.
Related reading
- CloudTrail Lake: Query Agent IAM Abuses
- Amazon Detective: Investigate Compromised Credentials
- ADOT: Trace Multi-Hop Agent Tool Calls
- AWS Budgets + Cost Anomaly Detection
Park the JSON in S3. Ask SQL questions. Skip the warehouse until Athena’s bills annoy you — then go columnar, not theatrical.
Last updated on October 4, 2026
Most viewed
- Python Decorators Explained: From Simple Wrappers to Production Patterns
- AI Agent Frameworks in 2025: LangGraph vs CrewAI vs AutoGen vs Raw API
- Python String Methods: Every str Method With Real Production Examples
- REST API Design Best Practices: The Patterns That Make APIs a Joy to Use
- Java Virtual Threads vs Traditional Threads: What Nobody Tells You
Newly added
- AWS Systems Manager Parameter Store: Hierarchical Config Coding Agents Must Not Hardcode
- Amazon Cognito Identity Pools: Federate Coding-Agent Tool Callers Without Long-Lived Keys
- Amazon Athena: Query Coding-Agent Tool Audit Logs Without a Warehouse
- AWS Batch: Overnight Parallel Coding-Agent Jobs Without Babysitting EC2
- Amazon Bedrock Prompt Management: Version and A/B Test Coding-Agent System Prompts
Deep-dive PDF
Get the expanded guide for this post — extra diagrams-style checklists, failure modes, and a production walkthrough. Free when you subscribe to CheatCoders.
Already subscribed? or open the subscribe page.
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.