Skip to content

feat(dbi): Enable PostgreSQL execution plan collection - #2225

Merged
AshuSrv merged 4 commits into
mainfrom
iamashu/dbi-enable-explain-plans
Aug 6, 2026
Merged

AshuSrv merged 4 commits into
mainfrom
iamashu/dbi-enable-explain-plans

Conversation

@AshuSrv

@AshuSrv AshuSrv commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Description of the issue

PostgreSQL execution plans are never collected for Database Insights. The translator sets the per-interval explain budget to 0, and the receiver gates explain attempts on explained < maxExplainEachInterval, so that comparison is
never true. Every db.server.top_query event is emitted with an empty postgresql.query_plan attribute.

Description of changes

Set the per-interval explain budget to 1000 in the PostgreSQL receiver translator so execution plans are collected by default.

-cfg.MaxExplainEachInterval = 0
+cfg.MaxExplainEachInterval = 1000

The value is kept as an explicit assignment rather than removed so it remains easy to adjust.

The expected translator outputs under translator/tocwconfig/sampleConfig are updated to match, and a test assertion pins the value so it cannot silently regress to disabled.

1000 is the upstream default for this setting, so this restores upstream behaviour rather than introducing a value we would have to carry as a divergence.

The number is not the effective cap on work. The explain loop is bounded by top_n_query, which is 200, so at most 200 explains can be attempted in an interval regardless of this setting.

License

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Tests

Unit tests

go test ./translator/translate/otel/receiver/postgresql/... ./translator/tocwconfig/
ok  	github.com/aws/amazon-cloudwatch-agent/translator/translate/otel/receiver/postgresql
ok  	github.com/aws/amazon-cloudwatch-agent/translator/tocwconfig

make fmt, make fmt-sh and make lint are clean.

Verified on EC2 instance

Amazon Linux 2, PostgreSQL 14.23 with pg_stat_statements (track = all), a non-superuser role owning the workload tables, and a monitoring user granted pg_monitor plus SELECT on those tables.

Agent configuration used:

{
  "agent": { "region": "us-west-2" },
  "opentelemetry": {
    "collect": {
      "database_insights": {
        "postgresql": [
          {
            "endpoint": "localhost:5432",
            "instance_name": "explain-plans-test",
            "username": "cw_monitor",
            "password_file": "/opt/databaseinsights/.pgpass",
            "logs": { "file_path": "/var/log/postgresql/postgresql-*.log" }
          }
        ]
      }
    }
  }
}

The generated collector configuration now carries the budget:

top_query_collection:
    collection_interval: 1m0s
    max_explain_each_interval: 1000
    max_rows_per_query: 5000
    query_plan_cache_size: 1000
    query_plan_cache_ttl: 1h0m0s
    top_n_query: 200

Sample db.server.top_query record after the change, from
/aws/self-managed-database-insights/postgresql/raw-events:

"attributes": {
        "db.system.name": "postgresql",
        "db.namespace": "testdb",
        "db.query.text": "SELECT COALESCE ( ( SELECT extname FROM pg_extension WHERE extname = ? ) )",
        "postgresql.calls": 1,
        "postgresql.rows": 1,
         .
         .
         .
        "postgresql.query_plan": "[{\"Plan\":{\"Node Type\":\"Result\",\"Parallel Aware\":false,\"Async Capable\":false,\"Startup Cost\":1.01,\"Total Cost\":1.02,\"Plan Rows\":1,\"Plan Width\":64,\"Plans\":[{\"Node Type\":\"Seq Scan\",\"Parent Relationship\":\"InitPlan\",\"Subplan Name\":\"InitPlan 1 (returns $0)\",\"Parallel Aware\":false,\"Async Capable\":false,\"Relation Name\":\"pg_extension\",\"Alias\":\"pg_extension\",\"Startup Cost\":0.00,\"Total Cost\":1.01,\"Plan Rows\":1,\"Plan Width\":64,\"Filter\":\"( extname = ? )\"}]}}]"
    },

Requirements

  • Run make fmt and make fmt-sh
  • Run make lint

The PostgreSQL receiver can collect query execution plans and attach them to top query events as postgresql.query_plan, but the agent pinned max_explain_each_interval to 0, which disabled collection entirely and left the attribute as an empty string.

