pkg/rules/http/net_http_otel_instrumenter.go (191 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 (
"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"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/propagation"
)
type netHttpInnerEnabler struct {
enabled bool
}
func (n netHttpInnerEnabler) Enable() bool {
return n.enabled
}
var netHttpEnabler = netHttpInnerEnabler{os.Getenv("OTEL_INSTRUMENTATION_NETHTTP_ENABLED") != "false"}
var emptyHttpResponse = netHttpResponse{}
type netHttpClientAttrsGetter struct {
}
func (n netHttpClientAttrsGetter) GetRequestMethod(request *netHttpRequest) string {
return request.method
}
func (n netHttpClientAttrsGetter) GetHttpRequestHeader(request *netHttpRequest, name string) []string {
return request.header.Values(name)
}
func (n netHttpClientAttrsGetter) GetHttpResponseStatusCode(request *netHttpRequest, response *netHttpResponse, err error) int {
return response.statusCode
}
func (n netHttpClientAttrsGetter) GetHttpResponseHeader(request *netHttpRequest, response *netHttpResponse, name string) []string {
return response.header.Values(name)
}
func (n netHttpClientAttrsGetter) GetErrorType(request *netHttpRequest, response *netHttpResponse, err error) string {
// TODO return status code as error type
return ""
}
func (n netHttpClientAttrsGetter) GetNetworkType(request *netHttpRequest, response *netHttpResponse) string {
return "ipv4"
}
func (n netHttpClientAttrsGetter) GetNetworkTransport(request *netHttpRequest, response *netHttpResponse) string {
return "tcp"
}
func (n netHttpClientAttrsGetter) GetNetworkProtocolName(request *netHttpRequest, response *netHttpResponse) string {
if request.isTls == false {
return "http"
} else {
return "https"
}
}
func (n netHttpClientAttrsGetter) GetNetworkProtocolVersion(request *netHttpRequest, response *netHttpResponse) string {
return request.version
}
func (n netHttpClientAttrsGetter) GetNetworkLocalInetAddress(request *netHttpRequest, response *netHttpResponse) string {
return ""
}
func (n netHttpClientAttrsGetter) GetNetworkLocalPort(request *netHttpRequest, response *netHttpResponse) int {
return 0
}
func (n netHttpClientAttrsGetter) GetNetworkPeerInetAddress(request *netHttpRequest, response *netHttpResponse) string {
return request.host
}
func (n netHttpClientAttrsGetter) GetNetworkPeerPort(request *netHttpRequest, response *netHttpResponse) int {
if request.url == nil {
return 0
}
port, err := strconv.Atoi(request.url.Port())
if err != nil {
return 0
}
return port
}
func (n netHttpClientAttrsGetter) GetUrlFull(request *netHttpRequest) string {
return request.url.String()
}
func (n netHttpClientAttrsGetter) GetServerAddress(request *netHttpRequest) string {
return request.host
}
func (n netHttpClientAttrsGetter) GetServerPort(request *netHttpRequest) int {
if request.url == nil {
return 0
}
port, err := strconv.Atoi(request.url.Port())
if err != nil {
return 0
}
return port
}
type netHttpServerAttrsGetter struct {
}
func (n netHttpServerAttrsGetter) GetRequestMethod(request *netHttpRequest) string {
return request.method
}
func (n netHttpServerAttrsGetter) GetHttpRequestHeader(request *netHttpRequest, name string) []string {
return request.header.Values(name)
}
func (n netHttpServerAttrsGetter) GetHttpResponseStatusCode(request *netHttpRequest, response *netHttpResponse, err error) int {
return response.statusCode
}
func (n netHttpServerAttrsGetter) GetHttpResponseHeader(request *netHttpRequest, response *netHttpResponse, name string) []string {
return response.header.Values(name)
}
func (n netHttpServerAttrsGetter) GetErrorType(request *netHttpRequest, response *netHttpResponse, err error) string {
// TODO return status code as error type
return ""
}
func (n netHttpServerAttrsGetter) GetUrlScheme(request *netHttpRequest) string {
if request.url.Scheme != "" {
return request.url.Scheme
}
return n.GetNetworkProtocolName(request, &emptyHttpResponse)
}
func (n netHttpServerAttrsGetter) GetUrlPath(request *netHttpRequest) string {
return request.url.Path
}
func (n netHttpServerAttrsGetter) GetUrlQuery(request *netHttpRequest) string {
return request.url.RawQuery
}
func (n netHttpServerAttrsGetter) GetNetworkType(request *netHttpRequest, response *netHttpResponse) string {
return "ipv4"
}
func (n netHttpServerAttrsGetter) GetNetworkTransport(request *netHttpRequest, response *netHttpResponse) string {
return "tcp"
}
func (n netHttpServerAttrsGetter) GetNetworkProtocolName(request *netHttpRequest, response *netHttpResponse) string {
if !request.isTls {
return "http"
}
return "https"
}
func (n netHttpServerAttrsGetter) GetNetworkProtocolVersion(request *netHttpRequest, response *netHttpResponse) string {
return request.version
}
func (n netHttpServerAttrsGetter) GetNetworkLocalInetAddress(request *netHttpRequest, response *netHttpResponse) string {
return ""
}
func (n netHttpServerAttrsGetter) GetNetworkLocalPort(request *netHttpRequest, response *netHttpResponse) int {
return 0
}
func (n netHttpServerAttrsGetter) GetNetworkPeerInetAddress(request *netHttpRequest, response *netHttpResponse) string {
return request.host
}
func (n netHttpServerAttrsGetter) GetNetworkPeerPort(request *netHttpRequest, response *netHttpResponse) int {
port, err := strconv.Atoi(request.url.Port())
if err != nil {
return 0
}
return port
}
func (n netHttpServerAttrsGetter) GetHttpRoute(request *netHttpRequest) string {
return request.url.Path
}
func BuildNetHttpClientOtelInstrumenter() *instrumenter.PropagatingToDownstreamInstrumenter[*netHttpRequest, *netHttpResponse] {
builder := &instrumenter.Builder[*netHttpRequest, *netHttpResponse]{}
clientGetter := netHttpClientAttrsGetter{}
commonExtractor := http.HttpCommonAttrsExtractor[*netHttpRequest, *netHttpResponse, http.HttpClientAttrsGetter[*netHttpRequest, *netHttpResponse], net.NetworkAttrsGetter[*netHttpRequest, *netHttpResponse]]{HttpGetter: clientGetter, NetGetter: clientGetter}
networkExtractor := net.NetworkAttrsExtractor[*netHttpRequest, *netHttpResponse, net.NetworkAttrsGetter[*netHttpRequest, *netHttpResponse]]{Getter: clientGetter}
return builder.Init().SetSpanStatusExtractor(http.HttpClientSpanStatusExtractor[*netHttpRequest, *netHttpResponse]{Getter: clientGetter}).SetSpanNameExtractor(&http.HttpClientSpanNameExtractor[*netHttpRequest, *netHttpResponse]{Getter: clientGetter}).
SetSpanKindExtractor(&instrumenter.AlwaysClientExtractor[*netHttpRequest]{}).
AddOperationListeners(http.HttpClientMetrics("net.http.client")).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.NET_HTTP_CLIENT_SCOPE_NAME,
Version: version.Tag,
}).
AddAttributesExtractor(&http.HttpClientAttrsExtractor[*netHttpRequest, *netHttpResponse, http.HttpClientAttrsGetter[*netHttpRequest, *netHttpResponse], net.NetworkAttrsGetter[*netHttpRequest, *netHttpResponse]]{Base: commonExtractor, NetworkExtractor: networkExtractor}).BuildPropagatingToDownstreamInstrumenter(func(n *netHttpRequest) propagation.TextMapCarrier {
if n.header == nil {
return nil
}
return propagation.HeaderCarrier(n.header)
}, otel.GetTextMapPropagator())
}
func BuildNetHttpServerOtelInstrumenter() *instrumenter.PropagatingFromUpstreamInstrumenter[*netHttpRequest, *netHttpResponse] {
builder := &instrumenter.Builder[*netHttpRequest, *netHttpResponse]{}
serverGetter := netHttpServerAttrsGetter{}
commonExtractor := http.HttpCommonAttrsExtractor[*netHttpRequest, *netHttpResponse, http.HttpServerAttrsGetter[*netHttpRequest, *netHttpResponse], net.NetworkAttrsGetter[*netHttpRequest, *netHttpResponse]]{HttpGetter: serverGetter, NetGetter: serverGetter}
networkExtractor := net.NetworkAttrsExtractor[*netHttpRequest, *netHttpResponse, net.NetworkAttrsGetter[*netHttpRequest, *netHttpResponse]]{Getter: serverGetter}
urlExtractor := net.UrlAttrsExtractor[*netHttpRequest, *netHttpResponse, net.UrlAttrsGetter[*netHttpRequest]]{Getter: serverGetter}
return builder.Init().SetSpanStatusExtractor(http.HttpServerSpanStatusExtractor[*netHttpRequest, *netHttpResponse]{Getter: serverGetter}).SetSpanNameExtractor(&http.HttpServerSpanNameExtractor[*netHttpRequest, *netHttpResponse]{Getter: serverGetter}).
SetSpanKindExtractor(&instrumenter.AlwaysServerExtractor[*netHttpRequest]{}).
AddOperationListeners(http.HttpServerMetrics("net.http.server")).
SetInstrumentationScope(instrumentation.Scope{
Name: utils.NET_HTTP_SERVER_SCOPE_NAME,
Version: version.Tag,
}).
AddAttributesExtractor(&http.HttpServerAttrsExtractor[*netHttpRequest, *netHttpResponse, http.HttpServerAttrsGetter[*netHttpRequest, *netHttpResponse], net.NetworkAttrsGetter[*netHttpRequest, *netHttpResponse], net.UrlAttrsGetter[*netHttpRequest]]{Base: commonExtractor, NetworkExtractor: networkExtractor, UrlExtractor: urlExtractor}).BuildPropagatingFromUpstreamInstrumenter(func(n *netHttpRequest) propagation.TextMapCarrier {
if n.header == nil {
return nil
}
return propagation.HeaderCarrier(n.header)
}, otel.GetTextMapPropagator())
}