pkg/rules/fiberv2/fiberv2_otel_instrumenter.go (124 lines of code) (raw):
// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// 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 fiberv2
import (
"os"
"strconv"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/version"
"go.opentelemetry.io/otel/sdk/instrumentation"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/http"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api-semconv/instrumenter/net"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/instrumenter"
"github.com/valyala/fasthttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
var emptyFiberv2Response = fiberv2Response{}
type fiberV2InnerEnabler struct {
enabled bool
}
func (g fiberV2InnerEnabler) Enable() bool {
return g.enabled
}
var fiberV2Enabler = fiberV2InnerEnabler{os.Getenv("OTEL_INSTRUMENTATION_FIBERV2_ENABLED") != "false"}
type fiberv2ServerAttrsGetter struct {
}
func (n fiberv2ServerAttrsGetter) GetRequestMethod(request *fiberv2Request) string {
return request.method
}
func (n fiberv2ServerAttrsGetter) GetHttpRequestHeader(request *fiberv2Request, name string) []string {
all := make([]string, 0)
for _, header := range request.header.PeekAll(name) {
all = append(all, string(header))
}
return all
}
func (n fiberv2ServerAttrsGetter) GetHttpResponseStatusCode(request *fiberv2Request, response *fiberv2Response, err error) int {
return response.statusCode
}
func (n fiberv2ServerAttrsGetter) GetHttpResponseHeader(request *fiberv2Request, response *fiberv2Response, name string) []string {
all := make([]string, 0)
for _, header := range response.header.PeekAll(name) {
all = append(all, string(header))
}
return all
}
func (n fiberv2ServerAttrsGetter) GetErrorType(request *fiberv2Request, response *fiberv2Response, err error) string {
return ""
}
func (n fiberv2ServerAttrsGetter) GetUrlScheme(request *fiberv2Request) string {
return request.url.Scheme
}
func (n fiberv2ServerAttrsGetter) GetUrlPath(request *fiberv2Request) string {
return request.url.Path
}
func (n fiberv2ServerAttrsGetter) GetUrlQuery(request *fiberv2Request) string {
return request.url.RawQuery
}
func (n fiberv2ServerAttrsGetter) GetNetworkType(request *fiberv2Request, response *fiberv2Response) string {
return "ipv4"
}
func (n fiberv2ServerAttrsGetter) GetNetworkTransport(request *fiberv2Request, response *fiberv2Response) string {
return "tcp"
}
func (n fiberv2ServerAttrsGetter) GetNetworkProtocolName(request *fiberv2Request, response *fiberv2Response) string {
if !request.isTls {
return "http"
}
return "https"
}
func (n fiberv2ServerAttrsGetter) GetNetworkProtocolVersion(request *fiberv2Request, response *fiberv2Response) string {
return ""
}
func (n fiberv2ServerAttrsGetter) GetNetworkLocalInetAddress(request *fiberv2Request, response *fiberv2Response) string {
return ""
}
func (n fiberv2ServerAttrsGetter) GetNetworkLocalPort(request *fiberv2Request, response *fiberv2Response) int {
return 0
}
func (n fiberv2ServerAttrsGetter) GetNetworkPeerInetAddress(request *fiberv2Request, response *fiberv2Response) string {
return request.url.Host
}
func (n fiberv2ServerAttrsGetter) GetNetworkPeerPort(request *fiberv2Request, response *fiberv2Response) int {
port, err := strconv.Atoi(request.url.Port())
if err != nil {
return 0
}
return port
}
func (n fiberv2ServerAttrsGetter) GetHttpRoute(request *fiberv2Request) string {
return request.url.Path
}
type fiberv2RequestCarrier struct {
req *fasthttp.RequestHeader
}
func (f fiberv2RequestCarrier) Get(key string) string {
return string(f.req.Peek(key))
}
func (f fiberv2RequestCarrier) Set(key string, value string) {
f.req.Set(key, value)
}
func (f fiberv2RequestCarrier) Keys() []string {
keyStrs := make([]string, 0)
peekKeys := f.req.PeekKeys()
for _, peekKey := range peekKeys {
keyStrs = append(keyStrs, string(peekKey))
}
return keyStrs
}
func BuildFiberV2ServerOtelInstrumenter() *instrumenter.PropagatingFromUpstreamInstrumenter[*fiberv2Request, *fiberv2Response] {
builder := instrumenter.Builder[*fiberv2Request, *fiberv2Response]{}
serverGetter := fiberv2ServerAttrsGetter{}
commonExtractor := http.HttpCommonAttrsExtractor[*fiberv2Request, *fiberv2Response, fiberv2ServerAttrsGetter, fiberv2ServerAttrsGetter]{HttpGetter: serverGetter, NetGetter: serverGetter}
networkExtractor := net.NetworkAttrsExtractor[*fiberv2Request, *fiberv2Response, fiberv2ServerAttrsGetter]{Getter: serverGetter}
urlExtractor := net.UrlAttrsExtractor[*fiberv2Request, *fiberv2Response, fiberv2ServerAttrsGetter]{Getter: serverGetter}
return builder.Init().SetSpanStatusExtractor(http.HttpServerSpanStatusExtractor[*fiberv2Request, *fiberv2Response]{Getter: serverGetter}).SetSpanNameExtractor(&http.HttpServerSpanNameExtractor[*fiberv2Request, *fiberv2Response]{Getter: serverGetter}).
AddOperationListeners(http.HttpServerMetrics("fiberv2.server")).
SetSpanKindExtractor(&instrumenter.AlwaysServerExtractor[*fiberv2Request]{}).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.FIBER_V2_SERVER_SCOPE_NAME,
Version: version.Tag,
}).
AddAttributesExtractor(&http.HttpServerAttrsExtractor[*fiberv2Request, *fiberv2Response, fiberv2ServerAttrsGetter, fiberv2ServerAttrsGetter, fiberv2ServerAttrsGetter]{Base: commonExtractor, NetworkExtractor: networkExtractor, UrlExtractor: urlExtractor}).BuildPropagatingFromUpstreamInstrumenter(func(n *fiberv2Request) propagation.TextMapCarrier {
return fiberv2RequestCarrier{req: n.header}
}, otel.GetTextMapPropagator())
}