Update custom-metrics-apiserver and metrics-server

This commit is contained in:
Johannes Würbach 2020-09-27 22:14:53 +02:00
parent 4c673534f2
commit b480e45a67
No known key found for this signature in database
GPG key ID: 74DB0F4D956CCCE3
915 changed files with 63694 additions and 106514 deletions

View file

@ -100,6 +100,10 @@ type Config struct {
// needs to process an incoming event.
IndexerFuncs storage.IndexerFuncs
// Indexers is used to accelerate the list operation, falls back to regular list
// operation if no indexer found.
Indexers *cache.Indexers
// NewFunc is a function that creates new empty object storing a object of type Type.
NewFunc func() runtime.Object
@ -367,7 +371,7 @@ func NewCacherFromConfig(config Config) (*Cacher, error) {
}
watchCache := newWatchCache(
config.CacheCapacity, config.KeyFunc, cacher.processEvent, config.GetAttrsFunc, config.Versioner)
config.CacheCapacity, config.KeyFunc, cacher.processEvent, config.GetAttrsFunc, config.Versioner, config.Indexers)
listerWatcher := NewCacherListerWatcher(config.Storage, config.ResourcePrefix, config.NewListFunc)
reflectorName := "storage/cacher.go:" + config.ResourcePrefix
@ -701,7 +705,7 @@ func (c *Cacher) List(ctx context.Context, key string, resourceVersion string, p
}
filter := filterWithAttrsFunction(key, pred)
objs, readResourceVersion, err := c.watchCache.WaitUntilFreshAndList(listRV, trace)
objs, readResourceVersion, err := c.watchCache.WaitUntilFreshAndList(listRV, pred.MatcherIndex(), trace)
if err != nil {
return err
}

View file

