Skip to content

Commit 26d50f8

Browse files
committed
sandbox: correct stackdriver labels
The generic_task target has a required label format that was not being met. Moves metadata fetching into a helper function. Removes call to view.RegisterExporter for StackDriver exporter, which was unncessary. Updates golang/go#25224 Updates golang/go#38530 Change-Id: Ib009f5ce906f5b9479cdda8c7e8322d06e3036e4 Reviewed-on: https://go-review.googlesource.com/c/playground/+/229958 Run-TryBot: Alexander Rakoczy <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
1 parent ccdf1e5 commit 26d50f8

File tree

1 file changed

+62
-16
lines changed

1 file changed

+62
-16
lines changed

sandbox/metrics.go

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
package main
66

77
import (
8+
"errors"
89
"fmt"
910
"net/http"
11+
"path"
1012
"time"
1113

1214
"cloud.google.com/go/compute/metadata"
@@ -126,26 +128,14 @@ func newMetricService() (*metricService, error) {
126128
if err != nil {
127129
return nil, err
128130
}
129-
zone, err := metadata.Zone()
130-
if err != nil {
131-
return nil, err
132-
}
133-
iname, err := metadata.InstanceName()
131+
gr, err := gceResource("go-playground-sandbox")
134132
if err != nil {
135133
return nil, err
136134
}
137135

138136
sd, err := stackdriver.NewExporter(stackdriver.Options{
139-
ProjectID: projID,
140-
MonitoredResource: (*monitoredResource)(&mrpb.MonitoredResource{
141-
Type: "generic_task",
142-
Labels: map[string]string{
143-
"instance_id": iname,
144-
"job": "go-playground-sandbox",
145-
"project_id": projID,
146-
"zone": zone,
147-
},
148-
}),
137+
ProjectID: projID,
138+
MonitoredResource: gr,
149139
ReportingInterval: time.Minute, // Minimum interval for stackdriver is 1 minute.
150140
})
151141
if err != nil {
@@ -154,7 +144,6 @@ func newMetricService() (*metricService, error) {
154144

155145
// Minimum interval for stackdriver is 1 minute.
156146
view.SetReportingPeriod(time.Minute)
157-
view.RegisterExporter(sd)
158147
// Start the metrics exporter.
159148
if err := sd.StartMetricsExporter(); err != nil {
160149
return nil, err
@@ -163,6 +152,7 @@ func newMetricService() (*metricService, error) {
163152
return &metricService{sdExporter: sd}, nil
164153
}
165154

155+
// metricService controls metric exporters.
166156
type metricService struct {
167157
sdExporter *stackdriver.Exporter
168158
pExporter *prometheus.Exporter
@@ -176,6 +166,7 @@ func (m *metricService) ServeHTTP(w http.ResponseWriter, r *http.Request) {
176166
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
177167
}
178168

169+
// Stop flushes metrics and stops exporting. Stop should be called before exiting.
179170
func (m *metricService) Stop() {
180171
if sde := m.sdExporter; sde != nil {
181172
// Flush any unsent data before exiting.
@@ -192,3 +183,58 @@ type monitoredResource mrpb.MonitoredResource
192183
func (r *monitoredResource) MonitoredResource() (resType string, labels map[string]string) {
193184
return r.Type, r.Labels
194185
}
186+
187+
// gceResource populates a monitoredResource with GCE Metadata.
188+
//
189+
// The returned monitoredResource will have the type set to "generic_task".
190+
func gceResource(jobName string) (*monitoredResource, error) {
191+
projID, err := metadata.ProjectID()
192+
if err != nil {
193+
return nil, err
194+
}
195+
zone, err := metadata.Zone()
196+
if err != nil {
197+
return nil, err
198+
}
199+
iname, err := metadata.InstanceName()
200+
if err != nil {
201+
return nil, err
202+
}
203+
igName, err := instanceGroupName()
204+
if err != nil {
205+
return nil, err
206+
} else if igName == "" {
207+
igName = projID
208+
}
209+
210+
return (*monitoredResource)(&mrpb.MonitoredResource{
211+
Type: "generic_task", // See: https://cloud.google.com/monitoring/api/resources#tag_generic_task
212+
Labels: map[string]string{
213+
"project_id": projID,
214+
"location": zone,
215+
"namespace": igName,
216+
"job": jobName,
217+
"task_id": iname,
218+
},
219+
}), nil
220+
}
221+
222+
// instanceGroupName fetches the instanceGroupName from the instance metadata.
223+
//
224+
// The instance group manager applies a custom "created-by" attribute to the instance, which is not part of the
225+
// metadata package API, and must be queried separately.
226+
//
227+
// An empty string will be returned if a metadata.NotDefinedError is returned when fetching metadata.
228+
// An error will be returned if other errors occur when fetching metadata.
229+
func instanceGroupName() (string, error) {
230+
ig, err := metadata.InstanceAttributeValue("created-by")
231+
if nde := metadata.NotDefinedError(""); err != nil && !errors.As(err, &nde) {
232+
return "", err
233+
}
234+
if ig == "" {
235+
return "", nil
236+
}
237+
// "created-by" format: "projects/{{InstanceID}}/zones/{{Zone}}/instanceGroupManagers/{{Instance Group Name}}
238+
ig = path.Base(ig)
239+
return ig, err
240+
}

0 commit comments

Comments
 (0)