diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go index a59665450a1..a1185d16fee 100644 --- a/go/vt/vttablet/tabletserver/query_engine.go +++ b/go/vt/vttablet/tabletserver/query_engine.go @@ -27,12 +27,9 @@ import ( "sync/atomic" "time" - "vitess.io/vitess/go/mysql/sqlerror" - vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/acl" "vitess.io/vitess/go/cache" + "vitess.io/vitess/go/mysql/sqlerror" "vitess.io/vitess/go/pools" "vitess.io/vitess/go/stats" "vitess.io/vitess/go/streamlog" @@ -41,9 +38,12 @@ import ( "vitess.io/vitess/go/vt/dbconnpool" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/proto/topodata" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/tableacl" tacl "vitess.io/vitess/go/vt/tableacl/acl" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tabletserver/connpool" "vitess.io/vitess/go/vt/vttablet/tabletserver/planbuilder" "vitess.io/vitess/go/vt/vttablet/tabletserver/rules" @@ -172,7 +172,7 @@ type QueryEngine struct { // stats // Note: queryErrorCountsWithCode is similar to queryErrorCounts except it contains error code as an additional dimension - queryCounts, queryTimes, queryErrorCounts, queryErrorCountsWithCode, queryRowsAffected, queryRowsReturned *stats.CountersWithMultiLabels + queryCounts, queryCountsWithTabletType, queryTimes, queryErrorCounts, queryErrorCountsWithCode, queryRowsAffected, queryRowsReturned *stats.CountersWithMultiLabels // stats flags enablePerWorkloadTableMetrics bool @@ -258,6 +258,7 @@ func NewQueryEngine(env tabletenv.Env, se *schema.Engine) *QueryEngine { } qe.queryCounts = env.Exporter().NewCountersWithMultiLabels("QueryCounts", "query counts", labels) + qe.queryCountsWithTabletType = env.Exporter().NewCountersWithMultiLabels("QueryCountsWithTabletType", "query counts with tablet type labels", []string{"Table", "Plan", "TabletType"}) qe.queryTimes = env.Exporter().NewCountersWithMultiLabels("QueryTimesNs", "query times in ns", labels) qe.queryRowsAffected = env.Exporter().NewCountersWithMultiLabels("QueryRowsAffected", "query rows affected", labels) qe.queryRowsReturned = env.Exporter().NewCountersWithMultiLabels("QueryRowsReturned", "query rows returned", labels) @@ -490,7 +491,7 @@ func (qe *QueryEngine) QueryPlanCacheLen() int { } // AddStats adds the given stats for the planName.tableName -func (qe *QueryEngine) AddStats(planType planbuilder.PlanType, tableName, workload string, queryCount int64, duration, mysqlTime time.Duration, rowsAffected, rowsReturned, errorCount int64, errorCode string) { +func (qe *QueryEngine) AddStats(planType planbuilder.PlanType, tableName, workload string, tabletType topodata.TabletType, queryCount int64, duration, mysqlTime time.Duration, rowsAffected, rowsReturned, errorCount int64, errorCode string) { // table names can contain "." characters, replace them! keys := []string{tableName, planType.String()} // Only use the workload as a label if that's enabled in the configuration. @@ -500,6 +501,9 @@ func (qe *QueryEngine) AddStats(planType planbuilder.PlanType, tableName, worklo qe.queryCounts.Add(keys, queryCount) qe.queryTimes.Add(keys, int64(duration)) qe.queryErrorCounts.Add(keys, errorCount) + + qe.queryCountsWithTabletType.Add([]string{tableName, planType.String(), tabletType.String()}, queryCount) + // queryErrorCountsWithCode is similar to queryErrorCounts except we have an additional dimension // of error code. if errorCount > 0 { diff --git a/go/vt/vttablet/tabletserver/query_engine_test.go b/go/vt/vttablet/tabletserver/query_engine_test.go index 33849c3f5e6..e073b6f8c49 100644 --- a/go/vt/vttablet/tabletserver/query_engine_test.go +++ b/go/vt/vttablet/tabletserver/query_engine_test.go @@ -32,6 +32,8 @@ import ( "testing" "time" + "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/mysql" @@ -577,6 +579,7 @@ func TestAddQueryStats(t *testing.T) { name string planType planbuilder.PlanType tableName string + tabletType topodata.TabletType queryCount int64 duration time.Duration mysqlTime time.Duration @@ -587,6 +590,7 @@ func TestAddQueryStats(t *testing.T) { enablePerWorkloadTableMetrics bool workload string expectedQueryCounts string + expectedQueryCountsWithTableType string expectedQueryTimes string expectedQueryRowsAffected string expectedQueryRowsReturned string @@ -597,6 +601,27 @@ func TestAddQueryStats(t *testing.T) { name: "select query", planType: planbuilder.PlanSelect, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, + queryCount: 1, + duration: 10, + rowsAffected: 0, + rowsReturned: 15, + errorCount: 0, + errorCode: "OK", + enablePerWorkloadTableMetrics: false, + workload: "some-workload", + expectedQueryCounts: `{"A.Select": 1}`, + expectedQueryTimes: `{"A.Select": 10}`, + expectedQueryRowsAffected: `{}`, + expectedQueryRowsReturned: `{"A.Select": 15}`, + expectedQueryErrorCounts: `{"A.Select": 0}`, + expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Select.PRIMARY": 1}`, + }, { + name: "select query against a replica", + planType: planbuilder.PlanSelect, + tableName: "A", + tabletType: topodata.TabletType_REPLICA, queryCount: 1, duration: 10, rowsAffected: 0, @@ -611,10 +636,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{"A.Select": 15}`, expectedQueryErrorCounts: `{"A.Select": 0}`, expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Select.REPLICA": 1}`, }, { name: "select into query", planType: planbuilder.PlanSelect, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 15, @@ -629,10 +656,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{"A.Select": 0}`, expectedQueryErrorCounts: `{"A.Select": 0}`, expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Select.PRIMARY": 1}`, }, { name: "error", planType: planbuilder.PlanSelect, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 0, @@ -647,10 +676,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{"A.Select": 0}`, expectedQueryErrorCounts: `{"A.Select": 1}`, expectedQueryErrorCountsWithCode: `{"A.Select.RESOURCE_EXHAUSTED": 1}`, + expectedQueryCountsWithTableType: `{"A.Select.PRIMARY": 1}`, }, { name: "insert query", planType: planbuilder.PlanInsert, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 15, @@ -665,10 +696,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{}`, expectedQueryErrorCounts: `{"A.Insert": 0}`, expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Insert.PRIMARY": 1}`, }, { name: "select query with per workload metrics", planType: planbuilder.PlanSelect, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 0, @@ -683,10 +716,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{"A.Select.some-workload": 15}`, expectedQueryErrorCounts: `{"A.Select.some-workload": 0}`, expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Select.PRIMARY": 1}`, }, { name: "select into query with per workload metrics", planType: planbuilder.PlanSelect, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 15, @@ -701,10 +736,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{"A.Select.some-workload": 0}`, expectedQueryErrorCounts: `{"A.Select.some-workload": 0}`, expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Select.PRIMARY": 1}`, }, { name: "error with per workload metrics", planType: planbuilder.PlanSelect, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 0, @@ -719,10 +756,12 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{"A.Select.some-workload": 0}`, expectedQueryErrorCounts: `{"A.Select.some-workload": 1}`, expectedQueryErrorCountsWithCode: `{"A.Select.RESOURCE_EXHAUSTED": 1}`, + expectedQueryCountsWithTableType: `{"A.Select.PRIMARY": 1}`, }, { name: "insert query with per workload metrics", planType: planbuilder.PlanInsert, tableName: "A", + tabletType: topodata.TabletType_PRIMARY, queryCount: 1, duration: 10, rowsAffected: 15, @@ -737,6 +776,7 @@ func TestAddQueryStats(t *testing.T) { expectedQueryRowsReturned: `{}`, expectedQueryErrorCounts: `{"A.Insert.some-workload": 0}`, expectedQueryErrorCountsWithCode: `{}`, + expectedQueryCountsWithTableType: `{"A.Insert.PRIMARY": 1}`, }, } @@ -749,8 +789,9 @@ func TestAddQueryStats(t *testing.T) { env := tabletenv.NewEnv(config, "TestAddQueryStats_"+testcase.name) se := schema.NewEngine(env) qe := NewQueryEngine(env, se) - qe.AddStats(testcase.planType, testcase.tableName, testcase.workload, testcase.queryCount, testcase.duration, testcase.mysqlTime, testcase.rowsAffected, testcase.rowsReturned, testcase.errorCount, testcase.errorCode) + qe.AddStats(testcase.planType, testcase.tableName, testcase.workload, testcase.tabletType, testcase.queryCount, testcase.duration, testcase.mysqlTime, testcase.rowsAffected, testcase.rowsReturned, testcase.errorCount, testcase.errorCode) assert.Equal(t, testcase.expectedQueryCounts, qe.queryCounts.String()) + assert.Equal(t, testcase.expectedQueryCountsWithTableType, qe.queryCountsWithTabletType.String()) assert.Equal(t, testcase.expectedQueryTimes, qe.queryTimes.String()) assert.Equal(t, testcase.expectedQueryRowsAffected, qe.queryRowsAffected.String()) assert.Equal(t, testcase.expectedQueryRowsReturned, qe.queryRowsReturned.String()) diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index edd786492e9..c11c811935d 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -136,13 +136,14 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { var errCode string vtErrorCode := vterrors.Code(err) errCode = vtErrorCode.String() + if reply == nil { - qre.tsv.qe.AddStats(qre.plan.PlanID, tableName, qre.options.GetWorkloadName(), 1, duration, mysqlTime, 0, 0, 1, errCode) + qre.tsv.qe.AddStats(qre.plan.PlanID, tableName, qre.options.GetWorkloadName(), qre.tabletType, 1, duration, mysqlTime, 0, 0, 1, errCode) qre.plan.AddStats(1, duration, mysqlTime, 0, 0, 1) return } - qre.tsv.qe.AddStats(qre.plan.PlanID, tableName, qre.options.GetWorkloadName(), 1, duration, mysqlTime, int64(reply.RowsAffected), int64(len(reply.Rows)), 0, errCode) + qre.tsv.qe.AddStats(qre.plan.PlanID, tableName, qre.options.GetWorkloadName(), qre.tabletType, 1, duration, mysqlTime, int64(reply.RowsAffected), int64(len(reply.Rows)), 0, errCode) qre.plan.AddStats(1, duration, mysqlTime, reply.RowsAffected, uint64(len(reply.Rows)), 0) qre.logStats.RowsAffected = int(reply.RowsAffected) qre.logStats.Rows = reply.Rows