go.temporal.io/server@v1.23.0/common/metrics/config_test.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 metrics
    26  
    27  import (
    28  	"testing"
    29  
    30  	"github.com/golang/mock/gomock"
    31  	"github.com/stretchr/testify/assert"
    32  	"github.com/stretchr/testify/require"
    33  	"github.com/stretchr/testify/suite"
    34  	"github.com/uber-go/tally/v4"
    35  	"github.com/uber-go/tally/v4/m3"
    36  
    37  	"go.temporal.io/server/common/log"
    38  )
    39  
    40  type MetricsSuite struct {
    41  	*require.Assertions
    42  	suite.Suite
    43  	controller *gomock.Controller
    44  }
    45  
    46  func TestMetricsSuite(t *testing.T) {
    47  	suite.Run(t, new(MetricsSuite))
    48  }
    49  
    50  func (s *MetricsSuite) SetupTest() {
    51  	s.Assertions = require.New(s.T())
    52  	s.controller = gomock.NewController(s.T())
    53  }
    54  
    55  func (s *MetricsSuite) TestStatsd() {
    56  	statsd := &StatsdConfig{
    57  		HostPort: "127.0.0.1:8125",
    58  		Prefix:   "testStatsd",
    59  	}
    60  
    61  	config := new(Config)
    62  	config.Statsd = statsd
    63  	scope := NewScope(log.NewNoopLogger(), config)
    64  	s.NotNil(scope)
    65  }
    66  
    67  func (s *MetricsSuite) TestM3() {
    68  	m3 := &m3.Configuration{
    69  		HostPort: "127.0.0.1:8125",
    70  		Service:  "testM3",
    71  		Env:      "devel",
    72  	}
    73  	config := new(Config)
    74  	config.M3 = m3
    75  	scope := NewScope(log.NewNoopLogger(), config)
    76  	s.NotNil(scope)
    77  }
    78  
    79  func (s *MetricsSuite) TestPrometheus() {
    80  	prom := &PrometheusConfig{
    81  		OnError:       "panic",
    82  		TimerType:     "histogram",
    83  		ListenAddress: "127.0.0.1:0",
    84  	}
    85  	config := new(Config)
    86  	config.Prometheus = prom
    87  	scope := NewScope(log.NewNoopLogger(), config)
    88  	s.NotNil(scope)
    89  }
    90  
    91  func (s *MetricsSuite) TestPrometheusWithSanitizeOptions() {
    92  	validChars := &ValidCharacters{
    93  		Ranges: []SanitizeRange{
    94  			{
    95  				StartRange: "a",
    96  				EndRange:   "z",
    97  			},
    98  			{
    99  				StartRange: "A",
   100  				EndRange:   "Z",
   101  			},
   102  			{
   103  				StartRange: "0",
   104  				EndRange:   "9",
   105  			},
   106  		},
   107  		SafeCharacters: "-",
   108  	}
   109  
   110  	prom := &PrometheusConfig{
   111  		OnError:       "panic",
   112  		TimerType:     "histogram",
   113  		ListenAddress: "127.0.0.1:0",
   114  		SanitizeOptions: &SanitizeOptions{
   115  			NameCharacters:       validChars,
   116  			KeyCharacters:        validChars,
   117  			ValueCharacters:      validChars,
   118  			ReplacementCharacter: "_",
   119  		},
   120  	}
   121  	config := new(Config)
   122  	config.Prometheus = prom
   123  	scope := NewScope(log.NewNoopLogger(), config)
   124  	s.NotNil(scope)
   125  }
   126  
   127  func (s *MetricsSuite) TestNoop() {
   128  	config := &Config{}
   129  	scope := NewScope(log.NewNoopLogger(), config)
   130  	s.Equal(tally.NoopScope, scope)
   131  }
   132  
   133  func (s *MetricsSuite) TestSetDefaultPerUnitHistogramBoundaries() {
   134  	type histogramTest struct {
   135  		input        map[string][]float64
   136  		expectResult map[string][]float64
   137  	}
   138  
   139  	customizedBoundaries := map[string][]float64{
   140  		Dimensionless: {1},
   141  		Milliseconds:  defaultPerUnitHistogramBoundaries[Milliseconds],
   142  		Bytes:         defaultPerUnitHistogramBoundaries[Bytes],
   143  	}
   144  	testCases := []histogramTest{
   145  		{
   146  			input:        nil,
   147  			expectResult: defaultPerUnitHistogramBoundaries,
   148  		},
   149  		{
   150  			input: map[string][]float64{
   151  				UnitNameDimensionless: {1},
   152  				"notDefine":           {1},
   153  			},
   154  			expectResult: customizedBoundaries,
   155  		},
   156  	}
   157  
   158  	for _, test := range testCases {
   159  		config := &ClientConfig{PerUnitHistogramBoundaries: test.input}
   160  		setDefaultPerUnitHistogramBoundaries(config)
   161  		s.Equal(test.expectResult, config.PerUnitHistogramBoundaries)
   162  	}
   163  }
   164  
   165  func TestMetricsHandlerFromConfig(t *testing.T) {
   166  	t.Parallel()
   167  
   168  	logger := log.NewTestLogger()
   169  
   170  	for _, c := range []struct {
   171  		name         string
   172  		cfg          *Config
   173  		expectedType interface{}
   174  	}{
   175  		{
   176  			name:         "nil config",
   177  			cfg:          nil,
   178  			expectedType: &noopMetricsHandler{},
   179  		},
   180  		{
   181  			name: "tally",
   182  			cfg: &Config{
   183  				Prometheus: &PrometheusConfig{
   184  					Framework:     FrameworkTally,
   185  					ListenAddress: "localhost:0",
   186  				},
   187  			},
   188  			expectedType: &tallyMetricsHandler{},
   189  		},
   190  		{
   191  			name: "opentelemetry",
   192  			cfg: &Config{
   193  				Prometheus: &PrometheusConfig{
   194  					Framework:     FrameworkOpentelemetry,
   195  					ListenAddress: "localhost:0",
   196  				},
   197  			},
   198  			expectedType: &otelMetricsHandler{},
   199  		},
   200  	} {
   201  		c := c
   202  		t.Run(c.name, func(t *testing.T) {
   203  			t.Parallel()
   204  
   205  			handler, err := MetricsHandlerFromConfig(logger, c.cfg)
   206  			require.NoError(t, err)
   207  			t.Cleanup(func() {
   208  				handler.Stop(logger)
   209  			})
   210  			assert.IsType(t, c.expectedType, handler)
   211  		})
   212  	}
   213  
   214  }