Set it to the receiver default of 1000. The effective ceiling is top_n_query (200) plan-only operations per collection interval, since only that many queries are considered; cached plans do not consume budget, and the plan cache has a one hour TTL. EXPLAIN is issued without ANALYZE, so no query is executed.
@AshuSrv
AshuSrv requested a review from a team as a code owner July 31, 2026 14:07
@AshuSrv AshuSrv added the ready for testing Indicates this PR is ready for integration tests to run label Jul 31, 2026
@github-actions

github-actions Bot commented Jul 31, 2026 •

Copy link
Copy Markdown
Contributor

Binary Size Report

linux/amd64

Binary PR vs main (5efb6c4) vs v1.300070.0
amazon-cloudwatch-agent 193.3 MB +0 B ${\color{green}▼}$ 38.0 MB (-16.4%)
amazon-cloudwatch-agent-config-wizard 2.0 MB +0 B ${\color{red}▲}$ +86.0 KB (+4.5%)
config-downloader 2.0 MB +0 B ${\color{red}▲}$ +86.0 KB (+4.5%)
config-translator 2.0 MB +0 B ${\color{red}▲}$ +86.0 KB (+4.5%)
start-amazon-cloudwatch-agent 2.5 MB +0 B ${\color{red}▲}$ +81.9 KB (+3.4%)
workload-discovery 3.0 MB +0 B ${\color{red}▲}$ +94.2 KB (+3.2%)
Total 204.8 MB +0 B ${\color{green}▼}$ 37.6 MB (-15.5%)
linux/amd64 amazon-cloudwatch-agent (last 9 main commits + this PR)

 193 ┤                                        
     ┤                            ███ ███ ███ 
     ┤                            ███ ███ ███ 
     ┤                            ███ ███ ███ 
     ┤                            ███ ███ ███ 
     ┤                            ███ ███ ███ 
     ┤                            ███ ███ ███ 
     ┤                            ███ ███ ███ 
 193 ┤▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ███ ███ ███ 
 MB  └────────────────────────────────────────
      43f2526                             PR
linux/arm64
Binary PR vs main (5efb6c4) vs v1.300070.0
amazon-cloudwatch-agent 177.1 MB +0 B ${\color{green}▼}$ 34.4 MB (-16.3%)
amazon-cloudwatch-agent-config-wizard 2.0 MB +0 B ${\color{green}▼}$ 22 B (-0.0%)
config-downloader 2.0 MB +0 B ${\color{green}▼}$ 22 B (-0.0%)
config-translator 2.0 MB +0 B ${\color{green}▼}$ 22 B (-0.0%)
start-amazon-cloudwatch-agent 2.4 MB +0 B ${\color{red}▲}$ +65.5 KB (+2.8%)
workload-discovery 2.9 MB +0 B ${\color{red}▲}$ +65.5 KB (+2.3%)
Total 188.4 MB +0 B ${\color{green}▼}$ 34.3 MB (-15.4%)
windows/amd64
Binary PR vs main (5efb6c4) vs v1.300070.0
amazon-cloudwatch-agent.exe 196.1 MB ${\color{red}▲}$ +6.1 KB (+0.0%) ${\color{green}▼}$ 38.1 MB (-16.3%)
amazon-cloudwatch-agent-config-wizard.exe 2.1 MB +0 B ${\color{red}▲}$ +130.6 KB (+6.5%)
config-downloader.exe 2.1 MB +0 B ${\color{red}▲}$ +130.0 KB (+6.5%)
config-translator.exe 2.1 MB +0 B ${\color{red}▲}$ +130.6 KB (+6.5%)
start-amazon-cloudwatch-agent.exe 2.3 MB +0 B ${\color{red}▲}$ +112.1 KB (+5.2%)
workload-discovery.exe 2.9 MB +0 B ${\color{red}▲}$ +97.3 KB (+3.5%)
Total 207.7 MB ${\color{red}▲}$ +6.1 KB (+0.0%) ${\color{green}▼}$ 37.5 MB (-15.3%)
Investigating size changes

Use go-size-analyzer to compare binaries:

GOEXPERIMENT=jsonv2 go install github.com/Zxilly/go-size-analyzer/cmd/gsa@latest
gsa diff --old <baseline-binary> --new <new-binary>

@AshuSrv
AshuSrv merged commit 7ce23ff into main Aug 6, 2026
1227 of 1251 checks passed
@AshuSrv
AshuSrv deleted the iamashu/dbi-enable-explain-plans branch August 6, 2026 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready for testing Indicates this PR is ready for integration tests to run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants