feat: Homogenize tracing of requests to other services

The "tracing.GetNewRequest" and "tracing.GetNewRequestWithContext" aims
to replace the "http.NewRequest" and "http.NewRequestWithContext"
respectively by including tracing data.

For requests that have been already created, such as the case of some
reva requests, "tracing.InjectTracingHeaders" is provided.

Note that some outgoing requests might be required NOT to use tracing
headers.
This commit is contained in:
Juan Pablo Villafáñez
2025-07-18 14:40:55 +02:00
parent 8360bdf8c5
commit a388c8d642
8 changed files with 54 additions and 24 deletions

View File

@@ -15,7 +15,6 @@ var propagator = propagation.NewCompositeTextMapPropagator(
func TraceContext(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := propagator.Extract(r.Context(), propagation.HeaderCarrier(r.Header))
propagator.Inject(ctx, propagation.HeaderCarrier(r.Header))
next.ServeHTTP(w, r.WithContext(ctx))
})
}

View File

@@ -17,8 +17,8 @@ import (
goidc "github.com/coreos/go-oidc/v3/oidc"
"github.com/golang-jwt/jwt/v5"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
"go.opentelemetry.io/otel/propagation"
"golang.org/x/oauth2"
)
@@ -105,17 +105,11 @@ func (c *oidcClient) lookupWellKnownOpenidConfiguration(ctx context.Context) err
c.providerLock.Lock()
defer c.providerLock.Unlock()
if c.provider == nil {
propagator := propagation.NewCompositeTextMapPropagator(
propagation.Baggage{},
propagation.TraceContext{},
)
wellKnown := strings.TrimSuffix(c.issuer, "/") + wellknownPath
req, err := http.NewRequest("GET", wellKnown, nil)
req, err := tracing.GetNewRequest(ctx, http.MethodGet, wellKnown, nil)
if err != nil {
return err
}
propagator.Inject(ctx, propagation.HeaderCarrier(req.Header))
resp, err := c.httpClient.Do(req.WithContext(ctx))
if err != nil {
return err
@@ -221,11 +215,6 @@ func (u *UserInfo) Claims(v interface{}) error {
// UserInfo retrieves the userinfo from a Token
func (c *oidcClient) UserInfo(ctx context.Context, tokenSource oauth2.TokenSource) (*UserInfo, error) {
propagator := propagation.NewCompositeTextMapPropagator(
propagation.Baggage{},
propagation.TraceContext{},
)
if err := c.lookupWellKnownOpenidConfiguration(ctx); err != nil {
return nil, err
}
@@ -234,11 +223,10 @@ func (c *oidcClient) UserInfo(ctx context.Context, tokenSource oauth2.TokenSourc
return nil, errors.New("oidc: user info endpoint is not supported by this provider")
}
req, err := http.NewRequest("GET", c.provider.UserinfoEndpoint, nil)
req, err := tracing.GetNewRequest(ctx, http.MethodGet, c.provider.UserinfoEndpoint, nil)
if err != nil {
return nil, fmt.Errorf("oidc: create GET request: %v", err)
}
propagator.Inject(ctx, propagation.HeaderCarrier(req.Header))
token, err := tokenSource.Token()
if err != nil {

View File

@@ -3,6 +3,8 @@ package tracing
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"reflect"
"strings"
@@ -172,3 +174,43 @@ func parseAgentConfig(ae string) (string, string, error) {
}
return p[0], p[1], nil
}
// GetNewRequest gets a new HTTP request with tracing data coming from the
// provided context. Note that the provided context will NOT be used for the
// request, just to get the data.
// The request will have a new "context.Background()" context associated. This
// means that cancelling the provided context will NOT stop the request.
func GetNewRequest(injectCtx context.Context, method, url string, body io.Reader) (*http.Request, error) {
return GetNewRequestWithDifferentContext(context.Background(), injectCtx, method, url, body)
}
// GetNewRequestWithContext gets a new HTTP request with tracing data coming
// from the provided context. The request will also have the same provided
// context associated (in case the context is cancelled)
func GetNewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*http.Request, error) {
return GetNewRequestWithDifferentContext(ctx, ctx, method, url, body)
}
// GetNewRequestWithDifferentContext gets a new HTTP request with tracing
// data coming from the "injectCtx" context. The "reqCtx" context will be
// associated with the request.
//
// This method is intended to be used if you want to associate a context
// with a request, and at the same time use a different context to get the
// tracing info.
func GetNewRequestWithDifferentContext(reqCtx, injectCtx context.Context, method, url string, body io.Reader) (*http.Request, error) {
req, err := http.NewRequestWithContext(reqCtx, method, url, body)
if err != nil {
return req, err
}
InjectTracingHeaders(injectCtx, req)
return req, nil
}
// InjectTracingHeaders sets the tracing info from the context as HTTP headers
// in the provided request.
func InjectTracingHeaders(ctx context.Context, req *http.Request) {
propagator := GetPropagator()
propagator.Inject(ctx, propagation.HeaderCarrier(req.Header))
}

View File

@@ -21,7 +21,6 @@ import (
revactx "github.com/owncloud/reva/v2/pkg/ctx"
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
"github.com/rs/zerolog"
"go.opentelemetry.io/otel/propagation"
)
// ContentConnectorService is the interface to implement the "File contents"
@@ -57,7 +56,7 @@ func NewContentConnector(gws pool.Selectable[gatewayv1beta1.GatewayAPIClient], c
}
func newHttpRequest(ctx context.Context, wopiContext middleware.WopiContext, method, url, transferToken string, body io.Reader) (*http.Request, error) {
httpReq, err := http.NewRequestWithContext(ctx, method, url, body)
httpReq, err := tracing.GetNewRequestWithContext(ctx, method, url, body)
if err != nil {
return nil, err
}
@@ -72,8 +71,6 @@ func newHttpRequest(ctx context.Context, wopiContext middleware.WopiContext, met
} else {
httpReq.Header.Add("X-Access-Token", wopiContext.AccessToken)
}
tracingProp := tracing.GetPropagator()
tracingProp.Inject(ctx, propagation.HeaderCarrier(httpReq.Header))
return httpReq, nil
}

View File

@@ -11,6 +11,7 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
revactx "github.com/owncloud/reva/v2/pkg/ctx"
"github.com/owncloud/reva/v2/pkg/rgrpc/todo/pool"
)
@@ -66,7 +67,7 @@ func (s cs3) Retrieve(ctx context.Context, rID *provider.ResourceId) (io.ReadClo
ep, tt = res.Protocols[0].DownloadEndpoint, res.Protocols[0].Token
}
req, err := http.NewRequest(http.MethodGet, ep, nil)
req, err := tracing.GetNewRequest(ctx, http.MethodGet, ep, nil)
if err != nil {
return nil, err
}

View File

@@ -10,6 +10,7 @@ import (
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/errors"
"github.com/owncloud/reva/v2/pkg/bytesize"
@@ -58,7 +59,7 @@ func (s CS3) Get(ctx context.Context, path string) (io.ReadCloser, error) {
}
}
ctx = metadata.AppendToOutgoingContext(context.Background(), revactx.TokenHeader, auth)
ctx = metadata.AppendToOutgoingContext(ctx, revactx.TokenHeader, auth)
err = s.checkImageFileSize(ctx, ref)
if err != nil {
return nil, err
@@ -89,6 +90,7 @@ func (s CS3) Get(ctx context.Context, path string) (io.ReadCloser, error) {
}
httpReq, err := rhttp.NewRequest(ctx, "GET", ep, nil)
tracing.InjectTracingHeaders(ctx, httpReq)
if err != nil {
return nil, err
}

View File

@@ -11,6 +11,7 @@ import (
"net/http"
"strconv"
"github.com/owncloud/ocis/v2/ocis-pkg/tracing"
"github.com/owncloud/ocis/v2/services/thumbnails/pkg/config"
thumbnailerErrors "github.com/owncloud/ocis/v2/services/thumbnails/pkg/errors"
"github.com/owncloud/reva/v2/pkg/bytesize"
@@ -34,7 +35,7 @@ type WebDav struct {
// Get downloads the file from a webdav service
// The caller MUST make sure to close the returned ReadCloser
func (s WebDav) Get(ctx context.Context, url string) (io.ReadCloser, error) {
req, err := http.NewRequest(http.MethodGet, url, nil)
req, err := tracing.GetNewRequest(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, errors.Wrapf(err, `could not get the image "%s"`, url)
}

View File

@@ -471,7 +471,7 @@ func (g Webdav) sendThumbnailResponse(rsp *thumbnailssvc.GetThumbnailResponse, w
// Timeout: time.Second * 5,
}
dlReq, err := http.NewRequest(http.MethodGet, rsp.DataEndpoint, http.NoBody)
dlReq, err := tracing.GetNewRequest(r.Context(), http.MethodGet, rsp.DataEndpoint, http.NoBody)
if err != nil {
renderError(w, r, errInternalError(err.Error()))
logger.Error().Err(err).Msg("could not create download thumbnail request")