diff --git a/cmd/defaults.yaml b/cmd/defaults.yaml index 45d598ee86..0f56ddb8ba 100644 --- a/cmd/defaults.yaml +++ b/cmd/defaults.yaml @@ -25,6 +25,18 @@ Tracing: # The endpoint of the otel collector endpoint Endpoint: "" #ZITADEL_TRACING_ENDPOINT +# Profiler enables capturing profiling data (CPU, Memory, ...) for performance analysis +Profiler: + # Choose one of "google" and "none" + # Depending on the type there are different configuration options + # for type 'google' + # ProjectID: google-project-id + # + # type 'none' or '' disables profiling + Type: none # ZITADEL_PROFILER_TYPE + # projectID for google + ProjectID: '' # ZITADEL_PROFILER_PROJECTID + Telemetry: # As long as Enabled is true, ZITADEL tries to send usage data to the configured Telemetry.Endpoints. # Data is projected by ZITADEL even if Enabled is false. diff --git a/cmd/start/config.go b/cmd/start/config.go index 71175024e6..1e36d3310a 100644 --- a/cmd/start/config.go +++ b/cmd/start/config.go @@ -31,6 +31,7 @@ import ( "github.com/zitadel/zitadel/internal/query/projection" static_config "github.com/zitadel/zitadel/internal/static/config" metrics "github.com/zitadel/zitadel/internal/telemetry/metrics/config" + profiler "github.com/zitadel/zitadel/internal/telemetry/profiler/config" tracing "github.com/zitadel/zitadel/internal/telemetry/tracing/config" ) @@ -49,6 +50,7 @@ type Config struct { Database database.Config Tracing tracing.Config Metrics metrics.Config + Profiler profiler.Config Projections projection.Config Auth auth_es.Config Admin admin_es.Config @@ -114,6 +116,9 @@ func MustNewConfig(v *viper.Viper) *Config { err = config.Metrics.NewMeter() logging.OnError(err).Fatal("unable to set meter") + err = config.Profiler.NewProfiler() + logging.OnError(err).Fatal("unable to set profiler") + id.Configure(config.Machine) actions.SetHTTPConfig(&config.Actions.HTTP) diff --git a/go.mod b/go.mod index 0d17be8be0..dae92417fa 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/zitadel/zitadel go 1.22.2 require ( + cloud.google.com/go/profiler v0.4.1 cloud.google.com/go/storage v1.43.0 github.com/BurntSushi/toml v1.4.0 github.com/DATA-DOG/go-sqlmock v1.5.2 @@ -103,7 +104,7 @@ require ( github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-tpm v0.9.0 // indirect - github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd // indirect + github.com/google/pprof v0.0.0-20240528025155-186aa0362fba // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect diff --git a/go.sum b/go.sum index ab2038280b..16c1046d56 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuA cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= cloud.google.com/go/monitoring v1.19.0 h1:NCXf8hfQi+Kmr56QJezXRZ6GPb80ZI7El1XztyUuLQI= cloud.google.com/go/monitoring v1.19.0/go.mod h1:25IeMR5cQ5BoZ8j1eogHE5VPJLlReQ7zFp5OiLgiGZw= +cloud.google.com/go/profiler v0.4.1 h1:Q7+lOvikTGMJ/IAWocpYYGit4SIIoILmVZfEEWTORSY= +cloud.google.com/go/profiler v0.4.1/go.mod h1:LBrtEX6nbvhv1w/e5CPZmX9ajGG9BGLtGbv56Tg4SHs= cloud.google.com/go/storage v1.43.0 h1:CcxnSohZwizt4LCzQHWvBf1/kvtHUn7gk9QERXPyXFs= cloud.google.com/go/storage v1.43.0/go.mod h1:ajvxEa7WmZS1PxvKRq4bq0tFT3vMd502JwstCcYv0Q0= cloud.google.com/go/trace v1.10.7 h1:gK8z2BIJQ3KIYGddw9RJLne5Fx0FEXkrEQzPaeEYVvk= @@ -313,8 +315,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba h1:ql1qNgCyOB7iAEk8JTNM+zJrgIbnyCKX/wdlyPufP5g= +github.com/google/pprof v0.0.0-20240528025155-186aa0362fba/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= diff --git a/internal/telemetry/profiler/config/config.go b/internal/telemetry/profiler/config/config.go new file mode 100644 index 0000000000..5ca0023a82 --- /dev/null +++ b/internal/telemetry/profiler/config/config.go @@ -0,0 +1,30 @@ +package config + +import ( + "github.com/zitadel/zitadel/internal/telemetry/profiler/google" + "github.com/zitadel/zitadel/internal/zerrors" +) + +type Config struct { + Type string + Config map[string]interface{} `mapstructure:",remain"` +} + +var profiler = map[string]func(map[string]interface{}) error{ + "google": google.NewProfiler, + "none": NoProfiler, + "": NoProfiler, +} + +func (c *Config) NewProfiler() error { + t, ok := profiler[c.Type] + if !ok { + return zerrors.ThrowInternalf(nil, "PROFI-Dfqsx", "config type %s not supported", c.Type) + } + + return t(c.Config) +} + +func NoProfiler(_ map[string]interface{}) error { + return nil +} diff --git a/internal/telemetry/profiler/google/profiler.go b/internal/telemetry/profiler/google/profiler.go new file mode 100644 index 0000000000..a1e1855d5e --- /dev/null +++ b/internal/telemetry/profiler/google/profiler.go @@ -0,0 +1,26 @@ +package google + +import ( + "cloud.google.com/go/profiler" + + "github.com/zitadel/zitadel/cmd/build" +) + +type Config struct { + ProjectID string +} + +func NewProfiler(rawConfig map[string]interface{}) (err error) { + c := new(Config) + c.ProjectID, _ = rawConfig["projectid"].(string) + return c.NewProfiler() +} + +func (c *Config) NewProfiler() (err error) { + cfg := profiler.Config{ + Service: "zitadel", + ServiceVersion: build.Version(), + ProjectID: c.ProjectID, + } + return profiler.Start(cfg) +}