github.com/sunriselayer/sunrise-da@v0.13.1-sr3/cmd/flags_misc.go (about)

     1  package cmd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"net/http/pprof"
     8  	"strings"
     9  
    10  	otelpyroscope "github.com/grafana/otel-profiling-go"
    11  	logging "github.com/ipfs/go-log/v2"
    12  	"github.com/spf13/cobra"
    13  	flag "github.com/spf13/pflag"
    14  	"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
    15  	"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
    16  
    17  	"github.com/sunriselayer/sunrise-da/logs"
    18  	"github.com/sunriselayer/sunrise-da/nodebuilder"
    19  	modp2p "github.com/sunriselayer/sunrise-da/nodebuilder/p2p"
    20  )
    21  
    22  var (
    23  	LogLevelFlag        = "log.level"
    24  	LogLevelModuleFlag  = "log.level.module"
    25  	pprofFlag           = "pprof"
    26  	tracingFlag         = "tracing"
    27  	tracingEndpointFlag = "tracing.endpoint"
    28  	tracingTlS          = "tracing.tls"
    29  	metricsFlag         = "metrics"
    30  	metricsEndpointFlag = "metrics.endpoint"
    31  	metricsTlS          = "metrics.tls"
    32  	p2pMetrics          = "p2p.metrics"
    33  	pyroscopeFlag       = "pyroscope"
    34  	pyroscopeTracing    = "pyroscope.tracing"
    35  	pyroscopeEndpoint   = "pyroscope.endpoint"
    36  )
    37  
    38  // MiscFlags gives a set of hardcoded miscellaneous flags.
    39  func MiscFlags() *flag.FlagSet {
    40  	flags := &flag.FlagSet{}
    41  
    42  	flags.String(
    43  		LogLevelFlag,
    44  		"INFO",
    45  		`DEBUG, INFO, WARN, ERROR, DPANIC, PANIC, FATAL
    46  and their lower-case forms`,
    47  	)
    48  
    49  	flags.StringSlice(
    50  		LogLevelModuleFlag,
    51  		nil,
    52  		"<module>:<level>, e.g. pubsub:debug",
    53  	)
    54  
    55  	flags.Bool(
    56  		pprofFlag,
    57  		false,
    58  		"Enables standard profiling handler (pprof) and exposes the profiles on port 6000",
    59  	)
    60  
    61  	flags.Bool(
    62  		tracingFlag,
    63  		false,
    64  		"Enables OTLP tracing with HTTP exporter",
    65  	)
    66  
    67  	flags.String(
    68  		tracingEndpointFlag,
    69  		"localhost:4318",
    70  		"Sets HTTP endpoint for OTLP traces to be exported to. Depends on '--tracing'",
    71  	)
    72  
    73  	flags.Bool(
    74  		tracingTlS,
    75  		true,
    76  		"Enable TLS connection to OTLP tracing backend",
    77  	)
    78  
    79  	flags.Bool(
    80  		metricsFlag,
    81  		false,
    82  		"Enables OTLP metrics with HTTP exporter",
    83  	)
    84  
    85  	flags.String(
    86  		metricsEndpointFlag,
    87  		"localhost:4318",
    88  		"Sets HTTP endpoint for OTLP metrics to be exported to. Depends on '--metrics'",
    89  	)
    90  
    91  	flags.Bool(
    92  		metricsTlS,
    93  		true,
    94  		"Enable TLS connection to OTLP metric backend",
    95  	)
    96  
    97  	flags.Bool(
    98  		p2pMetrics,
    99  		false,
   100  		"Enable libp2p metrics",
   101  	)
   102  
   103  	flags.Bool(
   104  		pyroscopeFlag,
   105  		false,
   106  		"Enables Pyroscope profiling",
   107  	)
   108  
   109  	flags.Bool(
   110  		pyroscopeTracing,
   111  		false,
   112  		"Enables Pyroscope tracing integration. Depends on --tracing",
   113  	)
   114  
   115  	flags.String(
   116  		pyroscopeEndpoint,
   117  		"http://localhost:4040",
   118  		"Sets HTTP endpoint for Pyroscope profiles to be exported to. Depends on '--pyroscope'",
   119  	)
   120  
   121  	return flags
   122  }
   123  
   124  // ParseMiscFlags parses miscellaneous flags from the given cmd and applies values to Env.
   125  func ParseMiscFlags(ctx context.Context, cmd *cobra.Command) (context.Context, error) {
   126  	logLevel := cmd.Flag(LogLevelFlag).Value.String()
   127  	if logLevel != "" {
   128  		level, err := logging.LevelFromString(logLevel)
   129  		if err != nil {
   130  			return ctx, fmt.Errorf("cmd: while parsing '%s': %w", LogLevelFlag, err)
   131  		}
   132  
   133  		logs.SetAllLoggers(level)
   134  	}
   135  
   136  	logModules, err := cmd.Flags().GetStringSlice(LogLevelModuleFlag)
   137  	if err != nil {
   138  		panic(err)
   139  	}
   140  	for _, ll := range logModules {
   141  		params := strings.Split(ll, ":")
   142  		if len(params) != 2 {
   143  			return ctx, fmt.Errorf("cmd: %s arg must be in form <module>:<level>, e.g. pubsub:debug", LogLevelModuleFlag)
   144  		}
   145  
   146  		err := logging.SetLogLevel(params[0], params[1])
   147  		if err != nil {
   148  			return ctx, err
   149  		}
   150  	}
   151  
   152  	ok, err := cmd.Flags().GetBool(pprofFlag)
   153  	if err != nil {
   154  		panic(err)
   155  	}
   156  
   157  	if ok {
   158  		// TODO(@Wondertan): Eventually, this should be registered on http server in RPC
   159  		//  by passing the http.Server with preregistered pprof handlers to the node.
   160  		//  Node should not register pprof itself.
   161  		go func() {
   162  			mux := http.NewServeMux()
   163  			mux.HandleFunc("/debug/pprof/", pprof.Index)
   164  			mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
   165  			mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
   166  			mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
   167  			mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
   168  			err := http.ListenAndServe("0.0.0.0:6000", mux) //nolint:gosec
   169  			if err != nil {
   170  				log.Fatalw("failed to start pprof server", "err", err)
   171  			} else {
   172  				log.Info("started pprof server on port 6000")
   173  			}
   174  		}()
   175  	}
   176  
   177  	ok, err = cmd.Flags().GetBool(pyroscopeFlag)
   178  	if err != nil {
   179  		panic(err)
   180  	}
   181  
   182  	if ok {
   183  		ctx = WithNodeOptions(ctx,
   184  			nodebuilder.WithPyroscope(
   185  				cmd.Flag(pyroscopeEndpoint).Value.String(),
   186  				NodeType(ctx),
   187  			),
   188  		)
   189  	}
   190  
   191  	ok, err = cmd.Flags().GetBool(tracingFlag)
   192  	if err != nil {
   193  		panic(err)
   194  	}
   195  
   196  	if ok {
   197  		opts := []otlptracehttp.Option{
   198  			otlptracehttp.WithCompression(otlptracehttp.GzipCompression),
   199  			otlptracehttp.WithEndpoint(cmd.Flag(tracingEndpointFlag).Value.String()),
   200  		}
   201  		if ok, err := cmd.Flags().GetBool(tracingTlS); err != nil {
   202  			panic(err)
   203  		} else if !ok {
   204  			opts = append(opts, otlptracehttp.WithInsecure())
   205  		}
   206  
   207  		pyroOpts := make([]otelpyroscope.Option, 0)
   208  		ok, err = cmd.Flags().GetBool(pyroscopeTracing)
   209  		if err != nil {
   210  			panic(err)
   211  		}
   212  		if ok {
   213  			pyroOpts = append(pyroOpts,
   214  				otelpyroscope.WithAppName("sunrise.da-node"),
   215  				otelpyroscope.WithPyroscopeURL(cmd.Flag(pyroscopeEndpoint).Value.String()),
   216  				otelpyroscope.WithRootSpanOnly(true),
   217  				otelpyroscope.WithAddSpanName(true),
   218  				otelpyroscope.WithProfileURL(true),
   219  				otelpyroscope.WithProfileBaselineURL(true),
   220  			)
   221  		}
   222  		ctx = WithNodeOptions(ctx, nodebuilder.WithTraces(opts, pyroOpts))
   223  	}
   224  
   225  	ok, err = cmd.Flags().GetBool(metricsFlag)
   226  	if err != nil {
   227  		panic(err)
   228  	}
   229  
   230  	if ok {
   231  		opts := []otlpmetrichttp.Option{
   232  			otlpmetrichttp.WithCompression(otlpmetrichttp.GzipCompression),
   233  			otlpmetrichttp.WithEndpoint(cmd.Flag(metricsEndpointFlag).Value.String()),
   234  		}
   235  		if ok, err := cmd.Flags().GetBool(metricsTlS); err != nil {
   236  			panic(err)
   237  		} else if !ok {
   238  			opts = append(opts, otlpmetrichttp.WithInsecure())
   239  		}
   240  
   241  		ctx = WithNodeOptions(ctx, nodebuilder.WithMetrics(opts, NodeType(ctx)))
   242  	}
   243  
   244  	ok, err = cmd.Flags().GetBool(p2pMetrics)
   245  	if err != nil {
   246  		panic(err)
   247  	}
   248  
   249  	if ok {
   250  		if metricsEnabled, _ := cmd.Flags().GetBool(metricsFlag); !metricsEnabled {
   251  			log.Error("--p2p.metrics used without --metrics being enabled")
   252  		} else {
   253  			ctx = WithNodeOptions(ctx, modp2p.WithMetrics())
   254  		}
   255  	}
   256  
   257  	return ctx, err
   258  }