diff --git a/modelwriter.go b/modelwriter.go index fd327e099..c6677ba2c 100644 --- a/modelwriter.go +++ b/modelwriter.go @@ -117,6 +117,7 @@ func (w *modelWriter) buildModelTransaction(out *model.Transaction, tx *Transact out.Name = truncateString(td.Name) out.Type = truncateString(td.Type) out.Result = truncateString(td.Result) + out.Outcome = normalizeOutcome(td.Outcome) out.Timestamp = model.Time(td.timestamp.UTC()) out.Duration = td.Duration.Seconds() * 1000 out.SpanCount.Started = td.spansCreated @@ -151,6 +152,7 @@ func (w *modelWriter) buildModelSpan(out *model.Span, span *Span, sd *SpanData) out.Action = truncateString(sd.Action) out.Timestamp = model.Time(sd.timestamp.UTC()) out.Duration = sd.Duration.Seconds() * 1000 + out.Outcome = normalizeOutcome(sd.Outcome) out.Context = sd.Context.build() // Copy the span type to context.destination.service.type. @@ -271,3 +273,12 @@ func (w *modelWriter) setStacktraceContext(stack []model.StacktraceFrame) { w.stats.Errors.SetContext++ } } + +func normalizeOutcome(outcome string) string { + switch outcome { + case "success", "failure", "unknown": + return outcome + default: + return "unknown" + } +} diff --git a/span.go b/span.go index 85b244c1d..c34429c7f 100644 --- a/span.go +++ b/span.go @@ -394,6 +394,15 @@ type SpanData struct { // duration based on the elapsed time since the span's start time. Duration time.Duration + // Outcome holds the span outcome: success, failure, or unknown (the default). + // If Outcome is set to something else, it will be replaced with "unknown". + // + // Outcome is used for error rate calculations. A value of "success" indicates + // that a operation succeeded, while "failure" indicates that the operation + // failed. If Outcome is set to "unknown" (or some other value), then the + // span will not be included in error rate calculations. + Outcome string + // Context describes the context in which span occurs. Context SpanContext diff --git a/transaction.go b/transaction.go index e5617fbe5..4db04e99b 100644 --- a/transaction.go +++ b/transaction.go @@ -322,6 +322,17 @@ type TransactionData struct { // Result holds the transaction result. Result string + // Outcome holds the transaction outcome: success, failure, or + // unknown (the default). If Outcome is set to something else, + // it will be replaced with "unknown". + // + // Outcome is used for error rate calculations. A value of "success" + // indicates that a transaction succeeded, while "failure" indicates + // that the transaction failed. If Outcome is set to "unknown" (or + // some other value), then the transaction will not be included in + // error rate calculations. + Outcome string + recording bool maxSpans int spanFramesMinDuration time.Duration diff --git a/validation_test.go b/validation_test.go index 8df960f6d..d964a75b1 100644 --- a/validation_test.go +++ b/validation_test.go @@ -78,6 +78,14 @@ func TestValidateTransactionResult(t *testing.T) { }) } +func TestValidateTransactionOutcome(t *testing.T) { + validatePayloads(t, func(tracer *apm.Tracer) { + tx := tracer.StartTransaction("name", "type") + tx.Outcome = "excellent" // changed to "unknown" + tx.End() + }) +} + func TestValidateSpanName(t *testing.T) { validateTransaction(t, func(tx *apm.Transaction) { tx.StartSpan(strings.Repeat("x", 1025), "type", nil).End() @@ -90,6 +98,14 @@ func TestValidateSpanType(t *testing.T) { }) } +func TestValidateSpanOutcome(t *testing.T) { + validateTransaction(t, func(tx *apm.Transaction) { + span := tx.StartSpan("name", "type", nil) + span.Outcome = "excellent" // changed to "unknown" + span.End() + }) +} + func TestValidateDatabaseSpanContext(t *testing.T) { validateSpan(t, func(s *apm.Span) { s.Context.SetDatabase(apm.DatabaseSpanContext{