Skip to content

Commit

Permalink
builtins: add builtin to retrieve the payload(s) for a span.
Browse files Browse the repository at this point in the history
The `crdb_internal.payloads_for_span` builtin retrieves all
payloads for a given span ID, given that the span is part of an
active trace. The payloads are returned in JSONB format. If the
span is not found, or if the span does not have any payloads, the
builtin returns an empty JSON object.

With the appropriate usage of this builtin and the
`crdb_internal.trace_id` builtin as shown in the `contention_event`
logic test, all payloads for the current trace may be surfaced.

Release note (sql change): add `payloads_for_span` builtin that
takes in a span ID and returns its paylods in JSONB format. If
the span is not found, or if the span does not have any payloads,
the builtin returns an empty JSON object.
  • Loading branch information
angelapwen committed Feb 16, 2021
1 parent 421b24f commit f9f0faa
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/generated/sql/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2638,6 +2638,8 @@ SELECT * FROM crdb_internal.check_consistency(true, ‘\x02’, ‘\x04’)</p>
</span></td></tr>
<tr><td><a name="crdb_internal.num_inverted_index_entries"></a><code>crdb_internal.num_inverted_index_entries(val: jsonb, version: <a href="int.html">int</a>) &rarr; <a href="int.html">int</a></code></td><td><span class="funcdesc"><p>This function is used only by CockroachDB’s developers for testing purposes.</p>
</span></td></tr>
<tr><td><a name="crdb_internal.payloads_for_span"></a><code>crdb_internal.payloads_for_span(span ID: <a href="int.html">int</a>) &rarr; jsonb</code></td><td><span class="funcdesc"><p>Returns the payload(s) of the span whose ID is passed in the argument.</p>
</span></td></tr>
<tr><td><a name="crdb_internal.pretty_key"></a><code>crdb_internal.pretty_key(raw_key: <a href="bytes.html">bytes</a>, skip_fields: <a href="int.html">int</a>) &rarr; <a href="string.html">string</a></code></td><td><span class="funcdesc"><p>This function is used only by CockroachDB’s developers for testing purposes.</p>
</span></td></tr>
<tr><td><a name="crdb_internal.range_stats"></a><code>crdb_internal.range_stats(key: <a href="bytes.html">bytes</a>) &rarr; jsonb</code></td><td><span class="funcdesc"><p>This function is used to retrieve range statistics information as a JSON object.</p>
Expand Down
16 changes: 16 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/contention_event
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,23 @@ user root
#
# NB: this needs the 5node-pretend59315 config because otherwise the span is not
# tracked.
#
# TODO(angelapwen): Remove this test along with num_payloads column
query B
SELECT count(num_payloads) > 0 FROM crdb_internal.node_inflight_trace_spans WHERE trace_id = crdb_internal.trace_id();
----
true

# For all spans, make sure there is 1 payload that is a contention event.
query B
WITH Spans AS (
SELECT span_id FROM crdb_internal.node_inflight_trace_spans
WHERE trace_id = crdb_internal.trace_id()
), PayloadTypes AS (
SELECT jsonb_array_elements(crdb_internal.payloads_for_span(span_id))->>'@type' AS type, crdb_internal.payload_for_span(span_id)
FROM Spans
) SELECT COUNT(*) = 1
FROM PayloadTypes
WHERE type = 'type.googleapis.com/cockroach.roachpb.ContentionEvent';
----
true
1 change: 1 addition & 0 deletions pkg/sql/sem/builtins/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ go_library(
"//pkg/util/uuid",
"@com_github_cockroachdb_apd_v2//:apd",
"@com_github_cockroachdb_errors//:errors",
"@com_github_gogo_protobuf//types",
"@com_github_golang_geo//s1",
"@com_github_knz_strtime//:strtime",
"@com_github_lib_pq//oid",
Expand Down
44 changes: 44 additions & 0 deletions pkg/sql/sem/builtins/builtins.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/util/unaccent"
"github.com/cockroachdb/cockroach/pkg/util/uuid"
"github.com/cockroachdb/errors"
pbtypes "github.com/gogo/protobuf/types"
"github.com/knz/strtime"
)

Expand Down Expand Up @@ -3597,6 +3598,49 @@ may increase either contention or retry errors, or both.`,
},
),

"crdb_internal.payloads_for_span": makeBuiltin(
tree.FunctionProperties{Category: categorySystemInfo},
tree.Overload{
Types: tree.ArgTypes{{"span ID", types.Int}},
ReturnType: tree.FixedReturnType(types.Jsonb),
Fn: func(ctx *tree.EvalContext, args tree.Datums) (tree.Datum, error) {
builder := json.NewArrayBuilder(len(args))
var payloads []string
spanID := uint64(*(args[0].(*tree.DInt)))

var payload json.JSON
var err error
// Search all spans of the current trace for the span that matches the builtin's argument.
ctx.Settings.Tracer.VisitSpans(func(span *tracing.Span) error {
// TODO(angelapwen): Once a trace's activeSpans map is keyed on span ID, we can skip the iteration.
for _, rec := range span.GetRecording() {
if spanID == rec.SpanID {
rec.Structured(func(item *pbtypes.Any) {
payload, err = protoreflect.MessageToJSON(item, true /* emitDefaults */)
if err != nil {
return
}
if payload != nil {
builder.Add(payload)
payloads = append(payloads, payload.String())
}
})
// Return as soon as we found the correct span.
return nil
}
}
return nil
})
if builder == nil {
return tree.NewDJSON(nil), nil
}
return tree.NewDJSON(builder.Build()), nil
},
Info: "Returns the payload(s) of the span whose ID is passed in the argument.",
Volatility: tree.VolatilityStable,
},
),

"crdb_internal.locality_value": makeBuiltin(
tree.FunctionProperties{Category: categorySystemInfo},
tree.Overload{
Expand Down
1 change: 1 addition & 0 deletions pkg/util/tracing/tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ type Tracer struct {
// removed on .Finish().
//
// The map can be introspected by `Tracer.VisitSpans`.
// TODO(angelapwen): Key this map on span ID instead of its memory address.
activeSpans struct {
// NB: it might be tempting to use a sync.Map here, but
// this incurs an allocation per Span (sync.Map does
Expand Down

0 comments on commit f9f0faa

Please sign in to comment.