github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/show_trace.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql 12 13 import ( 14 "context" 15 "fmt" 16 "regexp" 17 "strings" 18 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 20 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 21 "github.com/cockroachdb/cockroach/pkg/util/encoding" 22 ) 23 24 // showTraceNode is a planNode that processes session trace data. 25 type showTraceNode struct { 26 columns sqlbase.ResultColumns 27 compact bool 28 29 // If set, the trace will also include "KV trace" messages - verbose messages 30 // around the interaction of SQL with KV. Some of the messages are per-row. 31 kvTracingEnabled bool 32 33 run traceRun 34 } 35 36 // ShowTrace shows the current stored session trace, or the trace of a given 37 // query. 38 // Privileges: None. 39 func (p *planner) ShowTrace(ctx context.Context, n *tree.ShowTraceForSession) (planNode, error) { 40 var node planNode = p.makeShowTraceNode(n.Compact, n.TraceType == tree.ShowTraceKV) 41 42 // Ensure the messages are sorted in age order, so that the user 43 // does not get confused. 44 ageColIdx := sqlbase.GetTraceAgeColumnIdx(n.Compact) 45 node = &sortNode{ 46 plan: node, 47 ordering: sqlbase.ColumnOrdering{ 48 sqlbase.ColumnOrderInfo{ColIdx: ageColIdx, Direction: encoding.Ascending}, 49 }, 50 } 51 52 if n.TraceType == tree.ShowTraceReplica { 53 node = &showTraceReplicaNode{plan: node} 54 } 55 return node, nil 56 } 57 58 // makeShowTraceNode creates a new showTraceNode. 59 // 60 // Args: 61 // kvTracingEnabled: If set, the trace will also include "KV trace" messages - 62 // verbose messages around the interaction of SQL with KV. Some of the 63 // messages are per-row. 64 func (p *planner) makeShowTraceNode(compact bool, kvTracingEnabled bool) *showTraceNode { 65 n := &showTraceNode{ 66 kvTracingEnabled: kvTracingEnabled, 67 compact: compact, 68 } 69 if compact { 70 // We make a copy here because n.columns can be mutated to rename columns. 71 n.columns = append(n.columns, sqlbase.ShowCompactTraceColumns...) 72 } else { 73 n.columns = append(n.columns, sqlbase.ShowTraceColumns...) 74 } 75 return n 76 } 77 78 // traceRun contains the run-time state of showTraceNode during local execution. 79 type traceRun struct { 80 resultRows []tree.Datums 81 curRow int 82 } 83 84 func (n *showTraceNode) startExec(params runParams) error { 85 // Get all the data upfront and process the traces. Subsequent 86 // invocations of Next() will merely return the results. 87 traceRows, err := params.extendedEvalCtx.Tracing.getSessionTrace() 88 if err != nil { 89 return err 90 } 91 n.processTraceRows(params.EvalContext(), traceRows) 92 return nil 93 } 94 95 // Next implements the planNode interface 96 func (n *showTraceNode) Next(params runParams) (bool, error) { 97 if n.run.curRow >= len(n.run.resultRows) { 98 return false, nil 99 } 100 n.run.curRow++ 101 return true, nil 102 } 103 104 // processTraceRows populates n.resultRows. 105 // This code must be careful not to overwrite traceRows, 106 // because this is a shared slice which will be reused 107 // by subsequent SHOW TRACE FOR SESSION statements. 108 func (n *showTraceNode) processTraceRows(evalCtx *tree.EvalContext, traceRows []traceRow) { 109 // Filter trace rows based on the message (in the SHOW KV TRACE case) 110 if n.kvTracingEnabled { 111 res := make([]traceRow, 0, len(traceRows)) 112 for _, r := range traceRows { 113 msg := r[traceMsgCol].(*tree.DString) 114 if kvMsgRegexp.MatchString(string(*msg)) { 115 res = append(res, r) 116 } 117 } 118 traceRows = res 119 } 120 if len(traceRows) == 0 { 121 return 122 } 123 124 // Render the final rows. 125 n.run.resultRows = make([]tree.Datums, len(traceRows)) 126 for i, r := range traceRows { 127 ts := r[traceTimestampCol].(*tree.DTimestampTZ) 128 loc := r[traceLocCol] 129 tag := r[traceTagCol] 130 msg := r[traceMsgCol] 131 spanIdx := r[traceSpanIdxCol] 132 op := r[traceOpCol] 133 age := r[traceAgeCol] 134 135 if !n.compact { 136 n.run.resultRows[i] = tree.Datums{ts, age, msg, tag, loc, op, spanIdx} 137 } else { 138 msgStr := msg.(*tree.DString) 139 if locStr := string(*loc.(*tree.DString)); locStr != "" { 140 msgStr = tree.NewDString(fmt.Sprintf("%s %s", locStr, string(*msgStr))) 141 } 142 n.run.resultRows[i] = tree.Datums{age, msgStr, tag, op} 143 } 144 } 145 } 146 147 func (n *showTraceNode) Values() tree.Datums { 148 return n.run.resultRows[n.run.curRow-1] 149 } 150 151 func (n *showTraceNode) Close(ctx context.Context) { 152 n.run.resultRows = nil 153 } 154 155 // kvMsgRegexp is the message filter used for SHOW KV TRACE. 156 var kvMsgRegexp = regexp.MustCompile( 157 strings.Join([]string{ 158 "^fetched: ", 159 "^CPut ", 160 "^Put ", 161 "^InitPut ", 162 "^DelRange ", 163 "^ClearRange ", 164 "^Del ", 165 "^Get ", 166 "^Scan ", 167 "^FKScan ", 168 "^CascadeScan ", 169 "^querying next range at ", 170 "^output row: ", 171 "^rows affected: ", 172 "^execution failed after ", 173 "^r.*: sending batch ", 174 "^cascading ", 175 "^fast path completed", 176 }, "|"), 177 )