From 5d8e3049158a6dc0ccffb9557a97035f4a2bed82 Mon Sep 17 00:00:00 2001 From: Gerry Agbobada Date: Mon, 27 Nov 2023 20:38:17 +0100 Subject: [PATCH] Update README and example codes so it compiles correctly --- README.md | 76 ++++++++++++++-------------- examples/otel/cmd/main.go | 35 +++++++------ examples/web/cmd/main.go | 33 ++++++------ examples/web/cmd/main.go.orig | 34 ++++++------- otel/autometrics/init.go | 24 +++++++++ otel/autometrics/otel.go | 5 ++ prometheus/autometrics/init.go | 16 ++++++ prometheus/autometrics/prometheus.go | 5 ++ 8 files changed, 139 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 56d44a6..1af32be 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,21 @@ import ( And then in your main function initialize the metrics ``` go + shutdown, err := autometrics.Init() + if err != nil { + log.Fatalf("could not initialize autometrics: %s", err) + } + defer shutdown(nil) +``` + +`Init` takes optional arguments to customize the metrics. The main ones are `WithBranch`, +`WithService`, `WithVersion`, and `WithCommit`; it will add relevant information on the +metrics for better intelligence: + +```go shutdown, err := autometrics.Init( - nil, - autometrics.DefBuckets, - autometrics.BuildInfo{Version: "0.4.0", Commit: "anySHA", Branch: "", Service: "myApp"}, - nil, - nil, + autometrics.WithService("myApp"), + autometrics.WithVersion("0.4.0"), ) if err != nil { log.Fatalf("could not initialize autometrics: %s", err) @@ -106,8 +115,7 @@ And then in your main function initialize the metrics defer shutdown(nil) ``` -Everything in `BuildInfo` is optional. It will add relevant information on the -metrics for better intelligence. You can use any string variable whose value is +You can use any string variable whose value is injected at build time by `ldflags` for example, or use environment variables. > **Note** @@ -270,11 +278,9 @@ import ( func main() { shutdown, err := autometrics.Init( - nil, - autometrics.DefBuckets, - autometrics.BuildInfo{Version: "0.4.0", Commit: "anySHA", Branch: "", Service: "myApp"}, - nil, - nil, + autometrics.WithVersion("0.4.0"), + autometrics.WithCommit("anySHA"), + autometrics.WithService("myApp"), ) http.Handle("/metrics", promhttp.Handler()) } @@ -375,18 +381,18 @@ import ( + "github.com/autometrics-dev/autometrics-go/otel/autometrics" ) ``` -- change the call to `autometrics.Init` to the new signature: instead of a registry, +- maybe change the call to `autometrics.Init` to the new signature: instead of a registry, the `Init` function takes a meter name for the `otel_scope` label of the exported -metric. You can use the name of the application or its version for example +metric. That means `autometrics` won't have a `WithRegistry` option anymore, but a +`WithMeterName` instead. ``` patch shutdown, err := autometrics.Init( -- nil, -+ "myApp/v2/prod", - autometrics.DefBuckets, - autometrics.BuildInfo{ Version: "2.1.37", Commit: "anySHA", Branch: "", Service: "myApp" }, - nil, - nil, +- autometrics.WithRegistry(nil), ++ autometrics.WithMeterName("myApp/v2/prod"), + autometrics.WithVersion("2.1.37"), + autimetrics.WithCommit("anySHA"), + autometrics.WithService("myApp"), ) ``` @@ -436,21 +442,17 @@ If you have a Prometheus [push gateway](https://prometheus.io/docs/instrumenting/pushing/) or an OTLP [collector](https://opentelemetry.io/docs/collector/) setup with an accessible URL, then you can directly switch from metric polling to metric pushing by -passing a non `nil` argument to `autometrics.Init` for the `pushConfiguration`: +passing the push-related options to `autometrics.Init`: ``` patch shutdown, err := autometrics.Init( - "myApp/v2/prod", - autometrics.DefBuckets, - autometrics.BuildInfo{ Version: "2.1.37", Commit: "anySHA", Branch: "", Service: "myApp" }, -- nil, -+ &autometrics.PushConfiguration{ -+ CollectorURL: "https://collector.example.com", -+ JobName: "instance_2", // You can leave the JobName out to let autometrics generate one -+ Period: 1 * time.Second, // Period is only relevant when using OpenTelemetry implementation -+ Timeout: 500 * time.Millisecond, // Timeout is only relevant when using OpenTelementry implementation -+ }, - nil, + autometrics.WithMeterName("myApp/v2/prod"), + autometrics.WithVersion("2.1.37"), + autometrics.WithService("myApp"), ++ autometrics.WithPushCollectorURL("https://collector.example.com"), ++ autometrics.WithPushJobName("instance_2"), // You can leave the JobName out to let autometrics generate one ++ autometrics.WithPushPeriod(1 * time.Second), // Period is only relevant (and available) when using OpenTelemetry implementation ++ autometrics.WithPushTimeout(500 * time.Millisecond), // Timeout is only relevant (and available) when using OpenTelementry implementation ) ``` @@ -480,12 +482,10 @@ the `Init` call: ``` patch shutdown, err := autometrics.Init( - nil, - autometrics.DefBuckets, - autometrics.BuildInfo{ Version: "2.1.37", Commit: "anySHA", Branch: "", Service: "myApp" }, - nil, -- nil, -+ autometrics.PrintLogger{}, + autometrics.WithMeterName("myApp/v2/prod"), + autometrics.WithVersion("2.1.37"), + autometrics.WithService("myApp"), ++ autometrics.WithLogger(autometrics.PrintLogger{}), ) ``` diff --git a/examples/otel/cmd/main.go b/examples/otel/cmd/main.go index 90c346d..749262a 100644 --- a/examples/otel/cmd/main.go +++ b/examples/otel/cmd/main.go @@ -26,33 +26,32 @@ var ( func main() { rand.Seed(time.Now().UnixNano()) - var pushConfiguration *autometrics.PushConfiguration + autometricsInitOpts := make([]autometrics.InitOption, 0) + if os.Getenv("AUTOMETRICS_OTLP_URL") != "" { - pushConfiguration = &autometrics.PushConfiguration{ - CollectorURL: os.Getenv("AUTOMETRICS_OTLP_URL"), + autometricsInitOpts = append(autometricsInitOpts, + autometrics.WithPushCollectorURL(os.Getenv("AUTOMETRICS_OTLP_URL")), // NOTE: Setting the JobName is useful when you fully control the instances that will run it. // Otherwise (auto-scaling scenarii), it's better to leave this value out, and let // autometrics generate an IP-based or Ulid-based identifier for you. - // JobName: "autometrics_go_otel_example", - Period: 1 * time.Second, - Timeout: 500 * time.Millisecond, - } + // autometrics.WithPushJobName("autometrics_go_otel_example"), + autometrics.WithPushPeriod(1*time.Second), + autometrics.WithPushTimeout(500*time.Millisecond), + ) } - // Everything in BuildInfo is optional. + // Every option customization is optional. // You can also use any string variable whose value is // injected at build time by ldflags. - shutdown, err := autometrics.Init( - "web-server-go-component", - autometrics.DefBuckets, - autometrics.BuildInfo{ - Version: Version, - Commit: Commit, - Branch: Branch, - }, - pushConfiguration, - autometrics.PrintLogger{}, + autometricsInitOpts = append(autometricsInitOpts, + autometrics.WithMeterName("web-server-go-component"), + autometrics.WithBranch(Branch), + autometrics.WithCommit(Commit), + autometrics.WithVersion(Version), + autometrics.WithLogger(autometrics.PrintLogger{}), ) + + shutdown, err := autometrics.Init(autometricsInitOpts...) if err != nil { log.Fatalf("Failed initialization of autometrics: %s", err) } diff --git a/examples/web/cmd/main.go b/examples/web/cmd/main.go index 193e5c6..a5a8e4d 100644 --- a/examples/web/cmd/main.go +++ b/examples/web/cmd/main.go @@ -28,30 +28,31 @@ var ( func main() { rand.Seed(time.Now().UnixNano()) + autometricsInitOpts := make([]autometrics.InitOption, 0, 6) + // Allow the application to use a push gateway with an environment variable // In production, you would do it with a command-line flag. - var pushConfiguration *autometrics.PushConfiguration if os.Getenv("AUTOMETRICS_PUSH_GATEWAY_URL") != "" { - pushConfiguration = &autometrics.PushConfiguration{ - CollectorURL: os.Getenv("AUTOMETRICS_PUSH_GATEWAY_URL"), - JobName: "autometrics_go_test", - } + autometricsInitOpts = append(autometricsInitOpts, + autometrics.WithPushCollectorURL(os.Getenv("AUTOMETRICS_PUSH_GATEWAY_URL")), + // NOTE: Setting the JobName is useful when you fully control the instances that will run it. + // Otherwise (auto-scaling scenarii), it's better to leave this value out, and let + // autometrics generate an IP-based or Ulid-based identifier for you. + autometrics.WithPushJobName("autometrics_go_test"), + ) } - // Everything in BuildInfo is optional. + // Every option customization is optional. // You can also use any string variable whose value is // injected at build time by ldflags. - shutdown, err := autometrics.Init( - nil, - autometrics.DefBuckets, - autometrics.BuildInfo{ - Version: Version, - Commit: Commit, - Branch: Branch, - }, - pushConfiguration, - autometrics.PrintLogger{}, + autometricsInitOpts = append(autometricsInitOpts, + autometrics.WithVersion(Version), + autometrics.WithCommit(Commit), + autometrics.WithBranch(Branch), + autometrics.WithLogger(autometrics.PrintLogger{}), ) + + shutdown, err := autometrics.Init(autometricsInitOpts...) if err != nil { log.Fatalf("Failed initialization of autometrics: %s", err) } diff --git a/examples/web/cmd/main.go.orig b/examples/web/cmd/main.go.orig index 89adbc6..7b75c7e 100644 --- a/examples/web/cmd/main.go.orig +++ b/examples/web/cmd/main.go.orig @@ -27,31 +27,31 @@ var ( func main() { rand.Seed(time.Now().UnixNano()) + autometricsInitOpts := make([]autometrics.InitOption, 0, 6) + // Allow the application to use a push gateway with an environment variable // In production, you would do it with a command-line flag. - var pushConfiguration *autometrics.PushConfiguration if os.Getenv("AUTOMETRICS_PUSH_GATEWAY_URL") != "" { - pushConfiguration = &autometrics.PushConfiguration{ - CollectorURL: os.Getenv("AUTOMETRICS_PUSH_GATEWAY_URL"), - JobName: "autometrics_go_test", - } + autometricsInitOpts = append(autometricsInitOpts, + autometrics.WithPushCollectorURL(os.Getenv("AUTOMETRICS_PUSH_GATEWAY_URL")), + // NOTE: Setting the JobName is useful when you fully control the instances that will run it. + // Otherwise (auto-scaling scenarii), it's better to leave this value out, and let + // autometrics generate an IP-based or Ulid-based identifier for you. + autometrics.WithPushJobName("autometrics_go_test"), + ) } - // Everything in BuildInfo is optional. + // Every option customization is optional. // You can also use any string variable whose value is // injected at build time by ldflags. - shutdown, err := autometrics.Init( - nil, - autometrics.DefBuckets, - autometrics.BuildInfo{ - Version: Version, - Commit: Commit, - Branch: Branch, - Service: "autometrics-go-example-prometheus" - }, - pushConfiguration, - autometrics.PrintLogger{}, + autometricsInitOpts = append(autometricsInitOpts, + autometrics.WithVersion(Version), + autometrics.WithCommit(Commit), + autometrics.WithBranch(Branch), + autometrics.WithLogger(autometrics.PrintLogger{}), ) + + shutdown, err := autometrics.Init(autometricsInitOpts...) if err != nil { log.Fatalf("Failed initialization of autometrics: %s", err) } diff --git a/otel/autometrics/init.go b/otel/autometrics/init.go index 3d5999d..48f592b 100644 --- a/otel/autometrics/init.go +++ b/otel/autometrics/init.go @@ -1,6 +1,8 @@ package autometrics // import "github.com/autometrics-dev/autometrics-go/prometheus/autometrics" import ( + "errors" + "strings" "time" am "github.com/autometrics-dev/autometrics-go/pkg/autometrics" @@ -62,6 +64,7 @@ func (fn initOptionFunc) Apply(initArgs *initArguments) error { // The default value is an empty string func WithMeterName(currentMeterName string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.meterName = currentMeterName return nil }) } @@ -72,6 +75,7 @@ func WithMeterName(currentMeterName string) InitOption { // autometrics-specific events. func WithLogger(logger log.Logger) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.logger = logger return nil }) } @@ -81,6 +85,7 @@ func WithLogger(logger log.Logger) InitOption { // The default value is an empty string. func WithCommit(currentCommit string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.commit = currentCommit return nil }) } @@ -90,6 +95,7 @@ func WithCommit(currentCommit string) InitOption { // The default value is an empty string. func WithVersion(currentVersion string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.version = currentVersion return nil }) } @@ -99,6 +105,7 @@ func WithVersion(currentVersion string) InitOption { // The default value is an empty string. func WithBranch(currentBranch string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.branch = currentBranch return nil }) } @@ -108,6 +115,7 @@ func WithBranch(currentBranch string) InitOption { // The default value is an empty string. func WithService(currentService string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.service = currentService return nil }) } @@ -117,6 +125,7 @@ func WithService(currentService string) InitOption { // The default value is an empty string. func WithRepoURL(currentRepoURL string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoURL = currentRepoURL return nil }) } @@ -126,6 +135,7 @@ func WithRepoURL(currentRepoURL string) InitOption { // The default value is an empty string. func WithRepoProvider(currentRepoProvider string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoProvider = currentRepoProvider return nil }) } @@ -138,6 +148,10 @@ func WithRepoProvider(currentRepoProvider string) InitOption { // The default value is an empty string, which also disables metric pushing. func WithPushCollectorURL(pushCollectorURL string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + if strings.Contains(pushCollectorURL, "/metrics/jobs") { + return errors.New("set push collector URL: the URL should not contain the /metrics/jobs part") + } + initArgs.pushCollectorURL = pushCollectorURL return nil }) } @@ -154,6 +168,7 @@ func WithPushCollectorURL(pushCollectorURL string) InitOption { // The default value is an empty string, which will make autometrics generate a Ulid func WithPushJobName(pushJobName string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushJobName = pushJobName return nil }) } @@ -163,6 +178,7 @@ func WithPushJobName(pushJobName string) InitOption { // The default value is 10 seconds. func WithPushPeriod(pushPeriod time.Duration) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushPeriod = pushPeriod return nil }) } @@ -172,6 +188,7 @@ func WithPushPeriod(pushPeriod time.Duration) InitOption { // The default value is 5 seconds. func WithPushTimeout(pushTimeout time.Duration) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushTimeout = pushTimeout return nil }) } @@ -181,6 +198,7 @@ func WithPushTimeout(pushTimeout time.Duration) InitOption { // The default value is to use gRPC. func WithPushHTTP() InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushUseHTTP = true return nil }) } @@ -191,6 +209,7 @@ func WithPushHTTP() InitOption { // The default value is to use secure channels only. func WithPushInsecure() InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushInsecure = true return nil }) } @@ -201,6 +220,7 @@ func WithPushInsecure() InitOption { // The default value is empty. func WithPushHeaders(headers map[string]string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushHeaders = headers return nil }) } @@ -213,6 +233,10 @@ func WithPushHeaders(headers map[string]string) InitOption { // The default value is [autometrics.DefBuckets] func WithHistogramBuckets(histogramBuckets []float64) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + if len(histogramBuckets) == 0 { + return errors.New("setting histogram buckets: the histogram buckets should have at least 1 value.") + } + initArgs.histogramBuckets = histogramBuckets return nil }) } diff --git a/otel/autometrics/otel.go b/otel/autometrics/otel.go index 3202e73..7d66dec 100644 --- a/otel/autometrics/otel.go +++ b/otel/autometrics/otel.go @@ -153,6 +153,11 @@ func Init(initOpts ...InitOption) (context.CancelCauseFunc, error) { } } + err = initArgs.Validate() + if err != nil { + return nil, fmt.Errorf("init options validation: %w", err) + } + autometrics.SetCommit(initArgs.commit) autometrics.SetVersion(initArgs.version) autometrics.SetBranch(initArgs.branch) diff --git a/prometheus/autometrics/init.go b/prometheus/autometrics/init.go index 707df95..91e6380 100644 --- a/prometheus/autometrics/init.go +++ b/prometheus/autometrics/init.go @@ -1,6 +1,8 @@ package autometrics // import "github.com/autometrics-dev/autometrics-go/prometheus/autometrics" import ( + "errors" + am "github.com/autometrics-dev/autometrics-go/pkg/autometrics" "github.com/autometrics-dev/autometrics-go/pkg/autometrics/log" "github.com/prometheus/client_golang/prometheus" @@ -52,6 +54,7 @@ func (fn initOptionFunc) Apply(initArgs *initArguments) error { // prometheus default registry. func WithRegistry(registry *prometheus.Registry) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.registry = registry return nil }) } @@ -62,6 +65,7 @@ func WithRegistry(registry *prometheus.Registry) InitOption { // autometrics-specific events. func WithLogger(logger log.Logger) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.logger = logger return nil }) } @@ -71,6 +75,7 @@ func WithLogger(logger log.Logger) InitOption { // The default value is an empty string. func WithCommit(currentCommit string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.commit = currentCommit return nil }) } @@ -80,6 +85,7 @@ func WithCommit(currentCommit string) InitOption { // The default value is an empty string. func WithVersion(currentVersion string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.version = currentVersion return nil }) } @@ -89,6 +95,7 @@ func WithVersion(currentVersion string) InitOption { // The default value is an empty string. func WithBranch(currentBranch string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.branch = currentBranch return nil }) } @@ -98,6 +105,7 @@ func WithBranch(currentBranch string) InitOption { // The default value is an empty string. func WithService(currentService string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.service = currentService return nil }) } @@ -107,6 +115,7 @@ func WithService(currentService string) InitOption { // The default value is an empty string. func WithRepoURL(currentRepoURL string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoURL = currentRepoURL return nil }) } @@ -116,6 +125,7 @@ func WithRepoURL(currentRepoURL string) InitOption { // The default value is an empty string. func WithRepoProvider(currentRepoProvider string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoProvider = currentRepoProvider return nil }) } @@ -128,6 +138,7 @@ func WithRepoProvider(currentRepoProvider string) InitOption { // The default value is an empty string, which also disables metric pushing. func WithPushCollectorURL(pushCollectorURL string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushCollectorURL = pushCollectorURL return nil }) } @@ -144,6 +155,7 @@ func WithPushCollectorURL(pushCollectorURL string) InitOption { // The default value is an empty string, which will make autometrics generate a Ulid func WithPushJobName(pushJobName string) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushJobName = pushJobName return nil }) } @@ -156,6 +168,10 @@ func WithPushJobName(pushJobName string) InitOption { // The default value is [autometrics.DefBuckets] func WithHistogramBuckets(histogramBuckets []float64) InitOption { return initOptionFunc(func(initArgs *initArguments) error { + if len(histogramBuckets) == 0 { + return errors.New("setting histogram buckets: the buckets for the histogram must have at least one value.") + } + initArgs.histogramBuckets = histogramBuckets return nil }) } diff --git a/prometheus/autometrics/prometheus.go b/prometheus/autometrics/prometheus.go index 8ab2101..5de2cce 100644 --- a/prometheus/autometrics/prometheus.go +++ b/prometheus/autometrics/prometheus.go @@ -153,6 +153,11 @@ func Init(initOpts ...InitOption) (context.CancelCauseFunc, error) { } } + err := initArgs.Validate() + if err != nil { + return nil, fmt.Errorf("init options validation: %w", err) + } + autometrics.SetCommit(initArgs.commit) autometrics.SetVersion(initArgs.version) autometrics.SetBranch(initArgs.branch)