diff --git a/pkg/apiserver/slowquery/model.go b/pkg/apiserver/slowquery/model.go index ff35921766..4ee7704a6d 100644 --- a/pkg/apiserver/slowquery/model.go +++ b/pkg/apiserver/slowquery/model.go @@ -55,8 +55,9 @@ type Model struct { PlanFromBinding int `gorm:"column:Plan_from_binding" json:"plan_from_binding"` // Connection - User string `gorm:"column:User" json:"user"` - Host string `gorm:"column:Host" json:"host"` + User string `gorm:"column:User" json:"user"` + Host string `gorm:"column:Host" json:"host"` + SessionConnectAttrs *string `gorm:"column:Session_connect_attrs" json:"session_connect_attrs"` // Time ProcessTime float64 `gorm:"column:Process_time" json:"process_time"` diff --git a/tests/fixtures/CLUSTER_SLOW_QUERY.yml b/tests/fixtures/CLUSTER_SLOW_QUERY.yml index 29594a8847..499447acc3 100644 --- a/tests/fixtures/CLUSTER_SLOW_QUERY.yml +++ b/tests/fixtures/CLUSTER_SLOW_QUERY.yml @@ -5,6 +5,7 @@ User: "1" Host: "1" Conn_ID: 1 + Session_connect_attrs: '{"_client_name":"Go-MySQL-Driver","_os":"linux","app_name":"test_app"}' Exec_retry_count: 1 Exec_retry_time: 1 Query_time: 0.462883101 @@ -78,6 +79,7 @@ User: root Host: 127.0.0.1 Conn_ID: 7 + Session_connect_attrs: '{"_client_name":"Go-MySQL-Driver","_os":"linux","app_name":"test_app"}' Exec_retry_count: 0 Exec_retry_time: 0 Query_time: 6.3039e-05 diff --git a/tests/integration/slowquery/mock_db_test.go b/tests/integration/slowquery/mock_db_test.go index 85117809d3..cb818b59fa 100644 --- a/tests/integration/slowquery/mock_db_test.go +++ b/tests/integration/slowquery/mock_db_test.go @@ -60,6 +60,17 @@ func (s *testMockDBSuite) mockDBSession() *gorm.DB { return s.db.Gorm().Debug().Table(TestSlowQueryTableName) } +func (s *testMockDBSuite) supportsSessionConnectAttrs() bool { + cls, err := slowquery.GetAvailableFields(s.sysSchema, s.db.Gorm().Debug().Table(slowquery.SlowQueryTable)) + s.Require().NoError(err) + for _, cl := range cls { + if cl == "session_connect_attrs" { + return true + } + } + return false +} + func (s *testMockDBSuite) TestGetListDefaultRequest() { ds := s.mustQuerySlowLogList(&slowquery.GetListRequest{}) @@ -114,6 +125,12 @@ func (s *testMockDBSuite) TestGetListAllFieldsRequest() { s.Require().NotEmpty(d.Digest) s.Require().NotEmpty(d.GetCommitTSTime) s.Require().NotEmpty(d.Host) + if s.supportsSessionConnectAttrs() { + s.Require().NotNil(d.SessionConnectAttrs) + s.Require().JSONEq(`{"_client_name":"Go-MySQL-Driver","_os":"linux","app_name":"test_app"}`, *d.SessionConnectAttrs) + } else { + s.Require().Nil(d.SessionConnectAttrs) + } s.Require().NotEmpty(d.IndexNames) s.Require().NotEmpty(d.Instance) s.Require().NotEmpty(d.IsInternal) @@ -142,6 +159,16 @@ func (s *testMockDBSuite) TestGetListAllFieldsRequest() { s.Require().NotEmpty(d.WriteSize) } +func (s *testMockDBSuite) TestGetAvailableFields() { + cls, err := slowquery.GetAvailableFields(s.sysSchema, s.mockDBSession()) + s.Require().NoError(err) + if s.supportsSessionConnectAttrs() { + s.Require().Contains(cls, "session_connect_attrs") + } else { + s.Require().NotContains(cls, "session_connect_attrs") + } +} + func (s *testMockDBSuite) TestGetListTimeRangeRequest() { // 1639928730 - 2021-12-19T23:45:30+08:00 // 1639928987 - 2021-12-19T23:49:48+08:00 @@ -282,4 +309,18 @@ func (s *testMockDBSuite) TestGetDetailRequest() { s.Require().Equal(ds2.Timestamp, 1639928987.802016) s.Require().Equal(ds2.Digest, "2375da6810d9c5a0d1c84875b1376bfd469ad952c1884f5dc1d6f36fc953b5df") s.Require().Equal(ds2.ConnectionID, "7") + if s.supportsSessionConnectAttrs() { + s.Require().Nil(ds2.SessionConnectAttrs) + ds3, err := s.mustQuerySlowLogDetail(&slowquery.GetDetailRequest{ + Digest: "TEST_ALL_FIELDS", + Timestamp: 1639928730.786521, + ConnectID: "1", + }) + s.Require().Nil(err) + s.Require().NotNil(ds3) + s.Require().NotNil(ds3.SessionConnectAttrs) + s.Require().JSONEq(`{"_client_name":"Go-MySQL-Driver","_os":"linux","app_name":"test_app"}`, *ds3.SessionConnectAttrs) + } else { + s.Require().Nil(ds2.SessionConnectAttrs) + } } diff --git a/tests/schema/test.CLUSTER_SLOW_QUERY-schema.sql b/tests/schema/test.CLUSTER_SLOW_QUERY-schema.sql index 86fa6159b5..7ef5ac6fa0 100644 --- a/tests/schema/test.CLUSTER_SLOW_QUERY-schema.sql +++ b/tests/schema/test.CLUSTER_SLOW_QUERY-schema.sql @@ -1,3 +1,3 @@ /*!40101 SET NAMES binary*/; /*T![placement] SET PLACEMENT_CHECKS = 0*/; -CREATE TABLE `CLUSTER_SLOW_QUERY` (`INSTANCE` varchar(64) DEFAULT NULL, `Time` timestamp(6) NOT NULL, `Txn_start_ts` bigint(20) unsigned DEFAULT NULL, `User` varchar(64) DEFAULT NULL, `Host` varchar(64) DEFAULT NULL, `Conn_ID` bigint(20) unsigned DEFAULT NULL, `Session_alias` varchar(64) DEFAULT NULL, `Exec_retry_count` bigint(20) unsigned DEFAULT NULL, `Exec_retry_time` double DEFAULT NULL, `Query_time` double DEFAULT NULL, `Parse_time` double DEFAULT NULL, `Compile_time` double DEFAULT NULL, `Rewrite_time` double DEFAULT NULL, `Preproc_subqueries` bigint(20) unsigned DEFAULT NULL, `Preproc_subqueries_time` double DEFAULT NULL, `Optimize_time` double DEFAULT NULL, `Wait_TS` double DEFAULT NULL, `Prewrite_time` double DEFAULT NULL, `Wait_prewrite_binlog_time` double DEFAULT NULL, `Commit_time` double DEFAULT NULL, `Get_commit_ts_time` double DEFAULT NULL, `Commit_backoff_time` double DEFAULT NULL, `Backoff_types` varchar(64) DEFAULT NULL, `Resolve_lock_time` double DEFAULT NULL, `Local_latch_wait_time` double DEFAULT NULL, `Write_keys` bigint(22) DEFAULT NULL, `Write_size` bigint(22) DEFAULT NULL, `Prewrite_region` bigint(22) DEFAULT NULL, `Txn_retry` bigint(22) DEFAULT NULL, `Cop_time` double DEFAULT NULL, `Process_time` double DEFAULT NULL, `Wait_time` double DEFAULT NULL, `Backoff_time` double DEFAULT NULL, `LockKeys_time` double DEFAULT NULL, `Request_count` bigint(20) unsigned DEFAULT NULL, `Total_keys` bigint(20) unsigned DEFAULT NULL, `Process_keys` bigint(20) unsigned DEFAULT NULL, `Rocksdb_delete_skipped_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_key_skipped_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_block_cache_hit_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_block_read_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_block_read_byte` bigint(20) unsigned DEFAULT NULL, `DB` varchar(64) DEFAULT NULL, `Index_names` varchar(100) DEFAULT NULL, `Is_internal` tinyint(1) DEFAULT NULL, `Digest` varchar(64) DEFAULT NULL, `Stats` varchar(512) DEFAULT NULL, `Cop_proc_avg` double DEFAULT NULL, `Cop_proc_p90` double DEFAULT NULL, `Cop_proc_max` double DEFAULT NULL, `Cop_proc_addr` varchar(64) DEFAULT NULL, `Cop_wait_avg` double DEFAULT NULL, `Cop_wait_p90` double DEFAULT NULL, `Cop_wait_max` double DEFAULT NULL, `Cop_wait_addr` varchar(64) DEFAULT NULL, `Mem_max` bigint(20) DEFAULT NULL, `Disk_max` bigint(20) DEFAULT NULL, `KV_total` double DEFAULT NULL, `PD_total` double DEFAULT NULL, `Backoff_total` double DEFAULT NULL, `Write_sql_response_total` double DEFAULT NULL, `Result_rows` bigint(22) DEFAULT NULL, `Warnings` longtext DEFAULT NULL, `Backoff_Detail` varchar(4096) DEFAULT NULL, `Prepared` tinyint(1) DEFAULT NULL, `Succ` tinyint(1) DEFAULT NULL, `IsExplicitTxn` tinyint(1) DEFAULT NULL, `IsWriteCacheTable` tinyint(1) DEFAULT NULL, `Plan_from_cache` tinyint(1) DEFAULT NULL, `Plan_from_binding` tinyint(1) DEFAULT NULL, `Has_more_results` tinyint(1) DEFAULT NULL, `Resource_group` varchar(64) DEFAULT NULL, `Request_unit_read` double DEFAULT NULL, `Request_unit_write` double DEFAULT NULL, `Time_queued_by_rc` double DEFAULT NULL, `Plan` longtext DEFAULT NULL, `Plan_digest` varchar(128) DEFAULT NULL, `Binary_plan` longtext DEFAULT NULL, `Prev_stmt` longtext DEFAULT NULL, `Query` longtext DEFAULT NULL, PRIMARY KEY (`Time`) /*T![clustered_index] CLUSTERED */ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; \ No newline at end of file +CREATE TABLE `CLUSTER_SLOW_QUERY` (`INSTANCE` varchar(64) DEFAULT NULL, `Time` timestamp(6) NOT NULL, `Txn_start_ts` bigint(20) unsigned DEFAULT NULL, `User` varchar(64) DEFAULT NULL, `Host` varchar(64) DEFAULT NULL, `Conn_ID` bigint(20) unsigned DEFAULT NULL, `Session_alias` varchar(64) DEFAULT NULL, `Session_connect_attrs` json DEFAULT NULL, `Exec_retry_count` bigint(20) unsigned DEFAULT NULL, `Exec_retry_time` double DEFAULT NULL, `Query_time` double DEFAULT NULL, `Parse_time` double DEFAULT NULL, `Compile_time` double DEFAULT NULL, `Rewrite_time` double DEFAULT NULL, `Preproc_subqueries` bigint(20) unsigned DEFAULT NULL, `Preproc_subqueries_time` double DEFAULT NULL, `Optimize_time` double DEFAULT NULL, `Wait_TS` double DEFAULT NULL, `Prewrite_time` double DEFAULT NULL, `Wait_prewrite_binlog_time` double DEFAULT NULL, `Commit_time` double DEFAULT NULL, `Get_commit_ts_time` double DEFAULT NULL, `Commit_backoff_time` double DEFAULT NULL, `Backoff_types` varchar(64) DEFAULT NULL, `Resolve_lock_time` double DEFAULT NULL, `Local_latch_wait_time` double DEFAULT NULL, `Write_keys` bigint(22) DEFAULT NULL, `Write_size` bigint(22) DEFAULT NULL, `Prewrite_region` bigint(22) DEFAULT NULL, `Txn_retry` bigint(22) DEFAULT NULL, `Cop_time` double DEFAULT NULL, `Process_time` double DEFAULT NULL, `Wait_time` double DEFAULT NULL, `Backoff_time` double DEFAULT NULL, `LockKeys_time` double DEFAULT NULL, `Request_count` bigint(20) unsigned DEFAULT NULL, `Total_keys` bigint(20) unsigned DEFAULT NULL, `Process_keys` bigint(20) unsigned DEFAULT NULL, `Rocksdb_delete_skipped_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_key_skipped_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_block_cache_hit_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_block_read_count` bigint(20) unsigned DEFAULT NULL, `Rocksdb_block_read_byte` bigint(20) unsigned DEFAULT NULL, `DB` varchar(64) DEFAULT NULL, `Index_names` varchar(100) DEFAULT NULL, `Is_internal` tinyint(1) DEFAULT NULL, `Digest` varchar(64) DEFAULT NULL, `Stats` varchar(512) DEFAULT NULL, `Cop_proc_avg` double DEFAULT NULL, `Cop_proc_p90` double DEFAULT NULL, `Cop_proc_max` double DEFAULT NULL, `Cop_proc_addr` varchar(64) DEFAULT NULL, `Cop_wait_avg` double DEFAULT NULL, `Cop_wait_p90` double DEFAULT NULL, `Cop_wait_max` double DEFAULT NULL, `Cop_wait_addr` varchar(64) DEFAULT NULL, `Mem_max` bigint(20) DEFAULT NULL, `Disk_max` bigint(20) DEFAULT NULL, `KV_total` double DEFAULT NULL, `PD_total` double DEFAULT NULL, `Backoff_total` double DEFAULT NULL, `Write_sql_response_total` double DEFAULT NULL, `Result_rows` bigint(22) DEFAULT NULL, `Warnings` longtext DEFAULT NULL, `Backoff_Detail` varchar(4096) DEFAULT NULL, `Prepared` tinyint(1) DEFAULT NULL, `Succ` tinyint(1) DEFAULT NULL, `IsExplicitTxn` tinyint(1) DEFAULT NULL, `IsWriteCacheTable` tinyint(1) DEFAULT NULL, `Plan_from_cache` tinyint(1) DEFAULT NULL, `Plan_from_binding` tinyint(1) DEFAULT NULL, `Has_more_results` tinyint(1) DEFAULT NULL, `Resource_group` varchar(64) DEFAULT NULL, `Request_unit_read` double DEFAULT NULL, `Request_unit_write` double DEFAULT NULL, `Time_queued_by_rc` double DEFAULT NULL, `Plan` longtext DEFAULT NULL, `Plan_digest` varchar(128) DEFAULT NULL, `Binary_plan` longtext DEFAULT NULL, `Prev_stmt` longtext DEFAULT NULL, `Query` longtext DEFAULT NULL, PRIMARY KEY (`Time`) /*T![clustered_index] CLUSTERED */ ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/ui/packages/tidb-dashboard-client/src/client/api/models/slowquery-model.ts b/ui/packages/tidb-dashboard-client/src/client/api/models/slowquery-model.ts index 7f9f418f43..750d9eb2e6 100644 --- a/ui/packages/tidb-dashboard-client/src/client/api/models/slowquery-model.ts +++ b/ui/packages/tidb-dashboard-client/src/client/api/models/slowquery-model.ts @@ -344,6 +344,12 @@ export interface SlowqueryModel { * @memberof SlowqueryModel */ 'ru'?: number; + /** + * + * @type {string} + * @memberof SlowqueryModel + */ + 'session_connect_attrs'?: string; /** * * @type {string} @@ -435,4 +441,3 @@ export interface SlowqueryModel { */ 'write_sql_response_total'?: number; } - diff --git a/ui/packages/tidb-dashboard-client/swagger/spec.json b/ui/packages/tidb-dashboard-client/swagger/spec.json index cae73c2d13..06588698fe 100644 --- a/ui/packages/tidb-dashboard-client/swagger/spec.json +++ b/ui/packages/tidb-dashboard-client/swagger/spec.json @@ -5367,6 +5367,9 @@ "description": "Resource Control", "type": "number" }, + "session_connect_attrs": { + "type": "string" + }, "stats": { "type": "string" }, diff --git a/ui/packages/tidb-dashboard-lib/src/apps/SlowQuery/pages/Detail/DetailTabs.tsx b/ui/packages/tidb-dashboard-lib/src/apps/SlowQuery/pages/Detail/DetailTabs.tsx index 1dc66fc4c3..0a4cbda7f3 100644 --- a/ui/packages/tidb-dashboard-lib/src/apps/SlowQuery/pages/Detail/DetailTabs.tsx +++ b/ui/packages/tidb-dashboard-lib/src/apps/SlowQuery/pages/Detail/DetailTabs.tsx @@ -13,6 +13,17 @@ import { tabTxnItems } from './DetailTabTxn' import { useSchemaColumns } from '../../utils/useSchemaColumns' import { SlowQueryContext } from '../../context' +function parseSessionConnectAttrs(raw?: string | null) { + if (!raw || raw === 'null') { + return null + } + try { + return JSON.parse(raw) + } catch { + return raw + } +} + export default function DetailTabs({ data }: { data: SlowqueryModel }) { const ctx = useContext(SlowQueryContext) @@ -92,7 +103,38 @@ export default function DetailTabs({ data }: { data: SlowqueryModel }) { } } ] - if (data.warnings) { + const hasSessionConnectAttrs = schemaColumns.includes( + 'session_connect_attrs' + ) + const sessionConnectAttrsRaw = hasSessionConnectAttrs + ? data.session_connect_attrs + : null + const sessionConnectAttrs = parseSessionConnectAttrs(sessionConnectAttrsRaw) + if (hasSessionConnectAttrs) { + tbs.push({ + key: 'session_attrs', + title: t('slow_query.detail.tabs.session_attrs'), + content: () => { + if ( + sessionConnectAttrs == null || + typeof sessionConnectAttrs === 'string' + ) { + return
{sessionConnectAttrsRaw ?? 'null'}
+ }
+ return (
+