github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/conf/tracer/tracer.go (about)

     1  package tracer
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"os"
     7  	"os/signal"
     8  	"syscall"
     9  
    10  	"github.com/google/uuid"
    11  	"github.com/pkg/errors"
    12  	"go.opentelemetry.io/otel"
    13  	"go.opentelemetry.io/otel/attribute"
    14  	"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
    15  	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
    16  	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    17  	"go.opentelemetry.io/otel/propagation"
    18  	"go.opentelemetry.io/otel/sdk/resource"
    19  	"go.opentelemetry.io/otel/sdk/trace"
    20  	semconv "go.opentelemetry.io/otel/semconv/v1.16.0"
    21  	"google.golang.org/grpc/credentials"
    22  
    23  	"github.com/machinefi/w3bstream/pkg/depends/base/consts"
    24  	"github.com/machinefi/w3bstream/pkg/depends/base/types"
    25  	"github.com/machinefi/w3bstream/pkg/depends/conf/logger"
    26  	conftls "github.com/machinefi/w3bstream/pkg/depends/conf/tls"
    27  	"github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/datatypes"
    28  )
    29  
    30  type Config struct {
    31  	// GrpcEndpoint provider grpc endpoint
    32  	GrpcEndpoint types.Endpoint `env:""`
    33  	// HttpEndpoint provider http endpoint
    34  	HttpEndpoint types.Endpoint `env:""`
    35  	// ServiceName service name, default use env `PRJ_NAME`
    36  	ServiceName string `env:""`
    37  	// ServiceVersion service version, default use env `PRJ_VERSION`
    38  	ServiceVersion string `env:""`
    39  	// InstanceID the unique id of current service, default gen uuid when trace config init
    40  	InstanceID string `env:""`
    41  	// DebugMode if enable debug mode
    42  	DebugMode datatypes.Bool `env:""`
    43  	// TLS config for connecting provider Endpoint
    44  	TLS *conftls.X509KeyPair
    45  
    46  	provider *trace.TracerProvider
    47  }
    48  
    49  func (c *Config) IsZero() bool {
    50  	return c.GrpcEndpoint.IsZero() && c.HttpEndpoint.IsZero()
    51  }
    52  
    53  func (c *Config) SetDefault() {
    54  	if !c.GrpcEndpoint.IsZero() && c.GrpcEndpoint.Port == 0 {
    55  		c.GrpcEndpoint.Port = 4317
    56  	}
    57  	if !c.HttpEndpoint.IsZero() && c.HttpEndpoint.Port == 0 {
    58  		c.HttpEndpoint.Port = 4318
    59  	}
    60  	if c.DebugMode == 0 {
    61  		c.DebugMode = datatypes.FALSE
    62  	}
    63  }
    64  
    65  func (c *Config) grpcExporter() (*otlptrace.Exporter, error) {
    66  	options := []otlptracegrpc.Option{otlptracegrpc.WithEndpoint(c.GrpcEndpoint.Host())}
    67  	if c.GrpcEndpoint.IsTLS() {
    68  		if !c.TLS.IsZero() {
    69  			options = append(options, otlptracegrpc.WithTLSCredentials(
    70  				credentials.NewClientTLSFromCert(c.TLS.TLSConfig().RootCAs, ""),
    71  			))
    72  		}
    73  	} else {
    74  		options = append(options, otlptracegrpc.WithInsecure())
    75  	}
    76  
    77  	return otlptracegrpc.New(context.Background(), options...)
    78  }
    79  
    80  func (c *Config) httpExporter() (*otlptrace.Exporter, error) {
    81  	options := []otlptracehttp.Option{otlptracehttp.WithEndpoint(c.HttpEndpoint.Host())}
    82  	if c.GrpcEndpoint.IsTLS() {
    83  		if !c.TLS.IsZero() {
    84  			options = append(options, otlptracehttp.WithTLSClientConfig(c.TLS.TLSConfig()))
    85  		}
    86  	} else {
    87  		options = append(options, otlptracehttp.WithInsecure())
    88  	}
    89  
    90  	return otlptracehttp.New(context.Background(), options...)
    91  }
    92  
    93  func (c *Config) Init() error {
    94  	if c.IsZero() {
    95  		return nil // return nil and using global.defaultTracerValue
    96  	}
    97  
    98  	if c.ServiceName == "" {
    99  		c.ServiceName = os.Getenv(consts.EnvProjectName)
   100  	}
   101  	if c.ServiceVersion == "" {
   102  		c.ServiceVersion = os.Getenv(consts.EnvProjectVersion)
   103  	}
   104  	if c.InstanceID == "" {
   105  		c.InstanceID = uuid.NewString()
   106  	}
   107  
   108  	var (
   109  		exp trace.SpanExporter
   110  		err error
   111  		ep  types.Endpoint
   112  	)
   113  
   114  	if !c.GrpcEndpoint.IsZero() {
   115  		ep = c.GrpcEndpoint
   116  		exp, err = c.grpcExporter()
   117  	} else {
   118  		ep = c.HttpEndpoint
   119  		exp, err = c.httpExporter()
   120  	}
   121  	if err != nil {
   122  		return errors.Errorf("new exporter failed: ep[%v] err[%v]", ep, err)
   123  	}
   124  
   125  	// resource
   126  	res := resource.NewWithAttributes(
   127  		semconv.SchemaURL,
   128  		semconv.ServiceNameKey.String(c.ServiceName),
   129  		semconv.ServiceVersionKey.String(c.ServiceVersion),
   130  		attribute.String("instance", c.InstanceID),
   131  	)
   132  	if err != nil {
   133  		return errors.Errorf("new otlp resource failed: %v", err)
   134  	}
   135  
   136  	options := []trace.TracerProviderOption{
   137  		trace.WithSampler(trace.AlwaysSample()),
   138  		trace.WithResource(res),
   139  		trace.WithSyncer(logger.WithSpanMapExporter(logger.OutputFilter())(logger.StdoutSpanExporter())),
   140  	}
   141  	if c.DebugMode == datatypes.TRUE {
   142  		options = append(options,
   143  			trace.WithBatcher(logger.WithSpanMapExporter(logger.OutputFilter())(exp)),
   144  		)
   145  	} else {
   146  		options = append(options,
   147  			trace.WithBatcher(logger.WithSpanMapExporter(logger.OutputFilter())(logger.WithErrIgnoreExporter()(exp))),
   148  		)
   149  	}
   150  
   151  	c.provider = trace.NewTracerProvider(options...)
   152  
   153  	// set global trace provider
   154  	otel.SetTracerProvider(c.provider)
   155  	otel.SetTextMapPropagator(propagation.Baggage{})
   156  
   157  	log.Printf("Trace provider for service `%s@%s` initialized\n", c.ServiceName, c.ServiceVersion)
   158  	go func() {
   159  		stopCh := make(chan os.Signal, 1)
   160  		signal.Notify(stopCh, os.Interrupt, syscall.SIGTERM)
   161  		<-stopCh
   162  		err := c.Shutdown(context.Background())
   163  		log.Printf("Trace provider for service `%s@%s` shutdown: %v\n", c.ServiceName, c.ServiceVersion, err)
   164  	}()
   165  
   166  	return nil
   167  }
   168  
   169  func (c *Config) Shutdown(ctx context.Context) error {
   170  	err := c.provider.Shutdown(ctx)
   171  	log.Printf("Trace provider for service `%s@%s` shutdown: %v\n", c.ServiceName, c.ServiceVersion, err)
   172  	return err
   173  }