pkg/rules/http/client_setup.go (65 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 http
import (
"context"
"net/http"
"strings"
_ "unsafe"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/inst-api/utils"
)
// TODO: use a interface to filter
var netHttpFilter = utils.DefaultUrlFilter{}
var netHttpClientInstrumenter = BuildNetHttpClientOtelInstrumenter()
const otelExporterPrefix = "OTel OTLP Exporter Go"
//go:linkname clientOnEnter net/http.clientOnEnter
func clientOnEnter(call api.CallContext, t *http.Transport, req *http.Request) {
if !netHttpEnabler.Enable() {
return
}
// filter span generated by OpenTelemetry HTTP Exporter
if strings.HasPrefix(req.Header.Get("user-agent"), otelExporterPrefix) {
return
}
if netHttpFilter.FilterUrl(req.URL) {
return
}
netHttpRequest := &netHttpRequest{
method: req.Method,
url: req.URL,
header: req.Header,
host: req.Host,
isTls: req.TLS != nil,
}
netHttpRequest.version = getProtocolVersion(req.ProtoMajor, req.ProtoMinor)
ctx := netHttpClientInstrumenter.Start(req.Context(), netHttpRequest)
req = req.WithContext(ctx)
call.SetParam(1, req)
data := make(map[string]interface{}, 1)
data["ctx"] = ctx
call.SetData(data)
return
}
//go:linkname clientOnExit net/http.clientOnExit
func clientOnExit(call api.CallContext, res *http.Response, err error) {
if !netHttpEnabler.Enable() {
return
}
data, ok := call.GetData().(map[string]interface{})
if !ok || data == nil || data["ctx"] == nil {
return
}
ctx := data["ctx"].(context.Context)
if res != nil {
netHttpClientInstrumenter.End(ctx, &netHttpRequest{
method: res.Request.Method,
url: res.Request.URL,
header: res.Request.Header,
version: getProtocolVersion(res.Request.ProtoMajor, res.Request.ProtoMinor),
host: res.Request.Host,
isTls: res.Request.TLS != nil,
}, &netHttpResponse{
statusCode: res.StatusCode,
header: res.Header,
}, err)
} else {
netHttpClientInstrumenter.End(ctx, &netHttpRequest{}, &netHttpResponse{
statusCode: 500,
}, err)
}
}