Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow setting status code and description at the end of background spans #197 #201

Merged
merged 3 commits into from
May 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion data_for_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,17 @@ var suites = []FixtureSuite{
SpanCount: 1,
EventCount: 1,
},
// this validates options sent to otel-cli span end
CheckFuncs: []CheckFunc{
func(t *testing.T, f Fixture, r Results) {
if r.Span.StatusCode != 2 {
t.Errorf("expected 2 for span status code, but got %d", r.Span.StatusCode)
}
if r.Span.StatusDescription != "I can't do that Dave." {
t.Errorf("got wrong string for status description: %q", r.Span.StatusDescription)
}
},
},
},
{
Name: "otel-cli span event",
Expand All @@ -597,7 +608,13 @@ var suites = []FixtureSuite{
{
Name: "otel-cli span end",
Config: FixtureConfig{
CliArgs: []string{"span", "end", "--sockdir", "."},
CliArgs: []string{
"span", "end",
"--sockdir", ".",
// these are validated by checkfuncs defined above ^^
"--status-code", "error",
"--status-description", "I can't do that Dave.",
},
},
Expect: Results{Config: otelcli.DefaultConfig()},
},
Expand Down
16 changes: 11 additions & 5 deletions otelcli/protobuf_span.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,21 @@ func NewProtobufSpanWithConfig(c Config) tracepb.Span {
span.SpanId = emptySpanId
}

// Only set status description when an error status.
// https://github.com/open-telemetry/opentelemetry-specification/blob/480a19d702470563d32a870932be5ddae798079c/specification/trace/api.md#set-status
SetSpanStatus(&span, c)

return span
}

// SetSpanStatus checks for status code error in the config and sets the
// span's 2 values as appropriate.
// Only set status description when an error status.
// https://github.com/open-telemetry/opentelemetry-specification/blob/480a19d702470563d32a870932be5ddae798079c/specification/trace/api.md#set-status
func SetSpanStatus(span *tracepb.Span, c Config) {
statusCode := SpanStatusStringToInt(c.StatusCode)
if statusCode == tracepb.Status_STATUS_CODE_ERROR {
if statusCode != tracepb.Status_STATUS_CODE_UNSET {
span.Status.Code = statusCode
span.Status.Message = c.StatusDescription
}

return span
}

// generateTraceId generates a random 16 byte trace id
Expand Down
7 changes: 7 additions & 0 deletions otelcli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ func addSpanParams(cmd *cobra.Command) {
cmd.Flags().StringVarP(&config.ServiceName, "service", "s", defaults.ServiceName, "set the name of the application sent on the traces")
// --kind / -k
cmd.Flags().StringVarP(&config.Kind, "kind", "k", defaults.Kind, "set the trace kind, e.g. internal, server, client, producer, consumer")

addSpanStatusParams(cmd)
}

func addSpanStatusParams(cmd *cobra.Command) {
defaults := DefaultConfig()

// --status-code / -sc
cmd.Flags().StringVar(&config.StatusCode, "status-code", defaults.StatusCode, "set the span status code, e.g. unset|ok|error")
// --status-description / -sd
Expand Down
2 changes: 1 addition & 1 deletion otelcli/span_background.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func doSpanBackground(cmd *cobra.Command, args []string) {
// propagation before the server starts, instead of after
propagateTraceparent(span, os.Stdout)

bgs := createBgServer(spanBgSockfile(), span)
bgs := createBgServer(spanBgSockfile(), &span)

// set up signal handlers to cleanly exit on SIGINT/SIGTERM etc
signals := make(chan os.Signal)
Expand Down
15 changes: 10 additions & 5 deletions otelcli/span_background_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ type BgSpanEvent struct {
}

// BgEnd is an empty struct that can be sent to call End().
type BgEnd struct{}
type BgEnd struct {
StatusCode string `json:"status_code"`
StatusDesc string `json:"status_description"`
}

// AddEvent takes a BgSpanEvent from the client and attaches an event to the span.
func (bs BgSpan) AddEvent(bse *BgSpanEvent, reply *BgSpan) error {
Expand Down Expand Up @@ -63,8 +66,10 @@ func (bs BgSpan) Wait(in, reply *struct{}) error {
// End takes a BgEnd (empty) struct, replies with the usual trace info, then
// ends the span end exits the background process.
func (bs BgSpan) End(in *BgEnd, reply *BgSpan) error {
// TODO: maybe accept an end timestamp?
//endSpan(bs.span)
// handle --status-code and --status-description args to span end
c := config.WithStatusCode(in.StatusCode).WithStatusDescription(in.StatusDesc)
SetSpanStatus(bs.span, c)

// running the shutdown as a goroutine prevents the client from getting an
// error here when the server gets closed. defer didn't do the trick.
go bs.shutdown()
Expand All @@ -81,7 +86,7 @@ type bgServer struct {

// createBgServer opens a new span background server on a unix socket and
// returns with the server ready to go. Not expected to block.
func createBgServer(sockfile string, span tracepb.Span) *bgServer {
func createBgServer(sockfile string, span *tracepb.Span) *bgServer {
var err error

bgs := bgServer{
Expand All @@ -97,7 +102,7 @@ func createBgServer(sockfile string, span tracepb.Span) *bgServer {
bgspan := BgSpan{
TraceID: hex.EncodeToString(span.TraceId),
SpanID: hex.EncodeToString(span.SpanId),
span: &span,
span: span,
shutdown: func() { bgs.Shutdown() },
}
// makes methods on BgSpan available over RPC
Expand Down
10 changes: 9 additions & 1 deletion otelcli/span_end.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ func init() {
//spanEndCmd.Flags().StringVar(&config.Timeout, "timeout", defaults.Timeout, "timeout for otel-cli operations, all timeouts in otel-cli use this value")
spanEndCmd.Flags().StringVar(&config.BackgroundSockdir, "sockdir", defaults.BackgroundSockdir, "a directory where a socket can be placed safely")
spanEndCmd.MarkFlagRequired("sockdir")

spanEndCmd.Flags().StringVar(&config.SpanEndTime, "end", defaults.SpanEndTime, "an Unix epoch or RFC3339 timestamp for the end of the span")

addSpanStatusParams(spanEndCmd)
}

func doSpanEnd(cmd *cobra.Command, args []string) {
client, shutdown := createBgClient()

rpcArgs := BgEnd{}
rpcArgs := BgEnd{
StatusCode: config.StatusCode,
StatusDesc: config.StatusDescription,
}

res := BgSpan{}
err := client.Call("BgSpan.End", rpcArgs, &res)
if err != nil {
Expand Down
6 changes: 6 additions & 0 deletions otlpserver/clievent.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type CliEvent struct {
ElapsedMs int64 `json:"elapsed_ms"`
Attributes map[string]string `json:"attributes"`
ServiceAttributes map[string]string `json:"service_attributes"`
StatusCode int32
StatusDescription string
// for a span this is the start nanos, for an event it's just the timestamp
// mostly here for sorting CliEventList but could be any uint64
Nanos uint64 `json:"nanos"`
Expand Down Expand Up @@ -62,6 +64,8 @@ func (ce CliEvent) ToStringMap() map[string]string {
"end": etime,
"attributes": mapToKVString(ce.Attributes),
"service_attributes": mapToKVString(ce.ServiceAttributes),
"status_code": strconv.FormatInt(int64(ce.StatusCode), 10),
"status_description": ce.StatusDescription,
"is_populated": strconv.FormatBool(ce.IsPopulated),
"server_meta": mapToKVString(ce.ServerMeta),
}
Expand All @@ -88,6 +92,8 @@ func NewCliEventFromSpan(span *v1.Span, scopeSpans *v1.ScopeSpans, rss *v1.Resou
Attributes: make(map[string]string),
ServiceAttributes: make(map[string]string),
Nanos: span.GetStartTimeUnixNano(),
StatusCode: int32(span.GetStatus().Code),
StatusDescription: span.GetStatus().Message,
IsPopulated: true,
ServerMeta: make(map[string]string),
}
Expand Down