How to apply concurrency in golang to pass multiple app metrics to datadog

77 views
Skip to first unread message

Shatabdi Pal

unread,
Nov 23, 2020, 10:40:46 AM11/23/20
to golang-nuts
Hello,

I have a requirement to create a datadog dashboard with application metrics. The app names are read from a config.toml. The code runs only for the first app provided in the toml file and never proceeds to the second app. The structure is a follows:  

config.toml
application = ["app1", "app2", "app3"]
customer = ["abc"]

main.go
// Sending Metrics to Datadog UI
func sendMetrics(name string, channel chan string) {
// Calculates the Epoch Time for App
EpochTime1 := epochTime()
// Calculates the Epoch Time for Github
EpochTime2 := gitEpochTime()
// Lead Time from Github Commit to App Deployment
calculated_time := EpochTime1 - EpochTime2
v := versionDetails()
dd_tags := "metric_tag:" + v
tags := []string{dd_tags}
rate := float64(1)
c, err := statsd.New("127.0.0.1:18125")
if err != nil {
log.Fatal(err)
}
e := c.Gauge(name, float64(calculated_time), tags, rate)
if e != nil {
log.Println(e)
fmt.Println("name:::", name)
fmt.Println("lead time:::", leadTime)
channel <- name
}
fmt.Println("name:::", name)
fmt.Println("lead time:::", leadTime)
channel <- name
log.Printf("Metrics for %s sent successfully!!", name)
}

func main() {
channel := make(chan string)
appName, _ := getTag() //gets the appName and customerName both of which are [] string type
fmt.Println("App names: ", appName, reflect.TypeOf(appName))
for _, app := range appName {
// Calculate the Epoch Time
fmt.Println("Executing app............ ", app)
if epochTime() == 0 {
log.Println("No deployment present during the Time Frame!")
for res := range channel {
go func(app string) {
time.Sleep(3 * time.Second)
sendMetrics(app, channel)
}(res)
}
} else {
go sendMetrics(app, channel)
for res := range channel {
go func(name string) {
time.Sleep(3 * time.Second)
sendMetrics(name, channel)
}(res)
}
}
}
}

I am new to Golang and any help is highly appreciated.

Thanks,
Shatabdi

Anderson Queiroz

unread,
Nov 25, 2020, 3:56:28 AM11/25/20
to golang-nuts
I didn't have much time to look at it, but try to rebind the `app` variable:


for _, app := range appName {
// Calculate the Epoch Time
app := app // rebidding app

a short, and not quite formal, explanation is that the loop variable is reused during the iterations, and when a loop variable is captured in a clojure, it isn't copied, so when the clojure executes the captured variable will have the value for the current loop iteration. And it happens that the clojure executed in a go routine will only run after the for loop have finished, and therefore all the goroutines referencing the loop variable will read the value for the last iteration.

here you're capturing it:

go func(app string) {
time.Sleep(3 * time.Second)
sendMetrics(app, channel)
}(res)

I hope it helps :)

Best,
Anderson
Reply all
Reply to author
Forward
0 new messages