go.temporal.io/server@v1.23.0/common/metrics/metricstest/capture_handler.go (about)

     1  // The MIT License
     2  //
     3  // Copyright (c) 2020 Temporal Technologies Inc.  All rights reserved.
     4  //
     5  // Copyright (c) 2020 Uber Technologies, Inc.
     6  //
     7  // Permission is hereby granted, free of charge, to any person obtaining a copy
     8  // of this software and associated documentation files (the "Software"), to deal
     9  // in the Software without restriction, including without limitation the rights
    10  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    11  // copies of the Software, and to permit persons to whom the Software is
    12  // furnished to do so, subject to the following conditions:
    13  //
    14  // The above copyright notice and this permission notice shall be included in
    15  // all copies or substantial portions of the Software.
    16  //
    17  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    18  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    19  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    20  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    21  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    22  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    23  // THE SOFTWARE.
    24  
    25  package metricstest
    26  
    27  import (
    28  	"sync"
    29  	"time"
    30  
    31  	"go.temporal.io/server/common/log"
    32  	"go.temporal.io/server/common/metrics"
    33  )
    34  
    35  // CapturedRecording is a single recording. Fields here should not be mutated.
    36  type CapturedRecording struct {
    37  	Value any
    38  	Tags  map[string]string
    39  	Unit  metrics.MetricUnit
    40  }
    41  
    42  // Capture is a specific capture instance.
    43  type Capture struct {
    44  	recordings     map[string][]*CapturedRecording
    45  	recordingsLock sync.RWMutex
    46  }
    47  
    48  // Snapshot returns a copy of all metrics recorded, keyed by name.
    49  func (c *Capture) Snapshot() map[string][]*CapturedRecording {
    50  	c.recordingsLock.RLock()
    51  	defer c.recordingsLock.RUnlock()
    52  	ret := make(map[string][]*CapturedRecording, len(c.recordings))
    53  	for k, v := range c.recordings {
    54  		recs := make([]*CapturedRecording, len(v))
    55  		copy(recs, v)
    56  		ret[k] = recs
    57  	}
    58  	return ret
    59  }
    60  
    61  func (c *Capture) record(name string, r *CapturedRecording) {
    62  	c.recordingsLock.Lock()
    63  	defer c.recordingsLock.Unlock()
    64  	c.recordings[name] = append(c.recordings[name], r)
    65  }
    66  
    67  // CaptureHandler is a [metrics.Handler] that captures each metric recording.
    68  type CaptureHandler struct {
    69  	tags         []metrics.Tag
    70  	captures     map[*Capture]struct{}
    71  	capturesLock *sync.RWMutex
    72  }
    73  
    74  var _ metrics.Handler = (*CaptureHandler)(nil)
    75  
    76  // NewCaptureHandler creates a new [metrics.Handler] that captures.
    77  func NewCaptureHandler() *CaptureHandler {
    78  	return &CaptureHandler{
    79  		captures:     map[*Capture]struct{}{},
    80  		capturesLock: &sync.RWMutex{},
    81  	}
    82  }
    83  
    84  // StartCapture returns a started capture. StopCapture should be called on
    85  // complete.
    86  func (c *CaptureHandler) StartCapture() *Capture {
    87  	capture := &Capture{recordings: map[string][]*CapturedRecording{}}
    88  	c.capturesLock.Lock()
    89  	defer c.capturesLock.Unlock()
    90  	c.captures[capture] = struct{}{}
    91  	return capture
    92  }
    93  
    94  // StopCapture stops capturing metrics for the given capture instance.
    95  func (c *CaptureHandler) StopCapture(capture *Capture) {
    96  	c.capturesLock.Lock()
    97  	defer c.capturesLock.Unlock()
    98  	delete(c.captures, capture)
    99  }
   100  
   101  // WithTags implements [metrics.Handler.WithTags].
   102  func (c *CaptureHandler) WithTags(tags ...metrics.Tag) metrics.Handler {
   103  	return &CaptureHandler{
   104  		tags:         append(append(make([]metrics.Tag, 0, len(c.tags)+len(tags)), c.tags...), tags...),
   105  		captures:     c.captures,
   106  		capturesLock: c.capturesLock,
   107  	}
   108  }
   109  
   110  func (c *CaptureHandler) record(name string, v any, unit metrics.MetricUnit, tags ...metrics.Tag) {
   111  	rec := &CapturedRecording{Value: v, Tags: make(map[string]string, len(c.tags)+len(tags)), Unit: unit}
   112  	for _, tag := range c.tags {
   113  		rec.Tags[tag.Key()] = tag.Value()
   114  	}
   115  	for _, tag := range tags {
   116  		rec.Tags[tag.Key()] = tag.Value()
   117  	}
   118  	c.capturesLock.RLock()
   119  	defer c.capturesLock.RUnlock()
   120  	for c := range c.captures {
   121  		c.record(name, rec)
   122  	}
   123  }
   124  
   125  // Counter implements [metrics.Handler.Counter].
   126  func (c *CaptureHandler) Counter(name string) metrics.CounterIface {
   127  	return metrics.CounterFunc(func(v int64, tags ...metrics.Tag) { c.record(name, v, "", tags...) })
   128  }
   129  
   130  // Gauge implements [metrics.Handler.Gauge].
   131  func (c *CaptureHandler) Gauge(name string) metrics.GaugeIface {
   132  	return metrics.GaugeFunc(func(v float64, tags ...metrics.Tag) { c.record(name, v, "", tags...) })
   133  }
   134  
   135  // Timer implements [metrics.Handler.Timer].
   136  func (c *CaptureHandler) Timer(name string) metrics.TimerIface {
   137  	return metrics.TimerFunc(func(v time.Duration, tags ...metrics.Tag) { c.record(name, v, "", tags...) })
   138  }
   139  
   140  // Histogram implements [metrics.Handler.Histogram].
   141  func (c *CaptureHandler) Histogram(name string, unit metrics.MetricUnit) metrics.HistogramIface {
   142  	return metrics.HistogramFunc(func(v int64, tags ...metrics.Tag) { c.record(name, v, unit, tags...) })
   143  }
   144  
   145  // Stop implements [metrics.Handler.Stop].
   146  func (*CaptureHandler) Stop(log.Logger) {}