Skip to content

Commit d58e0e8

Browse files
feat: Add integration for github.com/astaxie/beego (#200)
* feat: added beego integration configuration options * feat: added beego middleware * feat: added doc * chore: add readme * fix: test cases * fix: use json in test case * chore: update comments * fix: parameter name to clarify purpose * chore: add additional unit tests * fix: linting * feat: add additional test cases for http * feat: add ability to race template render * chore: update readme * fix: typos * fix: test case and go version * fix: make test cases consistent * fix: replace beego instance each test * fix: address pr to switch config to use providers * fix: address pr feedback by removing unecessary documentation in readme * fix: reduce cardinality of span names by using route template * fix: remove readme and add example * fix: update comment * fix: add comment and update mod * chore: update changelog
1 parent 0d5bd34 commit d58e0e8

File tree

9 files changed

+1254
-0
lines changed

9 files changed

+1254
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1111
### Added
1212

1313
- Top-level `Version()` and `SemVersion()` functions defining the current version of the contrib package. (#225)
14+
- Instrumentation for the `github.com/astaxie/beego` package. (#200)
1415

1516
### Changed
1617

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright The OpenTelemetry Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package beego
16+
17+
import (
18+
"context"
19+
"net/http"
20+
21+
"google.golang.org/grpc/codes"
22+
23+
otelhttp "go.opentelemetry.io/contrib/instrumentation/net/http"
24+
"go.opentelemetry.io/otel/api/trace"
25+
26+
"github.com/astaxie/beego"
27+
)
28+
29+
// OTelBeegoHandler implements the http.Handler interface and provides
30+
// trace and metrics to beego web apps.
31+
type OTelBeegoHandler struct {
32+
http.Handler
33+
}
34+
35+
// ServerHTTP calls the configured handler to serve HTTP for req to rr.
36+
func (o *OTelBeegoHandler) ServeHTTP(rr http.ResponseWriter, req *http.Request) {
37+
ctx := beego.BeeApp.Handlers.GetContext()
38+
defer beego.BeeApp.Handlers.GiveBackContext(ctx)
39+
ctx.Reset(rr, req)
40+
// use the beego context to try to find a route template
41+
if router, found := beego.BeeApp.Handlers.FindRouter(ctx); found {
42+
// if found, save it to the context
43+
reqCtx := context.WithValue(req.Context(), ctxRouteTemplateKey, router.GetPattern())
44+
req = req.WithContext(reqCtx)
45+
}
46+
o.Handler.ServeHTTP(rr, req)
47+
}
48+
49+
// defaultSpanNameFormatter is the default formatter for spans created with the beego
50+
// integration. Returns the route path template, or the URL path if the current path
51+
// is not associated with a router.
52+
func defaultSpanNameFormatter(operation string, req *http.Request) string {
53+
if val := req.Context().Value(ctxRouteTemplateKey); val != nil {
54+
str, ok := val.(string)
55+
if ok {
56+
return str
57+
}
58+
}
59+
return req.Method
60+
}
61+
62+
// NewOTelBeegoMiddleWare creates a MiddleWare that provides OpenTelemetry
63+
// tracing and metrics to a Beego web app.
64+
// Parameter service should describe the name of the (virtual) server handling the request.
65+
// The OTelBeegoMiddleWare can be configured using the provided Options.
66+
func NewOTelBeegoMiddleWare(service string, options ...Option) beego.MiddleWare {
67+
cfg := configure(options...)
68+
69+
httpOptions := []otelhttp.Option{
70+
otelhttp.WithTracer(cfg.traceProvider.Tracer(packageName)),
71+
otelhttp.WithMeter(cfg.meterProvider.Meter(packageName)),
72+
otelhttp.WithPropagators(cfg.propagators),
73+
}
74+
75+
for _, f := range cfg.filters {
76+
httpOptions = append(
77+
httpOptions,
78+
otelhttp.WithFilter(otelhttp.Filter(f)),
79+
)
80+
}
81+
82+
if cfg.formatter != nil {
83+
httpOptions = append(httpOptions, otelhttp.WithSpanNameFormatter(cfg.formatter))
84+
}
85+
86+
return func(handler http.Handler) http.Handler {
87+
return &OTelBeegoHandler{
88+
otelhttp.NewHandler(
89+
handler,
90+
service,
91+
httpOptions...,
92+
),
93+
}
94+
}
95+
}
96+
97+
// Render traces beego.Controller.Render. Use this function
98+
// if you want to add a child span for the rendering of a template file.
99+
// Disable autorender before use, and call this function explicitly.
100+
func Render(c *beego.Controller) error {
101+
ctx, span := span(c, renderTemplateSpanName)
102+
defer span.End()
103+
err := c.Render()
104+
if err != nil {
105+
span.RecordError(ctx, err)
106+
span.SetStatus(codes.Internal, "template failure")
107+
}
108+
return err
109+
}
110+
111+
// RenderString traces beego.Controller.RenderString. Use this function
112+
// if you want to add a child span for the rendering of a template file to
113+
// its string representation.
114+
// Disable autorender before use, and call this function explicitly.
115+
func RenderString(c *beego.Controller) (string, error) {
116+
ctx, span := span(c, renderStringSpanName)
117+
defer span.End()
118+
str, err := c.RenderString()
119+
if err != nil {
120+
span.RecordError(ctx, err)
121+
span.SetStatus(codes.Internal, "render string failure")
122+
}
123+
return str, err
124+
}
125+
126+
// RenderBytes traces beego.Controller.RenderBytes. Use this function if
127+
// you want to add a child span for the rendering of a template file to its
128+
// byte representation.
129+
// Disable autorender before use, and call this function explicitly.
130+
func RenderBytes(c *beego.Controller) ([]byte, error) {
131+
ctx, span := span(c, renderBytesSpanName)
132+
defer span.End()
133+
bytes, err := c.RenderBytes()
134+
if err != nil {
135+
span.RecordError(ctx, err)
136+
span.SetStatus(codes.Internal, "render bytes failure")
137+
}
138+
return bytes, err
139+
}
140+
141+
func span(c *beego.Controller, spanName string) (context.Context, trace.Span) {
142+
ctx := c.Ctx.Request.Context()
143+
span := trace.SpanFromContext(ctx)
144+
tracer := span.Tracer()
145+
return tracer.Start(
146+
ctx,
147+
spanName,
148+
trace.WithAttributes(
149+
Template(c.TplName),
150+
),
151+
)
152+
153+
}

0 commit comments

Comments
 (0)