@ -82,6 +82,35 @@ func storeElementKey(obj interface{}) (string, error) {
return elem.Key, nil
}
func storeElementObject(obj interface{}) (runtime.Object, error) {
elem, ok := obj.(*storeElement)
if !ok {
return nil, fmt.Errorf("not a storeElement: %v", obj)
}
return elem.Object, nil
}
func storeElementIndexFunc(objIndexFunc cache.IndexFunc) cache.IndexFunc {
return func(obj interface{}) (strings []string, e error) {
seo, err := storeElementObject(obj)
if err != nil {
return nil, err
}
return objIndexFunc(seo)
}
}
func storeElementIndexers(indexers *cache.Indexers) cache.Indexers {
if indexers == nil {
return cache.Indexers{}
}
ret := cache.Indexers{}
for indexName, indexFunc := range *indexers {
ret[indexName] = storeElementIndexFunc(indexFunc)
}
return ret
}
// watchCache implements a Store interface.
// However, it depends on the elements implementing runtime.Object interface.
//
@ -116,7 +145,7 @@ type watchCache struct {
// history" i.e. from the moment just after the newest cached watched event.
// It is necessary to effectively allow clients to start watching at now.
// NOTE: We assume that <store> is thread-safe.
store cache.Store
store cache.Indexer
// ResourceVersion up to which the watchCache is propagated.
resourceVersion uint64
@ -143,7 +172,8 @@ func newWatchCache(
keyFunc func(runtime.Object) (string, error),
eventHandler func(*watchCacheEvent),
getAttrsFunc func(runtime.Object) (labels.Set, fields.Set, error),
versioner storage.Versioner) *watchCache {
versioner storage.Versioner,
indexers *cache.Indexers) *watchCache {
wc := &watchCache{
capacity: capacity,
keyFunc: keyFunc,
@ -151,7 +181,7 @@ func newWatchCache(
cache: make([]*watchCacheEvent, capacity),
startIndex: 0,
endIndex: 0,
store: cache.NewStore(storeElementKey),
store: cache.NewIndexer(storeElementKey, storeElementIndexers(indexers)),
resourceVersion: 0,
listResourceVersion: 0,
eventHandler: eventHandler,
@ -319,12 +349,22 @@ func (w *watchCache) waitUntilFreshAndBlock(resourceVersion uint64, trace *utilt
}
// WaitUntilFreshAndList returns list of pointers to <storeElement> objects.
func (w *watchCache) WaitUntilFreshAndList(resourceVersion uint64, trace *utiltrace.Trace) ([]interface{}, uint64, error) {
func (w *watchCache) WaitUntilFreshAndList(resourceVersion uint64, matchValues []storage.MatchValue, trace *utiltrace.Trace) ([]interface{}, uint64, error) {
err := w.waitUntilFreshAndBlock(resourceVersion, trace)
defer w.RUnlock()
if err != nil {
return nil, 0, err
}
// This isn't the place where we do "final filtering" - only some "prefiltering" is happening here. So the only
// requirement here is to NOT miss anything that should be returned. We can return as many non-matching items as we
// want - they will be filtered out later. The fact that we return less things is only further performance improvement.
// TODO: if multiple indexes match, return the one with the fewest items, so as to do as much filtering as possible.
for _, matchValue := range matchValues {
if result, err := w.store.ByIndex(matchValue.IndexName, matchValue.Value); err == nil {
return result, w.resourceVersion, nil
}
}
return w.store.List(), w.resourceVersion, nil
}

View file

@ -49,16 +49,6 @@ var (
},
[]string{"resource"},
)
deprecatedEtcdRequestLatenciesSummary = compbasemetrics.NewSummaryVec(
&compbasemetrics.SummaryOpts{
Name: "etcd_request_latencies_summary",
Help: "Etcd request latency summary in microseconds for each operation and object type.",
StabilityLevel: compbasemetrics.ALPHA,
DeprecatedVersion: "1.14.0",
},
[]string{"operation", "type"},
)
)
var registerMetrics sync.Once
@ -69,9 +59,6 @@ func Register() {
registerMetrics.Do(func() {
legacyregistry.MustRegister(etcdRequestLatency)
legacyregistry.MustRegister(objectCounts)
// TODO(danielqsj): Remove the following metrics, they are deprecated
legacyregistry.MustRegister(deprecatedEtcdRequestLatenciesSummary)
})
}
@ -83,19 +70,11 @@ func UpdateObjectCount(resourcePrefix string, count int64) {
// RecordEtcdRequestLatency sets the etcd_request_duration_seconds metrics.
func RecordEtcdRequestLatency(verb, resource string, startTime time.Time) {
etcdRequestLatency.WithLabelValues(verb, resource).Observe(sinceInSeconds(startTime))
deprecatedEtcdRequestLatenciesSummary.WithLabelValues(verb, resource).Observe(sinceInMicroseconds(startTime))
}
// Reset resets the etcd_request_duration_seconds metric.
func Reset() {
etcdRequestLatency.Reset()
deprecatedEtcdRequestLatenciesSummary.Reset()
}
// sinceInMicroseconds gets the time since the specified start in microseconds.
func sinceInMicroseconds(start time.Time) float64 {
return float64(time.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds())
}
// sinceInSeconds gets the time since the specified start in seconds.

View file

@ -32,6 +32,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/conversion"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
@ -394,6 +395,8 @@ func (s *store) GetToList(ctx context.Context, key string, resourceVersion strin
return fmt.Errorf("need ptr to slice: %v", err)
}
newItemFunc := getNewItemFunc(listObj, v)
key = path.Join(s.pathPrefix, key)
startTime := time.Now()
getResp, err := s.client.KV.Get(ctx, key, s.getOps...)
@ -410,7 +413,7 @@ func (s *store) GetToList(ctx context.Context, key string, resourceVersion strin
if err != nil {
return storage.NewInternalError(err.Error())
}
if err := appendListItem(v, data, uint64(getResp.Kvs[0].ModRevision), pred, s.codec, s.versioner); err != nil {
if err := appendListItem(v, data, uint64(getResp.Kvs[0].ModRevision), pred, s.codec, s.versioner, newItemFunc); err != nil {
return err
}
}
@ -418,6 +421,23 @@ func (s *store) GetToList(ctx context.Context, key string, resourceVersion strin
return s.versioner.UpdateList(listObj, uint64(getResp.Header.Revision), "", nil)
}
func getNewItemFunc(listObj runtime.Object, v reflect.Value) func() runtime.Object {
// For unstructured lists with a target group/version, preserve the group/version in the instantiated list items
if unstructuredList, isUnstructured := listObj.(*unstructured.UnstructuredList); isUnstructured {
if apiVersion := unstructuredList.GetAPIVersion(); len(apiVersion) > 0 {
return func() runtime.Object {
return &unstructured.Unstructured{Object: map[string]interface{}{"apiVersion": apiVersion}}
}
}
}
// Otherwise just instantiate an empty item
elem := v.Type().Elem()
return func() runtime.Object {
return reflect.New(elem).Interface().(runtime.Object)
}
}
func (s *store) Count(key string) (int64, error) {
key = path.Join(s.pathPrefix, key)
startTime := time.Now()
@ -525,6 +545,8 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
options = append(options, clientv3.WithLimit(pred.Limit))
}
newItemFunc := getNewItemFunc(listObj, v)
var returnedRV, continueRV int64
var continueKey string
switch {
@ -609,7 +631,7 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
return storage.NewInternalErrorf("unable to transform key %q: %v", kv.Key, err)
}
if err := appendListItem(v, data, uint64(kv.ModRevision), pred, s.codec, s.versioner); err != nil {
if err := appendListItem(v, data, uint64(kv.ModRevision), pred, s.codec, s.versioner, newItemFunc); err != nil {
return err
}
}
@ -832,8 +854,8 @@ func decode(codec runtime.Codec, versioner storage.Versioner, value []byte, objP
}
// appendListItem decodes and appends the object (if it passes filter) to v, which must be a slice.
func appendListItem(v reflect.Value, data []byte, rev uint64, pred storage.SelectionPredicate, codec runtime.Codec, versioner storage.Versioner) error {
obj, _, err := codec.Decode(data, nil, reflect.New(v.Type().Elem()).Interface().(runtime.Object))
func appendListItem(v reflect.Value, data []byte, rev uint64, pred storage.SelectionPredicate, codec runtime.Codec, versioner storage.Versioner, newItemFunc func() runtime.Object) error {
obj, _, err := codec.Decode(data, nil, newItemFunc())
if err != nil {
return err
}

View file

@ -25,7 +25,7 @@ import (
"strings"
"sync"
apierrs "k8s.io/apimachinery/pkg/api/errors"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/storage"
@ -191,6 +191,15 @@ func (wc *watchChan) sync() error {
return nil
}
// logWatchChannelErr checks whether the error is about mvcc revision compaction which is regarded as warning
func logWatchChannelErr(err error) {
if !strings.Contains(err.Error(), "mvcc: required revision has been compacted") {
klog.Errorf("watch chan error: %v", err)
} else {
klog.Warningf("watch chan error: %v", err)
}
}
// startWatching does:
// - get current objects if initialRev=0; set initialRev to current rev
// - watch on given key and send events to process.
@ -211,14 +220,14 @@ func (wc *watchChan) startWatching(watchClosedCh chan struct{}) {
if wres.Err() != nil {
err := wres.Err()
// If there is an error on server (e.g. compaction), the channel will return it before closed.
klog.Errorf("watch chan error: %v", err)
logWatchChannelErr(err)
wc.sendError(err)
return
}
for _, e := range wres.Events {
parsedEvent, err := parseEvent(e)
if err != nil {
klog.Errorf("watch chan error: %v", err)
logWatchChannelErr(err)
wc.sendError(err)
return
}
@ -332,10 +341,10 @@ func (wc *watchChan) transform(e *event) (res *watch.Event) {
func transformErrorToEvent(err error) *watch.Event {
err = interpretWatchError(err)
if _, ok := err.(apierrs.APIStatus); !ok {
err = apierrs.NewInternalError(err)
if _, ok := err.(apierrors.APIStatus); !ok {
err = apierrors.NewInternalError(err)
}
status := err.(apierrs.APIStatus).Status()
status := err.(apierrors.APIStatus).Status()
return &watch.Event{
Type: watch.Error,
Object: &status,

View file

@ -87,6 +87,12 @@ var Everything = SelectionPredicate{
Field: fields.Everything(),
}
// MatchValue defines a pair (<index name>, <value for that index>).
type MatchValue struct {
IndexName string
Value string
}
// Pass an UpdateFunc to Interface.GuaranteedUpdate to make an update
// that is guaranteed to succeed.
// See the comment for GuaranteedUpdate for more details.
@ -218,7 +224,7 @@ type Interface interface {
// err := s.GuaranteedUpdate(
// "myKey", &MyType{}, true,
// func(input runtime.Object, res ResponseMeta) (runtime.Object, *uint64, error) {
// // Before each incovation of the user defined function, "input" is reset to
// // Before each invocation of the user defined function, "input" is reset to
// // current contents for "myKey" in database.
// curr := input.(*MyType) // Guaranteed to succeed.
//

View file

@ -74,6 +74,7 @@ type SelectionPredicate struct {
Label labels.Selector
Field fields.Selector
GetAttrs AttrFunc
IndexLabels []string
IndexFields []string
Limit int64
Continue string
@ -128,3 +129,31 @@ func (s *SelectionPredicate) MatchesSingle() (string, bool) {
func (s *SelectionPredicate) Empty() bool {
return s.Label.Empty() && s.Field.Empty()
}
// For any index defined by IndexFields, if a matcher can match only (a subset)
// of objects that return <value> for a given index, a pair (<index name>, <value>)
// wil be returned.
func (s *SelectionPredicate) MatcherIndex() []MatchValue {
var result []MatchValue
for _, field := range s.IndexFields {
if value, ok := s.Field.RequiresExactMatch(field); ok {
result = append(result, MatchValue{IndexName: FieldIndex(field), Value: value})
}
}
for _, label := range s.IndexLabels {
if value, ok := s.Label.RequiresExactMatch(label); ok {
result = append(result, MatchValue{IndexName: LabelIndex(label), Value: value})
}
}
return result
}
// LabelIndex add prefix for label index.
func LabelIndex(label string) string {
return "l:" + label
}
// FiledIndex add prefix for field index.
func FieldIndex(field string) string {
return "f:" + field
}

View file

@ -31,11 +31,9 @@ import (
"golang.org/x/crypto/cryptobyte"
)
// defaultCacheSize is the number of decrypted DEKs which would be cached by the transformer.
const defaultCacheSize = 1000
func init() {
value.RegisterMetrics()
registerMetrics()
}
// Service allows encrypting and decrypting data using an external Key Management Service.
@ -54,6 +52,9 @@ type envelopeTransformer struct {
// baseTransformerFunc creates a new transformer for encrypting the data with the DEK.
baseTransformerFunc func(cipher.Block) value.Transformer
cacheSize int
cacheEnabled bool
}
// NewEnvelopeTransformer returns a transformer which implements a KEK-DEK based envelope encryption scheme.
@ -61,22 +62,30 @@ type envelopeTransformer struct {
// the data items they encrypt. A cache (of size cacheSize) is maintained to store the most recently
// used decrypted DEKs in memory.
func NewEnvelopeTransformer(envelopeService Service, cacheSize int, baseTransformerFunc func(cipher.Block) value.Transformer) (value.Transformer, error) {
if cacheSize == 0 {
cacheSize = defaultCacheSize
}
cache, err := lru.New(cacheSize)
if err != nil {
return nil, err
var (
cache *lru.Cache
err error
)
if cacheSize > 0 {
cache, err = lru.New(cacheSize)
if err != nil {
return nil, err
}
}
return &envelopeTransformer{
envelopeService: envelopeService,
transformers: cache,
baseTransformerFunc: baseTransformerFunc,
cacheEnabled: cacheSize > 0,
cacheSize: cacheSize,
}, nil
}
// TransformFromStorage decrypts data encrypted by this transformer using envelope encryption.
func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Context) ([]byte, bool, error) {
recordArrival(fromStorageLabel, time.Now())
// Read the 16 bit length-of-DEK encoded at the start of the encrypted DEK. 16 bits can
// represent a maximum key length of 65536 bytes. We are using a 256 bit key, whose
// length cannot fit in 8 bits (1 byte). Thus, we use 16 bits (2 bytes) to store the length.
@ -91,7 +100,9 @@ func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Co
// Look up the decrypted DEK from cache or Envelope.
transformer := t.getTransformer(encKey)
if transformer == nil {
value.RecordCacheMiss()
if t.cacheEnabled {
value.RecordCacheMiss()
}
key, err := t.envelopeService.Decrypt(encKey)
if err != nil {
// Do NOT wrap this err using fmt.Errorf() or similar functions
@ -99,6 +110,7 @@ func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Co
// record the metric.
return nil, false, err
}
transformer, err = t.addTransformer(encKey, key)
if err != nil {
return nil, false, err
@ -110,6 +122,7 @@ func (t *envelopeTransformer) TransformFromStorage(data []byte, context value.Co
// TransformToStorage encrypts data to be written to disk using envelope encryption.
func (t *envelopeTransformer) TransformToStorage(data []byte, context value.Context) ([]byte, error) {
recordArrival(toStorageLabel, time.Now())
newKey, err := generateKey(32)
if err != nil {
return nil, err
@ -153,12 +166,19 @@ func (t *envelopeTransformer) addTransformer(encKey []byte, key []byte) (value.T
transformer := t.baseTransformerFunc(block)
// Use base64 of encKey as the key into the cache because hashicorp/golang-lru
// cannot hash []uint8.
t.transformers.Add(base64.StdEncoding.EncodeToString(encKey), transformer)
if t.cacheEnabled {
t.transformers.Add(base64.StdEncoding.EncodeToString(encKey), transformer)
dekCacheFillPercent.Set(float64(t.transformers.Len()) / float64(t.cacheSize))
}
return transformer, nil
}
// getTransformer fetches the transformer corresponding to encKey from cache, if it exists.
func (t *envelopeTransformer) getTransformer(encKey []byte) value.Transformer {
if !t.cacheEnabled {
return nil
}
_transformer, found := t.transformers.Get(base64.StdEncoding.EncodeToString(encKey))
if found {
return _transformer.(value.Transformer)

View file

@ -0,0 +1,102 @@
/*
Copyright 2020 The Kubernetes Authors.
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 envelope
import (
"sync"
"time"
"k8s.io/component-base/metrics"
"k8s.io/component-base/metrics/legacyregistry"
)
const (
namespace = "apiserver"
subsystem = "envelope_encryption"
fromStorageLabel = "from_storage"
toStorageLabel = "to_storage"
)
/*
* By default, all the following metrics are defined as falling under
* ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/20190404-kubernetes-control-plane-metrics-stability.md#stability-classes)
*
* Promoting the stability level of the metric is a responsibility of the component owner, since it
* involves explicitly acknowledging support for the metric across multiple releases, in accordance with
* the metric stability policy.
*/
var (
lockLastFromStorage sync.Mutex
lockLastToStorage sync.Mutex
lastFromStorage time.Time
lastToStorage time.Time
dekCacheFillPercent = metrics.NewGauge(
&metrics.GaugeOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "dek_cache_fill_percent",
Help: "Percent of the cache slots currently occupied by cached DEKs.",
StabilityLevel: metrics.ALPHA,
},
)
dekCacheInterArrivals = metrics.NewHistogramVec(
&metrics.HistogramOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "dek_cache_inter_arrival_time_seconds",
Help: "Time (in seconds) of inter arrival of transformation requests.",
StabilityLevel: metrics.ALPHA,
Buckets: metrics.ExponentialBuckets(60, 2, 10),
},
[]string{"transformation_type"},
)
)
var registerMetricsFunc sync.Once
func registerMetrics() {
registerMetricsFunc.Do(func() {
legacyregistry.MustRegister(dekCacheFillPercent)
legacyregistry.MustRegister(dekCacheInterArrivals)
})
}
func recordArrival(transformationType string, start time.Time) {
switch transformationType {
case fromStorageLabel:
lockLastFromStorage.Lock()
defer lockLastFromStorage.Unlock()
if lastFromStorage.IsZero() {
lastFromStorage = start
}
dekCacheInterArrivals.WithLabelValues(transformationType).Observe(start.Sub(lastFromStorage).Seconds())
lastFromStorage = start
case toStorageLabel:
lockLastToStorage.Lock()
defer lockLastToStorage.Unlock()
if lastToStorage.IsZero() {
lastToStorage = start
}
dekCacheInterArrivals.WithLabelValues(transformationType).Observe(start.Sub(lastToStorage).Seconds())
lastToStorage = start
}
}

View file

@ -38,7 +38,7 @@ var _ = math.Inf
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
type VersionRequest struct {
// Version of the KMS plugin API.

View file

@ -53,20 +53,6 @@ var (
},
[]string{"transformation_type"},
)
deprecatedTransformerLatencies = metrics.NewHistogramVec(
&metrics.HistogramOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "transformation_latencies_microseconds",
Help: "Latencies in microseconds of value transformation operations.",
// In-process transformations (ex. AES CBC) complete on the order of 20 microseconds. However, when
// external KMS is involved latencies may climb into milliseconds.
Buckets: metrics.ExponentialBuckets(5, 2, 14),
StabilityLevel: metrics.ALPHA,
DeprecatedVersion: "1.14.0",
},
[]string{"transformation_type"},
)
transformerOperationsTotal = metrics.NewCounterVec(
&metrics.CounterOpts{
@ -79,18 +65,6 @@ var (
[]string{"transformation_type", "transformer_prefix", "status"},
)
deprecatedTransformerFailuresTotal = metrics.NewCounterVec(
&metrics.CounterOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "transformation_failures_total",
Help: "Total number of failed transformation operations.",
StabilityLevel: metrics.ALPHA,
DeprecatedVersion: "1.15.0",
},
[]string{"transformation_type"},
)
envelopeTransformationCacheMissTotal = metrics.NewCounter(
&metrics.CounterOpts{
Namespace: namespace,
@ -111,17 +85,7 @@ var (
StabilityLevel: metrics.ALPHA,
},
)
deprecatedDataKeyGenerationLatencies = metrics.NewHistogram(
&metrics.HistogramOpts{
Namespace: namespace,
Subsystem: subsystem,
Name: "data_key_generation_latencies_microseconds",
Help: "Latencies in microseconds of data encryption key(DEK) generation operations.",
Buckets: metrics.ExponentialBuckets(5, 2, 14),
StabilityLevel: metrics.ALPHA,
DeprecatedVersion: "1.14.0",
},
)
dataKeyGenerationFailuresTotal = metrics.NewCounter(
&metrics.CounterOpts{
Namespace: namespace,
@ -138,12 +102,9 @@ var registerMetrics sync.Once
func RegisterMetrics() {
registerMetrics.Do(func() {
legacyregistry.MustRegister(transformerLatencies)
legacyregistry.MustRegister(deprecatedTransformerLatencies)
legacyregistry.MustRegister(transformerOperationsTotal)
legacyregistry.MustRegister(deprecatedTransformerFailuresTotal)
legacyregistry.MustRegister(envelopeTransformationCacheMissTotal)
legacyregistry.MustRegister(dataKeyGenerationLatencies)
legacyregistry.MustRegister(deprecatedDataKeyGenerationLatencies)
legacyregistry.MustRegister(dataKeyGenerationFailuresTotal)
})
}
@ -156,9 +117,6 @@ func RecordTransformation(transformationType, transformerPrefix string, start ti
switch {
case err == nil:
transformerLatencies.WithLabelValues(transformationType).Observe(sinceInSeconds(start))
deprecatedTransformerLatencies.WithLabelValues(transformationType).Observe(sinceInMicroseconds(start))
default:
deprecatedTransformerFailuresTotal.WithLabelValues(transformationType).Inc()
}
}
@ -175,12 +133,6 @@ func RecordDataKeyGeneration(start time.Time, err error) {
}
dataKeyGenerationLatencies.Observe(sinceInSeconds(start))
deprecatedDataKeyGenerationLatencies.Observe(sinceInMicroseconds(start))
}
// sinceInMicroseconds gets the time since the specified start in microseconds.
func sinceInMicroseconds(start time.Time) float64 {
return float64(time.Since(start).Nanoseconds() / time.Microsecond.Nanoseconds())
}
// sinceInSeconds gets the time since the specified start in seconds.