From ebefae186533b74832c140badcde5dfc5be92dff Mon Sep 17 00:00:00 2001 From: Gerry Agbobada <10496163+gagbo@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:07:49 +0100 Subject: [PATCH] Use WithFoo() arguments to autometrics.Init instead of long function signature (#83) * Use WithFoo() arguments to autometrics.Init instead of long function signature * Update README and example codes so it compiles correctly * Update Changelog * Remove dead code * Small array capacity optimization * Read Otel metric export configuration from env vars --- CHANGELOG.md | 8 + README.md | 76 ++++---- examples/otel/cmd/main.go | 35 ++-- examples/web/cmd/main.go | 33 ++-- examples/web/cmd/main.go.orig | 34 ++-- go.mod | 1 - go.sum | 58 ------- go.work.sum | 1 + otel/autometrics/init.go | 248 +++++++++++++++++++++++++++ otel/autometrics/otel.go | 172 ++++++++----------- pkg/autometrics/global_state.go | 10 ++ pkg/autometrics/main.go | 21 --- prometheus/autometrics/init.go | 182 ++++++++++++++++++++ prometheus/autometrics/prometheus.go | 89 ++++------ 14 files changed, 646 insertions(+), 322 deletions(-) create mode 100644 otel/autometrics/init.go create mode 100644 prometheus/autometrics/init.go diff --git a/CHANGELOG.md b/CHANGELOG.md index ab5e8c0..446e739 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,20 @@ versioning](https://go.dev/doc/modules/version-numbers). ### Changed +- [All] The `Init` API has changed, to use arguments of type `InitOption` instead of using + separate types. This means all default arguments do not need to be mentioned in the + call of `Init`, and for the rest `autometrics` provides `With...` functions that allow + customization. + ### Deprecated ### Removed ### Fixed +- Fix a bug where the repository provider label would overwrite the repository URL label + instead of using its own label. + ### Security ## [0.9.0](https://github.com/autometrics-dev/autometrics-go/releases/tag/v0.9.0) 2023-11-17 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..da56ca4 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, 6) + 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/go.mod b/go.mod index 71b3914..3a8c2e4 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,6 @@ require ( github.com/dave/jennifer v1.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.5.3 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 diff --git a/go.sum b/go.sum index 834caeb..85bade4 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ github.com/alexflint/go-arg v1.4.3 h1:9rwwEBpMXfKQKceuZfYcwuc/7YY7tWJbFsgG5cAU/uo= github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258mRXkFH4IA= -github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM= github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw= github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= @@ -10,8 +9,6 @@ github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqy github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/dave/dst v0.27.2 h1:4Y5VFTkhGLC1oddtNwuxxe36pnyLxMFXT51FOzH8Ekc= -github.com/dave/dst v0.27.2/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= github.com/dave/jennifer v1.6.0 h1:MQ/6emI2xM7wt0tJzJzyUik2Q3Tcn2eE0vtYgh4GPVI= @@ -20,15 +17,11 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -36,14 +29,10 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU= @@ -51,20 +40,12 @@ github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNs github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q= github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -74,84 +55,45 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -go.opentelemetry.io/otel v1.17.0 h1:MW+phZ6WZ5/uk2nd93ANk/6yJ+dVrvNWUjGhnnFU5jM= -go.opentelemetry.io/otel v1.17.0/go.mod h1:I2vmBGtFaODIVMBSTPVDlJSzBDNf93k60E6Ft0nyjo0= go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs= go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.40.0 h1:MZbjiZeMmn5wFMORhozpouGKDxj9POHTuU5UA8msBQk= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.40.0/go.mod h1:C7tOYVCJmrDTCwxNny0MuUtnDIR3032vFHYke0F2ZrU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0 h1:ZtfnDL+tUrs1F0Pzfwbg2d59Gru9NCH3bgSHBM6LDwU= go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.42.0/go.mod h1:hG4Fj/y8TR/tlEDREo8tWstl9fO9gcFkn4xrx0Io8xU= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.40.0 h1:q3FNPi8FLQVjLlmV+WWHQfH9ZCCtQIS0O/+dn1+4cJ4= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.40.0/go.mod h1:rmx4n0uSIAkKBeQYkygcv9dENAlL2/tv3OSq68h1JAo= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0 h1:NmnYCiR0qNufkldjVvyQfZTHSdzeHoZ41zggMsdMcLM= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.42.0/go.mod h1:UVAO61+umUsHLtYb8KXXRoHtxUkdOPkYidzW3gipRLQ= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.40.0 h1:SZaSbubADNhH2Gxm+1GaZ/cFsGiYefZoodMMX79AOd4= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.40.0/go.mod h1:N65FzQDfQH7NY7umgb0U+7ypGKVYKwwE24L6KXT4OA8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0 h1:wNMDy/LVGLj2h3p6zg4d0gypKfWKSWI14E1C4smOgl8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.42.0/go.mod h1:YfbDdXAAkemWJK3H/DshvlrxqFB2rtW4rY6ky/3x/H0= -go.opentelemetry.io/otel/exporters/prometheus v0.40.0 h1:9h6lCssr1j5aYVvWT6oc+ERB6R034zmsHjBRLyxrAR8= -go.opentelemetry.io/otel/exporters/prometheus v0.40.0/go.mod h1:5USWZ0ovyQB5CIM3IO3bGRSoDPMXiT3t+15gu8Zo9HQ= go.opentelemetry.io/otel/exporters/prometheus v0.42.0 h1:jwV9iQdvp38fxXi8ZC+lNpxjK16MRcZlpDYvbuO1FiA= go.opentelemetry.io/otel/exporters/prometheus v0.42.0/go.mod h1:f3bYiqNqhoPxkvI2LrXqQVC546K7BuRDL/kKuxkujhA= -go.opentelemetry.io/otel/metric v1.17.0 h1:iG6LGVz5Gh+IuO0jmgvpTB6YVrCGngi8QGm+pMd8Pdc= -go.opentelemetry.io/otel/metric v1.17.0/go.mod h1:h4skoxdZI17AxwITdmdZjjYJQH5nzijUUjm+wtPph5o= go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE= go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8= -go.opentelemetry.io/otel/sdk v1.17.0 h1:FLN2X66Ke/k5Sg3V623Q7h7nt3cHXaW1FOvKKrW0IpE= -go.opentelemetry.io/otel/sdk v1.17.0/go.mod h1:U87sE0f5vQB7hwUoW98pW5Rz4ZDuCFBZFNUBlSgmDFQ= go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/sdk/metric v0.40.0 h1:qOM29YaGcxipWjL5FzpyZDpCYrDREvX0mVlmXdOjCHU= -go.opentelemetry.io/otel/sdk/metric v0.40.0/go.mod h1:dWxHtdzdJvg+ciJUKLTKwrMe5P6Dv3FyDbh8UkfgkVs= go.opentelemetry.io/otel/sdk/metric v1.19.0 h1:EJoTO5qysMsYCa+w4UghwFV/ptQgqSL/8Ni+hx+8i1k= go.opentelemetry.io/otel/sdk/metric v1.19.0/go.mod h1:XjG0jQyFJrv2PbMvwND7LwCEhsJzCzV5210euduKcKY= -go.opentelemetry.io/otel/trace v1.17.0 h1:/SWhSRHmDPOImIAetP1QAeMnZYiQXrTy4fMMYOdSKWQ= -go.opentelemetry.io/otel/trace v1.17.0/go.mod h1:I/4vKTgFclIsXRVucpH25X0mpFSczM7aHeaz0ZBLWjY= go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg= go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -golang.org/x/exp v0.0.0-20230223210539-50820d90acfd h1:wtFuj4DoOcAdb82Zh2PI90xiaqgp7maYA7KxjQXVtkY= -golang.org/x/exp v0.0.0-20230223210539-50820d90acfd/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw= google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM= -google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405 h1:HJMDndgxest5n2y77fnErkM62iUsptE/H8p0dC2Huo4= google.golang.org/genproto/googleapis/api v0.0.0-20231030173426-d783a09b4405/go.mod h1:oT32Z4o8Zv2xPQTg0pbVaPr0MPOH6f14RgXt7zfIpwg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik= google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= diff --git a/go.work.sum b/go.work.sum index cf32a8a..cb6f727 100644 --- a/go.work.sum +++ b/go.work.sum @@ -355,6 +355,7 @@ github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3x github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= diff --git a/otel/autometrics/init.go b/otel/autometrics/init.go new file mode 100644 index 0000000..057638d --- /dev/null +++ b/otel/autometrics/init.go @@ -0,0 +1,248 @@ +package autometrics // import "github.com/autometrics-dev/autometrics-go/prometheus/autometrics" + +import ( + "errors" + "strings" + "time" + + am "github.com/autometrics-dev/autometrics-go/pkg/autometrics" + "github.com/autometrics-dev/autometrics-go/pkg/autometrics/log" +) + +type initArguments struct { + meterName string + histogramBuckets []float64 + logger log.Logger + commit string + version string + branch string + service string + repoURL string + repoProvider string + pushCollectorURL string + pushPeriod time.Duration + pushTimeout time.Duration + pushUseHTTP bool + pushHeaders map[string]string + pushInsecure bool + pushJobName string +} + +func defaultInitArguments() initArguments { + return initArguments{ + histogramBuckets: am.DefBuckets, + logger: log.NoOpLogger{}, + pushJobName: am.DefaultJobName(), + pushPeriod: defaultPushPeriod, + pushTimeout: defaultPushTimeout, + pushUseHTTP: false, + pushInsecure: false, + } +} + +func (initArgs initArguments) Validate() error { + return nil +} + +func (initArgs initArguments) HasPushEnabled() bool { + return initArgs.pushCollectorURL != "" +} + +type InitOption interface { + Apply(*initArguments) error +} + +type initOptionFunc func(*initArguments) error + +func (fn initOptionFunc) Apply(initArgs *initArguments) error { + return fn(initArgs) +} + +// WithMeterName sets the name of the meter to use for opentelemetry metrics. +// The name will be prefixed with "autometrics/" to help figure out the origin. +// +// The default value is an empty string +func WithMeterName(currentMeterName string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.meterName = currentMeterName + return nil + }) +} + +// WithLogger sets the logger to use when initializing autometrics. +// +// The default logger is a no-op logger that will never log +// autometrics-specific events. +func WithLogger(logger log.Logger) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.logger = logger + return nil + }) +} + +// WithCommit sets the commit of the codebase to export with the metrics. +// +// The default value is an empty string. +func WithCommit(currentCommit string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.commit = currentCommit + return nil + }) +} + +// WithVersion sets the version of the codebase to export with the metrics. +// +// The default value is an empty string. +func WithVersion(currentVersion string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.version = currentVersion + return nil + }) +} + +// WithBranch sets the name of the branch to export with the metrics. +// +// The default value is an empty string. +func WithBranch(currentBranch string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.branch = currentBranch + return nil + }) +} + +// WithService sets the name of the current service, to export with the metrics. +// +// The default value is an empty string. +func WithService(currentService string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.service = currentService + return nil + }) +} + +// WithRepoURL sets the URL of the repository containing the codebase being instrumented. +// +// The default value is an empty string. +func WithRepoURL(currentRepoURL string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoURL = currentRepoURL + return nil + }) +} + +// WithRepoProvider sets the provider of the repository containing the codebase being instrumented. +// +// The default value is an empty string. +func WithRepoProvider(currentRepoProvider string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoProvider = currentRepoProvider + return nil + }) +} + +// WithPushCollectorURL enables Pushing metrics to a remote location, and sets the URL of the +// collector to target. +// You can use just host:port or ip:port as url, in which case “http://” is added automatically. +// Alternatively, include the schema in the URL. However, do not include the “/metrics/jobs/…” part. +// +// 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 + }) +} + +// WithPushJobName sets the name of job to use when pushing metrics. +// +// Good values for this (taking into account replicated services) are for example: +// - The (internal) IP the job is coming from, +// - a [Uuid v1](https://pkg.go.dev/github.com/google/uuid#NewUUID) +// or a [Ulid](https://github.com/oklog/ulid) to get sortable IDs and keeping +// relationship to the machine generating metrics. +// - a Uuid v4 if you don't want metrics leaking extra information about the IPs +// +// 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 + }) +} + +// WithPushPeriod sets the duration between consecutive metrics pushes. +// +// The standard `OTEL_METRIC_EXPORT_INTERVAL` environment variable overrides +// this initialization argument. +// +// The default value is 10 seconds. +func WithPushPeriod(pushPeriod time.Duration) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushPeriod = pushPeriod + return nil + }) +} + +// WithPushTimeout sets the timeout duration of a single metric push +// +// The standard `OTEL_METRIC_EXPORT_TIMEOUT` environment variable overrides +// this initialization argument. +// +// The default value is 5 seconds. +func WithPushTimeout(pushTimeout time.Duration) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushTimeout = pushTimeout + return nil + }) +} + +// WlthPushHTTP sets the metrics pushing mechanism to use the HTTP format over gRPC +// +// The default value is to use gRPC. +func WithPushHTTP() InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushUseHTTP = true + return nil + }) +} + +// WlthPushInsecure allows to use insecure (clear text) connections between the +// codebase and the metrics collector. +// +// The default value is to use secure channels only. +func WithPushInsecure() InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushInsecure = true + return nil + }) +} + +// WithPushHeaders allows adding headers to the payload of metrics when pushed to the +// collector (for BasicAuth authentication for example) +// +// The default value is empty. +func WithPushHeaders(headers map[string]string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushHeaders = headers + return nil + }) +} + +// WithHistogramBuckets sets the buckets to use for the latency histograms. +// +// WARNING: your latency SLOs should always use thresolds that are _exactly_ a bucket boundary +// to ensure alert precision. +// +// 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 c404401..601e488 100644 --- a/otel/autometrics/otel.go +++ b/otel/autometrics/otel.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strconv" "sync" "time" @@ -114,12 +115,6 @@ func completeMeterName(meterName string) string { return fmt.Sprintf("autometrics/%v", meterName) } -// BuildInfo holds meta information about the build of the instrumented code. -// -// This is a reexport of the autometrics type to allow [Init] to work with only -// the current (otel) package imported at the call site. -type BuildInfo = autometrics.BuildInfo - // Logger is an interface for logging autometrics-related events. // // This is a reexport to allow using only the current package at call site. @@ -131,56 +126,6 @@ type PrintLogger = log.PrintLogger // This is a reexport to allow using only the current package at call site. type NoOpLogger = log.NoOpLogger -// PushConfiguration holds meta information about the push-to-collector configuration of the instrumented code. -type PushConfiguration struct { - // URL of the collector to push to. It must be non-empty if this struct is built. - // You can use just host:port or ip:port as url, in which case “http://” is added automatically. - // Alternatively, include the schema in the URL. However, do not include the “/metrics/jobs/…” part. - CollectorURL string - - // JobName is the name of the job to use when pushing metrics. - // - // Good values for this (taking into account replicated services) are for example: - // - [GetOutboundIP] to automatically populate the jobname with the IP it's coming from, - // - a [Uuid v1](https://pkg.go.dev/github.com/google/uuid#NewUUID) - // or a [Ulid](https://github.com/oklog/ulid) to get sortable IDs and keeping - // relationship to the machine generating metrics. - // - a Uuid v4 if you don't want metrics leaking extra information about the IPs - // - // If JobName is empty here, autometrics will use the outbound IP if readable, - // or a ulid here, see [DefaultJobName]. - JobName string - - // UseHttp forces the use of HTTP over GRPC as a protocol to push metrics to a - // collector. - // - // It defaults to false, meaning that by default, autometrics will push GRPC - // metrics to the collector. - UseHttp bool - - // Headers is a map of headers to add to the payload when pushing metrics. - Headers map[string]string - - // IsInsecure disables client transport security (such as TLS). - IsInsecure bool - - // Period is the interval at which the metrics will be pushed to the collector. - // - // This option overrides any value set for the OTEL_METRIC_EXPORT_INTERVAL environment variable. - // - // It should be greater than Timeout, and if the Period is non-positive, a default - // value of 10 seconds will be used. - Period time.Duration - - // Timeout is the timeout duration for metrics pushes to the collector. - // - // This option overrides any value set for the OTEL_METRIC_EXPORT_TIMEOUT environment variable. - // - // It should be smaller than Period, and if the Timeout is non-positive, a default - // value of 5 seconds will be used. - Timeout time.Duration -} - // Init sets up the metrics required for autometrics' decorated functions and registers // them to the Prometheus exporter. // @@ -191,23 +136,31 @@ type PushConfiguration struct { // Make sure that all the latency targets you want to use for SLOs are // present in the histogramBuckets array, otherwise the alerts will fail // to work (they will never trigger). -func Init(meterName string, histogramBuckets []float64, buildInformation BuildInfo, pushConfiguration *PushConfiguration, logger log.Logger) (context.CancelCauseFunc, error) { +func Init(initOpts ...InitOption) (context.CancelCauseFunc, error) { var err error newCtx, cancelFunc := context.WithCancelCause(context.Background()) amCtx = newCtx - autometrics.SetCommit(buildInformation.Commit) - autometrics.SetVersion(buildInformation.Version) - autometrics.SetBranch(buildInformation.Branch) - if logger == nil { - autometrics.SetLogger(log.NoOpLogger{}) - } else { - autometrics.SetLogger(logger) + initArgs := defaultInitArguments() + for _, initOpt := range initOpts { + if err := initOpt.Apply(&initArgs); err != nil { + return nil, fmt.Errorf("initializing options: %w", err) + } + } + + 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) + autometrics.SetLogger(initArgs.logger) + var pushExporter metric.Exporter - if pushConfiguration != nil { - pushExporter, err = initPushExporter(pushConfiguration) + if initArgs.HasPushEnabled() { + pushExporter, err = initPushExporter(initArgs) if err != nil { return nil, fmt.Errorf("impossible to initialize OTLP exporter: %w", err) } @@ -217,26 +170,26 @@ func Init(meterName string, histogramBuckets []float64, buildInformation BuildIn autometrics.SetService(serviceName) } else if serviceName, ok := os.LookupEnv(autometrics.OTelServiceNameEnv); ok { autometrics.SetService(serviceName) - } else if buildInformation.Service != "" { - autometrics.SetService(buildInformation.Service) + } else { + autometrics.SetService(initArgs.service) } if repoURL, ok := os.LookupEnv(autometrics.AutometricsRepoURLEnv); ok { autometrics.SetRepositoryURL(repoURL) - } else if buildInformation.RepositoryURL != "" { - autometrics.SetRepositoryURL(buildInformation.RepositoryURL) + } else { + autometrics.SetRepositoryURL(initArgs.repoURL) } if repoProvider, ok := os.LookupEnv(autometrics.AutometricsRepoProviderEnv); ok { - autometrics.SetRepositoryURL(repoProvider) - } else if buildInformation.RepositoryProvider != "" { - autometrics.SetRepositoryURL(buildInformation.RepositoryProvider) + autometrics.SetRepositoryProvider(repoProvider) + } else { + autometrics.SetRepositoryProvider(initArgs.repoProvider) } - provider, err := initProvider(pushExporter, pushConfiguration, meterName, histogramBuckets) + provider, err := initProvider(pushExporter, initArgs) if err != nil { return nil, err } - meter := provider.Meter(completeMeterName(meterName)) + meter := provider.Meter(completeMeterName(initArgs.meterName)) functionCallsCount, err = meter.Int64Counter(FunctionCallsCountName, instruments.WithDescription("The number of times the function has been called")) if err != nil { @@ -261,9 +214,9 @@ func Init(meterName string, histogramBuckets []float64, buildInformation BuildIn buildInfo.Add(amCtx, 1, instruments.WithAttributes( []attribute.KeyValue{ - attribute.Key(CommitLabel).String(buildInformation.Commit), - attribute.Key(VersionLabel).String(buildInformation.Version), - attribute.Key(BranchLabel).String(buildInformation.Branch), + attribute.Key(CommitLabel).String(autometrics.GetCommit()), + attribute.Key(VersionLabel).String(autometrics.GetVersion()), + attribute.Key(BranchLabel).String(autometrics.GetBranch()), attribute.Key(ServiceNameLabel).String(autometrics.GetService()), attribute.Key(RepositoryProviderLabel).String(autometrics.GetRepositoryProvider()), attribute.Key(RepositoryURLLabel).String(autometrics.GetRepositoryURL()), @@ -298,14 +251,14 @@ func ForceFlush() error { return nil } -func initProvider(pushExporter metric.Exporter, pushConfiguration *PushConfiguration, meterName string, histogramBuckets []float64) (*metric.MeterProvider, error) { +func initProvider(pushExporter metric.Exporter, initArgs initArguments) (*metric.MeterProvider, error) { instrumentView := metric.Instrument{ Name: FunctionCallsDurationName, - Scope: instrumentation.Scope{Name: completeMeterName(meterName)}, + Scope: instrumentation.Scope{Name: completeMeterName(initArgs.meterName)}, } streamView := metric.Stream{ Aggregation: metric.AggregationExplicitBucketHistogram{ - Boundaries: histogramBuckets, + Boundaries: initArgs.histogramBuckets, }, } @@ -362,11 +315,32 @@ func initProvider(pushExporter metric.Exporter, pushConfiguration *PushConfigura timeout := defaultPushTimeout interval := defaultPushPeriod - if pushConfiguration.Period > 0 { - interval = pushConfiguration.Period + readInitArgs := false + if pushPeriod, ok := os.LookupEnv(autometrics.OTelPushPeriodEnv); ok { + pushPeriodMs, err := strconv.ParseInt(pushPeriod, 10, 32) + if err != nil { + autometrics.GetLogger().Warn("opentelemetry: the push period environment variable has non-integer value, ignoring: %s", err) + readInitArgs = true + } else { + interval = time.Duration(pushPeriodMs) * time.Millisecond + } + } + if readInitArgs && initArgs.pushPeriod > 0 { + interval = initArgs.pushPeriod + } + + readInitArgs = false + if pushTimeout, ok := os.LookupEnv(autometrics.OTelPushTimeoutEnv); ok { + pushTimeoutMs, err := strconv.ParseInt(pushTimeout, 10, 32) + if err != nil { + autometrics.GetLogger().Warn("opentelemetry: the push timeout environment variable has non-integer value, ignoring: %s", err) + readInitArgs = true + } else { + timeout = time.Duration(pushTimeoutMs) * time.Millisecond + } } - if pushConfiguration.Timeout > 0 { - timeout = pushConfiguration.Timeout + if readInitArgs && initArgs.pushTimeout > 0 { + timeout = initArgs.pushTimeout } pushPeriodicReader = metric.NewPeriodicReader( @@ -383,30 +357,26 @@ func initProvider(pushExporter metric.Exporter, pushConfiguration *PushConfigura } } -func initPushExporter(pushConfiguration *PushConfiguration) (metric.Exporter, error) { +func initPushExporter(initArgs initArguments) (metric.Exporter, error) { autometrics.GetLogger().Debug("opentelemetry: Init: detected push configuration") - if pushConfiguration.CollectorURL == "" { - return nil, errors.New("invalid PushConfiguration: the CollectorURL must be set.") + if initArgs.pushCollectorURL == "" { + return nil, errors.New("invalid Push Configuration: the CollectorURL must be set.") } - autometrics.SetPushJobURL(pushConfiguration.CollectorURL) + autometrics.SetPushJobURL(initArgs.pushCollectorURL) - if pushConfiguration.JobName == "" { - autometrics.SetPushJobName(autometrics.DefaultJobName()) - } else { - autometrics.SetPushJobName(pushConfiguration.JobName) - } + autometrics.SetPushJobName(initArgs.pushJobName) - if pushConfiguration.UseHttp { + if initArgs.pushUseHTTP { options := []otlpmetrichttp.Option{ otlpmetrichttp.WithEndpoint(autometrics.GetPushJobURL()), } - if pushConfiguration.IsInsecure { + if initArgs.pushInsecure { options = append(options, otlpmetrichttp.WithInsecure()) } - if pushConfiguration.Headers != nil { - options = append(options, otlpmetrichttp.WithHeaders(pushConfiguration.Headers)) + if initArgs.pushHeaders != nil { + options = append(options, otlpmetrichttp.WithHeaders(initArgs.pushHeaders)) } return otlpmetrichttp.New( @@ -422,12 +392,12 @@ func initPushExporter(pushConfiguration *PushConfiguration) (metric.Exporter, er otlpmetricgrpc.WithEndpoint(autometrics.GetPushJobURL()), } - if pushConfiguration.IsInsecure { + if initArgs.pushInsecure { options = append(options, otlpmetricgrpc.WithInsecure()) } - if pushConfiguration.Headers != nil { - options = append(options, otlpmetricgrpc.WithHeaders(pushConfiguration.Headers)) + if initArgs.pushHeaders != nil { + options = append(options, otlpmetricgrpc.WithHeaders(initArgs.pushHeaders)) } return otlpmetricgrpc.New( diff --git a/pkg/autometrics/global_state.go b/pkg/autometrics/global_state.go index 0501880..dd572f9 100644 --- a/pkg/autometrics/global_state.go +++ b/pkg/autometrics/global_state.go @@ -26,6 +26,16 @@ const ( // the repository provider to use as a label. This environment variable has precedence over // over hardcoding the variable directly in [BuildInfo] struct in the Init call. AutometricsRepoProviderEnv = "AUTOMETRICS_REPOSITORY_PROVIDER" + // OTelPushPeriodEnv is the name of the environment variable to declare to change the interval + // between 2 metrics pushes in milliseconds. + // + // Reference: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#periodic-exporting-metricreader + OTelPushPeriodEnv = "OTEL_METRIC_EXPORT_INTERVAL" + // OTelPushTimeoutEnv is the name of the environment variable to declare to change the timeout + // threshold of a single metrics push in milliseconds. + // + // Reference: https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/#periodic-exporting-metricreader + OTelPushTimeoutEnv = "OTEL_METRIC_EXPORT_TIMEOUT" ) var ( diff --git a/pkg/autometrics/main.go b/pkg/autometrics/main.go index a2df5b4..cd0922b 100644 --- a/pkg/autometrics/main.go +++ b/pkg/autometrics/main.go @@ -69,27 +69,6 @@ type BuildInfo struct { RepositoryProvider string } -// PushConfiguration holds the information necessary to push metrics to an OTEL Collector. -type PushConfiguration struct { - // URL of the collector to push to. It must be non-empty if this struct is built. - // You can use just host:port or ip:port as url, in which case “http://” is added automatically. - // Alternatively, include the schema in the URL. However, do not include the “/metrics/jobs/…” part. - CollectorURL string - - // JobName is the name of the job to use when pushing metrics. - // - // Good values for this (taking into account replicated services) are for example: - // - [GetOutboundIP] to automatically populate the jobname with the IP it's coming from, - // - a [Uuid v1](https://pkg.go.dev/github.com/google/uuid#NewUUID) - // or a [Ulid](https://github.com/oklog/ulid) to get sortable IDs and keeping - // relationship to the machine generating metrics. - // - a Uuid v4 if you don't want metrics leaking extra information about the IPs - // - // If JobName is empty here, autometrics will use the outbound IP if readable, - // or a ulid here, see [DefaultJobName]. - JobName string -} - // AlertConfiguration is the configuration for autometric alerting. type AlertConfiguration struct { // ServiceName is the name of the Service that will appear in the alerts. diff --git a/prometheus/autometrics/init.go b/prometheus/autometrics/init.go new file mode 100644 index 0000000..3366756 --- /dev/null +++ b/prometheus/autometrics/init.go @@ -0,0 +1,182 @@ +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" +) + +type initArguments struct { + registry *prometheus.Registry + histogramBuckets []float64 + logger log.Logger + commit string + version string + branch string + service string + repoURL string + repoProvider string + pushCollectorURL string + pushJobName string +} + +func defaultInitArguments() initArguments { + return initArguments{ + histogramBuckets: am.DefBuckets, + logger: log.NoOpLogger{}, + pushJobName: am.DefaultJobName(), + } +} + +func (initArgs initArguments) Validate() error { + return nil +} + +func (initArgs initArguments) HasPushEnabled() bool { + return initArgs.pushCollectorURL != "" +} + +type InitOption interface { + Apply(*initArguments) error +} + +type initOptionFunc func(*initArguments) error + +func (fn initOptionFunc) Apply(initArgs *initArguments) error { + return fn(initArgs) +} + +// WithRegistry sets the prometheus registry to use. +// +// The default is to use +// prometheus default registry. +func WithRegistry(registry *prometheus.Registry) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.registry = registry + return nil + }) +} + +// WithLogger sets the logger to use when initializing autometrics. +// +// The default logger is a no-op logger that will never log +// autometrics-specific events. +func WithLogger(logger log.Logger) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.logger = logger + return nil + }) +} + +// WithCommit sets the commit of the codebase to export with the metrics. +// +// The default value is an empty string. +func WithCommit(currentCommit string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.commit = currentCommit + return nil + }) +} + +// WithVersion sets the version of the codebase to export with the metrics. +// +// The default value is an empty string. +func WithVersion(currentVersion string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.version = currentVersion + return nil + }) +} + +// WithBranch sets the name of the branch to export with the metrics. +// +// The default value is an empty string. +func WithBranch(currentBranch string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.branch = currentBranch + return nil + }) +} + +// WithService sets the name of the current service, to export with the metrics. +// +// The default value is an empty string. +func WithService(currentService string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.service = currentService + return nil + }) +} + +// WithRepoURL sets the URL of the repository containing the codebase being instrumented. +// +// The default value is an empty string. +func WithRepoURL(currentRepoURL string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoURL = currentRepoURL + return nil + }) +} + +// WithRepoProvider sets the provider of the repository containing the codebase being instrumented. +// +// The default value is an empty string. +func WithRepoProvider(currentRepoProvider string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.repoProvider = currentRepoProvider + return nil + }) +} + +// WithPushCollectorURL enables Pushing metrics to a remote location, and sets the URL of the +// collector to target. +// +// Just as the prometheus library [push] configuration, +// "You can use just host:port or ip:port as url, in which case “http://” is +// added automatically. Alternatively, include the schema in the URL. However, +// do not include the “/metrics/jobs/…” part." +// +// The default value is an empty string, which also disables metric pushing. +// +// [push]: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus/push#New +func WithPushCollectorURL(pushCollectorURL string) InitOption { + return initOptionFunc(func(initArgs *initArguments) error { + initArgs.pushCollectorURL = pushCollectorURL + return nil + }) +} + +// WithPushJobName sets the name of job to use when pushing metrics. +// +// Good values for this (taking into account replicated services) are for example: +// - The (internal) IP the job is coming from, +// - a [Uuid v1](https://pkg.go.dev/github.com/google/uuid#NewUUID) +// or a [Ulid](https://github.com/oklog/ulid) to get sortable IDs and keeping +// relationship to the machine generating metrics. +// - a Uuid v4 if you don't want metrics leaking extra information about the IPs +// +// 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 + }) +} + +// WithHistogramBuckets sets the buckets to use for the latency histograms. +// +// WARNING: your latency SLOs should always use thresolds that are _exactly_ a bucket boundary +// to ensure alert precision. +// +// 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 6f763e6..f74e1d0 100644 --- a/prometheus/autometrics/prometheus.go +++ b/prometheus/autometrics/prometheus.go @@ -99,12 +99,6 @@ const ( parentSpanIdExemplar = "parent_id" ) -// BuildInfo holds meta information about the build of the instrumented code. -// -// This is a reexport of the autometrics type to allow [Init] to work with only -// the current (prometheus) package imported at the call site. -type BuildInfo = autometrics.BuildInfo - // Logger is an interface for logging autometrics-related events. // // This is a reexport to allow using only the current package at call site. @@ -116,19 +110,6 @@ type PrintLogger = log.PrintLogger // This is a reexport to allow using only the current package at call site. type NoOpLogger = log.NoOpLogger -// PushConfiguration holds meta information about the push-to-collector configuration of the instrumented code. -// -// This is a reexport of the autometrics type to allow [Init] to work with only -// the current (prometheus) package imported at the call site. -// -// For the CollectorURL part, just as the prometheus library [push] configuration, -// "You can use just host:port or ip:port as url, in which case “http://” is -// added automatically. Alternatively, include the schema in the URL. However, -// do not include the “/metrics/jobs/…” part." -// -// [push]: https://pkg.go.dev/github.com/prometheus/client_golang/prometheus/push#New -type PushConfiguration = autometrics.PushConfiguration - // Init sets up the metrics required for autometrics' decorated functions and registers // them to the argument registry. // @@ -142,33 +123,37 @@ type PushConfiguration = autometrics.PushConfiguration // Make sure that all the latency targets you want to use for SLOs are // present in the histogramBuckets array, otherwise the alerts will fail // to work (they will never trigger.) -func Init(reg *prometheus.Registry, histogramBuckets []float64, buildInformation BuildInfo, pushConfiguration *PushConfiguration, logger log.Logger) (context.CancelCauseFunc, error) { +func Init(initOpts ...InitOption) (context.CancelCauseFunc, error) { newCtx, cancelFunc := context.WithCancelCause(context.Background()) amCtx = newCtx - autometrics.SetCommit(buildInformation.Commit) - autometrics.SetVersion(buildInformation.Version) - autometrics.SetBranch(buildInformation.Branch) - if logger == nil { - autometrics.SetLogger(log.NoOpLogger{}) - } else { - autometrics.SetLogger(logger) + initArgs := defaultInitArguments() + for _, initOpt := range initOpts { + if err := initOpt.Apply(&initArgs); err != nil { + return nil, fmt.Errorf("initialization argument: %w", err) + } } + 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) + autometrics.SetLogger(initArgs.logger) + pusher = nil - if pushConfiguration != nil { - autometrics.GetLogger().Debug("Init: detected push configuration to %s", pushConfiguration.CollectorURL) + if initArgs.HasPushEnabled() { + autometrics.GetLogger().Debug("Init: detected push configuration to %s", initArgs.pushCollectorURL) - if pushConfiguration.CollectorURL == "" { - return nil, errors.New("invalid PushConfiguration: the CollectorURL must be set.") + if initArgs.pushCollectorURL == "" { + return nil, errors.New("invalid Push Configuration: the CollectorURL must be set.") } - autometrics.SetPushJobURL(pushConfiguration.CollectorURL) + autometrics.SetPushJobURL(initArgs.pushCollectorURL) - if pushConfiguration.JobName == "" { - autometrics.SetPushJobName(autometrics.DefaultJobName()) - } else { - autometrics.SetPushJobName(pushConfiguration.JobName) - } + autometrics.SetPushJobName(initArgs.pushJobName) pusher = push. New(autometrics.GetPushJobURL(), autometrics.GetPushJobName()). @@ -180,19 +165,19 @@ func Init(reg *prometheus.Registry, histogramBuckets []float64, buildInformation autometrics.SetService(serviceName) } else if serviceName, ok := os.LookupEnv(autometrics.OTelServiceNameEnv); ok { autometrics.SetService(serviceName) - } else if buildInformation.Service != "" { - autometrics.SetService(buildInformation.Service) + } else { + autometrics.SetService(initArgs.service) } if repoURL, ok := os.LookupEnv(autometrics.AutometricsRepoURLEnv); ok { autometrics.SetRepositoryURL(repoURL) - } else if buildInformation.RepositoryURL != "" { - autometrics.SetRepositoryURL(buildInformation.RepositoryURL) + } else { + autometrics.SetRepositoryURL(initArgs.repoURL) } if repoProvider, ok := os.LookupEnv(autometrics.AutometricsRepoProviderEnv); ok { autometrics.SetRepositoryURL(repoProvider) - } else if buildInformation.RepositoryProvider != "" { - autometrics.SetRepositoryURL(buildInformation.RepositoryProvider) + } else { + autometrics.SetRepositoryURL(initArgs.repoProvider) } functionCallsCount = prometheus.NewCounterVec(prometheus.CounterOpts{ @@ -201,7 +186,7 @@ func Init(reg *prometheus.Registry, histogramBuckets []float64, buildInformation functionCallsDuration = prometheus.NewHistogramVec(prometheus.HistogramOpts{ Name: FunctionCallsDurationName, - Buckets: histogramBuckets, + Buckets: initArgs.histogramBuckets, }, []string{FunctionLabel, ModuleLabel, CallerFunctionLabel, CallerModuleLabel, TargetLatencyLabel, TargetSuccessRateLabel, SloNameLabel, CommitLabel, VersionLabel, BranchLabel, ServiceNameLabel}) functionCallsConcurrent = prometheus.NewGaugeVec(prometheus.GaugeOpts{ @@ -212,11 +197,11 @@ func Init(reg *prometheus.Registry, histogramBuckets []float64, buildInformation Name: BuildInfoName, }, []string{CommitLabel, VersionLabel, BranchLabel, ServiceNameLabel, RepositoryURLLabel, RepositoryProviderLabel, AutometricsVersionLabel}) - if reg != nil { - reg.MustRegister(functionCallsCount) - reg.MustRegister(functionCallsDuration) - reg.MustRegister(functionCallsConcurrent) - reg.MustRegister(buildInfo) + if initArgs.registry != nil { + initArgs.registry.MustRegister(functionCallsCount) + initArgs.registry.MustRegister(functionCallsDuration) + initArgs.registry.MustRegister(functionCallsConcurrent) + initArgs.registry.MustRegister(buildInfo) } else { prometheus.DefaultRegisterer.MustRegister(functionCallsCount) prometheus.DefaultRegisterer.MustRegister(functionCallsDuration) @@ -225,9 +210,9 @@ func Init(reg *prometheus.Registry, histogramBuckets []float64, buildInformation } buildInfo.With(prometheus.Labels{ - CommitLabel: buildInformation.Commit, - VersionLabel: buildInformation.Version, - BranchLabel: buildInformation.Branch, + CommitLabel: autometrics.GetCommit(), + VersionLabel: autometrics.GetVersion(), + BranchLabel: autometrics.GetBranch(), ServiceNameLabel: autometrics.GetService(), RepositoryURLLabel: autometrics.GetRepositoryURL(), RepositoryProviderLabel: autometrics.GetRepositoryProvider(),