pkg/buildermetrics/buildermetrics.go (77 lines of code) (raw):

// Copyright 2022 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // Package buildermetrics provides functionality to write metrics to builderoutput. // THIS PACKAGE IS NOT THREADSAFE. package buildermetrics import ( "encoding/json" "sync" ) var ( bm *BuilderMetrics mu sync.Mutex once sync.Once ) // BuilderMetrics contains the metrics to be reported to RCS via BuilderOutput type BuilderMetrics struct { counters map[MetricID]*Counter floatDPs map[MetricID]*FloatDP } // NewBuilderMetrics returns a new, empty BuilderMetrics // For testing use only func NewBuilderMetrics() BuilderMetrics { return BuilderMetrics{make(map[MetricID]*Counter), make(map[MetricID]*FloatDP)} } // GetCounter returns the Counter with MetricID m, or creates it func (b *BuilderMetrics) GetCounter(m MetricID) *Counter { if _, found := b.counters[m]; !found { b.counters[m] = &Counter{} } return b.counters[m] } // ForEachCounter executes a function for each initialized Counter func (b *BuilderMetrics) ForEachCounter(f func(MetricID, *Counter)) { for id, c := range b.counters { f(id, c) } } // GetFloatDP returns the FloatDP with MetricID m, or creates it func (b *BuilderMetrics) GetFloatDP(m MetricID) *FloatDP { if _, found := b.floatDPs[m]; !found { b.floatDPs[m] = &FloatDP{} } return b.floatDPs[m] } // ForEachFloatDP executes a function for each initialized FloatDP func (b *BuilderMetrics) ForEachFloatDP(f func(MetricID, *FloatDP)) { for id, fm := range b.floatDPs { f(id, fm) } } // Reset resets the state of the metrics struct // For testing use only. func Reset() { mu.Lock() defer mu.Unlock() bm = &BuilderMetrics{make(map[MetricID]*Counter), make(map[MetricID]*FloatDP)} } // GlobalBuilderMetrics returns a pointer to the BuilderMetrics singleton func GlobalBuilderMetrics() *BuilderMetrics { mu.Lock() defer mu.Unlock() once.Do( func() { bm = &BuilderMetrics{make(map[MetricID]*Counter), make(map[MetricID]*FloatDP)} }) return bm } type metricsMaps struct { Counters map[MetricID]*Counter `json:"c,omitempty"` FloatDPs map[MetricID]*FloatDP `json:"f,omitempty"` } // MarshalJSON is a custom marshaler for BuilderMetrics func (b BuilderMetrics) MarshalJSON() ([]byte, error) { return json.Marshal(metricsMaps{Counters: b.counters, FloatDPs: b.floatDPs}) } // UnmarshalJSON is a custom unmarshaller for BuilderMetrics func (b *BuilderMetrics) UnmarshalJSON(j []byte) error { var val metricsMaps if err := json.Unmarshal(j, &val); err != nil { return err } if val.Counters == nil { b.counters = make(map[MetricID]*Counter) } else { b.counters = val.Counters } if val.FloatDPs == nil { b.floatDPs = make(map[MetricID]*FloatDP) } else { b.floatDPs = val.FloatDPs } return nil }