package otlpconfig
import (
"crypto/tls"
"fmt"
"net/http"
"net/url"
"path"
"strings"
"time"
"google.golang.org/grpc"
"google.golang.org/grpc/backoff"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/encoding/gzip"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc/internal/retry"
"go.opentelemetry.io/otel/internal/global"
)
const (
DefaultTracesPath string = "/v1/traces"
DefaultTimeout time .Duration = 10 * time .Second
)
type (
HTTPTransportProxyFunc func (*http .Request ) (*url .URL , error )
SignalConfig struct {
Endpoint string
Insecure bool
TLSCfg *tls .Config
Headers map [string ]string
Compression Compression
Timeout time .Duration
URLPath string
GRPCCredentials credentials .TransportCredentials
Proxy HTTPTransportProxyFunc
HTTPClient *http .Client
}
Config struct {
Traces SignalConfig
RetryConfig retry .Config
ReconnectionPeriod time .Duration
ServiceConfig string
DialOptions []grpc .DialOption
GRPCConn *grpc .ClientConn
}
)
func NewHTTPConfig (opts ...HTTPOption ) Config {
cfg := Config {
Traces : SignalConfig {
Endpoint : fmt .Sprintf ("%s:%d" , DefaultCollectorHost , DefaultCollectorHTTPPort ),
URLPath : DefaultTracesPath ,
Compression : NoCompression ,
Timeout : DefaultTimeout ,
},
RetryConfig : retry .DefaultConfig ,
}
cfg = ApplyHTTPEnvConfigs (cfg )
for _ , opt := range opts {
cfg = opt .ApplyHTTPOption (cfg )
}
cfg .Traces .URLPath = cleanPath (cfg .Traces .URLPath , DefaultTracesPath )
return cfg
}
func cleanPath(urlPath string , defaultPath string ) string {
tmp := strings .TrimSpace (urlPath )
if tmp == "" || tmp == "." {
return defaultPath
}
if !path .IsAbs (tmp ) {
tmp = "/" + tmp
}
return tmp
}
func NewGRPCConfig (opts ...GRPCOption ) Config {
userAgent := "OTel OTLP Exporter Go/" + otlptrace .Version ()
cfg := Config {
Traces : SignalConfig {
Endpoint : fmt .Sprintf ("%s:%d" , DefaultCollectorHost , DefaultCollectorGRPCPort ),
URLPath : DefaultTracesPath ,
Compression : NoCompression ,
Timeout : DefaultTimeout ,
},
RetryConfig : retry .DefaultConfig ,
DialOptions : []grpc .DialOption {grpc .WithUserAgent (userAgent )},
}
cfg = ApplyGRPCEnvConfigs (cfg )
for _ , opt := range opts {
cfg = opt .ApplyGRPCOption (cfg )
}
if cfg .ServiceConfig != "" {
cfg .DialOptions = append (cfg .DialOptions , grpc .WithDefaultServiceConfig (cfg .ServiceConfig ))
}
if cfg .Traces .GRPCCredentials != nil {
cfg .DialOptions = append (cfg .DialOptions , grpc .WithTransportCredentials (cfg .Traces .GRPCCredentials ))
} else if cfg .Traces .Insecure {
cfg .DialOptions = append (cfg .DialOptions , grpc .WithTransportCredentials (insecure .NewCredentials ()))
} else {
creds := credentials .NewTLS (nil )
cfg .Traces .GRPCCredentials = creds
cfg .DialOptions = append (cfg .DialOptions , grpc .WithTransportCredentials (creds ))
}
if cfg .Traces .Compression == GzipCompression {
cfg .DialOptions = append (cfg .DialOptions , grpc .WithDefaultCallOptions (grpc .UseCompressor (gzip .Name )))
}
if cfg .ReconnectionPeriod != 0 {
p := grpc .ConnectParams {
Backoff : backoff .DefaultConfig ,
MinConnectTimeout : cfg .ReconnectionPeriod ,
}
cfg .DialOptions = append (cfg .DialOptions , grpc .WithConnectParams (p ))
}
return cfg
}
type (
GenericOption interface {
ApplyHTTPOption (Config ) Config
ApplyGRPCOption (Config ) Config
private()
}
HTTPOption interface {
ApplyHTTPOption (Config ) Config
private()
}
GRPCOption interface {
ApplyGRPCOption (Config ) Config
private()
}
)
type genericOption struct {
fn func (Config ) Config
}
func (g *genericOption ) ApplyGRPCOption (cfg Config ) Config {
return g .fn (cfg )
}
func (g *genericOption ) ApplyHTTPOption (cfg Config ) Config {
return g .fn (cfg )
}
func (genericOption ) private () {}
func newGenericOption(fn func (cfg Config ) Config ) GenericOption {
return &genericOption {fn : fn }
}
type splitOption struct {
httpFn func (Config ) Config
grpcFn func (Config ) Config
}
func (g *splitOption ) ApplyGRPCOption (cfg Config ) Config {
return g .grpcFn (cfg )
}
func (g *splitOption ) ApplyHTTPOption (cfg Config ) Config {
return g .httpFn (cfg )
}
func (splitOption ) private () {}
func newSplitOption(httpFn func (cfg Config ) Config , grpcFn func (cfg Config ) Config ) GenericOption {
return &splitOption {httpFn : httpFn , grpcFn : grpcFn }
}
type httpOption struct {
fn func (Config ) Config
}
func (h *httpOption ) ApplyHTTPOption (cfg Config ) Config {
return h .fn (cfg )
}
func (httpOption ) private () {}
func NewHTTPOption (fn func (cfg Config ) Config ) HTTPOption {
return &httpOption {fn : fn }
}
type grpcOption struct {
fn func (Config ) Config
}
func (h *grpcOption ) ApplyGRPCOption (cfg Config ) Config {
return h .fn (cfg )
}
func (grpcOption ) private () {}
func NewGRPCOption (fn func (cfg Config ) Config ) GRPCOption {
return &grpcOption {fn : fn }
}
func WithEndpoint (endpoint string ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Endpoint = endpoint
return cfg
})
}
func WithEndpointURL (v string ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
u , err := url .Parse (v )
if err != nil {
global .Error (err , "otlptrace: parse endpoint url" , "url" , v )
return cfg
}
cfg .Traces .Endpoint = u .Host
cfg .Traces .URLPath = u .Path
cfg .Traces .Insecure = u .Scheme != "https"
return cfg
})
}
func WithCompression (compression Compression ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Compression = compression
return cfg
})
}
func WithURLPath (urlPath string ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .URLPath = urlPath
return cfg
})
}
func WithRetry (rc retry .Config ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .RetryConfig = rc
return cfg
})
}
func WithTLSClientConfig (tlsCfg *tls .Config ) GenericOption {
return newSplitOption (func (cfg Config ) Config {
cfg .Traces .TLSCfg = tlsCfg .Clone ()
return cfg
}, func (cfg Config ) Config {
cfg .Traces .GRPCCredentials = credentials .NewTLS (tlsCfg )
return cfg
})
}
func WithInsecure () GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Insecure = true
return cfg
})
}
func WithSecure () GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Insecure = false
return cfg
})
}
func WithHeaders (headers map [string ]string ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Headers = headers
return cfg
})
}
func WithTimeout (duration time .Duration ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Timeout = duration
return cfg
})
}
func WithProxy (pf HTTPTransportProxyFunc ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .Proxy = pf
return cfg
})
}
func WithHTTPClient (c *http .Client ) GenericOption {
return newGenericOption (func (cfg Config ) Config {
cfg .Traces .HTTPClient = c
return cfg
})
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .