diff --git a/e2e/basic/basic.go b/e2e/basic/basic.go index 66ef354..96f45bc 100644 --- a/e2e/basic/basic.go +++ b/e2e/basic/basic.go @@ -12,6 +12,7 @@ import ( "github.com/TykTechnologies/opentelemetry/config" "github.com/TykTechnologies/opentelemetry/trace" + "github.com/sirupsen/logrus" "go.opentelemetry.io/otel/attribute" ) @@ -22,14 +23,14 @@ func main() { cfg := config.OpenTelemetry{ Enabled: true, Exporter: "grpc", - Endpoint: "otel-collector:4317", + Endpoint: "localhost:4317", ConnectionTimeout: 10, ResourceName: "e2e-basic", } log.Println("Initializing OpenTelemetry at e2e-basic:", cfg.Endpoint) - provider, err := trace.NewProvider(trace.WithContext(ctx), trace.WithConfig(&cfg)) + provider, err := trace.NewProvider(trace.WithContext(ctx), trace.WithConfig(&cfg), trace.WithLogger(logrus.New())) if err != nil { log.Printf("error on otel provider init %s", err.Error()) return diff --git a/e2e/basic/go.mod b/e2e/basic/go.mod index 6d5c2d1..342823d 100644 --- a/e2e/basic/go.mod +++ b/e2e/basic/go.mod @@ -4,6 +4,7 @@ go 1.19 require ( github.com/TykTechnologies/opentelemetry v0.0.0-20230627083938-06db14948ffe + github.com/sirupsen/logrus v1.9.3 go.opentelemetry.io/otel v1.16.0 ) diff --git a/e2e/basic/go.sum b/e2e/basic/go.sum index 7261672..c29682f 100644 --- a/e2e/basic/go.sum +++ b/e2e/basic/go.sum @@ -53,6 +53,7 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -146,6 +147,7 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1: github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -289,6 +291,7 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/trace/exporter.go b/trace/exporter.go index fce3e56..ba2ae56 100644 --- a/trace/exporter.go +++ b/trace/exporter.go @@ -3,6 +3,9 @@ package trace import ( "context" "fmt" + "net" + "net/http" + "strings" "time" "github.com/TykTechnologies/opentelemetry/config" @@ -13,24 +16,44 @@ import ( sdktrace "go.opentelemetry.io/otel/sdk/trace" ) -func exporterFactory(ctx context.Context, cfg *config.OpenTelemetry) (sdktrace.SpanExporter, error) { +func exporterFactory(ctx context.Context, provider *traceProvider) (sdktrace.SpanExporter, error) { var client otlptrace.Client - switch cfg.Exporter { + switch provider.cfg.Exporter { case config.GRPCEXPORTER: - client = newGRPCClient(ctx, cfg) + client = newGRPCClient(ctx, provider.cfg) + + if !isGRPCEndpointActive(provider.cfg.Endpoint) { + provider.logger.Error("GRPC endpoint: ", provider.cfg.Endpoint, " is down") + } case config.HTTPEXPORTER: - client = newHTTPClient(ctx, cfg) + client = newHTTPClient(ctx, provider.cfg) + + if !isHTTPEndpointActive(provider.cfg.Endpoint) { + provider.logger.Error("HTTP endpoint: ", provider.cfg.Endpoint, " is down") + } default: - return nil, fmt.Errorf("invalid exporter type: %s", cfg.Exporter) + return nil, fmt.Errorf("invalid exporter type: %s", provider.cfg.Exporter) } - ctx, cancel := context.WithTimeout(ctx, time.Duration(cfg.ConnectionTimeout)*time.Second) + ctx, cancel := context.WithTimeout(ctx, time.Duration(provider.cfg.ConnectionTimeout)*time.Second) defer cancel() // Create the trace exporter return otlptrace.New(ctx, client) } +func isGRPCEndpointActive(endpoint string) bool { + conn, err := net.DialTimeout("tcp", endpoint, time.Second) + + if err != nil { + return false + } + + conn.Close() + + return true +} + func newGRPCClient(ctx context.Context, cfg *config.OpenTelemetry) otlptrace.Client { return otlptracegrpc.NewClient( otlptracegrpc.WithEndpoint(cfg.Endpoint), @@ -39,6 +62,27 @@ func newGRPCClient(ctx context.Context, cfg *config.OpenTelemetry) otlptrace.Cli ) } +func isHTTPEndpointActive(endpoint string) bool { + client := http.Client{ + Timeout: time.Second, + } + + // Check if the endpoint has a protocol scheme (http/https), if not, append one + if !strings.HasPrefix(strings.ToLower(endpoint), "http") { + endpoint = "http://" + endpoint + } + + // Using Head method to avoid downloading the whole body + req, err := http.NewRequestWithContext(context.Background(), http.MethodHead, endpoint, nil) + if err != nil { + return false + } + + _, err = client.Do(req) + + return err == nil +} + func newHTTPClient(ctx context.Context, cfg *config.OpenTelemetry) otlptrace.Client { return otlptracehttp.NewClient( otlptracehttp.WithEndpoint(cfg.Endpoint), diff --git a/trace/exporter_test.go b/trace/exporter_test.go index bcfb204..85ab7d2 100644 --- a/trace/exporter_test.go +++ b/trace/exporter_test.go @@ -109,8 +109,11 @@ func Test_ExporterFactory(t *testing.T) { tc.givenConfig.Endpoint = endpoint } - - exporter, err := exporterFactory(ctx, tc.givenConfig) + provider := &traceProvider{ + cfg: tc.givenConfig, + logger: &mockLogger{}, + } + exporter, err := exporterFactory(ctx, provider) if tc.expectedErr != nil { assert.NotNil(t, err) assert.Equal(t, tc.expectedErr.Error(), err.Error()) diff --git a/trace/provider.go b/trace/provider.go index 006895f..c76133f 100644 --- a/trace/provider.go +++ b/trace/provider.go @@ -89,7 +89,7 @@ func NewProvider(opts ...Option) (Provider, error) { } // create the exporter - here's where connecting to the collector happens - exporter, err := exporterFactory(provider.ctx, provider.cfg) + exporter, err := exporterFactory(provider.ctx, provider) if err != nil { provider.logger.Error("failed to create exporter", err) return provider, fmt.Errorf("failed to create exporter: %w", err) @@ -133,7 +133,6 @@ func NewProvider(opts ...Option) (Provider, error) { }) provider.logger.Info("Tracer provider initialized successfully") - return provider, nil }