core/metrics/pyroscope.go
package metrics
import (
otelpyroscope "github.com/grafana/otel-profiling-go"
"github.com/grafana/pyroscope-go"
"github.com/synapsecns/sanguine/core"
"github.com/synapsecns/sanguine/core/config"
"github.com/synapsecns/sanguine/core/metrics/internal"
"go.opentelemetry.io/otel/trace"
"os"
)
// StartPyroscope starts the pyroscope profiler.
// this will not run if the pyroscope endpoint is not set.
func StartPyroscope(info config.BuildInfo) *pyroscope.Profiler {
if !core.HasEnv(internal.PyroscopeEndpoint) {
return nil
}
// note: because pyroscope is a profiler, we cannot use buildinfo for the application name.
pf, err := pyroscope.Start(pyroscope.Config{
ApplicationName: info.Name(),
// replace this with the address of pyroscope server
ServerAddress: os.Getenv(internal.PyroscopeEndpoint),
// you can disable logging by setting this to nil
Logger: pyroscopeLogger{},
// Uncomment this line if you're having issues:
//Logger: pyroscope.StandardLogger,
// you can provide static tags via a map:
Tags: map[string]string{
"hostname": os.Getenv("HOSTNAME"),
"version": info.Version(),
"commit": info.Commit(),
},
ProfileTypes: []pyroscope.ProfileType{
// these profile types are enabled by default:
pyroscope.ProfileCPU,
pyroscope.ProfileAllocObjects,
pyroscope.ProfileAllocSpace,
pyroscope.ProfileInuseObjects,
pyroscope.ProfileInuseSpace,
},
})
if err != nil {
logger.Warn(err)
}
return pf
}
type pyroscopeLogger struct{}
func (p pyroscopeLogger) Infof(_ string, _ ...interface{}) {
// do nothing
}
func (p pyroscopeLogger) Debugf(_ string, _ ...interface{}) {
// do nothing
}
func (p pyroscopeLogger) Errorf(str string, args ...interface{}) {
logger.Warnf(str, args...)
}
var _ pyroscope.Logger = &pyroscopeLogger{}
// PyroscopeWrapTracerProvider wraps the tracer provider with pyroscope.
// The traceProvider is not affected if the pyroscope endpoint is not set.
func PyroscopeWrapTracerProvider(provider trace.TracerProvider, buildInfo config.BuildInfo, extraOpts ...otelpyroscope.Option) trace.TracerProvider {
if !core.HasEnv(pyroscopeEndpoint) {
return provider
}
opts := append([]otelpyroscope.Option{
otelpyroscope.WithAppName(buildInfo.Name()),
otelpyroscope.WithPyroscopeURL(os.Getenv(pyroscopeEndpoint)),
otelpyroscope.WithRootSpanOnly(true),
// we only need this sort of linkinf for the jaeger ui.
otelpyroscope.WithProfileURL(core.HasEnv(internal.PyroscopeJaegerUIEnabled)),
otelpyroscope.WithProfileBaselineURL(core.HasEnv(internal.PyroscopeJaegerUIEnabled)),
}, extraOpts...)
return otelpyroscope.NewTracerProvider(provider, opts...)
}