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  )