From 5967325454b40a400b4f4380ed504eb42ec3ed95 Mon Sep 17 00:00:00 2001 From: Seth Samuel Date: Fri, 8 May 2026 10:15:30 -0400 Subject: [PATCH 1/5] Centralize datadog_agent import --- postgres/datadog_checks/postgres/metadata.py | 7 +------ postgres/datadog_checks/postgres/postgres.py | 6 +----- postgres/datadog_checks/postgres/statement_samples.py | 7 +------ postgres/datadog_checks/postgres/statements.py | 7 +------ postgres/datadog_checks/postgres/util.py | 8 +++++++- 5 files changed, 11 insertions(+), 24 deletions(-) diff --git a/postgres/datadog_checks/postgres/metadata.py b/postgres/datadog_checks/postgres/metadata.py index cd341d12b23e5..2e08534c90b39 100644 --- a/postgres/datadog_checks/postgres/metadata.py +++ b/postgres/datadog_checks/postgres/metadata.py @@ -12,11 +12,6 @@ from .schemas import PostgresSchemaCollector -try: - import datadog_agent # type: ignore -except ImportError: - from datadog_checks.base.stubs import datadog_agent - from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -26,7 +21,7 @@ from datadog_checks.base.utils.tracking import tracked_method from datadog_checks.postgres.config_models import InstanceConfig -from .util import payload_pg_version +from .util import datadog_agent, payload_pg_version # PG_EXTENSION_INFO_QUERY is used to collect extension names and versions from # the pg_extension table. Schema names and roles are retrieved from their re- diff --git a/postgres/datadog_checks/postgres/postgres.py b/postgres/datadog_checks/postgres/postgres.py index 1d45a7726f553..58596c6125c03 100644 --- a/postgres/datadog_checks/postgres/postgres.py +++ b/postgres/datadog_checks/postgres/postgres.py @@ -48,6 +48,7 @@ from .__about__ import __version__ from .config import build_config, sanitize from .util import ( + datadog_agent, ANALYZE_PROGRESS_METRICS, AWS_RDS_HOSTNAME_SUFFIX, AZURE_DEPLOYMENT_TYPE_TO_RESOURCE_TYPE, @@ -92,11 +93,6 @@ ) from .version_utils import V9, V9_2, V10, V12, V13, V14, V15, V16, V17, V18, VersionUtils -try: - import datadog_agent -except ImportError: - from datadog_checks.base.stubs import datadog_agent - MAX_CUSTOM_RESULTS = 100 PG_SETTINGS_QUERY = "SELECT name, setting FROM pg_settings WHERE name IN (%s, %s, %s)" diff --git a/postgres/datadog_checks/postgres/statement_samples.py b/postgres/datadog_checks/postgres/statement_samples.py index e8b45dd1ef891..61e32eb67c0f5 100644 --- a/postgres/datadog_checks/postgres/statement_samples.py +++ b/postgres/datadog_checks/postgres/statement_samples.py @@ -15,11 +15,6 @@ from datadog_checks.postgres.config_models import InstanceConfig -try: - import datadog_agent -except ImportError: - from datadog_checks.base.stubs import datadog_agent - from typing import TYPE_CHECKING @@ -40,7 +35,7 @@ from datadog_checks.base.utils.tracking import tracked_method from datadog_checks.postgres.explain_parameterized_queries import ExplainParameterizedQueries -from .util import DatabaseConfigurationError, DBExplainError, trim_leading_set_stmts, warning_with_tags +from .util import datadog_agent, DatabaseConfigurationError, DBExplainError, trim_leading_set_stmts, warning_with_tags from .version_utils import V9_6, V10 # according to https://unicodebook.readthedocs.io/unicode_encodings.html, the max supported size of a UTF-8 encoded diff --git a/postgres/datadog_checks/postgres/statements.py b/postgres/datadog_checks/postgres/statements.py index 8cd273bbee7ba..f641ff0170f97 100644 --- a/postgres/datadog_checks/postgres/statements.py +++ b/postgres/datadog_checks/postgres/statements.py @@ -20,14 +20,9 @@ from datadog_checks.postgres.config_models import InstanceConfig from .query_calls_cache import QueryCallsCache -from .util import DatabaseConfigurationError, payload_pg_version, warning_with_tags +from .util import datadog_agent, DatabaseConfigurationError, payload_pg_version, warning_with_tags from .version_utils import V9_4, V10, V14 -try: - import datadog_agent -except ImportError: - from datadog_checks.base.stubs import datadog_agent - QUERYID_TO_CALLS_QUERY = """ SELECT queryid, calls FROM {pg_stat_statements_view} diff --git a/postgres/datadog_checks/postgres/util.py b/postgres/datadog_checks/postgres/util.py index 7d0af187575c0..1744bdebf0e3a 100644 --- a/postgres/datadog_checks/postgres/util.py +++ b/postgres/datadog_checks/postgres/util.py @@ -9,7 +9,13 @@ from datadog_checks.base import AgentCheck from datadog_checks.base.errors import CheckException - +# Centralize the import/fallback for the agent +# We fallback to the stubs during testing +try: + import datadog_agent # type: ignore +except ImportError: + from datadog_checks.base.stubs import datadog_agent +datadog_agent class PartialFormatter(string.Formatter): """Follows PEP3101, used to format only specified args in a string. Ex: From 48d548e6002210888d9893e56720ecc4cd2994a7 Mon Sep 17 00:00:00 2001 From: Seth Samuel Date: Fri, 8 May 2026 14:12:56 -0400 Subject: [PATCH 2/5] Revert --- .../datadog_checks/base/utils/db/utils.py | 9 +++++++++ postgres/datadog_checks/postgres/metadata.py | 7 ++++++- postgres/datadog_checks/postgres/postgres.py | 6 +++++- postgres/datadog_checks/postgres/statement_samples.py | 7 ++++++- postgres/datadog_checks/postgres/statements.py | 6 +++++- postgres/datadog_checks/postgres/util.py | 8 +------- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/utils/db/utils.py b/datadog_checks_base/datadog_checks/base/utils/db/utils.py index 6b371516cb6bd..a69f0add6bec0 100644 --- a/datadog_checks_base/datadog_checks/base/utils/db/utils.py +++ b/datadog_checks_base/datadog_checks/base/utils/db/utils.py @@ -26,6 +26,15 @@ from datadog_checks.base.utils.format import json from datadog_checks.base.utils.tracing import INTEGRATION_TRACING_SERVICE_NAME, tracing_enabled +# Centralize the import/fallback for the agent +# We fallback to the stubs during testing +try: + import datadog_agent # type: ignore +except ImportError: + from datadog_checks.base.stubs import datadog_agent +datadog_agent + + logger = logging.getLogger(__file__) # AgentCheck methods to transformer name e.g. set_metadata -> metadata diff --git a/postgres/datadog_checks/postgres/metadata.py b/postgres/datadog_checks/postgres/metadata.py index 2e08534c90b39..cd341d12b23e5 100644 --- a/postgres/datadog_checks/postgres/metadata.py +++ b/postgres/datadog_checks/postgres/metadata.py @@ -12,6 +12,11 @@ from .schemas import PostgresSchemaCollector +try: + import datadog_agent # type: ignore +except ImportError: + from datadog_checks.base.stubs import datadog_agent + from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -21,7 +26,7 @@ from datadog_checks.base.utils.tracking import tracked_method from datadog_checks.postgres.config_models import InstanceConfig -from .util import datadog_agent, payload_pg_version +from .util import payload_pg_version # PG_EXTENSION_INFO_QUERY is used to collect extension names and versions from # the pg_extension table. Schema names and roles are retrieved from their re- diff --git a/postgres/datadog_checks/postgres/postgres.py b/postgres/datadog_checks/postgres/postgres.py index 0f2592e411f20..113e4402af133 100644 --- a/postgres/datadog_checks/postgres/postgres.py +++ b/postgres/datadog_checks/postgres/postgres.py @@ -49,7 +49,6 @@ from .config import build_config, sanitize from .diagnose import PostgresDiagnose from .util import ( - datadog_agent, ANALYZE_PROGRESS_METRICS, AWS_RDS_HOSTNAME_SUFFIX, AZURE_DEPLOYMENT_TYPE_TO_RESOURCE_TYPE, @@ -94,6 +93,11 @@ ) from .version_utils import V9, V9_2, V10, V12, V13, V14, V15, V16, V17, V18, VersionUtils +try: + import datadog_agent +except ImportError: + from datadog_checks.base.stubs import datadog_agent + MAX_CUSTOM_RESULTS = 100 PG_SETTINGS_QUERY = "SELECT name, setting FROM pg_settings WHERE name IN (%s, %s, %s, %s)" diff --git a/postgres/datadog_checks/postgres/statement_samples.py b/postgres/datadog_checks/postgres/statement_samples.py index 61e32eb67c0f5..e8b45dd1ef891 100644 --- a/postgres/datadog_checks/postgres/statement_samples.py +++ b/postgres/datadog_checks/postgres/statement_samples.py @@ -15,6 +15,11 @@ from datadog_checks.postgres.config_models import InstanceConfig +try: + import datadog_agent +except ImportError: + from datadog_checks.base.stubs import datadog_agent + from typing import TYPE_CHECKING @@ -35,7 +40,7 @@ from datadog_checks.base.utils.tracking import tracked_method from datadog_checks.postgres.explain_parameterized_queries import ExplainParameterizedQueries -from .util import datadog_agent, DatabaseConfigurationError, DBExplainError, trim_leading_set_stmts, warning_with_tags +from .util import DatabaseConfigurationError, DBExplainError, trim_leading_set_stmts, warning_with_tags from .version_utils import V9_6, V10 # according to https://unicodebook.readthedocs.io/unicode_encodings.html, the max supported size of a UTF-8 encoded diff --git a/postgres/datadog_checks/postgres/statements.py b/postgres/datadog_checks/postgres/statements.py index 39387d49c5e01..8934812ecc79f 100644 --- a/postgres/datadog_checks/postgres/statements.py +++ b/postgres/datadog_checks/postgres/statements.py @@ -21,7 +21,6 @@ from .query_calls_cache import QueryCallsCache from .util import ( - datadog_agent, DatabaseConfigurationError, parse_shared_preload_libraries, payload_pg_version, @@ -29,6 +28,11 @@ ) from .version_utils import V9_4, V10, V14 +try: + import datadog_agent +except ImportError: + from datadog_checks.base.stubs import datadog_agent + QUERYID_TO_CALLS_QUERY = """ SELECT queryid, calls FROM {pg_stat_statements_view} diff --git a/postgres/datadog_checks/postgres/util.py b/postgres/datadog_checks/postgres/util.py index 4adf8ac9756fa..e556fa3fa45a0 100644 --- a/postgres/datadog_checks/postgres/util.py +++ b/postgres/datadog_checks/postgres/util.py @@ -9,13 +9,7 @@ from datadog_checks.base import AgentCheck from datadog_checks.base.errors import CheckException -# Centralize the import/fallback for the agent -# We fallback to the stubs during testing -try: - import datadog_agent # type: ignore -except ImportError: - from datadog_checks.base.stubs import datadog_agent -datadog_agent + class PartialFormatter(string.Formatter): """Follows PEP3101, used to format only specified args in a string. Ex: From 70d1d31007aed8ca2e77c69c654d5e541c5e98de Mon Sep 17 00:00:00 2001 From: Seth Samuel Date: Fri, 8 May 2026 14:38:03 -0400 Subject: [PATCH 3/5] Map diagnoses to health events --- postgres/datadog_checks/postgres/diagnose.py | 7 ++++++- postgres/datadog_checks/postgres/health.py | 17 +++++++++++++++++ postgres/datadog_checks/postgres/postgres.py | 7 ++++++- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/postgres/datadog_checks/postgres/diagnose.py b/postgres/datadog_checks/postgres/diagnose.py index 9044799e911f7..a8f5ec7a43460 100644 --- a/postgres/datadog_checks/postgres/diagnose.py +++ b/postgres/datadog_checks/postgres/diagnose.py @@ -15,9 +15,14 @@ validation failures) surface via ``log.error`` and the initialization health event instead. """ +from __future__ import annotations import psycopg +from typing import TYPE_CHECKING +if TYPE_CHECKING: + from .postgres import PostgreSql + from .util import ( DIAGNOSTIC_METADATA, DatabaseConfigurationError, @@ -35,7 +40,7 @@ class PostgresDiagnose: """Explicit pre-flight diagnostics for `datadog-agent diagnose`.""" - def __init__(self, check): + def __init__(self, check: PostgreSql): self._check = check # Codes that have FAIL'd in the current explicit run. Used for cascade skipping so we # don't emit downstream-effect FAILs with nonsensical remediations (e.g. "CREATE EXTENSION" diff --git a/postgres/datadog_checks/postgres/health.py b/postgres/datadog_checks/postgres/health.py index e900ad9d55032..80c576ca07132 100644 --- a/postgres/datadog_checks/postgres/health.py +++ b/postgres/datadog_checks/postgres/health.py @@ -5,6 +5,8 @@ from typing import TYPE_CHECKING +from datadog_checks.base.utils.diagnose import Diagnosis + if TYPE_CHECKING: from datadog_checks.postgres import PostgreSql @@ -62,3 +64,18 @@ def submit_health_event( }, **kwargs, ) + + def diagnose(self): + """ + Run the diagnostics for the Postgres check. + """ + self.check.diagnose.run() + for diagnosis in self.check.diagnosis.diagnoses: + if diagnosis.result == Diagnosis.DIAGNOSIS_FAIL: + self.submit_health_event( + name=diagnosis.name, + status= HealthStatus.WARNING if diagnosis.result == Diagnosis.DIAGNOSIS_WARNING else HealthStatus.ERROR, + data={ + "diagnosis": diagnosis, + }, + ) \ No newline at end of file diff --git a/postgres/datadog_checks/postgres/postgres.py b/postgres/datadog_checks/postgres/postgres.py index 113e4402af133..f269ca671a413 100644 --- a/postgres/datadog_checks/postgres/postgres.py +++ b/postgres/datadog_checks/postgres/postgres.py @@ -192,7 +192,8 @@ def __init__(self, name, init_config, instances): ) # type: TTLCache # Register explicit pre-flight diagnostics for `datadog-agent diagnose`. - PostgresDiagnose(self).register() + self.diagnose = PostgresDiagnose(self) + self.diagnose.register() def _submit_initialization_health_event(self): try: @@ -492,6 +493,7 @@ def cancel(self): if self.data_observability._job_loop_future: self.data_observability._job_loop_future.result() self._close_db_pool() + self.diagnose = None def _clean_state(self): self.log.debug("Cleaning state") @@ -1206,6 +1208,9 @@ def check(self, _): hostname=self.reported_hostname, raw=True, ) + + self.health.diagnose() + raise e else: self.service_check( From 1751e2e219f03ca7b1dad415ca0c2a552ecbbd0d Mon Sep 17 00:00:00 2001 From: Seth Samuel Date: Fri, 8 May 2026 14:44:16 -0400 Subject: [PATCH 4/5] Lint --- .../datadog_checks/base/utils/db/utils.py | 9 --------- postgres/datadog_checks/postgres/diagnose.py | 4 +++- postgres/datadog_checks/postgres/health.py | 6 ++++-- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/datadog_checks_base/datadog_checks/base/utils/db/utils.py b/datadog_checks_base/datadog_checks/base/utils/db/utils.py index a69f0add6bec0..6b371516cb6bd 100644 --- a/datadog_checks_base/datadog_checks/base/utils/db/utils.py +++ b/datadog_checks_base/datadog_checks/base/utils/db/utils.py @@ -26,15 +26,6 @@ from datadog_checks.base.utils.format import json from datadog_checks.base.utils.tracing import INTEGRATION_TRACING_SERVICE_NAME, tracing_enabled -# Centralize the import/fallback for the agent -# We fallback to the stubs during testing -try: - import datadog_agent # type: ignore -except ImportError: - from datadog_checks.base.stubs import datadog_agent -datadog_agent - - logger = logging.getLogger(__file__) # AgentCheck methods to transformer name e.g. set_metadata -> metadata diff --git a/postgres/datadog_checks/postgres/diagnose.py b/postgres/datadog_checks/postgres/diagnose.py index a8f5ec7a43460..eb6c5970fc059 100644 --- a/postgres/datadog_checks/postgres/diagnose.py +++ b/postgres/datadog_checks/postgres/diagnose.py @@ -15,11 +15,13 @@ validation failures) surface via ``log.error`` and the initialization health event instead. """ + from __future__ import annotations +from typing import TYPE_CHECKING + import psycopg -from typing import TYPE_CHECKING if TYPE_CHECKING: from .postgres import PostgreSql diff --git a/postgres/datadog_checks/postgres/health.py b/postgres/datadog_checks/postgres/health.py index 80c576ca07132..4c7ef041748eb 100644 --- a/postgres/datadog_checks/postgres/health.py +++ b/postgres/datadog_checks/postgres/health.py @@ -74,8 +74,10 @@ def diagnose(self): if diagnosis.result == Diagnosis.DIAGNOSIS_FAIL: self.submit_health_event( name=diagnosis.name, - status= HealthStatus.WARNING if diagnosis.result == Diagnosis.DIAGNOSIS_WARNING else HealthStatus.ERROR, + status=HealthStatus.WARNING + if diagnosis.result == Diagnosis.DIAGNOSIS_WARNING + else HealthStatus.ERROR, data={ "diagnosis": diagnosis, }, - ) \ No newline at end of file + ) From 0afd82277facc6074cb53f85678593d8fdb0266a Mon Sep 17 00:00:00 2001 From: Seth Samuel Date: Fri, 8 May 2026 14:49:44 -0400 Subject: [PATCH 5/5] Changelog --- postgres/changelog.d/23645.added | 1 + 1 file changed, 1 insertion(+) create mode 100644 postgres/changelog.d/23645.added diff --git a/postgres/changelog.d/23645.added b/postgres/changelog.d/23645.added new file mode 100644 index 0000000000000..949d76193e287 --- /dev/null +++ b/postgres/changelog.d/23645.added @@ -0,0 +1 @@ +Run `diagnose` when the main Postgres check fails then emit any warnings and failures as Agent Health events. \ No newline at end of file