feat: add project-owned error catalogs and HTTP 200 failure contracts
This commit is contained in:
51
telemetry/errorCatalog_test.go
Normal file
51
telemetry/errorCatalog_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package telemetry_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
omni "git.yuntuo.hk/k2safe/go-omni"
|
||||
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
"git.yuntuo.hk/k2safe/go-omni/response"
|
||||
"git.yuntuo.hk/k2safe/go-omni/telemetry"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/sdk/trace/tracetest"
|
||||
)
|
||||
|
||||
func TestCatalogFailureTraceWithHTTP200(t *testing.T) {
|
||||
exporter := tracetest.NewInMemoryExporter()
|
||||
runtime, err := telemetry.New(telemetry.Config{Service: "fixture", SampleRatio: 1, Exporter: exporter})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer runtime.Close()
|
||||
app := omni.New(omni.WithErrors(apierrors.Catalog{DefaultStatus: 200, Definitions: map[string]apierrors.Definition{"INVALID": {Code: 123, Message: "invalid"}}}), omni.WithResponse(response.Config{CodeType: "int32", SuccessCode: 0, ErrorCode: 9999}))
|
||||
defer app.Close()
|
||||
app.Use(runtime.Middleware())
|
||||
app.GET("/", func(c *omni.Context) error { c.WriteError(apierrors.ByCode("INVALID")); return nil })
|
||||
w := httptest.NewRecorder()
|
||||
app.ServeHTTP(w, httptest.NewRequest("GET", "/", nil))
|
||||
if w.Code != 200 {
|
||||
t.Fatal(w.Code)
|
||||
}
|
||||
if err := runtime.Flush(context.Background()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
spans := exporter.GetSpans()
|
||||
if len(spans) != 1 || spans[0].Status.Code != codes.Error {
|
||||
t.Fatal(spans)
|
||||
}
|
||||
seenStatus, seenFailure := false, false
|
||||
for _, attr := range spans[0].Attributes {
|
||||
if attr.Key == "http.response.status_code" && attr.Value.AsInt64() == 200 {
|
||||
seenStatus = true
|
||||
}
|
||||
if attr.Key == "omni.request.failed" && attr.Value.AsBool() {
|
||||
seenFailure = true
|
||||
}
|
||||
}
|
||||
if !seenStatus || !seenFailure {
|
||||
t.Fatal(spans[0].Attributes)
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,10 @@ package telemetry
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"git.yuntuo.hk/k2safe/go-omni/httpx"
|
||||
"git.yuntuo.hk/k2safe/go-omni/logx"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
@@ -15,9 +18,6 @@ import (
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@@ -99,15 +99,22 @@ func (r *Runtime) Middleware() httpx.Middleware {
|
||||
defer func() {
|
||||
status := c.Status()
|
||||
if err != nil && !c.Responded() {
|
||||
status = apierrors.From(err).Status
|
||||
status = c.ResolveError(err).Status
|
||||
}
|
||||
p := recover()
|
||||
if p != nil {
|
||||
status = 500
|
||||
}
|
||||
attrs := []attribute.KeyValue{attribute.String("http.request.method", method), attribute.String("http.route", route), attribute.Int("http.response.status_code", status)}
|
||||
failure := c.Failure()
|
||||
if failure == nil && err != nil {
|
||||
failure = c.ResolveError(err)
|
||||
}
|
||||
if failure != nil {
|
||||
attrs = append(attrs, attribute.Bool("omni.request.failed", true), attribute.String("omni.error.key", failure.Code))
|
||||
}
|
||||
span.SetAttributes(attrs...)
|
||||
if status >= 500 {
|
||||
if status >= 500 || (failure != nil && status < 400) {
|
||||
span.SetStatus(codes.Error, "request failed")
|
||||
}
|
||||
r.requests.Add(ctx, 1, metric.WithAttributes(attrs...))
|
||||
|
||||
Reference in New Issue
Block a user