@@ -7,6 +7,7 @@ package metrics
77import (
88 "context"
99 "fmt"
10+ "strings"
1011 "time"
1112
1213 monitoring "cloud.google.com/go/monitoring/apiv3"
@@ -51,9 +52,45 @@ type MetricSet struct {
5152
5253//metricsConfig holds a configuration specific for metrics metricset.
5354type metricsConfig struct {
54- ServiceName string `config:"service" validate:"required"`
55- MetricTypes []string `config:"metric_types" validate:"required"`
56- Aligner string `config:"aligner"`
55+ ServiceName string `config:"service" validate:"required"`
56+ // ServiceMetricPrefix allows to specify the prefix string for MetricTypes
57+ // Stackdriver requires metrics to be prefixed with a common prefix.
58+ // This prefix changes based on the services the metrics belongs to.
59+ ServiceMetricPrefix string `config:"service_metric_prefix"`
60+ MetricTypes []string `config:"metric_types" validate:"required"`
61+ Aligner string `config:"aligner"`
62+ }
63+
64+ // prefix returns the service metric prefix, falling back to the Google Cloud
65+ // monitoring service prefix when not specified.
66+ // The prefix is normalized to always end with '/'.
67+ func (mc metricsConfig ) prefix () string {
68+ prefix := mc .ServiceMetricPrefix
69+
70+ // NOTE: fallback to Google Cloud prefix for backward compatibility
71+ // Prefix <service>.googleapis.com/ works only for Google Cloud metrics
72+ // List: https://cloud.google.com/monitoring/api/metrics_gcp
73+ if prefix == "" {
74+ prefix = mc .ServiceName + ".googleapis.com/"
75+ }
76+
77+ // Final slash is part of prefix. Creating a prefix with final slash
78+ // normalize the prefix for other use cases
79+ if ! strings .HasSuffix (prefix , "/" ) {
80+ prefix = prefix + "/"
81+ }
82+
83+ return prefix
84+ }
85+
86+ // AddPrefixTo adds the required service metric prefix to the given metric
87+ func (mc metricsConfig ) AddPrefixTo (metric string ) string {
88+ return mc .prefix () + metric
89+ }
90+
91+ // RemovePrefixFrom removes service metric prefix from the given metric
92+ func (mc metricsConfig ) RemovePrefixFrom (metric string ) string {
93+ return strings .TrimPrefix (metric , mc .prefix ())
5794}
5895
5996type metricMeta struct {
@@ -135,7 +172,7 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) (err erro
135172 return err
136173 }
137174
138- events , err := m .eventMapping (ctx , responses , sdc . ServiceName )
175+ events , err := m .eventMapping (ctx , responses , sdc )
139176 if err != nil {
140177 err = errors .Wrap (err , "eventMapping failed" )
141178 m .Logger ().Error (err )
@@ -150,14 +187,14 @@ func (m *MetricSet) Fetch(ctx context.Context, reporter mb.ReporterV2) (err erro
150187 return nil
151188}
152189
153- func (m * MetricSet ) eventMapping (ctx context.Context , tss []timeSeriesWithAligner , serviceName string ) ([]mb.Event , error ) {
154- e := newIncomingFieldExtractor (m .Logger ())
190+ func (m * MetricSet ) eventMapping (ctx context.Context , tss []timeSeriesWithAligner , sdc metricsConfig ) ([]mb.Event , error ) {
191+ e := newIncomingFieldExtractor (m .Logger (), sdc )
155192
156193 var gcpService = gcp .NewStackdriverMetadataServiceForTimeSeries (nil )
157194 var err error
158195
159196 if ! m .config .ExcludeLabels {
160- if gcpService , err = NewMetadataServiceForConfig (m .config , serviceName ); err != nil {
197+ if gcpService , err = NewMetadataServiceForConfig (m .config , sdc . ServiceName ); err != nil {
161198 return nil , errors .Wrap (err , "error trying to create metadata service" )
162199 }
163200 }
@@ -182,7 +219,7 @@ func (m *MetricSet) eventMapping(ctx context.Context, tss []timeSeriesWithAligne
182219 event .MetricSetFields .Put (singleEvent .Key , singleEvent .Value )
183220 }
184221
185- if serviceName == "compute" {
222+ if sdc . ServiceName == "compute" {
186223 event .RootFields = addHostFields (groupedEvents )
187224 } else {
188225 event .RootFields = groupedEvents [0 ].ECS
0 commit comments