mirror of
https://github.com/astaxie/beego.git
synced 2024-11-24 02:40:55 +00:00
Support opentracing filter for Orm
This commit is contained in:
parent
26b016a3a4
commit
dec98f004c
@ -18,8 +18,12 @@ import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// FilterChain is used to build a Filter
|
||||
// don't forget to call next(...) inside your Filter
|
||||
type FilterChain func(next Filter) Filter
|
||||
|
||||
// Filter's behavior is a little big strang.
|
||||
// it's only be called when users call methods of Ormer
|
||||
type Filter func(ctx context.Context, inv *Invocation)
|
||||
|
||||
var globalFilterChains = make([]FilterChain, 0, 4)
|
||||
|
59
pkg/orm/filter/opentracing/filter.go
Normal file
59
pkg/orm/filter/opentracing/filter.go
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package opentracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/astaxie/beego/pkg/orm"
|
||||
)
|
||||
|
||||
// FilterChainBuilder provides an extension point
|
||||
// this Filter's behavior looks a little bit strange
|
||||
// for example:
|
||||
// if we want to trace QuerySetter
|
||||
// actually we trace invoking "QueryTable" and "QueryTableWithCtx"
|
||||
type FilterChainBuilder struct {
|
||||
// CustomSpanFunc users are able to custom their span
|
||||
CustomSpanFunc func(span opentracing.Span, ctx context.Context, inv *orm.Invocation)
|
||||
}
|
||||
|
||||
func (builder *FilterChainBuilder) FilterChain(next orm.Filter) orm.Filter {
|
||||
return func(ctx context.Context, inv *orm.Invocation) {
|
||||
operationName := builder.operationName(ctx, inv)
|
||||
span, spanCtx := opentracing.StartSpanFromContext(ctx, operationName)
|
||||
defer span.Finish()
|
||||
|
||||
next(spanCtx, inv)
|
||||
span.SetTag("Method", inv.Method)
|
||||
span.SetTag("Table", inv.GetTableName())
|
||||
span.SetTag("InsideTx", inv.InsideTx)
|
||||
span.SetTag("TxName", spanCtx.Value(orm.TxNameKey))
|
||||
|
||||
if builder.CustomSpanFunc != nil {
|
||||
builder.CustomSpanFunc(span, spanCtx, inv)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (builder *FilterChainBuilder) operationName(ctx context.Context, inv *orm.Invocation) string {
|
||||
if n, ok := ctx.Value(orm.TxNameKey).(string); ok {
|
||||
return inv.Method + "#" + n
|
||||
}
|
||||
return inv.Method + "#" + inv.GetTableName()
|
||||
}
|
43
pkg/orm/filter/opentracing/filter_test.go
Normal file
43
pkg/orm/filter/opentracing/filter_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package opentracing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/opentracing/opentracing-go"
|
||||
|
||||
"github.com/astaxie/beego/pkg/orm"
|
||||
)
|
||||
|
||||
func TestFilterChainBuilder_FilterChain(t *testing.T) {
|
||||
next := func(ctx context.Context, inv *orm.Invocation) {
|
||||
inv.TxName = "Hello"
|
||||
}
|
||||
|
||||
builder := &FilterChainBuilder{
|
||||
CustomSpanFunc: func(span opentracing.Span, ctx context.Context, inv *orm.Invocation) {
|
||||
span.SetTag("hello", "hell")
|
||||
},
|
||||
}
|
||||
|
||||
inv := &orm.Invocation{
|
||||
Method: "Hello",
|
||||
TxStartTime: time.Now(),
|
||||
}
|
||||
builder.FilterChain(next)(context.Background(), inv)
|
||||
}
|
@ -29,6 +29,10 @@ import (
|
||||
// FilterChainBuilder is an extension point,
|
||||
// when we want to support some configuration,
|
||||
// please use this structure
|
||||
// this Filter's behavior looks a little bit strange
|
||||
// for example:
|
||||
// if we want to records the metrics of QuerySetter
|
||||
// actually we only records metrics of invoking "QueryTable" and "QueryTableWithCtx"
|
||||
type FilterChainBuilder struct {
|
||||
summaryVec prometheus.ObserverVec
|
||||
}
|
||||
|
@ -30,22 +30,14 @@ type FilterChainBuilder struct {
|
||||
|
||||
func (builder *FilterChainBuilder) FilterChain(next beego.FilterFunc) beego.FilterFunc {
|
||||
return func(ctx *context.Context) {
|
||||
span := opentracing.SpanFromContext(ctx.Request.Context())
|
||||
spanCtx := ctx.Request.Context()
|
||||
if span == nil {
|
||||
operationName := ctx.Input.URL()
|
||||
// it means that there is not any span, so we create a span as the root span.
|
||||
// TODO, if we support multiple servers, this need to be changed
|
||||
route, found := beego.BeeApp.Handlers.FindRouter(ctx)
|
||||
if found {
|
||||
operationName = route.GetPattern()
|
||||
}
|
||||
span, spanCtx = opentracing.StartSpanFromContext(spanCtx, operationName)
|
||||
newReq := ctx.Request.Clone(spanCtx)
|
||||
ctx.Reset(ctx.ResponseWriter.ResponseWriter, newReq)
|
||||
}
|
||||
operationName := builder.operationName(ctx)
|
||||
|
||||
span, spanCtx := opentracing.StartSpanFromContext(ctx.Request.Context(), operationName)
|
||||
defer span.Finish()
|
||||
|
||||
newReq := ctx.Request.Clone(spanCtx)
|
||||
ctx.Reset(ctx.ResponseWriter.ResponseWriter, newReq)
|
||||
|
||||
next(ctx)
|
||||
// if you think we need to do more things, feel free to create an issue to tell us
|
||||
span.SetTag("status", ctx.Output.Status)
|
||||
@ -56,3 +48,14 @@ func (builder *FilterChainBuilder) FilterChain(next beego.FilterFunc) beego.Filt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (builder *FilterChainBuilder) operationName(ctx *context.Context) string {
|
||||
operationName := ctx.Input.URL()
|
||||
// it means that there is not any span, so we create a span as the root span.
|
||||
// TODO, if we support multiple servers, this need to be changed
|
||||
route, found := beego.BeeApp.Handlers.FindRouter(ctx)
|
||||
if found {
|
||||
operationName = route.GetPattern()
|
||||
}
|
||||
return operationName
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user