diff --git a/CHANGELOG.md b/CHANGELOG.md index 4060f54b..31e2f6c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ configuration. (Requires Python 3.9 or higher.) * Add a `y` command to copy focused query to the system clipboard, using OSC 52 escape sequence (#311). +* Support Citus query activity (`citus_stat_activity`) views, through a new + `--citus` command-line option. ### Fixed diff --git a/README.md b/README.md index cba37d23..ab8e4302 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ ex: --rds Enable support for AWS RDS (implies --no-tempfiles and filters out the rdsadmin database from space calculation). + --citus Enable support for Citus. --output FILEPATH Store running queries as CSV. --db-size, --no-db-size Enable/disable total size of DB. diff --git a/docs/man/pg_activity.1 b/docs/man/pg_activity.1 index 96ce9b49..aab5563f 100644 --- a/docs/man/pg_activity.1 +++ b/docs/man/pg_activity.1 @@ -366,6 +366,11 @@ required by another session. It shows following information: .Vb 1 \& Enable support for AWS RDS (implies \-\-no\-tempfiles and filters out the rdsadmin database from space calculation). .Ve +.IP "\fB\-\-citus\fR" 2 +.IX Item "--citus" +.Vb 1 +\& Enable support for Citus. +.Ve .IP "\fB\-\-output=FILEPATH\fR" 2 .IX Item "--output=FILEPATH" .Vb 1 diff --git a/docs/man/pg_activity.pod b/docs/man/pg_activity.pod index c0ad5a6c..3e50c53f 100644 --- a/docs/man/pg_activity.pod +++ b/docs/man/pg_activity.pod @@ -252,6 +252,10 @@ required by another session. It shows following information: Enable support for AWS RDS (implies --no-tempfiles and filters out the rdsadmin database from space calculation). +=item B<--citus> + + Enable support for Citus. + =item B<--output=FILEPATH> Store running queries as CSV. diff --git a/pgactivity/cli.py b/pgactivity/cli.py index 2a97e6b3..3969a7b6 100755 --- a/pgactivity/cli.py +++ b/pgactivity/cli.py @@ -104,6 +104,13 @@ def get_parser() -> argparse.ArgumentParser: help="Enable support for AWS RDS (implies --no-tempfiles and filters out the rdsadmin database from space calculation).", default=False, ) + group.add_argument( + "--citus", + dest="citus", + action="store_true", + help="Enable support for Citus.", + default=False, + ) group.add_argument( "--output", dest="output", diff --git a/pgactivity/data.py b/pgactivity/data.py index 58f6a741..06447d6f 100644 --- a/pgactivity/data.py +++ b/pgactivity/data.py @@ -73,6 +73,7 @@ class Data: filters: Filters dsn_parameters: dict[str, str] failed_queries: FailedQueriesInfo + pg_stat_activity: str @classmethod def pg_connect( @@ -85,6 +86,7 @@ def pg_connect( password: str | None = None, database: str = "postgres", rds_mode: bool = False, + citus: bool = False, dsn: str = "", hide_queries_in_logs: bool = False, filters: Filters = NO_FILTER, @@ -115,6 +117,7 @@ def pg_connect( failed_queries=FailedQueriesInfo(), filters=filters, dsn_parameters=pg.connection_parameters(pg_conn), + pg_stat_activity="citus_stat_activity" if citus else "pg_stat_activity", ) def try_reconnect(self) -> Data | None: @@ -320,7 +323,10 @@ def pg_get_server_information( else: query = queries.get("get_server_info_oldest") - qs = sql.SQL(query).format(dbname_filter=self.dbname_filter) + qs = sql.SQL(query).format( + pg_stat_activity=sql.Identifier(self.pg_stat_activity), + dbname_filter=self.dbname_filter, + ) try: ret = pg.fetchone( self.pg_conn, @@ -410,6 +416,7 @@ def pg_get_activities(self, duration_mode: int = 1) -> list[RunningProcess]: duration_column = self.get_duration_column(duration_mode) query = sql.SQL(qs).format( + pg_stat_activity=sql.Identifier(self.pg_stat_activity), dbname_filter=self.dbname_filter, duration_column=sql.Identifier(duration_column), min_duration=sql.Literal(self.min_duration), @@ -437,6 +444,7 @@ def pg_get_waiting(self, duration_mode: int = 1) -> list[WaitingProcess]: duration_column = self.get_duration_column(duration_mode) query = sql.SQL(qs).format( + pg_stat_activity=sql.Identifier(self.pg_stat_activity), dbname_filter=self.dbname_filter, duration_column=sql.Identifier(duration_column), min_duration=sql.Literal(self.min_duration), @@ -466,6 +474,7 @@ def pg_get_blocking(self, duration_mode: int = 1) -> list[BlockingProcess]: duration_column = self.get_duration_column(duration_mode) query = sql.SQL(qs).format( + pg_stat_activity=sql.Identifier(self.pg_stat_activity), dbname_filter=self.dbname_filter, duration_column=sql.Identifier(duration_column), min_duration=sql.Literal(self.min_duration), @@ -527,6 +536,7 @@ def pg_connect( password=password, database=options.dbname, rds_mode=options.rds, + citus=options.citus, min_duration=min_duration, filters=filters, hide_queries_in_logs=options.hide_queries_in_logs, diff --git a/pgactivity/queries/get_blocking_oldest.sql b/pgactivity/queries/get_blocking_oldest.sql index b238f262..bcc5e5bc 100644 --- a/pgactivity/queries/get_blocking_oldest.sql +++ b/pgactivity/queries/get_blocking_oldest.sql @@ -27,21 +27,21 @@ SELECT SELECT blocking.pid, '' AS application_name, - pg_stat_activity.current_query AS query, + {pg_stat_activity}.current_query AS query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, NULL AS state, blocking.relation::regclass AS relation, - pg_stat_activity.waiting + {pg_stat_activity}.waiting FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.transactionid = blocked.transactionid AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.procpid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.procpid) WHERE blocking.granted AND NOT blocked.granted @@ -57,21 +57,21 @@ SELECT SELECT blocking.pid, '' AS application_name, - pg_stat_activity.current_query AS query, + {pg_stat_activity}.current_query AS query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, NULL AS state, blocking.relation::regclass AS relation, - pg_stat_activity.waiting + {pg_stat_activity}.waiting FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.virtualxid = blocked.virtualxid AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.procpid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.procpid) WHERE blocking.granted AND NOT blocked.granted @@ -87,21 +87,21 @@ SELECT SELECT blocking.pid, '' AS application_name, - pg_stat_activity.current_query AS query, + {pg_stat_activity}.current_query AS query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, NULL AS state, blocking.relation::regclass AS relation, - pg_stat_activity.waiting + {pg_stat_activity}.waiting FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.database = blocked.database AND blocking.relation = blocked.relation AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.procpid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.procpid) WHERE blocking.granted AND NOT blocked.granted diff --git a/pgactivity/queries/get_blocking_post_090200.sql b/pgactivity/queries/get_blocking_post_090200.sql index 7baf9cc4..33e5c424 100644 --- a/pgactivity/queries/get_blocking_post_090200.sql +++ b/pgactivity/queries/get_blocking_post_090200.sql @@ -21,22 +21,22 @@ SELECT -- Transaction id lock SELECT blocking.pid, - pg_stat_activity.application_name, - pg_stat_activity.query, + {pg_stat_activity}.application_name, + {pg_stat_activity}.query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, - pg_stat_activity.state as state, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, + {pg_stat_activity}.state as state, blocking.relation::regclass AS relation, - pg_stat_activity.waiting + {pg_stat_activity}.waiting FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.transactionid = blocked.transactionid AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.pid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.pid) WHERE blocking.granted AND NOT blocked.granted @@ -51,22 +51,22 @@ SELECT -- VirtualXid Lock SELECT blocking.pid, - pg_stat_activity.application_name, - pg_stat_activity.query, + {pg_stat_activity}.application_name, + {pg_stat_activity}.query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, - pg_stat_activity.state as state, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, + {pg_stat_activity}.state as state, blocking.relation::regclass AS relation, - pg_stat_activity.waiting + {pg_stat_activity}.waiting FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.virtualxid = blocked.virtualxid AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.pid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.pid) WHERE blocking.granted AND NOT blocked.granted @@ -81,22 +81,22 @@ SELECT -- Relation or tuple Lock SELECT blocking.pid, - pg_stat_activity.application_name, - pg_stat_activity.query, + {pg_stat_activity}.application_name, + {pg_stat_activity}.query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, - pg_stat_activity.state as state, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, + {pg_stat_activity}.state as state, blocking.relation::regclass AS relation, - pg_stat_activity.waiting + {pg_stat_activity}.waiting FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.database = blocked.database AND blocking.relation = blocked.relation AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.pid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.pid) WHERE blocking.granted AND NOT blocked.granted diff --git a/pgactivity/queries/get_blocking_post_090600.sql b/pgactivity/queries/get_blocking_post_090600.sql index 1d82b131..944e9b26 100644 --- a/pgactivity/queries/get_blocking_post_090600.sql +++ b/pgactivity/queries/get_blocking_post_090600.sql @@ -19,22 +19,22 @@ SELECT -- Transaction id lock SELECT blocking.pid, - pg_stat_activity.application_name, - pg_stat_activity.query, + {pg_stat_activity}.application_name, + {pg_stat_activity}.query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, - pg_stat_activity.state as state, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, + {pg_stat_activity}.state as state, blocking.relation::regclass AS relation, - pg_stat_activity.wait_event + {pg_stat_activity}.wait_event FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.transactionid = blocked.transactionid AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.pid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.pid) WHERE blocking.granted AND NOT blocked.granted @@ -49,22 +49,22 @@ SELECT -- VirtualXid Lock SELECT blocking.pid, - pg_stat_activity.application_name, - pg_stat_activity.query, + {pg_stat_activity}.application_name, + {pg_stat_activity}.query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, - pg_stat_activity.state as state, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, + {pg_stat_activity}.state as state, blocking.relation::regclass AS relation, - pg_stat_activity.wait_event + {pg_stat_activity}.wait_event FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.virtualxid = blocked.virtualxid AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.pid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.pid) WHERE blocking.granted AND NOT blocked.granted @@ -79,22 +79,22 @@ SELECT -- Relation or tuple Lock SELECT blocking.pid, - pg_stat_activity.application_name, - pg_stat_activity.query, + {pg_stat_activity}.application_name, + {pg_stat_activity}.query, blocking.mode, - pg_stat_activity.datname, - pg_stat_activity.datid, - pg_stat_activity.usename, - pg_stat_activity.client_addr AS client, + {pg_stat_activity}.datname, + {pg_stat_activity}.datid, + {pg_stat_activity}.usename, + {pg_stat_activity}.client_addr AS client, blocking.locktype, - EXTRACT(epoch FROM (NOW() - pg_stat_activity.{duration_column})) AS duration, - pg_stat_activity.state as state, + EXTRACT(epoch FROM (NOW() - {pg_stat_activity}.{duration_column})) AS duration, + {pg_stat_activity}.state as state, blocking.relation::regclass AS relation, - pg_stat_activity.wait_event + {pg_stat_activity}.wait_event FROM pg_locks AS blocking JOIN pg_locks AS blocked ON (blocking.database = blocked.database AND blocking.relation = blocked.relation AND blocking.locktype = blocked.locktype) - JOIN pg_stat_activity ON (blocking.pid = pg_stat_activity.pid) + JOIN {pg_stat_activity} ON (blocking.pid = {pg_stat_activity}.pid) WHERE blocking.granted AND NOT blocked.granted diff --git a/pgactivity/queries/get_pg_activity_oldest.sql b/pgactivity/queries/get_pg_activity_oldest.sql index e635f1d7..9a4bd8c6 100644 --- a/pgactivity/queries/get_pg_activity_oldest.sql +++ b/pgactivity/queries/get_pg_activity_oldest.sql @@ -21,7 +21,7 @@ SELECT NULL AS query_leader_pid, false AS is_parallel_worker FROM - pg_stat_activity a + {pg_stat_activity} a LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE current_query <> '' diff --git a/pgactivity/queries/get_pg_activity_post_090200.sql b/pgactivity/queries/get_pg_activity_post_090200.sql index 857b5005..380dc747 100644 --- a/pgactivity/queries/get_pg_activity_post_090200.sql +++ b/pgactivity/queries/get_pg_activity_post_090200.sql @@ -15,7 +15,7 @@ SELECT NULL AS query_leader_pid, false AS is_parallel_worker FROM - pg_stat_activity a + {pg_stat_activity} a LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE state <> 'idle' diff --git a/pgactivity/queries/get_pg_activity_post_090600.sql b/pgactivity/queries/get_pg_activity_post_090600.sql index 60c6d1e9..0296debb 100644 --- a/pgactivity/queries/get_pg_activity_post_090600.sql +++ b/pgactivity/queries/get_pg_activity_post_090600.sql @@ -15,7 +15,7 @@ SELECT NULL AS query_leader_pid, false AS is_parallel_worker FROM - pg_stat_activity a + {pg_stat_activity} a LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE state <> 'idle' diff --git a/pgactivity/queries/get_pg_activity_post_100000.sql b/pgactivity/queries/get_pg_activity_post_100000.sql index 28261cc7..3f9780ca 100644 --- a/pgactivity/queries/get_pg_activity_post_100000.sql +++ b/pgactivity/queries/get_pg_activity_post_100000.sql @@ -17,7 +17,7 @@ SELECT AND a.query IS NOT NULL ) AS is_parallel_worker FROM - pg_stat_activity a + {pg_stat_activity} a LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE state <> 'idle' diff --git a/pgactivity/queries/get_pg_activity_post_110000.sql b/pgactivity/queries/get_pg_activity_post_110000.sql index e5685c05..4bd17f5c 100644 --- a/pgactivity/queries/get_pg_activity_post_110000.sql +++ b/pgactivity/queries/get_pg_activity_post_110000.sql @@ -14,7 +14,7 @@ SELECT NULL AS query_leader_pid, a.backend_type = 'parallel worker' AS is_parallel_worker FROM - pg_stat_activity a + {pg_stat_activity} a LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE a.state <> 'idle' diff --git a/pgactivity/queries/get_pg_activity_post_130000.sql b/pgactivity/queries/get_pg_activity_post_130000.sql index 18c991d2..b69e5aa8 100644 --- a/pgactivity/queries/get_pg_activity_post_130000.sql +++ b/pgactivity/queries/get_pg_activity_post_130000.sql @@ -14,7 +14,7 @@ SELECT coalesce(a.leader_pid, a.pid) AS query_leader_pid, a.backend_type = 'parallel worker' AS is_parallel_worker FROM - pg_stat_activity a + {pg_stat_activity} a LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE a.state <> 'idle' diff --git a/pgactivity/queries/get_server_info_oldest.sql b/pgactivity/queries/get_server_info_oldest.sql index 439f56b2..dc461a08 100644 --- a/pgactivity/queries/get_server_info_oldest.sql +++ b/pgactivity/queries/get_server_info_oldest.sql @@ -39,7 +39,7 @@ WITH dbinfo AS( NULL AS max_worker_processes, NULL AS max_wal_senders, NULL AS max_replication_slots - FROM pg_stat_activity + FROM {pg_stat_activity} WHERE CASE WHEN {dbname_filter} IS NULL THEN true ELSE datname ~* %(dbname_filter)s END diff --git a/pgactivity/queries/get_server_info_post_090100.sql b/pgactivity/queries/get_server_info_post_090100.sql index ecda4135..bdb62d3a 100644 --- a/pgactivity/queries/get_server_info_post_090100.sql +++ b/pgactivity/queries/get_server_info_post_090100.sql @@ -40,7 +40,7 @@ WITH dbinfo AS( NULL AS max_worker_processes, current_setting('max_wal_senders')::int AS max_wal_senders, NULL AS max_replication_slots - FROM pg_stat_activity + FROM {pg_stat_activity} WHERE CASE WHEN {dbname_filter} IS NULL THEN true ELSE datname ~* %(dbname_filter)s END diff --git a/pgactivity/queries/get_server_info_post_090200.sql b/pgactivity/queries/get_server_info_post_090200.sql index 451cf9f0..ebe7853a 100644 --- a/pgactivity/queries/get_server_info_post_090200.sql +++ b/pgactivity/queries/get_server_info_post_090200.sql @@ -40,7 +40,7 @@ WITH dbinfo AS( NULL AS max_worker_processes, current_setting('max_wal_senders')::int AS max_wal_senders, NULL AS max_replication_slots - FROM pg_stat_activity + FROM {pg_stat_activity} WHERE CASE WHEN {dbname_filter} IS NULL THEN true ELSE datname ~* %(dbname_filter)s END diff --git a/pgactivity/queries/get_server_info_post_090600.sql b/pgactivity/queries/get_server_info_post_090600.sql index 4fc7dc4b..bb7af741 100644 --- a/pgactivity/queries/get_server_info_post_090600.sql +++ b/pgactivity/queries/get_server_info_post_090600.sql @@ -41,7 +41,7 @@ WITH dbinfo AS( current_setting('max_worker_processes')::int AS max_worker_processes, current_setting('max_wal_senders')::int AS max_wal_senders, current_setting('max_replication_slots')::int AS max_replication_slots - FROM pg_stat_activity + FROM {pg_stat_activity} WHERE CASE WHEN {dbname_filter} IS NULL THEN true ELSE datname ~* %(dbname_filter)s END diff --git a/pgactivity/queries/get_server_info_post_100000.sql b/pgactivity/queries/get_server_info_post_100000.sql index 541d55c4..f4dfc5dc 100644 --- a/pgactivity/queries/get_server_info_post_100000.sql +++ b/pgactivity/queries/get_server_info_post_100000.sql @@ -42,7 +42,7 @@ WITH dbinfo AS( current_setting('max_worker_processes')::int AS max_worker_processes, current_setting('max_wal_senders')::int AS max_wal_senders, current_setting('max_replication_slots')::int AS max_replication_slots - FROM pg_stat_activity + FROM {pg_stat_activity} WHERE CASE WHEN {dbname_filter} IS NULL THEN true ELSE datname ~* %(dbname_filter)s END diff --git a/pgactivity/queries/get_server_info_post_110000.sql b/pgactivity/queries/get_server_info_post_110000.sql index 6b59ec19..c557cb29 100644 --- a/pgactivity/queries/get_server_info_post_110000.sql +++ b/pgactivity/queries/get_server_info_post_110000.sql @@ -40,7 +40,7 @@ WITH dbinfo AS( current_setting('max_worker_processes')::int AS max_worker_processes, current_setting('max_wal_senders')::int AS max_wal_senders, current_setting('max_replication_slots')::int AS max_replication_slots - FROM pg_stat_activity + FROM {pg_stat_activity} WHERE CASE WHEN {dbname_filter} IS NULL THEN true ELSE datname ~* %(dbname_filter)s END diff --git a/pgactivity/queries/get_waiting_oldest.sql b/pgactivity/queries/get_waiting_oldest.sql index 4ff98d92..489e5c1d 100644 --- a/pgactivity/queries/get_waiting_oldest.sql +++ b/pgactivity/queries/get_waiting_oldest.sql @@ -22,7 +22,7 @@ SELECT pg_catalog.pg_encoding_to_char(b.encoding) AS encoding FROM pg_catalog.pg_locks - JOIN pg_catalog.pg_stat_activity a ON (pg_catalog.pg_locks.pid = a.procpid) + JOIN {pg_stat_activity} a ON (pg_catalog.pg_locks.pid = a.procpid) LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE NOT pg_catalog.pg_locks.granted diff --git a/pgactivity/queries/get_waiting_post_090200.sql b/pgactivity/queries/get_waiting_post_090200.sql index b77c8790..310cd29d 100644 --- a/pgactivity/queries/get_waiting_post_090200.sql +++ b/pgactivity/queries/get_waiting_post_090200.sql @@ -17,7 +17,7 @@ SELECT pg_catalog.pg_encoding_to_char(b.encoding) AS encoding FROM pg_catalog.pg_locks - JOIN pg_catalog.pg_stat_activity a ON(pg_catalog.pg_locks.pid = a.pid) + JOIN {pg_stat_activity} a ON(pg_catalog.pg_locks.pid = a.pid) LEFT OUTER JOIN pg_database b ON a.datid = b.oid WHERE NOT pg_catalog.pg_locks.granted diff --git a/pgactivity/types.py b/pgactivity/types.py index 28119057..bfbc49c6 100644 --- a/pgactivity/types.py +++ b/pgactivity/types.py @@ -4,7 +4,7 @@ import functools from datetime import timedelta from ipaddress import IPv4Address, IPv6Address -from typing import Any, Tuple, TypeVar, Union, overload +from typing import Any, ClassVar, Tuple, TypeVar, Union, overload import attr import psutil @@ -212,7 +212,7 @@ def make(cls, config: HeaderSection | None, **options: bool | None) -> UIHeader: values.update({k: v for k, v in options.items() if v is not None}) return cls(**values) - def toggle_system(self) -> None: + def toggle_system(self) -> str | None: """Toggle the 'show_system' attribute. >>> h = UIHeader() @@ -226,8 +226,9 @@ def toggle_system(self) -> None: True """ self.show_system = not self.show_system + return None - def toggle_instance(self) -> None: + def toggle_instance(self) -> str | None: """Toggle the 'show_instance' attribute. >>> h = UIHeader() @@ -241,8 +242,9 @@ def toggle_instance(self) -> None: True """ self.show_instance = not self.show_instance + return None - def toggle_workers(self) -> None: + def toggle_workers(self) -> str | None: """Toggle the 'show_workers' attribute. >>> h = UIHeader() @@ -256,6 +258,34 @@ def toggle_workers(self) -> None: True """ self.show_workers = not self.show_workers + return None + + +@attr.s(auto_attribs=True, slots=True) +class DisabledUIHeader(UIHeader): + """Disable UI header. + + >>> h = DisabledUIHeader() + >>> h.show_instance + False + >>> h.toggle_workers() + 'header is disabled globally' + """ + + show_instance: bool = attr.ib(init=False, default=False) + show_system: bool = attr.ib(init=False, default=False) + show_workers: bool = attr.ib(init=False, default=False) + + _disabled_msg: ClassVar[str] = "header is disabled globally" + + def toggle_system(self) -> str: + return self._disabled_msg + + def toggle_instance(self) -> str: + return self._disabled_msg + + def toggle_workers(self) -> str: + return self._disabled_msg @attr.s(auto_attribs=True, slots=True) diff --git a/pgactivity/ui.py b/pgactivity/ui.py index 520926a0..32fdf783 100644 --- a/pgactivity/ui.py +++ b/pgactivity/ui.py @@ -39,13 +39,20 @@ def main( ) flag = Flag.load(config, is_local=is_local, **vars(options)) - ui = types.UI.make( - header=types.UIHeader.make( + + header: types.UIHeader + if options.citus: + header = types.DisabledUIHeader() + else: + header = types.UIHeader.make( config.header() if config else None, show_instance=options.header_show_instance, show_system=options.header_show_system, show_workers=options.header_show_workers, - ), + ) + + ui = types.UI.make( + header=header, config=config, flag=flag, refresh_time=options.refresh, @@ -104,11 +111,17 @@ def main( pg_procs.reset() ui.end_interactive() elif keys.is_toggle_header_system(key): - ui.header.toggle_system() + msg = ui.header.toggle_system() + if msg is not None: + msg_pile.send(msg) elif keys.is_toggle_header_instance(key): - ui.header.toggle_instance() + msg = ui.header.toggle_instance() + if msg is not None: + msg_pile.send(msg) elif keys.is_toggle_header_workers(key): - ui.header.toggle_workers() + msg = ui.header.toggle_workers() + if msg is not None: + msg_pile.send(msg) elif pg_procs.selected and key in ( keys.PROCESS_CANCEL, keys.PROCESS_KILL, diff --git a/tests/test_cli.py b/tests/test_cli.py index 4de9ccee..657ae6e5 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8,12 +8,13 @@ def test_parser() -> None: parser = cli.get_parser() ns = parser.parse_args( - ["--no-db-size", "-w", "-p", "5433", "--no-pid", "--no-app-name"] + ["--no-db-size", "-w", "-p", "5433", "--no-pid", "--no-app-name", "--citus"] ) assert vars(ns) == { "profile": None, "blocksize": 4096, "rds": False, + "citus": True, "output": None, "dbsize": False, "tempfiles": None, diff --git a/tests/test_cli_help.txt b/tests/test_cli_help.txt index 1a750392..270fd944 100644 --- a/tests/test_cli_help.txt +++ b/tests/test_cli_help.txt @@ -23,6 +23,7 @@ Options: --rds Enable support for AWS RDS (implies --no-tempfiles and filters out the rdsadmin database from space calculation). + --citus Enable support for Citus. --output FILEPATH Store running queries as CSV. --db-size, --no-db-size Enable/disable total size of DB. diff --git a/tests/test_cli_help_py38.txt b/tests/test_cli_help_py38.txt index 48a3c46e..ea71bab3 100644 --- a/tests/test_cli_help_py38.txt +++ b/tests/test_cli_help_py38.txt @@ -23,6 +23,7 @@ Options: --rds Enable support for AWS RDS (implies --no-tempfiles and filters out the rdsadmin database from space calculation). + --citus Enable support for Citus. --output FILEPATH Store running queries as CSV. --no-db-size Disable total size of DB. --no-tempfiles Disable tempfile count and size. diff --git a/tests/test_ui.txt b/tests/test_ui.txt index c5cfa79a..21d418ed 100644 --- a/tests/test_ui.txt +++ b/tests/test_ui.txt @@ -44,6 +44,7 @@ Default CLI options, passed to ui.main(): ... "output": None, ... "port": f"{postgres.info.port}", ... "rds": False, +... "citus": False, ... "username": f"{postgres.info.user}", ... "wrap_query": False, ... "header_show_instance": True,