Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add build information to the metrics/queries #34

Merged
merged 10 commits into from
May 9, 2023
35 changes: 31 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,18 @@ import (
And then in your main function initialize the metrics

``` go
amImpl.Init(nil, am.DefBuckets)
// Everything in BuildInfo is optional.
// You can also use any string variable whose value is
// injected at build time by ldflags.
gagbo marked this conversation as resolved.
Show resolved Hide resolved
amImpl.Init(
nil,
amImpl.DefBuckets,
amImpl.BuildInfo{
Version: "0.4.0",
Commit: "anySHA",
BuildTime: "",
},
)
```

> **Warning**
Expand Down Expand Up @@ -134,7 +145,15 @@ import (


func main() {
amImpl.Init(nil, am.DefBuckets)
amImpl.Init(
nil,
amImpl.DefBuckets,
amImpl.BuildInfo{
Version: "0.4.0",
Commit: "anySHA",
BuildTime: "",
},
)
http.Handle("/metrics", promhttp.Handler())
}
```
Expand Down Expand Up @@ -188,8 +207,16 @@ the `Init` function takes a meter name for the `otel_scope` label of the exporte
metric. You can use the name of the application or its version for example

``` patch
- amImpl.Init(nil, am.DefBuckets)
+ amImpl.Init("myApp/v2/prod", am.DefBuckets)
amImpl.Init(
- nil,
+ "myApp/v2/prod",
amImpl.DefBuckets,
amImpl.BuildInfo{
Version: "2.1.37",
Commit: "anySHA",
BuildTime: "",
},
)
```

- add the `-otel` flag to the `//go:generate` directive
Expand Down
13 changes: 12 additions & 1 deletion examples/otel/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ import (
func main() {
rand.Seed(time.Now().UnixNano())

amImpl.Init("web-server", amImpl.DefBuckets)
// Everything in BuildInfo is optional.
// You can also use any string variable whose value is
// injected at build time by ldflags.
amImpl.Init(
"web-server",
amImpl.DefBuckets,
amImpl.BuildInfo{
Version: "0.4.0",
Commit: "anySHA",
BuildTime: "",
},
)

http.HandleFunc("/", errorable(indexHandler))
http.HandleFunc("/random-error", errorable(randomErrorHandler))
Expand Down
13 changes: 12 additions & 1 deletion examples/web/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ import (
func main() {
rand.Seed(time.Now().UnixNano())

amImpl.Init(nil, amImpl.DefBuckets)
// Everything in BuildInfo is optional.
// You can also use any string variable whose value is
// injected at build time by ldflags.
gagbo marked this conversation as resolved.
Show resolved Hide resolved
amImpl.Init(
nil,
amImpl.DefBuckets,
amImpl.BuildInfo{
Version: "0.4.0",
Commit: "anySHA",
BuildTime: "",
},
)

http.HandleFunc("/", errorable(indexHandler))
http.HandleFunc("/random-error", errorable(randomErrorHandler))
Expand Down
13 changes: 12 additions & 1 deletion examples/web/cmd/main.go.orig
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,18 @@ import (
func main() {
rand.Seed(time.Now().UnixNano())

amImpl.Init(nil, amImpl.DefBuckets)
// Everything in BuildInfo is optional.
// You can also use any string variable whose value is
// injected at build time by ldflags.
amImpl.Init(
nil,
amImpl.DefBuckets,
amImpl.BuildInfo{
Version: "0.4.0",
Commit: "anySHA",
BuildTime: "",
},
)

http.HandleFunc("/", errorable(indexHandler))
http.HandleFunc("/random-error", errorable(randomErrorHandler))
Expand Down
53 changes: 49 additions & 4 deletions internal/autometrics/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,22 +46,67 @@ func (p Prometheus) makePrometheusUrl(query, comment string) url.URL {
return ret
}

func addBuildInfoLabels() string {
return fmt.Sprintf("* on (instance, job) group_left(%s, %s) %s",
prometheus.VersionLabel,
prometheus.CommitLabel,
prometheus.BuildInfoName,
)
}

func requestRateQuery(counterName, labelKey, labelValue string) string {
return fmt.Sprintf("sum by (%s, %s) (rate(%s{%s=\"%s\"}[5m]))", prometheus.FunctionLabel, prometheus.ModuleLabel, counterName, labelKey, labelValue)
return fmt.Sprintf("sum by (%s, %s, %s, %s) (rate(%s{%s=\"%s\"}[5m]) %s)",
prometheus.FunctionLabel,
prometheus.ModuleLabel,
prometheus.VersionLabel,
prometheus.CommitLabel,
counterName,
labelKey,
labelValue,
addBuildInfoLabels(),
)
}

func errorRatioQuery(counterName, labelKey, labelValue string) string {
return fmt.Sprintf("sum by (%s, %s) (rate(%s{%s=\"%s\",%s=\"error\"}[5m]))", prometheus.FunctionLabel, prometheus.ModuleLabel, counterName, labelKey, labelValue, prometheus.ResultLabel)
return fmt.Sprintf("sum by (%s, %s, %s, %s) (rate(%s{%s=\"%s\",%s=\"error\"}[5m]) %s)",
prometheus.FunctionLabel,
prometheus.ModuleLabel,
prometheus.VersionLabel,
prometheus.CommitLabel,
counterName,
labelKey,
labelValue,
prometheus.ResultLabel,
addBuildInfoLabels(),
)
}

func latencyQuery(bucketName, labelKey, labelValue string) string {
latency := fmt.Sprintf("sum by (le, %s, %s) (rate(%s_bucket{%s=\"%s\"}[5m]))", prometheus.FunctionLabel, prometheus.ModuleLabel, bucketName, labelKey, labelValue)
latency := fmt.Sprintf("sum by (le, %s, %s, %s, %s) (rate(%s_bucket{%s=\"%s\"}[5m]) %s)",
prometheus.FunctionLabel,
prometheus.ModuleLabel,
prometheus.VersionLabel,
prometheus.CommitLabel,
bucketName,
labelKey,
labelValue,
addBuildInfoLabels(),
)

return fmt.Sprintf("histogram_quantile(0.99, %s) or histogram_quantile(0.95, %s)", latency, latency)
}

func concurrentCallsQuery(gaugeName, labelKey, labelValue string) string {
return fmt.Sprintf("sum by (%s, %s) %s{%s=\"%s\"}", prometheus.FunctionLabel, prometheus.ModuleLabel, gaugeName, labelKey, labelValue)
return fmt.Sprintf("sum by (%s, %s, %s, %s) (%s{%s=\"%s\"} %s)",
prometheus.FunctionLabel,
prometheus.ModuleLabel,
prometheus.VersionLabel,
prometheus.CommitLabel,
gaugeName,
labelKey,
labelValue,
addBuildInfoLabels(),
)
}

func (p Prometheus) GenerateAutometricsComment(ctx GeneratorContext, funcName, moduleName string) []string {
Expand Down
28 changes: 14 additions & 14 deletions internal/generate/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,12 @@ func main() {
"//\n" +
"//\tautometrics:doc-end Generated documentation by Autometrics.\n" +
"//\n" +
"// [Request Rate]: http://localhost:9090/graph?g0.expr=%23+Rate+of+calls+to+the+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Error Ratio]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+calls+to+the+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Latency (95th and 99th percentiles)]: http://localhost:9090/graph?g0.expr=%23+95th+and+99th+percentile+latencies+%28in+seconds%29+for+the+%60main%60+function%0A%0Ahistogram_quantile%280.99%2C+sum+by+%28le%2C+function%2C+module%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29%29%29+or+histogram_quantile%280.95%2C+sum+by+%28le%2C+function%2C+module%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29%29%29&g0.tab=0\n" +
"// [Concurrent Calls]: http://localhost:9090/graph?g0.expr=%23+Concurrent+calls+to+the+%60main%60+function%0A%0Asum+by+%28function%2C+module%29+function_calls_concurrent%7Bfunction%3D%22main%22%7D&g0.tab=0\n" +
"// [Request Rate Callee]: http://localhost:9090/graph?g0.expr=%23+Rate+of+function+calls+emanating+from+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Error Ratio Callee]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+function+emanating+from+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Request Rate]: http://localhost:9090/graph?g0.expr=%23+Rate+of+calls+to+the+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Error Ratio]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+calls+to+the+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Latency (95th and 99th percentiles)]: http://localhost:9090/graph?g0.expr=%23+95th+and+99th+percentile+latencies+%28in+seconds%29+for+the+%60main%60+function%0A%0Ahistogram_quantile%280.99%2C+sum+by+%28le%2C+function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29%29+or+histogram_quantile%280.95%2C+sum+by+%28le%2C+function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29%29&g0.tab=0\n" +
"// [Concurrent Calls]: http://localhost:9090/graph?g0.expr=%23+Concurrent+calls+to+the+%60main%60+function%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28function_calls_concurrent%7Bfunction%3D%22main%22%7D+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Request Rate Callee]: http://localhost:9090/graph?g0.expr=%23+Rate+of+function+calls+emanating+from+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Error Ratio Callee]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+function+emanating+from+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"//\n" +
"//autometrics:doc --slo \"Service Test\" --success-target 99\n" +
"func main() {\n" +
Expand Down Expand Up @@ -148,12 +148,12 @@ func main() {
"//\n" +
"//\tautometrics:doc-end Generated documentation by Autometrics.\n" +
"//\n" +
"// [Request Rate]: http://localhost:9090/graph?g0.expr=%23+Rate+of+calls+to+the+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Error Ratio]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+calls+to+the+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Latency (95th and 99th percentiles)]: http://localhost:9090/graph?g0.expr=%23+95th+and+99th+percentile+latencies+%28in+seconds%29+for+the+%60main%60+function%0A%0Ahistogram_quantile%280.99%2C+sum+by+%28le%2C+function%2C+module%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29%29%29+or+histogram_quantile%280.95%2C+sum+by+%28le%2C+function%2C+module%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29%29%29&g0.tab=0\n" +
"// [Concurrent Calls]: http://localhost:9090/graph?g0.expr=%23+Concurrent+calls+to+the+%60main%60+function%0A%0Asum+by+%28function%2C+module%29+function_calls_concurrent%7Bfunction%3D%22main%22%7D&g0.tab=0\n" +
"// [Request Rate Callee]: http://localhost:9090/graph?g0.expr=%23+Rate+of+function+calls+emanating+from+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Error Ratio Callee]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+function+emanating+from+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29%29&g0.tab=0\n" +
"// [Request Rate]: http://localhost:9090/graph?g0.expr=%23+Rate+of+calls+to+the+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Error Ratio]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+calls+to+the+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bfunction%3D%22main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Latency (95th and 99th percentiles)]: http://localhost:9090/graph?g0.expr=%23+95th+and+99th+percentile+latencies+%28in+seconds%29+for+the+%60main%60+function%0A%0Ahistogram_quantile%280.99%2C+sum+by+%28le%2C+function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29%29+or+histogram_quantile%280.95%2C+sum+by+%28le%2C+function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_duration_bucket%7Bfunction%3D%22main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29%29&g0.tab=0\n" +
"// [Concurrent Calls]: http://localhost:9090/graph?g0.expr=%23+Concurrent+calls+to+the+%60main%60+function%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28function_calls_concurrent%7Bfunction%3D%22main%22%7D+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Request Rate Callee]: http://localhost:9090/graph?g0.expr=%23+Rate+of+function+calls+emanating+from+%60main%60+function+per+second%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"// [Error Ratio Callee]: http://localhost:9090/graph?g0.expr=%23+Percentage+of+function+emanating+from+%60main%60+function+that+return+errors%2C+averaged+over+5+minute+windows%0A%0Asum+by+%28function%2C+module%2C+version%2C+commit%29+%28rate%28function_calls_count%7Bcaller%3D%22main.main%22%2Cresult%3D%22error%22%7D%5B5m%5D%29+%2A+on+%28instance%2C+job%29+group_left%28version%2C+commit%29+build_info%29&g0.tab=0\n" +
"//\n" +
"//autometrics:doc --slo \"API\" --latency-target 99.9 --latency-ms 500\n" +
"func main() {\n" +
Expand Down Expand Up @@ -626,8 +626,8 @@ func implementContextCodeGenTest(t *testing.T, contextToSerialize autometrics.Co
sourceContext := internal.GeneratorContext{
RuntimeCtx: contextToSerialize,
FuncCtx: internal.GeneratorFunctionContext{
CommentIndex: -1,
ImplImportName: "autometrics",
CommentIndex: -1,
ImplImportName: "autometrics",
},
}

Expand Down
35 changes: 35 additions & 0 deletions pkg/autometrics/global_state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package autometrics // import "github.com/autometrics-dev/autometrics-go/pkg/autometrics"

var version string
var commit string
var buildTime string
gagbo marked this conversation as resolved.
Show resolved Hide resolved

// GetVersion returns the version of the codebase being instrumented.
func GetVersion() string {
return version
}

// SetVersion sets the version of the codebase being instrumented.
func SetVersion(newVersion string) {
version = newVersion
}

// GetCommit returns the commit of the codebase being instrumented.
func GetCommit() string {
return commit
}

// SetCommit sets the commit of the codebase being instrumented.
func SetCommit(newCommit string) {
commit = newCommit
}

// GetBuildTime returns the build timestamp of the codebase being instrumented.
func GetBuildTime() string {
return buildTime
}

// SetBuildTime sets the build timestamp of the codebase being instrumented.
func SetBuildTime(newBuildTime string) {
buildTime = newBuildTime
}
38 changes: 30 additions & 8 deletions pkg/autometrics/main.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package autometrics
package autometrics // import "github.com/autometrics-dev/autometrics-go/pkg/autometrics"

import (
"context"
Expand Down Expand Up @@ -38,19 +38,25 @@ type Context struct {
TrackCallerName bool
// AlertConf is an optional configuration to add alerting capabilities to the metrics.
AlertConf *AlertConfiguration
// startTime is the start time of a single function execution.
// Only autometrics.Instrument should read this value.
// Only autometrics.PreInstrument should write this value.
// StartTime is the start time of a single function execution.
// Only amImpl.Instrument should read this value.
gagbo marked this conversation as resolved.
Show resolved Hide resolved
// Only amImpl.PreInstrument should write this value.
//
// This value is only exported for the child packages "prometheus" and "otel"
StartTime time.Time
// callInfo contains all the relevant data for caller information.
// Only autometrics.Instrument should read this value.
// Only autometrics.PreInstrument should write/read this value.
// CallInfo contains all the relevant data for caller information.
// Only amImpl.Instrument should read this value.
// Only amImpl.PreInstrument should write/read this value.
//
// This value is only exported for the child packages "prometheus" and "otel"
CallInfo CallInfo
Context context.Context
// BuildInfo contains all the relevant data for caller information.
// Only amImpl.Instrument and PreInstrument should read this value.
// Only amImpl.Init should write/read this value.
//
// This value is only exported for the child packages "prometheus" and "otel"
BuildInfo BuildInfo
Context context.Context
}

// CallInfo holds the information about the current function call and its parent names.
Expand All @@ -65,6 +71,16 @@ type CallInfo struct {
ParentModuleName string
}

// BuildInfo holds the information about the current build of the instrumented code.
type BuildInfo struct {
gagbo marked this conversation as resolved.
Show resolved Hide resolved
// Commit is the commit of the code.
Commit string
// Version is the version of the code.
Version string
// BuildTime is the timestamp of the build of the codebase.
BuildTime string
}

func NewContext() Context {
return Context{
TrackConcurrentCalls: true,
Expand All @@ -74,6 +90,12 @@ func NewContext() Context {
}
}

func (c *Context) FillBuildInfo() {
c.BuildInfo.Version = GetVersion()
c.BuildInfo.Commit = GetCommit()
c.BuildInfo.BuildTime = GetBuildTime()
}

func (c Context) Validate(allowCustomLatencies bool) error {
if c.AlertConf != nil {
if c.AlertConf.ServiceName == "" {
Expand Down
Loading