Skip to content

Commit

Permalink
feature: add filter that sets a span tag on response status condition (
Browse files Browse the repository at this point in the history
…#3202)

* feature: add filter that sets a span tag on response status condition

Signed-off-by: Sandor Szücs <sandor.szuecs@zalando.de>
  • Loading branch information
szuecs authored and Pushpalanka committed Oct 11, 2024
1 parent 7f5d753 commit b041ce5
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 34 deletions.
9 changes: 9 additions & 0 deletions docs/reference/filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -3352,6 +3352,15 @@ tracingTag("http.flow_id", "${request.header.X-Flow-Id}")
This filter works just like [tracingTag](#tracingtag), but is applied after the request was processed. In particular, [template placeholders](#template-placeholders) referencing the response can be used in the parameters.
### tracingTagFromResponseIfStatus
Example: set error tag to true in case response status code is `>= 500` and `<= 599`
```
tracingTagFromResponseIfStatus("error", "true", 500, 599)
```
### tracingSpanName
This filter sets the name of the outgoing (client span) in opentracing. The default name is "proxy". Example:
Expand Down
1 change: 1 addition & 0 deletions filters/builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ func Filters() []filters.Spec {
tracing.NewBaggageToTagFilter(),
tracing.NewTag(),
tracing.NewTagFromResponse(),
tracing.NewTagFromResponseIfStatus(),
tracing.NewStateBagToTag(),
//lint:ignore SA1019 due to backward compatibility
accesslog.NewAccessLogDisabled(),
Expand Down
1 change: 1 addition & 0 deletions filters/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ const (
StateBagToTagName = "stateBagToTag"
TracingTagName = "tracingTag"
TracingTagFromResponseName = "tracingTagFromResponse"
TracingTagFromResponseIfStatusName = "tracingTagFromResponseIfStatus"
TracingSpanNameName = "tracingSpanName"
OriginMarkerName = "originMarker"
FadeInName = "fadeIn"
Expand Down
76 changes: 68 additions & 8 deletions filters/tracing/tag.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package tracing

import (
"net/http"

opentracing "github.com/opentracing/opentracing-go"
"github.com/zalando/skipper/eskip"
"github.com/zalando/skipper/filters"
Expand All @@ -10,11 +12,21 @@ type tagSpec struct {
typ string
}

type tagFilterType int

const (
tagRequest tagFilterType = iota + 1
tagResponse
tagResponseCondition
)

type tagFilter struct {
tagFromResponse bool
typ tagFilterType

tagName string
tagValue *eskip.Template

condition func(*http.Response) bool
}

// NewTag creates a filter specification for the tracingTag filter.
Expand All @@ -27,12 +39,34 @@ func NewTagFromResponse() filters.Spec {
return &tagSpec{typ: filters.TracingTagFromResponseName}
}

func NewTagFromResponseIfStatus() filters.Spec {
return &tagSpec{typ: filters.TracingTagFromResponseIfStatusName}
}

func (s *tagSpec) Name() string {
return s.typ
}

func (s *tagSpec) CreateFilter(args []interface{}) (filters.Filter, error) {
if len(args) != 2 {
var typ tagFilterType

switch s.typ {
case filters.TracingTagName:
if len(args) != 2 {
return nil, filters.ErrInvalidFilterParameters
}
typ = tagRequest
case filters.TracingTagFromResponseName:
if len(args) != 2 {
return nil, filters.ErrInvalidFilterParameters
}
typ = tagResponse
case filters.TracingTagFromResponseIfStatusName:
if len(args) != 4 {
return nil, filters.ErrInvalidFilterParameters
}
typ = tagResponseCondition
default:
return nil, filters.ErrInvalidFilterParameters
}

Expand All @@ -46,23 +80,49 @@ func (s *tagSpec) CreateFilter(args []interface{}) (filters.Filter, error) {
return nil, filters.ErrInvalidFilterParameters
}

return &tagFilter{
tagFromResponse: s.typ == filters.TracingTagFromResponseName,

f := &tagFilter{
typ: typ,
tagName: tagName,
tagValue: eskip.NewTemplate(tagValue),
}, nil
}

if len(args) == 4 {
minValue, ok := args[2].(float64)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
maxValue, ok := args[3].(float64)
if !ok {
return nil, filters.ErrInvalidFilterParameters
}
minVal := int(minValue)
maxVal := int(maxValue)
if minVal < 0 || maxVal > 599 || minVal > maxVal {
return nil, filters.ErrInvalidFilterParameters
}

f.condition = func(rsp *http.Response) bool {
return minVal <= rsp.StatusCode && rsp.StatusCode <= maxVal
}
}

return f, nil
}

func (f *tagFilter) Request(ctx filters.FilterContext) {
if !f.tagFromResponse {
if f.typ == tagRequest {
f.setTag(ctx)
}
}

func (f *tagFilter) Response(ctx filters.FilterContext) {
if f.tagFromResponse {
switch f.typ {
case tagResponse:
f.setTag(ctx)
case tagResponseCondition:
if f.condition(ctx.Response()) {
f.setTag(ctx)
}
}
}

Expand Down
Loading

0 comments on commit b041ce5

Please sign in to comment.