From 766afc4bf6d2a5a86d6b80daafc77c02c64d2eb5 Mon Sep 17 00:00:00 2001 From: oleiade Date: Thu, 10 Mar 2022 12:21:59 +0100 Subject: [PATCH] Move the `stats` package content to `metrics` package Until now, we had two separate `stats` and `metrics` packages. Although their content was related, some components were living in one, some in the other. It lead to difficulties when having to work with both, and made cyclic dependencies really easy to run into. To simplify our workflow, and facilitate further developments, this commit moves the content of the `stats` package in the top-level `metrics` package. As of this commit, the `stats` package is removed, and all dependencies using it have been updated to use the `metrics` package instead. --- .../workflows/xk6-tests/xk6-js-test/jstest.go | 10 +- .../xk6-tests/xk6-output-test/outputtest.go | 6 +- api/v1/metric.go | 9 +- api/v1/metric_jsonapi.go | 8 +- api/v1/metric_routes_test.go | 25 +- api/v1/metric_test.go | 23 +- cmd/config.go | 6 +- cmd/config_consolidation_test.go | 10 +- .../eventloop/eventloop_test.go | 5 +- cmd/options.go | 10 +- core/engine.go | 9 +- core/engine_test.go | 89 ++- core/local/local.go | 19 +- core/local/local_test.go | 89 ++- js/console_test.go | 5 +- js/empty_iterations_bench_test.go | 4 +- js/http_bench_test.go | 6 +- js/init_and_modules_test.go | 5 +- js/initcontext_test.go | 5 +- js/module_loading_test.go | 7 +- js/modules/k6/execution/execution_test.go | 4 +- js/modules/k6/grpc/client.go | 30 +- js/modules/k6/grpc/client_test.go | 35 +- js/modules/k6/http/request_test.go | 119 ++-- js/modules/k6/http/response_callback_test.go | 21 +- js/modules/k6/http/response_test.go | 27 +- js/modules/k6/k6.go | 22 +- js/modules/k6/k6_test.go | 41 +- js/modules/k6/marshalling_test.go | 3 +- js/modules/k6/metrics/metrics.go | 22 +- js/modules/k6/metrics/metrics_test.go | 25 +- js/modules/k6/ws/ws.go | 35 +- js/modules/k6/ws/ws_test.go | 122 ++-- js/runner.go | 35 +- js/runner_test.go | 85 ++- js/share_test.go | 3 +- js/summary.go | 16 +- js/summary_test.go | 59 +- lib/archive_test.go | 10 +- lib/execution.go | 5 +- lib/executor/base_executor.go | 10 +- lib/executor/common_test.go | 6 +- lib/executor/constant_arrival_rate.go | 6 +- lib/executor/constant_arrival_rate_test.go | 15 +- lib/executor/constant_vus.go | 4 +- lib/executor/externally_controlled.go | 4 +- lib/executor/helpers_test.go | 6 +- lib/executor/per_vu_iterations.go | 6 +- lib/executor/per_vu_iterations_test.go | 7 +- lib/executor/ramping_arrival_rate.go | 6 +- lib/executor/ramping_arrival_rate_test.go | 17 +- lib/executor/ramping_vus.go | 4 +- lib/executor/shared_iterations.go | 6 +- lib/executor/shared_iterations_test.go | 7 +- lib/executor/vu_handle_test.go | 8 +- lib/executors.go | 4 +- lib/netext/dialer.go | 27 +- lib/netext/httpext/request.go | 18 +- lib/netext/httpext/request_test.go | 33 +- lib/netext/httpext/tracer.go | 37 +- lib/netext/httpext/tracer_test.go | 5 +- lib/netext/httpext/transport.go | 36 +- lib/netext/httpext/transport_test.go | 8 +- lib/options.go | 8 +- lib/options_test.go | 18 +- lib/runner.go | 10 +- lib/state.go | 3 +- lib/testutils/minirunner/minirunner.go | 16 +- lib/testutils/mockoutput/mockoutput.go | 8 +- metrics/builtin.go | 114 ++-- metrics/engine/engine.go | 13 +- metrics/engine/ingester.go | 2 +- metrics/metric.go | 123 ++++ metrics/metric_test.go | 68 +++ metrics/metric_type.go | 86 +++ metrics/registry.go | 38 +- metrics/registry_test.go | 9 +- stats/stats.go => metrics/sample.go | 547 +++++------------- stats/stats_test.go => metrics/sample_test.go | 110 +--- {stats => metrics}/sink.go | 2 +- {stats => metrics}/sink_test.go | 2 +- {stats => metrics}/system_tag.go | 2 +- {stats => metrics}/system_tag_set_gen.go | 2 +- {stats => metrics}/system_tag_test.go | 14 +- {stats => metrics}/thresholds.go | 6 +- {stats => metrics}/thresholds_parser.go | 2 +- {stats => metrics}/thresholds_parser_test.go | 2 +- {stats => metrics}/thresholds_test.go | 2 +- {stats => metrics}/units.go | 2 +- metrics/value_type.go | 68 +++ output/cloud/bench_test.go | 16 +- output/cloud/cloud_easyjson.go | 8 +- output/cloud/data.go | 49 +- output/cloud/data_test.go | 17 +- output/cloud/output.go | 26 +- output/cloud/output_test.go | 71 ++- output/csv/output.go | 4 +- output/csv/output_test.go | 43 +- output/helpers.go | 10 +- output/helpers_test.go | 35 +- output/influxdb/bench_test.go | 11 +- output/influxdb/output.go | 6 +- output/influxdb/output_test.go | 19 +- output/json/json.go | 10 +- output/json/json_easyjson.go | 44 +- output/json/json_test.go | 30 +- output/json/wrapper.go | 10 +- output/manager.go | 4 +- output/statsd/config.go | 8 +- output/statsd/output.go | 12 +- output/statsd/output_test.go | 8 +- output/statsd/test_helper.go | 31 +- output/types.go | 5 +- 113 files changed, 1516 insertions(+), 1587 deletions(-) create mode 100644 metrics/metric.go create mode 100644 metrics/metric_test.go create mode 100644 metrics/metric_type.go rename stats/stats.go => metrics/sample.go (54%) rename stats/stats_test.go => metrics/sample_test.go (63%) rename {stats => metrics}/sink.go (99%) rename {stats => metrics}/sink_test.go (99%) rename {stats => metrics}/system_tag.go (99%) rename {stats => metrics}/system_tag_set_gen.go (99%) rename {stats => metrics}/system_tag_test.go (97%) rename {stats => metrics}/thresholds.go (97%) rename {stats => metrics}/thresholds_parser.go (99%) rename {stats => metrics}/thresholds_parser_test.go (99%) rename {stats => metrics}/thresholds_test.go (99%) rename {stats => metrics}/units.go (98%) create mode 100644 metrics/value_type.go diff --git a/.github/workflows/xk6-tests/xk6-js-test/jstest.go b/.github/workflows/xk6-tests/xk6-js-test/jstest.go index a12c80aa0be..a81b4f01025 100644 --- a/.github/workflows/xk6-tests/xk6-js-test/jstest.go +++ b/.github/workflows/xk6-tests/xk6-js-test/jstest.go @@ -5,7 +5,7 @@ import ( "time" "go.k6.io/k6/js/modules" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func init() { @@ -19,7 +19,7 @@ type ( JSTest struct { vu modules.VU - foos *stats.Metric + foos *metrics.Metric } ) @@ -39,7 +39,7 @@ func New() *RootModule { func (*RootModule) NewModuleInstance(vu modules.VU) modules.Instance { return &JSTest{ vu: vu, - foos: vu.InitEnv().Registry.MustNewMetric("foos", stats.Counter), + foos: vu.InitEnv().Registry.MustNewMetric("foos", metrics.Counter), } } @@ -60,9 +60,9 @@ func (j *JSTest) Foo(arg float64) (bool, error) { tags := state.CloneTags() tags["foo"] = "bar" - stats.PushIfNotDone(ctx, state.Samples, stats.Sample{ + metrics.PushIfNotDone(ctx, state.Samples, metrics.Sample{ Time: time.Now(), - Metric: j.foos, Tags: stats.IntoSampleTags(&tags), + Metric: j.foos, Tags: metrics.IntoSampleTags(&tags), Value: arg, }) diff --git a/.github/workflows/xk6-tests/xk6-output-test/outputtest.go b/.github/workflows/xk6-tests/xk6-output-test/outputtest.go index 82fff1ae2ec..146a133bf63 100644 --- a/.github/workflows/xk6-tests/xk6-output-test/outputtest.go +++ b/.github/workflows/xk6-tests/xk6-output-test/outputtest.go @@ -22,9 +22,9 @@ package outputtest import ( "strconv" - "go.k6.io/k6/output" - "go.k6.io/k6/stats" "github.com/spf13/afero" + "go.k6.io/k6/metrics" + "go.k6.io/k6/output" ) func init() { @@ -57,7 +57,7 @@ func (o *Output) Start() error { } // AddMetricSamples just plucks out the metric we're interested in. -func (o *Output) AddMetricSamples(sampleContainers []stats.SampleContainer) { +func (o *Output) AddMetricSamples(sampleContainers []metrics.SampleContainer) { for _, sc := range sampleContainers { for _, sample := range sc.GetSamples() { if sample.Metric.Name == "foos" { diff --git a/api/v1/metric.go b/api/v1/metric.go index b06f83dc0f2..3e4bed998e6 100644 --- a/api/v1/metric.go +++ b/api/v1/metric.go @@ -27,11 +27,11 @@ import ( "gopkg.in/guregu/null.v3" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) type NullMetricType struct { - Type stats.MetricType + Type metrics.MetricType Valid bool } @@ -52,7 +52,7 @@ func (t *NullMetricType) UnmarshalJSON(data []byte) error { } type NullValueType struct { - Type stats.ValueType + Type metrics.ValueType Valid bool } @@ -82,7 +82,8 @@ type Metric struct { Sample map[string]float64 `json:"sample" yaml:"sample"` } -func NewMetric(m *stats.Metric, t time.Duration) Metric { +// NewMetric constructs a new Metric +func NewMetric(m *metrics.Metric, t time.Duration) Metric { return Metric{ Name: m.Name, Type: NullMetricType{m.Type, true}, diff --git a/api/v1/metric_jsonapi.go b/api/v1/metric_jsonapi.go index d433000cd51..a89c29c4235 100644 --- a/api/v1/metric_jsonapi.go +++ b/api/v1/metric_jsonapi.go @@ -23,7 +23,7 @@ package v1 import ( "time" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // MetricsJSONAPI is JSON API envelop for metrics @@ -41,13 +41,13 @@ type metricData struct { Attributes Metric `json:"attributes"` } -func newMetricEnvelope(m *stats.Metric, t time.Duration) metricJSONAPI { +func newMetricEnvelope(m *metrics.Metric, t time.Duration) metricJSONAPI { return metricJSONAPI{ Data: newMetricData(m, t), } } -func newMetricsJSONAPI(list map[string]*stats.Metric, t time.Duration) MetricsJSONAPI { +func newMetricsJSONAPI(list map[string]*metrics.Metric, t time.Duration) MetricsJSONAPI { metrics := make([]metricData, 0, len(list)) for _, m := range list { @@ -59,7 +59,7 @@ func newMetricsJSONAPI(list map[string]*stats.Metric, t time.Duration) MetricsJS } } -func newMetricData(m *stats.Metric, t time.Duration) metricData { +func newMetricData(m *metrics.Metric, t time.Duration) metricData { metric := NewMetric(m, t) return metricData{ diff --git a/api/v1/metric_routes_test.go b/api/v1/metric_routes_test.go index 9cb661169c8..9e5aa2d728f 100644 --- a/api/v1/metric_routes_test.go +++ b/api/v1/metric_routes_test.go @@ -37,7 +37,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/minirunner" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestGetMetrics(t *testing.T) { @@ -47,14 +46,14 @@ func TestGetMetrics(t *testing.T) { logger.SetOutput(testutils.NewTestOutput(t)) registry := metrics.NewRegistry() builtinMetrics := metrics.RegisterBuiltinMetrics(registry) - testMetric, err := registry.NewMetric("my_metric", stats.Trend, stats.Time) + testMetric, err := registry.NewMetric("my_metric", metrics.Trend, metrics.Time) require.NoError(t, err) execScheduler, err := local.NewExecutionScheduler(&minirunner.MiniRunner{}, builtinMetrics, logger) require.NoError(t, err) engine, err := core.NewEngine(execScheduler, lib.Options{}, lib.RuntimeOptions{}, nil, logger, registry) require.NoError(t, err) - engine.MetricsEngine.ObservedMetrics = map[string]*stats.Metric{ + engine.MetricsEngine.ObservedMetrics = map[string]*metrics.Metric{ "my_metric": testMetric, } engine.MetricsEngine.ObservedMetrics["my_metric"].Tainted = null.BoolFrom(true) @@ -81,18 +80,18 @@ func TestGetMetrics(t *testing.T) { var envelop MetricsJSONAPI assert.NoError(t, json.Unmarshal(rw.Body.Bytes(), &envelop)) - metrics := envelop.Data - if !assert.Len(t, metrics, 1) { + metricsData := envelop.Data + if !assert.Len(t, metricsData, 1) { return } - metric := metrics[0].Attributes + metric := metricsData[0].Attributes - assert.Equal(t, "my_metric", metrics[0].ID) + assert.Equal(t, "my_metric", metricsData[0].ID) assert.True(t, metric.Type.Valid) - assert.Equal(t, stats.Trend, metric.Type.Type) + assert.Equal(t, metrics.Trend, metric.Type.Type) assert.True(t, metric.Contains.Valid) - assert.Equal(t, stats.Time, metric.Contains.Type) + assert.Equal(t, metrics.Time, metric.Contains.Type) assert.True(t, metric.Tainted.Valid) assert.True(t, metric.Tainted.Bool) @@ -108,7 +107,7 @@ func TestGetMetric(t *testing.T) { logger := logrus.New() logger.SetOutput(testutils.NewTestOutput(t)) registry := metrics.NewRegistry() - testMetric, err := registry.NewMetric("my_metric", stats.Trend, stats.Time) + testMetric, err := registry.NewMetric("my_metric", metrics.Trend, metrics.Time) require.NoError(t, err) builtinMetrics := metrics.RegisterBuiltinMetrics(registry) execScheduler, err := local.NewExecutionScheduler(&minirunner.MiniRunner{}, builtinMetrics, logger) @@ -116,7 +115,7 @@ func TestGetMetric(t *testing.T) { engine, err := core.NewEngine(execScheduler, lib.Options{}, lib.RuntimeOptions{}, nil, logger, registry) require.NoError(t, err) - engine.MetricsEngine.ObservedMetrics = map[string]*stats.Metric{ + engine.MetricsEngine.ObservedMetrics = map[string]*metrics.Metric{ "my_metric": testMetric, } engine.MetricsEngine.ObservedMetrics["my_metric"].Tainted = null.BoolFrom(true) @@ -156,9 +155,9 @@ func TestGetMetric(t *testing.T) { assert.Equal(t, "my_metric", envelop.Data.ID) assert.True(t, metric.Type.Valid) - assert.Equal(t, stats.Trend, metric.Type.Type) + assert.Equal(t, metrics.Trend, metric.Type.Type) assert.True(t, metric.Contains.Valid) - assert.Equal(t, stats.Time, metric.Contains.Type) + assert.Equal(t, metrics.Time, metric.Contains.Type) assert.True(t, metric.Tainted.Valid) assert.True(t, metric.Tainted.Bool) }) diff --git a/api/v1/metric_test.go b/api/v1/metric_test.go index cfd092b9a2e..31a73b69df8 100644 --- a/api/v1/metric_test.go +++ b/api/v1/metric_test.go @@ -29,18 +29,17 @@ import ( "gopkg.in/guregu/null.v3" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestNullMetricTypeJSON(t *testing.T) { t.Parallel() values := map[NullMetricType]string{ - {}: `null`, - {stats.Counter, true}: `"counter"`, - {stats.Gauge, true}: `"gauge"`, - {stats.Trend, true}: `"trend"`, - {stats.Rate, true}: `"rate"`, + {}: `null`, + {metrics.Counter, true}: `"counter"`, + {metrics.Gauge, true}: `"gauge"`, + {metrics.Trend, true}: `"trend"`, + {metrics.Rate, true}: `"rate"`, } t.Run("Marshal", func(t *testing.T) { t.Parallel() @@ -74,9 +73,9 @@ func TestNullValueTypeJSON(t *testing.T) { t.Parallel() values := map[NullValueType]string{ - {}: `null`, - {stats.Default, true}: `"default"`, - {stats.Time, true}: `"time"`, + {}: `null`, + {metrics.Default, true}: `"default"`, + {metrics.Time, true}: `"time"`, } t.Run("Marshal", func(t *testing.T) { t.Parallel() @@ -109,16 +108,16 @@ func TestNullValueTypeJSON(t *testing.T) { func TestNewMetric(t *testing.T) { t.Parallel() - old, err := metrics.NewRegistry().NewMetric("test_metric", stats.Trend, stats.Time) + old, err := metrics.NewRegistry().NewMetric("test_metric", metrics.Trend, metrics.Time) require.NoError(t, err) old.Tainted = null.BoolFrom(true) m := NewMetric(old, 0) assert.Equal(t, "test_metric", m.Name) assert.True(t, m.Type.Valid) - assert.Equal(t, stats.Trend, m.Type.Type) + assert.Equal(t, metrics.Trend, m.Type.Type) assert.True(t, m.Contains.Valid) assert.True(t, m.Tainted.Bool) assert.True(t, m.Tainted.Valid) - assert.Equal(t, stats.Time, m.Contains.Type) + assert.Equal(t, metrics.Time, m.Contains.Type) assert.NotEmpty(t, m.Sample) } diff --git a/cmd/config.go b/cmd/config.go index df1243a7665..bdfba86634a 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -39,7 +39,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/executor" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // configFlagSet returns a FlagSet with the default run configuration flags. @@ -201,7 +201,7 @@ func getConsolidatedConfig(globalState *globalState, cliConf Config, runnerOpts // for CLI flags in cmd.getOptions, in case other configuration sources // (e.g. env vars) overrode our default value. This is not done in // lib.Options.Validate to avoid circular imports. - if _, err = stats.GetResolversForTrendColumns(conf.SummaryTrendStats); err != nil { + if _, err = metrics.GetResolversForTrendColumns(conf.SummaryTrendStats); err != nil { return conf, err } @@ -214,7 +214,7 @@ func getConsolidatedConfig(globalState *globalState, cliConf Config, runnerOpts // Note that if you add option default value here, also add it in command line argument help text. func applyDefault(conf Config) Config { if conf.Options.SystemTags == nil { - conf.Options.SystemTags = &stats.DefaultSystemTagSet + conf.Options.SystemTags = &metrics.DefaultSystemTagSet } if conf.Options.SummaryTrendStats == nil { conf.Options.SummaryTrendStats = lib.DefaultSummaryTrendStats diff --git a/cmd/config_consolidation_test.go b/cmd/config_consolidation_test.go index a1dceb5d5dc..881dd1e5ce3 100644 --- a/cmd/config_consolidation_test.go +++ b/cmd/config_consolidation_test.go @@ -33,7 +33,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/executor" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func verifyOneIterPerOneVU(t *testing.T, c Config) { @@ -350,22 +350,22 @@ func getConfigConsolidationTestCases() []configConsolidationTestCase { // Test system tags {opts{}, exp{}, func(t *testing.T, c Config) { - assert.Equal(t, &stats.DefaultSystemTagSet, c.Options.SystemTags) + assert.Equal(t, &metrics.DefaultSystemTagSet, c.Options.SystemTags) }}, {opts{cli: []string{"--system-tags", `""`}}, exp{}, func(t *testing.T, c Config) { - assert.Equal(t, stats.SystemTagSet(0), *c.Options.SystemTags) + assert.Equal(t, metrics.SystemTagSet(0), *c.Options.SystemTags) }}, { opts{ runner: &lib.Options{ - SystemTags: stats.NewSystemTagSet(stats.TagSubproto, stats.TagURL), + SystemTags: metrics.NewSystemTagSet(metrics.TagSubproto, metrics.TagURL), }, }, exp{}, func(t *testing.T, c Config) { assert.Equal( t, - *stats.NewSystemTagSet(stats.TagSubproto, stats.TagURL), + *metrics.NewSystemTagSet(metrics.TagSubproto, metrics.TagURL), *c.Options.SystemTags, ) }, diff --git a/cmd/integration_tests/eventloop/eventloop_test.go b/cmd/integration_tests/eventloop/eventloop_test.go index 1de4efb3c15..8b1812c4b7d 100644 --- a/cmd/integration_tests/eventloop/eventloop_test.go +++ b/cmd/integration_tests/eventloop/eventloop_test.go @@ -20,7 +20,6 @@ import ( "go.k6.io/k6/lib/types" "go.k6.io/k6/loader" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" "gopkg.in/guregu/null.v3" ) @@ -201,7 +200,7 @@ export default function() { func newTestExecutionScheduler( t *testing.T, runner lib.Runner, logger *logrus.Logger, opts lib.Options, builtinMetrics *metrics.BuiltinMetrics, -) (ctx context.Context, cancel func(), execScheduler *local.ExecutionScheduler, samples chan stats.SampleContainer) { +) (ctx context.Context, cancel func(), execScheduler *local.ExecutionScheduler, samples chan metrics.SampleContainer) { if runner == nil { runner = &minirunner.MiniRunner{} } @@ -222,7 +221,7 @@ func newTestExecutionScheduler( execScheduler, err = local.NewExecutionScheduler(runner, builtinMetrics, logger) require.NoError(t, err) - samples = make(chan stats.SampleContainer, newOpts.MetricSamplesBufferSize.Int64) + samples = make(chan metrics.SampleContainer, newOpts.MetricSamplesBufferSize.Int64) go func() { for { select { diff --git a/cmd/options.go b/cmd/options.go index 4795f63c5fd..9981b4a2945 100644 --- a/cmd/options.go +++ b/cmd/options.go @@ -32,7 +32,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/consts" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) var ( @@ -86,7 +86,7 @@ func optionFlagSet() *pflag.FlagSet { // set it to nil here, and add the default in applyDefault() instead. systemTagsCliHelpText := fmt.Sprintf( "only include these system tags in metrics (default %q)", - stats.DefaultSystemTagSet.SetString(), + metrics.DefaultSystemTagSet.SetString(), ) flags.StringSlice("system-tags", nil, systemTagsCliHelpText) flags.StringSlice("tag", nil, "add a `tag` to be applied to all samples, as `[name]=[value]`") @@ -181,7 +181,7 @@ func getOptions(flags *pflag.FlagSet) (lib.Options, error) { if err != nil { return opts, err } - opts.SystemTags = stats.ToSystemTagSet(systemTagList) + opts.SystemTags = metrics.ToSystemTagSet(systemTagList) } blacklistIPStrings, err := flags.GetStringSlice("blacklist-ip") @@ -223,7 +223,7 @@ func getOptions(flags *pflag.FlagSet) (lib.Options, error) { if errSts != nil { return opts, errSts } - if _, errSts = stats.GetResolversForTrendColumns(trendStats); err != nil { + if _, errSts = metrics.GetResolversForTrendColumns(trendStats); err != nil { return opts, errSts } opts.SummaryTrendStats = trendStats @@ -255,7 +255,7 @@ func getOptions(flags *pflag.FlagSet) (lib.Options, error) { } parsedRunTags[name] = value } - opts.RunTags = stats.IntoSampleTags(&parsedRunTags) + opts.RunTags = metrics.IntoSampleTags(&parsedRunTags) } redirectConFile, err := flags.GetString("console-output") diff --git a/core/engine.go b/core/engine.go index 07e9ea8cc00..41c7e7f6833 100644 --- a/core/engine.go +++ b/core/engine.go @@ -34,7 +34,6 @@ import ( "go.k6.io/k6/metrics" "go.k6.io/k6/metrics/engine" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) const ( @@ -66,7 +65,7 @@ type Engine struct { stopOnce sync.Once stopChan chan struct{} - Samples chan stats.SampleContainer + Samples chan metrics.SampleContainer // Are thresholds tainted? thresholdsTaintedLock sync.Mutex @@ -86,7 +85,7 @@ func NewEngine( ExecutionScheduler: ex, runtimeOptions: rtOpts, - Samples: make(chan stats.SampleContainer, opts.MetricSamplesBufferSize.Int64), + Samples: make(chan metrics.SampleContainer, opts.MetricSamplesBufferSize.Int64), stopChan: make(chan struct{}), logger: logger.WithField("component", "engine"), } @@ -246,7 +245,7 @@ func (e *Engine) startBackgroundProcesses( } func (e *Engine) processMetrics(globalCtx context.Context, processMetricsAfterRun chan struct{}) { - sampleContainers := []stats.SampleContainer{} + sampleContainers := []metrics.SampleContainer{} defer func() { // Process any remaining metrics in the pipeline, by this point Run() @@ -278,7 +277,7 @@ func (e *Engine) processMetrics(globalCtx context.Context, processMetricsAfterRu // Make the new container with the same size as the previous // one, assuming that we produce roughly the same amount of // metrics data between ticks... - sampleContainers = make([]stats.SampleContainer, 0, cap(sampleContainers)) + sampleContainers = make([]metrics.SampleContainer, 0, cap(sampleContainers)) } } for { diff --git a/core/engine_test.go b/core/engine_test.go index 7f45d4bf19d..3a6f955641e 100644 --- a/core/engine_test.go +++ b/core/engine_test.go @@ -47,7 +47,6 @@ import ( "go.k6.io/k6/loader" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) const isWindows = runtime.GOOS == "windows" @@ -117,7 +116,7 @@ func TestEngineRun(t *testing.T) { t.Parallel() done := make(chan struct{}) runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, _ chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, _ chan<- metrics.SampleContainer) error { <-ctx.Done() close(done) return nil @@ -151,17 +150,17 @@ func TestEngineRun(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - testMetric, err := registry.NewMetric("test_metric", stats.Trend) + testMetric, err := registry.NewMetric("test_metric", metrics.Trend) require.NoError(t, err) signalChan := make(chan interface{}) runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { - stats.PushIfNotDone(ctx, out, stats.Sample{Metric: testMetric, Time: time.Now(), Value: 1}) + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { + metrics.PushIfNotDone(ctx, out, metrics.Sample{Metric: testMetric, Time: time.Now(), Value: 1}) close(signalChan) <-ctx.Done() - stats.PushIfNotDone(ctx, out, stats.Sample{Metric: testMetric, Time: time.Now(), Value: 1}) + metrics.PushIfNotDone(ctx, out, metrics.Sample{Metric: testMetric, Time: time.Now(), Value: 1}) return nil }, } @@ -226,12 +225,12 @@ func TestEngineOutput(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - testMetric, err := registry.NewMetric("test_metric", stats.Trend) + testMetric, err := registry.NewMetric("test_metric", metrics.Trend) require.NoError(t, err) runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { - out <- stats.Sample{Metric: testMetric} + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { + out <- metrics.Sample{Metric: testMetric} return nil }, } @@ -245,7 +244,7 @@ func TestEngineOutput(t *testing.T) { assert.NoError(t, run()) wait() - cSamples := []stats.Sample{} + cSamples := []metrics.Sample{} for _, sample := range mockOutput.Samples { if sample.Metric == testMetric { cSamples = append(cSamples, sample) @@ -253,7 +252,7 @@ func TestEngineOutput(t *testing.T) { } metric := e.MetricsEngine.ObservedMetrics["test_metric"] if assert.NotNil(t, metric) { - sink := metric.Sink.(*stats.TrendSink) + sink := metric.Sink.(*metrics.TrendSink) // nolint: forcetypeassert if assert.NotNil(t, sink) { numOutputSamples := len(cSamples) numEngineSamples := len(sink.Values) @@ -269,39 +268,39 @@ func TestEngine_processSamples(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - metric, err := registry.NewMetric("my_metric", stats.Gauge) + metric, err := registry.NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) e, _, wait := newTestEngineWithRegistry(t, nil, nil, nil, lib.Options{}, registry) e.OutputManager.AddMetricSamples( - []stats.SampleContainer{stats.Sample{Metric: metric, Value: 1.25, Tags: stats.IntoSampleTags(&map[string]string{"a": "1"})}}, + []metrics.SampleContainer{metrics.Sample{Metric: metric, Value: 1.25, Tags: metrics.IntoSampleTags(&map[string]string{"a": "1"})}}, ) e.Stop() wait() - assert.IsType(t, &stats.GaugeSink{}, e.MetricsEngine.ObservedMetrics["my_metric"].Sink) + assert.IsType(t, &metrics.GaugeSink{}, e.MetricsEngine.ObservedMetrics["my_metric"].Sink) }) t.Run("submetric", func(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - metric, err := registry.NewMetric("my_metric", stats.Gauge) + metric, err := registry.NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) - ths := stats.NewThresholds([]string{`value<2`}) + ths := metrics.NewThresholds([]string{`value<2`}) gotParseErr := ths.Parse() require.NoError(t, gotParseErr) e, _, wait := newTestEngineWithRegistry(t, nil, nil, nil, lib.Options{ - Thresholds: map[string]stats.Thresholds{ + Thresholds: map[string]metrics.Thresholds{ "my_metric{a:1}": ths, }, }, registry) e.OutputManager.AddMetricSamples( - []stats.SampleContainer{stats.Sample{Metric: metric, Value: 1.25, Tags: stats.IntoSampleTags(&map[string]string{"a": "1", "b": "2"})}}, + []metrics.SampleContainer{metrics.Sample{Metric: metric, Value: 1.25, Tags: metrics.IntoSampleTags(&map[string]string{"a": "1", "b": "2"})}}, ) e.Stop() @@ -311,8 +310,8 @@ func TestEngine_processSamples(t *testing.T) { sms := e.MetricsEngine.ObservedMetrics["my_metric{a:1}"] assert.EqualValues(t, map[string]string{"a": "1"}, sms.Sub.Tags.CloneTags()) - assert.IsType(t, &stats.GaugeSink{}, e.MetricsEngine.ObservedMetrics["my_metric"].Sink) - assert.IsType(t, &stats.GaugeSink{}, e.MetricsEngine.ObservedMetrics["my_metric{a:1}"].Sink) + assert.IsType(t, &metrics.GaugeSink{}, e.MetricsEngine.ObservedMetrics["my_metric"].Sink) + assert.IsType(t, &metrics.GaugeSink{}, e.MetricsEngine.ObservedMetrics["my_metric{a:1}"].Sink) }) } @@ -320,23 +319,23 @@ func TestEngineThresholdsWillAbort(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - metric, err := registry.NewMetric("my_metric", stats.Gauge) + metric, err := registry.NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) // The incoming samples for the metric set it to 1.25. Considering // the metric is of type Gauge, value > 1.25 should always fail, and // trigger an abort. - ths := stats.NewThresholds([]string{"value>1.25"}) + ths := metrics.NewThresholds([]string{"value>1.25"}) gotParseErr := ths.Parse() require.NoError(t, gotParseErr) ths.Thresholds[0].AbortOnFail = true - thresholds := map[string]stats.Thresholds{metric.Name: ths} + thresholds := map[string]metrics.Thresholds{metric.Name: ths} e, _, wait := newTestEngineWithRegistry(t, nil, nil, nil, lib.Options{Thresholds: thresholds}, registry) e.OutputManager.AddMetricSamples( - []stats.SampleContainer{stats.Sample{Metric: metric, Value: 1.25, Tags: stats.IntoSampleTags(&map[string]string{"a": "1"})}}, + []metrics.SampleContainer{metrics.Sample{Metric: metric, Value: 1.25, Tags: metrics.IntoSampleTags(&map[string]string{"a": "1"})}}, ) e.Stop() wait() @@ -347,24 +346,24 @@ func TestEngineAbortedByThresholds(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - metric, err := registry.NewMetric("my_metric", stats.Gauge) + metric, err := registry.NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) // The MiniRunner sets the value of the metric to 1.25. Considering // the metric is of type Gauge, value > 1.25 should always fail, and // trigger an abort. // **N.B**: a threshold returning an error, won't trigger an abort. - ths := stats.NewThresholds([]string{"value>1.25"}) + ths := metrics.NewThresholds([]string{"value>1.25"}) gotParseErr := ths.Parse() require.NoError(t, gotParseErr) ths.Thresholds[0].AbortOnFail = true - thresholds := map[string]stats.Thresholds{metric.Name: ths} + thresholds := map[string]metrics.Thresholds{metric.Name: ths} done := make(chan struct{}) runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { - out <- stats.Sample{Metric: metric, Value: 1.25, Tags: stats.IntoSampleTags(&map[string]string{"a": "1"})} + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { + out <- metrics.Sample{Metric: metric, Value: 1.25, Tags: metrics.IntoSampleTags(&map[string]string{"a": "1"})} <-ctx.Done() close(done) return nil @@ -422,16 +421,16 @@ func TestEngine_processThresholds(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - gaugeMetric, err := registry.NewMetric("my_metric", stats.Gauge) + gaugeMetric, err := registry.NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) - counterMetric, err := registry.NewMetric("used_counter", stats.Counter) + counterMetric, err := registry.NewMetric("used_counter", metrics.Counter) require.NoError(t, err) - _, err = registry.NewMetric("unused_counter", stats.Counter) + _, err = registry.NewMetric("unused_counter", metrics.Counter) require.NoError(t, err) - thresholds := make(map[string]stats.Thresholds, len(data.ths)) + thresholds := make(map[string]metrics.Thresholds, len(data.ths)) for m, srcs := range data.ths { - ths := stats.NewThresholds(srcs) + ths := metrics.NewThresholds(srcs) gotParseErr := ths.Parse() require.NoError(t, gotParseErr) thresholds[m] = ths @@ -444,9 +443,9 @@ func TestEngine_processThresholds(t *testing.T) { ) e.OutputManager.AddMetricSamples( - []stats.SampleContainer{ - stats.Sample{Metric: gaugeMetric, Value: 1.25, Tags: stats.IntoSampleTags(&map[string]string{"a": "1"})}, - stats.Sample{Metric: counterMetric, Value: 2, Tags: stats.IntoSampleTags(&map[string]string{"b": "1"})}, + []metrics.SampleContainer{ + metrics.Sample{Metric: gaugeMetric, Value: 1.25, Tags: metrics.IntoSampleTags(&map[string]string{"a": "1"})}, + metrics.Sample{Metric: counterMetric, Value: 2, Tags: metrics.IntoSampleTags(&map[string]string{"b": "1"})}, }, ) @@ -635,7 +634,7 @@ func TestRunTags(t *testing.T) { tb := httpmultibin.NewHTTPMultiBin(t) runTagsMap := map[string]string{"foo": "bar", "test": "mest", "over": "written"} - runTags := stats.NewSampleTags(runTagsMap) + runTags := metrics.NewSampleTags(runTagsMap) script := []byte(tb.Replacer.Replace(` import http from "k6/http"; @@ -706,7 +705,7 @@ func TestRunTags(t *testing.T) { VUs: null.IntFrom(2), Hosts: tb.Dialer.Hosts, RunTags: runTags, - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, InsecureSkipTLSVerify: null.BoolFrom(true), }) @@ -796,7 +795,7 @@ func TestSetupTeardownThresholds(t *testing.T) { require.NoError(t, err) engine, run, wait := newTestEngine(t, nil, runner, nil, lib.Options{ - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, SetupTimeout: types.NullDurationFrom(3 * time.Second), TeardownTimeout: types.NullDurationFrom(3 * time.Second), VUs: null.IntFrom(3), @@ -849,7 +848,7 @@ func TestSetupException(t *testing.T) { require.NoError(t, err) _, run, wait := newTestEngine(t, nil, runner, nil, lib.Options{ - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, SetupTimeout: types.NullDurationFrom(3 * time.Second), TeardownTimeout: types.NullDurationFrom(3 * time.Second), VUs: null.IntFrom(3), @@ -1192,18 +1191,18 @@ func TestEngineRunsTeardownEvenAfterTestRunIsAborted(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - testMetric, err := registry.NewMetric("teardown_metric", stats.Counter) + testMetric, err := registry.NewMetric("teardown_metric", metrics.Counter) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { cancel() // we cancel the runCtx immediately after the test starts return nil }, - TeardownFn: func(ctx context.Context, out chan<- stats.SampleContainer) error { - out <- stats.Sample{Metric: testMetric, Value: 1} + TeardownFn: func(ctx context.Context, out chan<- metrics.SampleContainer) error { + out <- metrics.Sample{Metric: testMetric, Value: 1} return nil }, } diff --git a/core/local/local.go b/core/local/local.go index 25f52b1d029..62482d82d82 100644 --- a/core/local/local.go +++ b/core/local/local.go @@ -34,7 +34,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/executor" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" "go.k6.io/k6/ui/pb" ) @@ -167,7 +166,7 @@ func (e *ExecutionScheduler) GetExecutionPlan() []lib.ExecutionStep { // in the Init() method, and also passed to executors so they can initialize // any unplanned VUs themselves. func (e *ExecutionScheduler) initVU( - samplesOut chan<- stats.SampleContainer, logger *logrus.Entry, + samplesOut chan<- metrics.SampleContainer, logger *logrus.Entry, ) (lib.InitializedVU, error) { // Get the VU IDs here, so that the VUs are (mostly) ordered by their // number in the channel buffer @@ -202,7 +201,7 @@ func (e *ExecutionScheduler) getRunStats() string { } func (e *ExecutionScheduler) initVUsConcurrently( - ctx context.Context, samplesOut chan<- stats.SampleContainer, count uint64, + ctx context.Context, samplesOut chan<- metrics.SampleContainer, count uint64, concurrency int, logger *logrus.Entry, ) chan error { doneInits := make(chan error, count) // poor man's early-return waitgroup @@ -234,13 +233,13 @@ func (e *ExecutionScheduler) initVUsConcurrently( return doneInits } -func (e *ExecutionScheduler) emitVUsAndVUsMax(ctx context.Context, out chan<- stats.SampleContainer) { +func (e *ExecutionScheduler) emitVUsAndVUsMax(ctx context.Context, out chan<- metrics.SampleContainer) { e.logger.Debug("Starting emission of VUs and VUsMax metrics...") emitMetrics := func() { t := time.Now() - samples := stats.ConnectedSamples{ - Samples: []stats.Sample{ + samples := metrics.ConnectedSamples{ + Samples: []metrics.Sample{ { Time: t, Metric: e.state.BuiltinMetrics.VUs, @@ -256,7 +255,7 @@ func (e *ExecutionScheduler) emitVUsAndVUsMax(ctx context.Context, out chan<- st Tags: e.options.RunTags, Time: t, } - stats.PushIfNotDone(ctx, out, samples) + metrics.PushIfNotDone(ctx, out, samples) } ticker := time.NewTicker(1 * time.Second) @@ -282,7 +281,7 @@ func (e *ExecutionScheduler) emitVUsAndVUsMax(ctx context.Context, out chan<- st // Init concurrently initializes all of the planned VUs and then sequentially // initializes all of the configured executors. -func (e *ExecutionScheduler) Init(ctx context.Context, samplesOut chan<- stats.SampleContainer) error { +func (e *ExecutionScheduler) Init(ctx context.Context, samplesOut chan<- metrics.SampleContainer) error { e.emitVUsAndVUsMax(ctx, samplesOut) logger := e.logger.WithField("phase", "local-execution-scheduler-init") @@ -348,7 +347,7 @@ func (e *ExecutionScheduler) Init(ctx context.Context, samplesOut chan<- stats.S // configured startTime for the specific executor and then running its Run() // method. func (e *ExecutionScheduler) runExecutor( - runCtx context.Context, runResults chan<- error, engineOut chan<- stats.SampleContainer, executor lib.Executor, + runCtx context.Context, runResults chan<- error, engineOut chan<- metrics.SampleContainer, executor lib.Executor, ) { executorConfig := executor.GetConfig() executorStartTime := executorConfig.GetStartTime() @@ -397,7 +396,7 @@ func (e *ExecutionScheduler) runExecutor( // Run the ExecutionScheduler, funneling all generated metric samples through the supplied // out channel. //nolint:funlen -func (e *ExecutionScheduler) Run(globalCtx, runCtx context.Context, engineOut chan<- stats.SampleContainer) error { +func (e *ExecutionScheduler) Run(globalCtx, runCtx context.Context, engineOut chan<- metrics.SampleContainer) error { defer func() { close(e.stopVUsEmission) <-e.vusEmissionStopped diff --git a/core/local/local_test.go b/core/local/local_test.go index cbdbf673c4f..bebfc73d321 100644 --- a/core/local/local_test.go +++ b/core/local/local_test.go @@ -51,12 +51,11 @@ import ( "go.k6.io/k6/lib/types" "go.k6.io/k6/loader" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func newTestExecutionScheduler( t *testing.T, runner lib.Runner, logger *logrus.Logger, opts lib.Options, -) (ctx context.Context, cancel func(), execScheduler *ExecutionScheduler, samples chan stats.SampleContainer) { +) (ctx context.Context, cancel func(), execScheduler *ExecutionScheduler, samples chan metrics.SampleContainer) { if runner == nil { runner = &minirunner.MiniRunner{} } @@ -79,7 +78,7 @@ func newTestExecutionScheduler( execScheduler, err = NewExecutionScheduler(runner, builtinMetrics, logger) require.NoError(t, err) - samples = make(chan stats.SampleContainer, newOpts.MetricSamplesBufferSize.Int64) + samples = make(chan metrics.SampleContainer, newOpts.MetricSamplesBufferSize.Int64) go func() { for { select { @@ -147,7 +146,7 @@ func TestExecutionSchedulerRunNonDefault(t *testing.T) { defer cancel() done := make(chan struct{}) - samples := make(chan stats.SampleContainer) + samples := make(chan metrics.SampleContainer) go func() { err := execScheduler.Init(ctx, samples) if tc.expErr != "" { @@ -259,7 +258,7 @@ func TestExecutionSchedulerRunEnv(t *testing.T) { defer cancel() done := make(chan struct{}) - samples := make(chan stats.SampleContainer) + samples := make(chan metrics.SampleContainer) go func() { assert.NoError(t, execScheduler.Init(ctx, samples)) assert.NoError(t, execScheduler.Run(ctx, ctx, samples)) @@ -268,7 +267,7 @@ func TestExecutionSchedulerRunEnv(t *testing.T) { for { select { case sample := <-samples: - if s, ok := sample.(stats.Sample); ok && s.Metric.Name == "errors" { + if s, ok := sample.(metrics.Sample); ok && s.Metric.Name == "errors" { assert.FailNow(t, "received error sample from test") } case <-done: @@ -320,7 +319,7 @@ func TestExecutionSchedulerSystemTags(t *testing.T) { require.NoError(t, err) require.NoError(t, runner.SetOptions(runner.GetOptions().Apply(lib.Options{ - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }))) execScheduler, err := NewExecutionScheduler(runner, builtinMetrics, logger) @@ -329,7 +328,7 @@ func TestExecutionSchedulerSystemTags(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() - samples := make(chan stats.SampleContainer) + samples := make(chan metrics.SampleContainer) done := make(chan struct{}) go func() { defer close(done) @@ -337,7 +336,7 @@ func TestExecutionSchedulerSystemTags(t *testing.T) { require.NoError(t, execScheduler.Run(ctx, ctx, samples)) }() - expCommonTrailTags := stats.IntoSampleTags(&map[string]string{ + expCommonTrailTags := metrics.IntoSampleTags(&map[string]string{ "group": "", "method": "GET", "name": sr("HTTPBIN_IP_URL/"), @@ -348,15 +347,15 @@ func TestExecutionSchedulerSystemTags(t *testing.T) { }) expTrailPVUTagsRaw := expCommonTrailTags.CloneTags() expTrailPVUTagsRaw["scenario"] = "per_vu_test" - expTrailPVUTags := stats.IntoSampleTags(&expTrailPVUTagsRaw) + expTrailPVUTags := metrics.IntoSampleTags(&expTrailPVUTagsRaw) expTrailSITagsRaw := expCommonTrailTags.CloneTags() expTrailSITagsRaw["scenario"] = "shared_test" - expTrailSITags := stats.IntoSampleTags(&expTrailSITagsRaw) - expNetTrailPVUTags := stats.IntoSampleTags(&map[string]string{ + expTrailSITags := metrics.IntoSampleTags(&expTrailSITagsRaw) + expNetTrailPVUTags := metrics.IntoSampleTags(&map[string]string{ "group": "", "scenario": "per_vu_test", }) - expNetTrailSITags := stats.IntoSampleTags(&map[string]string{ + expNetTrailSITags := metrics.IntoSampleTags(&map[string]string{ "group": "", "scenario": "shared_test", }) @@ -467,7 +466,7 @@ func TestExecutionSchedulerRunCustomTags(t *testing.T) { defer cancel() done := make(chan struct{}) - samples := make(chan stats.SampleContainer) + samples := make(chan metrics.SampleContainer) go func() { defer close(done) require.NoError(t, execScheduler.Init(ctx, samples)) @@ -629,7 +628,7 @@ func TestExecutionSchedulerRunCustomConfigNoCrossover(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - samples := make(chan stats.SampleContainer) + samples := make(chan metrics.SampleContainer) go func() { assert.NoError(t, execScheduler.Init(ctx, samples)) assert.NoError(t, execScheduler.Run(ctx, ctx, samples)) @@ -654,7 +653,7 @@ func TestExecutionSchedulerRunCustomConfigNoCrossover(t *testing.T) { var gotSampleTags int for sample := range samples { switch s := sample.(type) { - case stats.Sample: + case metrics.Sample: if s.Metric.Name == "errors" { assert.FailNow(t, "received error sample from test") } @@ -680,7 +679,7 @@ func TestExecutionSchedulerRunCustomConfigNoCrossover(t *testing.T) { gotSampleTags++ } } - case stats.ConnectedSamples: + case metrics.ConnectedSamples: for _, sm := range s.Samples { tags := sm.Tags.CloneTags() if reflect.DeepEqual(expectedConnSampleTags, tags) { @@ -699,11 +698,11 @@ func TestExecutionSchedulerSetupTeardownRun(t *testing.T) { setupC := make(chan struct{}) teardownC := make(chan struct{}) runner := &minirunner.MiniRunner{ - SetupFn: func(ctx context.Context, out chan<- stats.SampleContainer) ([]byte, error) { + SetupFn: func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error) { close(setupC) return nil, nil }, - TeardownFn: func(ctx context.Context, out chan<- stats.SampleContainer) error { + TeardownFn: func(ctx context.Context, out chan<- metrics.SampleContainer) error { close(teardownC) return nil }, @@ -720,7 +719,7 @@ func TestExecutionSchedulerSetupTeardownRun(t *testing.T) { t.Run("Setup Error", func(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - SetupFn: func(ctx context.Context, out chan<- stats.SampleContainer) ([]byte, error) { + SetupFn: func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error) { return nil, errors.New("setup error") }, } @@ -731,10 +730,10 @@ func TestExecutionSchedulerSetupTeardownRun(t *testing.T) { t.Run("Don't Run Setup", func(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - SetupFn: func(ctx context.Context, out chan<- stats.SampleContainer) ([]byte, error) { + SetupFn: func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error) { return nil, errors.New("setup error") }, - TeardownFn: func(ctx context.Context, out chan<- stats.SampleContainer) error { + TeardownFn: func(ctx context.Context, out chan<- metrics.SampleContainer) error { return errors.New("teardown error") }, } @@ -750,10 +749,10 @@ func TestExecutionSchedulerSetupTeardownRun(t *testing.T) { t.Run("Teardown Error", func(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - SetupFn: func(ctx context.Context, out chan<- stats.SampleContainer) ([]byte, error) { + SetupFn: func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error) { return nil, nil }, - TeardownFn: func(ctx context.Context, out chan<- stats.SampleContainer) error { + TeardownFn: func(ctx context.Context, out chan<- metrics.SampleContainer) error { return errors.New("teardown error") }, } @@ -768,10 +767,10 @@ func TestExecutionSchedulerSetupTeardownRun(t *testing.T) { t.Run("Don't Run Teardown", func(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - SetupFn: func(ctx context.Context, out chan<- stats.SampleContainer) ([]byte, error) { + SetupFn: func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error) { return nil, nil }, - TeardownFn: func(ctx context.Context, out chan<- stats.SampleContainer) error { + TeardownFn: func(ctx context.Context, out chan<- metrics.SampleContainer) error { return errors.New("teardown error") }, } @@ -816,7 +815,7 @@ func TestExecutionSchedulerStages(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { time.Sleep(100 * time.Millisecond) return nil }, @@ -835,7 +834,7 @@ func TestExecutionSchedulerStages(t *testing.T) { func TestExecutionSchedulerEndTime(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { time.Sleep(100 * time.Millisecond) return nil }, @@ -860,7 +859,7 @@ func TestExecutionSchedulerEndTime(t *testing.T) { func TestExecutionSchedulerRuntimeErrors(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { time.Sleep(10 * time.Millisecond) return errors.New("hi") }, @@ -898,7 +897,7 @@ func TestExecutionSchedulerEndErrors(t *testing.T) { exec.GracefulStop = types.NullDurationFrom(0 * time.Second) runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { <-ctx.Done() return errors.New("hi") }, @@ -925,7 +924,7 @@ func TestExecutionSchedulerEndErrors(t *testing.T) { func TestExecutionSchedulerEndIterations(t *testing.T) { t.Parallel() - metric := &stats.Metric{Name: "test_metric"} + metric := &metrics.Metric{Name: "test_metric"} options, err := executor.DeriveScenariosFromShortcuts(lib.Options{ VUs: null.IntFrom(1), @@ -936,13 +935,13 @@ func TestExecutionSchedulerEndIterations(t *testing.T) { var i int64 runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { select { case <-ctx.Done(): default: atomic.AddInt64(&i, 1) } - out <- stats.Sample{Metric: metric, Value: 1.0} + out <- metrics.Sample{Metric: metric, Value: 1.0} return nil }, Options: options, @@ -959,7 +958,7 @@ func TestExecutionSchedulerEndIterations(t *testing.T) { execScheduler, err := NewExecutionScheduler(runner, builtinMetrics, logger) require.NoError(t, err) - samples := make(chan stats.SampleContainer, 300) + samples := make(chan metrics.SampleContainer, 300) require.NoError(t, execScheduler.Init(ctx, samples)) require.NoError(t, execScheduler.Run(ctx, ctx, samples)) @@ -970,14 +969,14 @@ func TestExecutionSchedulerEndIterations(t *testing.T) { for i := 0; i < 100; i++ { mySample, ok := <-samples require.True(t, ok) - assert.Equal(t, stats.Sample{Metric: metric, Value: 1.0}, mySample) + assert.Equal(t, metrics.Sample{Metric: metric, Value: 1.0}, mySample) } } func TestExecutionSchedulerIsRunning(t *testing.T) { t.Parallel() runner := &minirunner.MiniRunner{ - Fn: func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { <-ctx.Done() return nil }, @@ -1153,7 +1152,7 @@ func TestRealTimeAndSetupTeardownMetrics(t *testing.T) { options, err := executor.DeriveScenariosFromShortcuts(runner.GetOptions().Apply(lib.Options{ Iterations: null.IntFrom(2), VUs: null.IntFrom(1), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, SetupTimeout: types.NullDurationFrom(4 * time.Second), TeardownTimeout: types.NullDurationFrom(4 * time.Second), }), nil) @@ -1167,14 +1166,14 @@ func TestRealTimeAndSetupTeardownMetrics(t *testing.T) { defer cancel() done := make(chan struct{}) - sampleContainers := make(chan stats.SampleContainer) + sampleContainers := make(chan metrics.SampleContainer) go func() { require.NoError(t, execScheduler.Init(ctx, sampleContainers)) assert.NoError(t, execScheduler.Run(ctx, ctx, sampleContainers)) close(done) }() - expectIn := func(from, to time.Duration, expected stats.SampleContainer) { + expectIn := func(from, to time.Duration, expected metrics.SampleContainer) { start := time.Now() from *= time.Millisecond to *= time.Millisecond @@ -1220,24 +1219,24 @@ func TestRealTimeAndSetupTeardownMetrics(t *testing.T) { } } - getTags := func(args ...string) *stats.SampleTags { + getTags := func(args ...string) *metrics.SampleTags { tags := map[string]string{} for i := 0; i < len(args)-1; i += 2 { tags[args[i]] = args[i+1] } - return stats.IntoSampleTags(&tags) + return metrics.IntoSampleTags(&tags) } - testCounter, err := registry.NewMetric("test_counter", stats.Counter) + testCounter, err := registry.NewMetric("test_counter", metrics.Counter) require.NoError(t, err) - getSample := func(expValue float64, expMetric *stats.Metric, expTags ...string) stats.SampleContainer { - return stats.Sample{ + getSample := func(expValue float64, expMetric *metrics.Metric, expTags ...string) metrics.SampleContainer { + return metrics.Sample{ Metric: expMetric, Time: time.Now(), Tags: getTags(expTags...), Value: expValue, } } - getDummyTrail := func(group string, emitIterations bool, addExpTags ...string) stats.SampleContainer { + getDummyTrail := func(group string, emitIterations bool, addExpTags ...string) metrics.SampleContainer { expTags := []string{"group", group} expTags = append(expTags, addExpTags...) return netext.NewDialer( diff --git a/js/console_test.go b/js/console_test.go index fc2bc220c1f..35e992f7d63 100644 --- a/js/console_test.go +++ b/js/console_test.go @@ -40,7 +40,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/loader" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestConsoleContext(t *testing.T) { @@ -137,7 +136,7 @@ func TestConsole(t *testing.T) { )) assert.NoError(t, err) - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.newVU(1, 1, samples) assert.NoError(t, err) @@ -239,7 +238,7 @@ func TestFileConsole(t *testing.T) { }) assert.NoError(t, err) - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.newVU(1, 1, samples) assert.NoError(t, err) diff --git a/js/empty_iterations_bench_test.go b/js/empty_iterations_bench_test.go index a2c6490d508..9c4e67d8f6b 100644 --- a/js/empty_iterations_bench_test.go +++ b/js/empty_iterations_bench_test.go @@ -28,7 +28,7 @@ import ( "github.com/stretchr/testify/require" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func BenchmarkEmptyIteration(b *testing.B) { @@ -40,7 +40,7 @@ func BenchmarkEmptyIteration(b *testing.B) { } require.NoError(b, err) - ch := make(chan stats.SampleContainer, 100) + ch := make(chan metrics.SampleContainer, 100) defer close(ch) go func() { // read the channel so it doesn't block for range ch { diff --git a/js/http_bench_test.go b/js/http_bench_test.go index 99415406f13..fc14418f7b4 100644 --- a/js/http_bench_test.go +++ b/js/http_bench_test.go @@ -30,7 +30,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils/httpmultibin" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func BenchmarkHTTPRequests(b *testing.B) { @@ -56,7 +56,7 @@ func BenchmarkHTTPRequests(b *testing.B) { }) require.NoError(b, err) - ch := make(chan stats.SampleContainer, 100) + ch := make(chan metrics.SampleContainer, 100) defer close(ch) go func() { // read the channel so it doesn't block for range ch { @@ -99,7 +99,7 @@ func BenchmarkHTTPRequestsBase(b *testing.B) { }) require.NoError(b, err) - ch := make(chan stats.SampleContainer, 100) + ch := make(chan metrics.SampleContainer, 100) defer close(ch) go func() { // read the channel so it doesn't block for range ch { diff --git a/js/init_and_modules_test.go b/js/init_and_modules_test.go index 7e7c9fe7b0f..72d5f8010ef 100644 --- a/js/init_and_modules_test.go +++ b/js/init_and_modules_test.go @@ -39,7 +39,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/loader" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) type CheckModule struct { @@ -93,7 +92,7 @@ func TestNewJSRunnerWithCustomModule(t *testing.T) { assert.Equal(t, checkModule.initCtxCalled, 1) assert.Equal(t, checkModule.vuCtxCalled, 0) - vu, err := runner.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + vu, err := runner.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) assert.Equal(t, checkModule.initCtxCalled, 2) assert.Equal(t, checkModule.vuCtxCalled, 0) @@ -117,7 +116,7 @@ func TestNewJSRunnerWithCustomModule(t *testing.T) { require.NoError(t, err) assert.Equal(t, checkModule.initCtxCalled, 3) // changes because we need to get the exported functions assert.Equal(t, checkModule.vuCtxCalled, 2) - vuFromArc, err := runnerFromArc.NewVU(2, 2, make(chan stats.SampleContainer, 100)) + vuFromArc, err := runnerFromArc.NewVU(2, 2, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) assert.Equal(t, checkModule.initCtxCalled, 4) assert.Equal(t, checkModule.vuCtxCalled, 2) diff --git a/js/initcontext_test.go b/js/initcontext_test.go index 8a941f42171..c1999c8ab65 100644 --- a/js/initcontext_test.go +++ b/js/initcontext_test.go @@ -44,7 +44,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestInitContextRequire(t *testing.T) { @@ -405,7 +404,7 @@ func TestRequestWithBinaryFile(t *testing.T) { )).DialContext, }, BPool: bpool.NewBufferPool(1), - Samples: make(chan stats.SampleContainer, 500), + Samples: make(chan metrics.SampleContainer, 500), BuiltinMetrics: builtinMetrics, Tags: lib.NewTagMap(nil), } @@ -553,7 +552,7 @@ func TestRequestWithMultipleBinaryFiles(t *testing.T) { )).DialContext, }, BPool: bpool.NewBufferPool(1), - Samples: make(chan stats.SampleContainer, 500), + Samples: make(chan metrics.SampleContainer, 500), BuiltinMetrics: builtinMetrics, Tags: lib.NewTagMap(nil), } diff --git a/js/module_loading_test.go b/js/module_loading_test.go index ae601dbe09e..47a52c8237d 100644 --- a/js/module_loading_test.go +++ b/js/module_loading_test.go @@ -34,11 +34,10 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/httpmultibin" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) -func newDevNullSampleChannel() chan stats.SampleContainer { - ch := make(chan stats.SampleContainer, 100) +func newDevNullSampleChannel() chan metrics.SampleContainer { + ch := make(chan metrics.SampleContainer, 100) go func() { for range ch { } @@ -468,7 +467,7 @@ func TestBrowserified(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - ch := make(chan stats.SampleContainer, 100) + ch := make(chan metrics.SampleContainer, 100) defer close(ch) initVU, err := r.NewVU(1, 1, ch) require.NoError(t, err) diff --git a/js/modules/k6/execution/execution_test.go b/js/modules/k6/execution/execution_test.go index e4f8507f971..85b3784f667 100644 --- a/js/modules/k6/execution/execution_test.go +++ b/js/modules/k6/execution/execution_test.go @@ -34,7 +34,7 @@ import ( "go.k6.io/k6/js/modulestest" "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "gopkg.in/guregu/null.v3" ) @@ -52,7 +52,7 @@ func setupTagsExecEnv(t *testing.T) execEnv { state := &lib.State{ Options: lib.Options{ - SystemTags: stats.NewSystemTagSet(stats.TagVU), + SystemTags: metrics.NewSystemTagSet(metrics.TagVU), }, Tags: lib.NewTagMap(map[string]string{ "vu": "42", diff --git a/js/modules/k6/grpc/client.go b/js/modules/k6/grpc/client.go index 1f74e6ac5b0..a7c28d079a4 100644 --- a/js/modules/k6/grpc/client.go +++ b/js/modules/k6/grpc/client.go @@ -55,7 +55,7 @@ import ( "go.k6.io/k6/js/common" "go.k6.io/k6/js/modules" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" ) @@ -482,19 +482,19 @@ func (c *Client) Invoke( tags[k] = v } - if state.Options.SystemTags.Has(stats.TagURL) { + if state.Options.SystemTags.Has(metrics.TagURL) { tags["url"] = fmt.Sprintf("%s%s", c.conn.Target(), method) } parts := strings.Split(method[1:], "/") - if state.Options.SystemTags.Has(stats.TagService) { + if state.Options.SystemTags.Has(metrics.TagService) { tags["service"] = parts[0] } - if state.Options.SystemTags.Has(stats.TagMethod) { + if state.Options.SystemTags.Has(metrics.TagMethod) { tags["method"] = parts[1] } // Only set the name system tag if the user didn't explicitly set it beforehand - if _, ok := tags["name"]; !ok && state.Options.SystemTags.Has(stats.TagName) { + if _, ok := tags["name"]; !ok && state.Options.SystemTags.Has(metrics.TagName) { tags["name"] = method } @@ -574,47 +574,47 @@ func (c *Client) Close() error { return err } -// TagConn implements the stats.Handler interface +// TagConn implements the metrics.Handler interface func (*Client) TagConn(ctx context.Context, _ *grpcstats.ConnTagInfo) context.Context { // noop return ctx } -// HandleConn implements the stats.Handler interface +// HandleConn implements the metrics.Handler interface func (*Client) HandleConn(context.Context, grpcstats.ConnStats) { // noop } -// TagRPC implements the stats.Handler interface +// TagRPC implements the metrics.Handler interface func (*Client) TagRPC(ctx context.Context, _ *grpcstats.RPCTagInfo) context.Context { // noop return ctx } -// HandleRPC implements the stats.Handler interface +// HandleRPC implements the metrics.Handler interface func (c *Client) HandleRPC(ctx context.Context, stat grpcstats.RPCStats) { state := c.vu.State() tags := getTags(ctx) switch s := stat.(type) { case *grpcstats.OutHeader: - if state.Options.SystemTags.Has(stats.TagIP) && s.RemoteAddr != nil { + if state.Options.SystemTags.Has(metrics.TagIP) && s.RemoteAddr != nil { if ip, _, err := net.SplitHostPort(s.RemoteAddr.String()); err == nil { tags["ip"] = ip } } case *grpcstats.End: - if state.Options.SystemTags.Has(stats.TagStatus) { + if state.Options.SystemTags.Has(metrics.TagStatus) { tags["status"] = strconv.Itoa(int(status.Code(s.Error))) } mTags := map[string]string(tags) - sampleTags := stats.IntoSampleTags(&mTags) - stats.PushIfNotDone(ctx, state.Samples, stats.ConnectedSamples{ - Samples: []stats.Sample{ + sampleTags := metrics.IntoSampleTags(&mTags) + metrics.PushIfNotDone(ctx, state.Samples, metrics.ConnectedSamples{ + Samples: []metrics.Sample{ { Metric: state.BuiltinMetrics.GRPCReqDuration, Tags: sampleTags, - Value: stats.D(s.EndTime.Sub(s.BeginTime)), + Value: metrics.D(s.EndTime.Sub(s.BeginTime)), Time: s.EndTime, }, }, diff --git a/js/modules/k6/grpc/client_test.go b/js/modules/k6/grpc/client_test.go index d34c1fbb2c2..d3dfe8ad985 100644 --- a/js/modules/k6/grpc/client_test.go +++ b/js/modules/k6/grpc/client_test.go @@ -59,7 +59,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/httpmultibin" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) const isWindows = runtime.GOOS == "windows" @@ -70,7 +69,7 @@ type codeBlock struct { val interface{} err string windowsErr string - asserts func(*testing.T, *httpmultibin.HTTPMultiBin, chan stats.SampleContainer, error) + asserts func(*testing.T, *httpmultibin.HTTPMultiBin, chan metrics.SampleContainer, error) } type testcase struct { @@ -88,7 +87,7 @@ func TestClient(t *testing.T) { vuState *lib.State env *common.InitEnvironment httpBin *httpmultibin.HTTPMultiBin - samples chan stats.SampleContainer + samples chan metrics.SampleContainer } setup := func(t *testing.T) testState { t.Helper() @@ -96,16 +95,16 @@ func TestClient(t *testing.T) { root, err := lib.NewGroup("", nil) require.NoError(t, err) tb := httpmultibin.NewHTTPMultiBin(t) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, TLSConfig: tb.TLSClientConfig, Samples: samples, Options: lib.Options{ - SystemTags: stats.NewSystemTagSet( - stats.TagName, - stats.TagURL, + SystemTags: metrics.NewSystemTagSet( + metrics.TagName, + metrics.TagURL, ), UserAgent: null.StringFrom("k6-test"), }, @@ -144,7 +143,7 @@ func TestClient(t *testing.T) { assertMetricEmitted := func( t *testing.T, metricName string, - sampleContainers []stats.SampleContainer, + sampleContainers []metrics.SampleContainer, url string, ) { seenMetric := false @@ -391,8 +390,8 @@ func TestClient(t *testing.T) { if (resp.status !== grpc.StatusOK) { throw new Error("unexpected error status: " + resp.status) }`, - asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan stats.SampleContainer, _ error) { - samplesBuf := stats.GetBufferedSamples(samples) + asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) { + samplesBuf := metrics.GetBufferedSamples(samples) assertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace("GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall")) }, }, @@ -465,8 +464,8 @@ func TestClient(t *testing.T) { if (!resp.message || resp.message.username !== "" || resp.message.oauthScope !== "水") { throw new Error("unexpected response message: " + JSON.stringify(resp.message)) }`, - asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan stats.SampleContainer, _ error) { - samplesBuf := stats.GetBufferedSamples(samples) + asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) { + samplesBuf := metrics.GetBufferedSamples(samples) assertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace("GRPCBIN_ADDR/grpc.testing.TestService/UnaryCall")) }, }, @@ -493,8 +492,8 @@ func TestClient(t *testing.T) { if (!resp.error || resp.error.message !== "foobar" || resp.error.code !== 15) { throw new Error("unexpected error object: " + JSON.stringify(resp.error.code)) }`, - asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan stats.SampleContainer, _ error) { - samplesBuf := stats.GetBufferedSamples(samples) + asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) { + samplesBuf := metrics.GetBufferedSamples(samples) assertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace("GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall")) }, }, @@ -523,8 +522,8 @@ func TestClient(t *testing.T) { if (!resp.headers || !resp.headers["foo"] || resp.headers["foo"][0] !== "bar") { throw new Error("unexpected headers object: " + JSON.stringify(resp.trailers)) }`, - asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan stats.SampleContainer, _ error) { - samplesBuf := stats.GetBufferedSamples(samples) + asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) { + samplesBuf := metrics.GetBufferedSamples(samples) assertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace("GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall")) }, }, @@ -553,8 +552,8 @@ func TestClient(t *testing.T) { if (!resp.trailers || !resp.trailers["foo"] || resp.trailers["foo"][0] !== "bar") { throw new Error("unexpected trailers object: " + JSON.stringify(resp.trailers)) }`, - asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan stats.SampleContainer, _ error) { - samplesBuf := stats.GetBufferedSamples(samples) + asserts: func(t *testing.T, rb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer, _ error) { + samplesBuf := metrics.GetBufferedSamples(samples) assertMetricEmitted(t, metrics.GRPCReqDurationName, samplesBuf, rb.Replacer.Replace("GRPCBIN_ADDR/grpc.testing.TestService/EmptyCall")) }, }, diff --git a/js/modules/k6/http/request_test.go b/js/modules/k6/http/request_test.go index d98f447f37a..cfc1851abfd 100644 --- a/js/modules/k6/http/request_test.go +++ b/js/modules/k6/http/request_test.go @@ -53,11 +53,10 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/httpmultibin" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // TODO replace this with the Single version -func assertRequestMetricsEmitted(t *testing.T, sampleContainers []stats.SampleContainer, method, url, name string, status int, group string) { +func assertRequestMetricsEmitted(t *testing.T, sampleContainers []metrics.SampleContainer, method, url, name string, status int, group string) { if name == "" { name = url } @@ -106,7 +105,7 @@ func assertRequestMetricsEmitted(t *testing.T, sampleContainers []stats.SampleCo assert.True(t, seenReceiving, "url %s didn't emit Receiving", url) } -func assertRequestMetricsEmittedSingle(t *testing.T, sampleContainer stats.SampleContainer, expectedTags map[string]string, metrics []string, callback func(sample stats.Sample)) { +func assertRequestMetricsEmittedSingle(t *testing.T, sampleContainer metrics.SampleContainer, expectedTags map[string]string, metrics []string, callback func(sample metrics.Sample)) { t.Helper() metricMap := make(map[string]bool, len(metrics)) @@ -130,7 +129,7 @@ func assertRequestMetricsEmittedSingle(t *testing.T, sampleContainer stats.Sampl } func newRuntime(t testing.TB) ( - *httpmultibin.HTTPMultiBin, *lib.State, chan stats.SampleContainer, *goja.Runtime, *ModuleInstance, + *httpmultibin.HTTPMultiBin, *lib.State, chan metrics.SampleContainer, *goja.Runtime, *ModuleInstance, ) { tb := httpmultibin.NewHTTPMultiBin(t) @@ -145,12 +144,12 @@ func newRuntime(t testing.TB) ( MaxRedirects: null.IntFrom(10), UserAgent: null.StringFrom("TestUserAgent"), Throw: null.BoolFrom(true), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, Batch: null.IntFrom(20), BatchPerHost: null.IntFrom(20), // HTTPDebug: null.StringFrom("full"), } - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Options: options, @@ -186,7 +185,7 @@ func TestRequestAndBatch(t *testing.T) { var res = http.get("HTTPBIN_URL/redirect/9"); `)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) reqsCount := 0 for _, container := range bufSamples { @@ -479,7 +478,7 @@ func TestRequestAndBatch(t *testing.T) { }) }) t.Run("HTTP/2", func(t *testing.T) { - stats.GetBufferedSamples(samples) // Clean up buffered samples from previous tests + metrics.GetBufferedSamples(samples) // Clean up buffered samples from previous tests _, err := rt.RunString(sr(` var res = http.request("GET", "HTTP2BIN_URL/get"); if (res.status != 200) { throw new Error("wrong status: " + res.status) } @@ -487,7 +486,7 @@ func TestRequestAndBatch(t *testing.T) { `)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTP2BIN_URL/get"), "", 200, "") for _, sampleC := range bufSamples { for _, sample := range sampleC.GetSamples() { @@ -616,7 +615,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `), literal)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) } @@ -640,7 +639,7 @@ func TestRequestAndBatch(t *testing.T) { } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies/set?key=value"), "", 302, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies/set?key=value"), "", 302, "") }) t.Run("vuJar", func(t *testing.T) { @@ -658,7 +657,7 @@ func TestRequestAndBatch(t *testing.T) { if (jarCookies.key2 != undefined) { throw new Error("unexpected cookie in jar"); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) t.Run("requestScope", func(t *testing.T) { @@ -673,7 +672,7 @@ func TestRequestAndBatch(t *testing.T) { if (jarCookies.key != undefined) { throw new Error("unexpected cookie in jar"); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) t.Run("requestScopeReplace", func(t *testing.T) { @@ -689,7 +688,7 @@ func TestRequestAndBatch(t *testing.T) { if (jarCookies.key[0] != "value") { throw new Error("wrong cookie value in jar"); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) t.Run("redirect", func(t *testing.T) { @@ -723,7 +722,7 @@ func TestRequestAndBatch(t *testing.T) { assertRequestMetricsEmitted( t, - stats.GetBufferedSamples(samples), + metrics.GetBufferedSamples(samples), "GET", sr("HTTPSBIN_URL/set-cookie-without-redirect"), sr("HTTPSBIN_URL/set-cookie-without-redirect"), @@ -750,7 +749,7 @@ func TestRequestAndBatch(t *testing.T) { assertRequestMetricsEmitted( t, - stats.GetBufferedSamples(samples), + metrics.GetBufferedSamples(samples), "GET", sr("HTTPSBIN_URL/cookies"), sr("HTTPSBIN_URL/cookies"), @@ -797,7 +796,7 @@ func TestRequestAndBatch(t *testing.T) { assertRequestMetricsEmitted( t, - stats.GetBufferedSamples(samples), + metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_IP_URL/get"), sr("HTTPBIN_IP_URL/get"), @@ -828,7 +827,7 @@ func TestRequestAndBatch(t *testing.T) { } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) t.Run("path", func(t *testing.T) { @@ -852,7 +851,7 @@ func TestRequestAndBatch(t *testing.T) { } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) t.Run("expires", func(t *testing.T) { @@ -873,7 +872,7 @@ func TestRequestAndBatch(t *testing.T) { } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) t.Run("secure", func(t *testing.T) { @@ -889,7 +888,7 @@ func TestRequestAndBatch(t *testing.T) { } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPSBIN_IP_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPSBIN_IP_URL/cookies"), "", 200, "") }) t.Run("localJar", func(t *testing.T) { @@ -907,7 +906,7 @@ func TestRequestAndBatch(t *testing.T) { if (jarCookies.key2 != undefined) { throw new Error("unexpected cookie in jar"); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/cookies"), "", 200, "") }) }) @@ -921,7 +920,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `, url)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", urlExpected, urlExpected, 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", urlExpected, urlExpected, 200, "") }) t.Run("digest", func(t *testing.T) { t.Run("success", func(t *testing.T) { @@ -935,7 +934,7 @@ func TestRequestAndBatch(t *testing.T) { `, url)) assert.NoError(t, err) - sampleContainers := stats.GetBufferedSamples(samples) + sampleContainers := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, sampleContainers[0:1], "GET", urlRaw, urlRaw, 401, "") assertRequestMetricsEmitted(t, sampleContainers[1:2], "GET", @@ -960,7 +959,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `), literal)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) } @@ -973,7 +972,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.json().headers["X-My-Header"] != "value") { throw new Error("wrong X-My-Header: " + res.json().headers["X-My-Header"]); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) t.Run("Host", func(t *testing.T) { @@ -985,7 +984,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.json().headers["Host"] != "HTTPBIN_DOMAIN") { throw new Error("wrong Host: " + res.json().headers["Host"]); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) t.Run("response_request", func(t *testing.T) { @@ -997,7 +996,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["Host"] != "HTTPBIN_DOMAIN") { throw new Error("wrong Host: " + res.request.headers["Host"]); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) t.Run("differentHost", func(t *testing.T) { @@ -1010,7 +1009,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["Host"] != custHost) { throw new Error("wrong Host: " + res.request.headers["Host"]); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) }) @@ -1022,7 +1021,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `), literal)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "", 200, "") }) } @@ -1032,7 +1031,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), sr("HTTPBIN_URL/headers"), 200, "") }) @@ -1042,7 +1041,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/headers"), "myReq", 200, "") }) @@ -1051,7 +1050,7 @@ func TestRequestAndBatch(t *testing.T) { assert.NoError(t, err) // There's no /anything endpoint in the go-httpbin library we're using, hence the 404, // but it doesn't matter for this test. - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/anything/2"), sr("HTTPBIN_URL/anything/${}"), 404, "") }) @@ -1061,7 +1060,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/headers"), "", 200, "") for _, sampleC := range bufSamples { for _, sample := range sampleC.GetSamples() { @@ -1086,7 +1085,7 @@ func TestRequestAndBatch(t *testing.T) { `)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/headers"), "myName", 200, "") for _, sampleC := range bufSamples { for _, sample := range sampleC.GetSamples() { @@ -1120,7 +1119,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["X-We-Want-This"] != "value") { throw new Error("Missing or invalid X-We-Want-This header!"); } `)) require.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "") t.Run("Tagged", func(t *testing.T) { _, err := rt.RunString(` @@ -1132,7 +1131,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.json().args.b != b) { throw new Error("wrong ?b: " + res.json().args.b); } `) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), sr("HTTPBIN_URL/get?a=${}&b=${}"), 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), sr("HTTPBIN_URL/get?a=${}&b=${}"), 200, "") }) }) t.Run("HEAD", func(t *testing.T) { @@ -1144,7 +1143,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["X-We-Want-This"] != "value") { throw new Error("Missing or invalid X-We-Want-This header!"); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "HEAD", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "HEAD", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "") }) t.Run("OPTIONS", func(t *testing.T) { @@ -1155,7 +1154,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["X-We-Want-This"] != "value") { throw new Error("Missing or invalid X-We-Want-This header!"); } `)) require.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "OPTIONS", sr("HTTPBIN_URL/?a=1&b=2"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "OPTIONS", sr("HTTPBIN_URL/?a=1&b=2"), "", 200, "") }) // DELETE HTTP requests shouldn't usually send a request body, they should use url parameters instead; references: @@ -1170,7 +1169,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["X-We-Want-This"] != "value") { throw new Error("Missing or invalid X-We-Want-This header!"); } `)) require.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "DELETE", sr("HTTPBIN_URL/delete?test=mest"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "DELETE", sr("HTTPBIN_URL/delete?test=mest"), "", 200, "") }) postMethods := map[string]string{ @@ -1188,7 +1187,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.request.headers["X-We-Want-This"] != "value") { throw new Error("Missing or invalid X-We-Want-This header!"); } `), fn, strings.ToLower(method))) require.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "") t.Run("object", func(t *testing.T) { _, err := rt.RunString(fmt.Sprintf(sr(` @@ -1203,7 +1202,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.json().headers["Content-Type"] != "application/x-www-form-urlencoded") { throw new Error("wrong content type: " + res.json().headers["Content-Type"]); } `), fn, strings.ToLower(method))) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "") t.Run("Content-Type", func(t *testing.T) { _, err := rt.RunString(fmt.Sprintf(sr(` var res = http.%s("HTTPBIN_URL/%s", {a: "a", b: 2}, {headers: {"Content-Type": "application/x-www-form-urlencoded; charset=utf-8"}}); @@ -1213,7 +1212,7 @@ func TestRequestAndBatch(t *testing.T) { if (res.json().headers["Content-Type"] != "application/x-www-form-urlencoded; charset=utf-8") { throw new Error("wrong content type: " + res.json().headers["Content-Type"]); } `), fn, strings.ToLower(method))) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), method, sr("HTTPBIN_URL/")+strings.ToLower(method), "", 200, "") }) }) }) @@ -1374,7 +1373,7 @@ func TestRequestAndBatch(t *testing.T) { } }`)) require.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/"), "", 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "") @@ -1393,7 +1392,7 @@ func TestRequestAndBatch(t *testing.T) { } }`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get"), sr("HTTPBIN_URL/${}"), 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "") }) @@ -1412,7 +1411,7 @@ func TestRequestAndBatch(t *testing.T) { } }`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/"), "", 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "") @@ -1431,7 +1430,7 @@ func TestRequestAndBatch(t *testing.T) { } }`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get"), sr("HTTPBIN_URL/${}"), 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "") }) @@ -1451,7 +1450,7 @@ func TestRequestAndBatch(t *testing.T) { } }`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/"), "", 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_IP_URL/"), "", 200, "") }) @@ -1470,7 +1469,7 @@ func TestRequestAndBatch(t *testing.T) { if (res[key].json().args.r != key) { throw new Error("wrong request id: " + key); } }`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=shorthand"), "", 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=arr"), "arr", 200, "") assertRequestMetricsEmitted(t, bufSamples, "GET", sr("HTTPBIN_URL/get?r=obj1"), "", 200, "") @@ -1515,7 +1514,7 @@ func TestRequestAndBatch(t *testing.T) { if (res[key].json().data != "testbody" && res[key].json().form.hello != "world!") { throw new Error("wrong response for " + key + ": " + res[key].body); } }`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, bufSamples, "POST", sr("HTTPBIN_URL/post"), "", 200, "") assertRequestMetricsEmitted(t, bufSamples, "POST", sr("HTTPBIN_IP_URL/post"), "myname", 200, "") }) @@ -1528,7 +1527,7 @@ func TestRequestAndBatch(t *testing.T) { if (res[key].json().form.key != "value") { throw new Error("wrong form: " + key + ": " + JSON.stringify(res[key].json().form)); } }`)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") }) t.Run("PUT", func(t *testing.T) { _, err := rt.RunString(sr(` @@ -1538,7 +1537,7 @@ func TestRequestAndBatch(t *testing.T) { if (res[key].json().form.key != "value") { throw new Error("wrong form: " + key + ": " + JSON.stringify(res[key].json().form)); } }`)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "PUT", sr("HTTPBIN_URL/put"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "PUT", sr("HTTPBIN_URL/put"), "", 200, "") }) }) @@ -1963,7 +1962,7 @@ func TestResponseTypes(t *testing.T) { assert.NoError(t, err) } -func checkErrorCode(t testing.TB, tags *stats.SampleTags, code int, msg string) { +func checkErrorCode(t testing.TB, tags *metrics.SampleTags, code int, msg string) { errorMsg, ok := tags.Get("error") if msg == "" { assert.False(t, ok) @@ -2065,7 +2064,7 @@ func TestErrorCodes(t *testing.T) { for _, testCase := range testCases { testCase := testCase // clear the Samples - stats.GetBufferedSamples(samples) + metrics.GetBufferedSamples(samples) t.Run(testCase.name, func(t *testing.T) { _, err := rt.RunString(sr(testCase.script + "\n" + fmt.Sprintf(` if (res.status != %d) { throw new Error("wrong status: "+ res.status);} @@ -2078,7 +2077,7 @@ func TestErrorCodes(t *testing.T) { require.Error(t, err) require.Equal(t, err.Error(), testCase.expectedScriptError) } - cs := stats.GetBufferedSamples(samples) + cs := metrics.GetBufferedSamples(samples) assert.Len(t, cs, 1+testCase.moreSamples) for _, c := range cs[len(cs)-1:] { assert.NotZero(t, len(c.GetSamples())) @@ -2198,7 +2197,7 @@ func TestRedirectMetricTags(t *testing.T) { require.Len(t, samples, 2) - checkTags := func(sc stats.SampleContainer, expTags map[string]string) { + checkTags := func(sc metrics.SampleContainer, expTags map[string]string) { allSamples := sc.GetSamples() assert.Len(t, allSamples, 9) for _, s := range allSamples { @@ -2347,7 +2346,7 @@ func TestRequestAndBatchTLS(t *testing.T) { if (res.tls_version != %s) { throw new Error("wrong TLS version: " + res.tls_version); } `, versionTest.URL, versionTest.Version)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", versionTest.URL, "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", versionTest.URL, "", 200, "") }) } tlsCipherSuiteTests := []struct { @@ -2364,7 +2363,7 @@ func TestRequestAndBatchTLS(t *testing.T) { if (res.tls_cipher_suite != "%s") { throw new Error("wrong TLS cipher suite: " + res.tls_cipher_suite); } `, cipherSuiteTest.URL, cipherSuiteTest.CipherSuite)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", cipherSuiteTest.URL, "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", cipherSuiteTest.URL, "", 200, "") }) } t.Run("ocsp_stapled_good", func(t *testing.T) { @@ -2374,7 +2373,7 @@ func TestRequestAndBatchTLS(t *testing.T) { if (res.ocsp.status != http.OCSP_STATUS_GOOD) { throw new Error("wrong ocsp stapled response status: " + res.ocsp.status); } `, website)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", website, "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", website, "", 200, "") }) } @@ -2407,7 +2406,7 @@ func TestDigestAuthWithBody(t *testing.T) { urlRaw := tb.Replacer.Replace( "http://HTTPBIN_IP:HTTPBIN_PORT/digest-auth-with-post/auth/testuser/testpwd") - sampleContainers := stats.GetBufferedSamples(samples) + sampleContainers := metrics.GetBufferedSamples(samples) assertRequestMetricsEmitted(t, sampleContainers[0:1], "POST", urlRaw, urlRaw, 401, "") assertRequestMetricsEmitted(t, sampleContainers[1:2], "POST", urlRaw, urlRaw, 200, "") } diff --git a/js/modules/k6/http/response_callback_test.go b/js/modules/k6/http/response_callback_test.go index 79c23615dcc..87e5036421d 100644 --- a/js/modules/k6/http/response_callback_test.go +++ b/js/modules/k6/http/response_callback_test.go @@ -30,7 +30,6 @@ import ( "github.com/stretchr/testify/require" "go.k6.io/k6/lib" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestExpectedStatuses(t *testing.T) { @@ -278,7 +277,7 @@ func TestResponseCallbackInAction(t *testing.T) { _, err := rt.RunString(sr(testCase.code)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) reqsCount := 0 for _, container := range bufSamples { @@ -387,7 +386,7 @@ func TestResponseCallbackBatch(t *testing.T) { _, err := rt.RunString(sr(testCase.code)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) reqsCount := 0 for _, container := range bufSamples { @@ -427,11 +426,11 @@ func TestResponseCallbackInActionWithoutPassedTag(t *testing.T) { metrics.HTTPReqWaitingName, metrics.HTTPReqTLSHandshakingName, } - deleteSystemTag(state, stats.TagExpectedResponse.String()) + deleteSystemTag(state, metrics.TagExpectedResponse.String()) _, err := rt.RunString(sr(`http.request("GET", "HTTPBIN_URL/redirect/1", null, {responseCallback: http.expectedStatuses(200)});`)) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) reqsCount := 0 for _, container := range bufSamples { @@ -452,7 +451,7 @@ func TestResponseCallbackInActionWithoutPassedTag(t *testing.T) { "group": "", "proto": "HTTP/1.1", } - assertRequestMetricsEmittedSingle(t, bufSamples[0], tags, allHTTPMetrics, func(sample stats.Sample) { + assertRequestMetricsEmittedSingle(t, bufSamples[0], tags, allHTTPMetrics, func(sample metrics.Sample) { if sample.Metric.Name == metrics.HTTPReqFailedName { require.EqualValues(t, sample.Value, 1) } @@ -460,7 +459,7 @@ func TestResponseCallbackInActionWithoutPassedTag(t *testing.T) { tags["url"] = sr("HTTPBIN_URL/get") tags["name"] = tags["url"] tags["status"] = "200" - assertRequestMetricsEmittedSingle(t, bufSamples[1], tags, allHTTPMetrics, func(sample stats.Sample) { + assertRequestMetricsEmittedSingle(t, bufSamples[1], tags, allHTTPMetrics, func(sample metrics.Sample) { if sample.Metric.Name == metrics.HTTPReqFailedName { require.EqualValues(t, sample.Value, 0) } @@ -492,7 +491,7 @@ func TestDigestWithResponseCallback(t *testing.T) { if (res.error_code !== 0) { throw new Error("wrong error code: " + res.error_code); } `, urlWithCreds)) require.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) reqsCount := 0 for _, container := range bufSamples { @@ -518,14 +517,14 @@ func TestDigestWithResponseCallback(t *testing.T) { "expected_response": "true", "error_code": "1401", } - assertRequestMetricsEmittedSingle(t, bufSamples[0], tags, allHTTPMetrics, func(sample stats.Sample) { + assertRequestMetricsEmittedSingle(t, bufSamples[0], tags, allHTTPMetrics, func(sample metrics.Sample) { if sample.Metric.Name == metrics.HTTPReqFailedName { require.EqualValues(t, sample.Value, 0) } }) tags["status"] = "200" delete(tags, "error_code") - assertRequestMetricsEmittedSingle(t, bufSamples[1], tags, allHTTPMetrics, func(sample stats.Sample) { + assertRequestMetricsEmittedSingle(t, bufSamples[1], tags, allHTTPMetrics, func(sample metrics.Sample) { if sample.Metric.Name == metrics.HTTPReqFailedName { require.EqualValues(t, sample.Value, 0) } @@ -539,5 +538,5 @@ func deleteSystemTag(state *lib.State, tag string) { for k := range enabledTags { tagsList = append(tagsList, k) } - state.Options.SystemTags = stats.ToSystemTagSet(tagsList) + state.Options.SystemTags = metrics.ToSystemTagSet(tagsList) } diff --git a/js/modules/k6/http/response_test.go b/js/modules/k6/http/response_test.go index 1bb36e7218c..75981fb0bb4 100644 --- a/js/modules/k6/http/response_test.go +++ b/js/modules/k6/http/response_test.go @@ -29,8 +29,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) const testGetFormHTML = ` @@ -141,7 +140,7 @@ func TestResponse(t *testing.T) { if (res.body.indexOf("Herman Melville - Moby-Dick") == -1) { throw new Error("wrong body: " + res.body); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/html"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/html"), "", 200, "") t.Run("html", func(t *testing.T) { _, err := rt.RunString(` @@ -182,7 +181,7 @@ func TestResponse(t *testing.T) { if (res.body.indexOf("Herman Melville - Moby-Dick") == -1) { throw new Error("wrong body: " + res.body); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/html"), "", 200, "::my group") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/html"), "", 200, "::my group") }) t.Run("NoResponseBody", func(t *testing.T) { @@ -200,7 +199,7 @@ func TestResponse(t *testing.T) { if (res.json().args.b != "2") { throw new Error("wrong ?b: " + res.json().args.b); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get?a=1&b=2"), "", 200, "") t.Run("Invalid", func(t *testing.T) { _, err := rt.RunString(sr(`http.request("GET", "HTTPBIN_URL/html").json();`)) @@ -261,7 +260,7 @@ func TestResponse(t *testing.T) { { throw new Error("Expected 'Dale', but got: " + value); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/json"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/json"), "", 200, "") }) t.Run("SubmitForm", func(t *testing.T) { @@ -281,7 +280,7 @@ func TestResponse(t *testing.T) { ) { throw new Error("incorrect body: " + JSON.stringify(data, null, 4) ); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") }) t.Run("withFields", func(t *testing.T) { @@ -300,7 +299,7 @@ func TestResponse(t *testing.T) { ) { throw new Error("incorrect body: " + JSON.stringify(data, null, 4) ); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") }) t.Run("withRequestParams", func(t *testing.T) { @@ -313,7 +312,7 @@ func TestResponse(t *testing.T) { if (headers["My-Fancy-Header"][0] !== "SomeValue" ) { throw new Error("incorrect headers: " + JSON.stringify(headers)); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") }) t.Run("withFormSelector", func(t *testing.T) { @@ -332,7 +331,7 @@ func TestResponse(t *testing.T) { ) { throw new Error("incorrect body: " + JSON.stringify(data, null, 4) ); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "POST", sr("HTTPBIN_URL/post"), "", 200, "") }) t.Run("withNonExistentForm", func(t *testing.T) { @@ -360,7 +359,7 @@ func TestResponse(t *testing.T) { ) { throw new Error("incorrect body: " + JSON.stringify(data, null, 4) ); } `)) require.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/myforms/get"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/myforms/get"), "", 200, "") }) }) @@ -373,7 +372,7 @@ func TestResponse(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/links/10/1"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/links/10/1"), "", 200, "") }) t.Run("withSelector", func(t *testing.T) { @@ -384,7 +383,7 @@ func TestResponse(t *testing.T) { if (res.status != 200) { throw new Error("wrong status: " + res.status); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/links/10/4"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/links/10/4"), "", 200, "") }) t.Run("withNonExistentLink", func(t *testing.T) { @@ -407,7 +406,7 @@ func TestResponse(t *testing.T) { if (headers["My-Fancy-Header"][0] !== "SomeValue" ) { throw new Error("incorrect headers: " + JSON.stringify(headers)); } `)) assert.NoError(t, err) - assertRequestMetricsEmitted(t, stats.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get"), "", 200, "") + assertRequestMetricsEmitted(t, metrics.GetBufferedSamples(samples), "GET", sr("HTTPBIN_URL/get"), "", 200, "") }) }) } diff --git a/js/modules/k6/k6.go b/js/modules/k6/k6.go index b5e25d9c891..0e098f3044f 100644 --- a/js/modules/k6/k6.go +++ b/js/modules/k6/k6.go @@ -31,7 +31,7 @@ import ( "go.k6.io/k6/js/common" "go.k6.io/k6/js/modules" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) var ( @@ -123,7 +123,7 @@ func (mi *K6) Group(name string, fn goja.Callable) (goja.Value, error) { old := state.Group state.Group = g - shouldUpdateTag := state.Options.SystemTags.Has(stats.TagGroup) + shouldUpdateTag := state.Options.SystemTags.Has(metrics.TagGroup) if shouldUpdateTag { state.Tags.Set("group", g.Path) } @@ -141,11 +141,11 @@ func (mi *K6) Group(name string, fn goja.Callable) (goja.Value, error) { tags := state.CloneTags() ctx := mi.vu.Context() - stats.PushIfNotDone(ctx, state.Samples, stats.Sample{ + metrics.PushIfNotDone(ctx, state.Samples, metrics.Sample{ Time: t, Metric: state.BuiltinMetrics.GroupDuration, - Tags: stats.IntoSampleTags(&tags), - Value: stats.D(t.Sub(startTime)), + Tags: metrics.IntoSampleTags(&tags), + Value: metrics.D(t.Sub(startTime)), }) return ret, err @@ -190,7 +190,7 @@ func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error) if err != nil { return false, err } - if state.Options.SystemTags.Has(stats.TagCheck) { + if state.Options.SystemTags.Has(metrics.TagCheck) { tags["check"] = check.Name } @@ -205,7 +205,7 @@ func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error) } } - sampleTags := stats.IntoSampleTags(&tags) + sampleTags := metrics.IntoSampleTags(&tags) // Emit! (But only if we have a valid context.) select { @@ -213,12 +213,12 @@ func (mi *K6) Check(arg0, checks goja.Value, extras ...goja.Value) (bool, error) default: if val.ToBoolean() { atomic.AddInt64(&check.Passes, 1) - stats.PushIfNotDone(ctx, state.Samples, - stats.Sample{Time: t, Metric: state.BuiltinMetrics.Checks, Tags: sampleTags, Value: 1}) + metrics.PushIfNotDone(ctx, state.Samples, + metrics.Sample{Time: t, Metric: state.BuiltinMetrics.Checks, Tags: sampleTags, Value: 1}) } else { atomic.AddInt64(&check.Fails, 1) - stats.PushIfNotDone(ctx, state.Samples, - stats.Sample{Time: t, Metric: state.BuiltinMetrics.Checks, Tags: sampleTags, Value: 0}) + metrics.PushIfNotDone(ctx, state.Samples, + metrics.Sample{Time: t, Metric: state.BuiltinMetrics.Checks, Tags: sampleTags, Value: 0}) // A single failure makes the return value false. succ = false } diff --git a/js/modules/k6/k6_test.go b/js/modules/k6/k6_test.go index 00c39927506..c0a7c909856 100644 --- a/js/modules/k6/k6_test.go +++ b/js/modules/k6/k6_test.go @@ -34,7 +34,6 @@ import ( "go.k6.io/k6/js/modulestest" "go.k6.io/k6/lib" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestFail(t *testing.T) { @@ -161,10 +160,10 @@ func TestGroup(t *testing.T) { rt := goja.New() state := &lib.State{ Group: root, - Samples: make(chan stats.SampleContainer, 1000), + Samples: make(chan metrics.SampleContainer, 1000), Tags: lib.NewTagMap(nil), Options: lib.Options{ - SystemTags: stats.NewSystemTagSet(stats.TagGroup), + SystemTags: metrics.NewSystemTagSet(metrics.TagGroup), }, } state.BuiltinMetrics = metrics.RegisterBuiltinMetrics(metrics.NewRegistry()) @@ -209,16 +208,16 @@ func TestGroup(t *testing.T) { }) } -func checkTestRuntime(t testing.TB) (*goja.Runtime, chan stats.SampleContainer, *metrics.BuiltinMetrics) { +func checkTestRuntime(t testing.TB) (*goja.Runtime, chan metrics.SampleContainer, *metrics.BuiltinMetrics) { rt := goja.New() root, err := lib.NewGroup("", nil) assert.NoError(t, err) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Options: lib.Options{ - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, Samples: samples, Tags: lib.NewTagMap(map[string]string{ @@ -248,9 +247,9 @@ func TestCheckObject(t *testing.T) { _, err := rt.RunString(`k6.check(null, { "check": true })`) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) if assert.Len(t, bufSamples, 1) { - sample, ok := bufSamples[0].(stats.Sample) + sample, ok := bufSamples[0].(metrics.Sample) require.True(t, ok) assert.NotZero(t, sample.Time) @@ -269,7 +268,7 @@ func TestCheckObject(t *testing.T) { _, err := rt.RunString(`k6.check(null, { "a": true, "b": false })`) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) assert.Len(t, bufSamples, 2) var foundA, foundB bool for _, sampleC := range bufSamples { @@ -307,9 +306,9 @@ func TestCheckArray(t *testing.T) { _, err := rt.RunString(`k6.check(null, [ true ])`) assert.NoError(t, err) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) if assert.Len(t, bufSamples, 1) { - sample, ok := bufSamples[0].(stats.Sample) + sample, ok := bufSamples[0].(metrics.Sample) require.True(t, ok) assert.NotZero(t, sample.Time) @@ -328,7 +327,7 @@ func TestCheckLiteral(t *testing.T) { _, err := rt.RunString(`k6.check(null, 12345)`) assert.NoError(t, err) - assert.Len(t, stats.GetBufferedSamples(samples), 0) + assert.Len(t, metrics.GetBufferedSamples(samples), 0) } func TestCheckNull(t *testing.T) { @@ -338,7 +337,7 @@ func TestCheckNull(t *testing.T) { _, err := rt.RunString(`k6.check(5)`) require.Error(t, err) assert.Contains(t, err.Error(), "no checks provided") - assert.Len(t, stats.GetBufferedSamples(samples), 0) + assert.Len(t, metrics.GetBufferedSamples(samples), 0) } func TestCheckThrows(t *testing.T) { @@ -352,9 +351,9 @@ func TestCheckThrows(t *testing.T) { `) assert.EqualError(t, err, "Error: error A at a (:3:28(3))") - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) if assert.Len(t, bufSamples, 1) { - sample, ok := bufSamples[0].(stats.Sample) + sample, ok := bufSamples[0].(metrics.Sample) require.True(t, ok) assert.NotZero(t, sample.Time) @@ -401,9 +400,9 @@ func TestCheckTypes(t *testing.T) { assert.Equal(t, succ, v.Export()) } - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) if assert.Len(t, bufSamples, 1) { - sample, ok := bufSamples[0].(stats.Sample) + sample, ok := bufSamples[0].(metrics.Sample) require.True(t, ok) assert.NotZero(t, sample.Time) @@ -432,11 +431,11 @@ func TestCheckContextExpiry(t *testing.T) { root, err := lib.NewGroup("", nil) require.NoError(t, err) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Options: lib.Options{ - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, Samples: samples, Tags: lib.NewTagMap(map[string]string{ @@ -484,9 +483,9 @@ func TestCheckTags(t *testing.T) { assert.Equal(t, true, v.Export()) } - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) if assert.Len(t, bufSamples, 1) { - sample, ok := bufSamples[0].(stats.Sample) + sample, ok := bufSamples[0].(metrics.Sample) require.True(t, ok) assert.NotZero(t, sample.Time) diff --git a/js/modules/k6/marshalling_test.go b/js/modules/k6/marshalling_test.go index 809b392531f..58ccb746168 100644 --- a/js/modules/k6/marshalling_test.go +++ b/js/modules/k6/marshalling_test.go @@ -36,7 +36,6 @@ import ( "go.k6.io/k6/lib/types" "go.k6.io/k6/loader" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestSetupDataMarshalling(t *testing.T) { @@ -137,7 +136,7 @@ func TestSetupDataMarshalling(t *testing.T) { require.NoError(t, err) - samples := make(chan<- stats.SampleContainer, 100) + samples := make(chan<- metrics.SampleContainer, 100) ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/js/modules/k6/metrics/metrics.go b/js/modules/k6/metrics/metrics.go index cf8516b5683..bbadad4aca5 100644 --- a/js/modules/k6/metrics/metrics.go +++ b/js/modules/k6/metrics/metrics.go @@ -32,27 +32,27 @@ import ( "go.k6.io/k6/js/common" "go.k6.io/k6/js/modules" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) type Metric struct { - metric *stats.Metric + metric *metrics.Metric vu modules.VU } // ErrMetricsAddInInitContext is error returned when adding to metric is done in the init context var ErrMetricsAddInInitContext = common.NewInitContextError("Adding to metrics in the init context is not supported") -func (mi *ModuleInstance) newMetric(call goja.ConstructorCall, t stats.MetricType) (*goja.Object, error) { +func (mi *ModuleInstance) newMetric(call goja.ConstructorCall, t metrics.MetricType) (*goja.Object, error) { initEnv := mi.vu.InitEnv() if initEnv == nil { return nil, errors.New("metrics must be declared in the init context") } rt := mi.vu.Runtime() c, _ := goja.AssertFunction(rt.ToValue(func(name string, isTime ...bool) (*goja.Object, error) { - valueType := stats.Default + valueType := metrics.Default if len(isTime) > 0 && isTime[0] { - valueType = stats.Time + valueType = metrics.Time } m, err := initEnv.Registry.NewMetric(name, t, valueType) if err != nil { @@ -135,8 +135,8 @@ func (m Metric) add(v goja.Value, addTags ...map[string]string) (bool, error) { } } - sample := stats.Sample{Time: time.Now(), Metric: m.metric, Value: vfloat, Tags: stats.IntoSampleTags(&tags)} - stats.PushIfNotDone(m.vu.Context(), state.Samples, sample) + sample := metrics.Sample{Time: time.Now(), Metric: m.metric, Value: vfloat, Tags: metrics.IntoSampleTags(&tags)} + metrics.PushIfNotDone(m.vu.Context(), state.Samples, sample) return true, nil } @@ -178,7 +178,7 @@ func (mi *ModuleInstance) Exports() modules.Exports { // XCounter is a counter constructor func (mi *ModuleInstance) XCounter(call goja.ConstructorCall, rt *goja.Runtime) *goja.Object { - v, err := mi.newMetric(call, stats.Counter) + v, err := mi.newMetric(call, metrics.Counter) if err != nil { common.Throw(rt, err) } @@ -187,7 +187,7 @@ func (mi *ModuleInstance) XCounter(call goja.ConstructorCall, rt *goja.Runtime) // XGauge is a gauge constructor func (mi *ModuleInstance) XGauge(call goja.ConstructorCall, rt *goja.Runtime) *goja.Object { - v, err := mi.newMetric(call, stats.Gauge) + v, err := mi.newMetric(call, metrics.Gauge) if err != nil { common.Throw(rt, err) } @@ -196,7 +196,7 @@ func (mi *ModuleInstance) XGauge(call goja.ConstructorCall, rt *goja.Runtime) *g // XTrend is a trend constructor func (mi *ModuleInstance) XTrend(call goja.ConstructorCall, rt *goja.Runtime) *goja.Object { - v, err := mi.newMetric(call, stats.Trend) + v, err := mi.newMetric(call, metrics.Trend) if err != nil { common.Throw(rt, err) } @@ -205,7 +205,7 @@ func (mi *ModuleInstance) XTrend(call goja.ConstructorCall, rt *goja.Runtime) *g // XRate is a rate constructor func (mi *ModuleInstance) XRate(call goja.ConstructorCall, rt *goja.Runtime) *goja.Object { - v, err := mi.newMetric(call, stats.Rate) + v, err := mi.newMetric(call, metrics.Rate) if err != nil { common.Throw(rt, err) } diff --git a/js/modules/k6/metrics/metrics_test.go b/js/modules/k6/metrics/metrics_test.go index cfd5547880c..d6d9716c694 100644 --- a/js/modules/k6/metrics/metrics_test.go +++ b/js/modules/k6/metrics/metrics_test.go @@ -36,7 +36,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) type addTestValue struct { @@ -50,10 +49,10 @@ type addTest struct { val addTestValue rt *goja.Runtime hook *testutils.SimpleLogrusHook - samples chan stats.SampleContainer + samples chan metrics.SampleContainer isThrow bool - mtyp stats.MetricType - valueType stats.ValueType + mtyp metrics.MetricType + valueType metrics.ValueType js string expectedTags map[string]string } @@ -73,9 +72,9 @@ func (a addTest) run(t *testing.T) { return } } - bufSamples := stats.GetBufferedSamples(a.samples) + bufSamples := metrics.GetBufferedSamples(a.samples) if assert.Len(t, bufSamples, 1) { - sample, ok := bufSamples[0].(stats.Sample) + sample, ok := bufSamples[0].(metrics.Sample) require.True(t, ok) assert.NotZero(t, sample.Time) @@ -89,11 +88,11 @@ func (a addTest) run(t *testing.T) { func TestMetrics(t *testing.T) { t.Parallel() - types := map[string]stats.MetricType{ - "Counter": stats.Counter, - "Gauge": stats.Gauge, - "Trend": stats.Trend, - "Rate": stats.Rate, + types := map[string]metrics.MetricType{ + "Counter": metrics.Counter, + "Gauge": metrics.Gauge, + "Trend": metrics.Trend, + "Rate": metrics.Rate, } values := map[string]addTestValue{ "Float": {JS: `2.5`, Float: 2.5}, @@ -113,7 +112,7 @@ func TestMetrics(t *testing.T) { fn, mtyp := fn, mtyp t.Run(fn, func(t *testing.T) { t.Parallel() - for isTime, valueType := range map[bool]stats.ValueType{false: stats.Default, true: stats.Time} { + for isTime, valueType := range map[bool]metrics.ValueType{false: metrics.Default, true: metrics.Time} { isTime, valueType := isTime, valueType t.Run(fmt.Sprintf("isTime=%v", isTime), func(t *testing.T) { t.Parallel() @@ -131,7 +130,7 @@ func TestMetrics(t *testing.T) { m, ok := New().NewModuleInstance(mii).(*ModuleInstance) require.True(t, ok) require.NoError(t, test.rt.Set("metrics", m.Exports().Named)) - test.samples = make(chan stats.SampleContainer, 1000) + test.samples = make(chan metrics.SampleContainer, 1000) state := &lib.State{ Options: lib.Options{}, Samples: test.samples, diff --git a/js/modules/k6/ws/ws.go b/js/modules/k6/ws/ws.go index 0bcc011136f..e48e2a49147 100644 --- a/js/modules/k6/ws/ws.go +++ b/js/modules/k6/ws/ws.go @@ -40,7 +40,6 @@ import ( "go.k6.io/k6/js/modules" httpModule "go.k6.io/k6/js/modules/k6/http" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) type ( @@ -96,8 +95,8 @@ type Socket struct { pingSendTimestamps map[string]time.Time pingSendCounter int - sampleTags *stats.SampleTags - samplesOutput chan<- stats.SampleContainer + sampleTags *metrics.SampleTags + samplesOutput chan<- metrics.SampleContainer builtinMetrics *metrics.BuiltinMetrics } @@ -216,7 +215,7 @@ func (mi *WS) Connect(url string, args ...goja.Value) (*WSHTTPResponse, error) { } - if state.Options.SystemTags.Has(stats.TagURL) { + if state.Options.SystemTags.Has(metrics.TagURL) { tags["url"] = url } @@ -244,20 +243,20 @@ func (mi *WS) Connect(url string, args ...goja.Value) (*WSHTTPResponse, error) { start := time.Now() conn, httpResponse, connErr := wsd.DialContext(ctx, url, header) connectionEnd := time.Now() - connectionDuration := stats.D(connectionEnd.Sub(start)) + connectionDuration := metrics.D(connectionEnd.Sub(start)) - if state.Options.SystemTags.Has(stats.TagIP) && conn.RemoteAddr() != nil { + if state.Options.SystemTags.Has(metrics.TagIP) && conn.RemoteAddr() != nil { if ip, _, err := net.SplitHostPort(conn.RemoteAddr().String()); err == nil { tags["ip"] = ip } } if httpResponse != nil { - if state.Options.SystemTags.Has(stats.TagStatus) { + if state.Options.SystemTags.Has(metrics.TagStatus) { tags["status"] = strconv.Itoa(httpResponse.StatusCode) } - if state.Options.SystemTags.Has(stats.TagSubproto) { + if state.Options.SystemTags.Has(metrics.TagSubproto) { tags["subproto"] = httpResponse.Header.Get("Sec-WebSocket-Protocol") } } @@ -271,12 +270,12 @@ func (mi *WS) Connect(url string, args ...goja.Value) (*WSHTTPResponse, error) { scheduled: make(chan goja.Callable), done: make(chan struct{}), samplesOutput: state.Samples, - sampleTags: stats.IntoSampleTags(&tags), + sampleTags: metrics.IntoSampleTags(&tags), builtinMetrics: state.BuiltinMetrics, } - stats.PushIfNotDone(ctx, state.Samples, stats.ConnectedSamples{ - Samples: []stats.Sample{ + metrics.PushIfNotDone(ctx, state.Samples, metrics.ConnectedSamples{ + Samples: []metrics.Sample{ {Metric: state.BuiltinMetrics.WSSessions, Time: start, Tags: socket.sampleTags, Value: 1}, {Metric: state.BuiltinMetrics.WSConnecting, Time: start, Tags: socket.sampleTags, Value: connectionDuration}, }, @@ -331,9 +330,9 @@ func (mi *WS) Connect(url string, args ...goja.Value) (*WSHTTPResponse, error) { defer func() { socket.Close() // just in case end := time.Now() - sessionDuration := stats.D(end.Sub(start)) + sessionDuration := metrics.D(end.Sub(start)) - stats.PushIfNotDone(ctx, state.Samples, stats.Sample{ + metrics.PushIfNotDone(ctx, state.Samples, metrics.Sample{ Metric: socket.builtinMetrics.WSSessionDuration, Tags: socket.sampleTags, Time: start, @@ -361,7 +360,7 @@ func (mi *WS) Connect(url string, args ...goja.Value) (*WSHTTPResponse, error) { socket.handleEvent("pong") case msg := <-readDataChan: - stats.PushIfNotDone(ctx, socket.samplesOutput, stats.Sample{ + metrics.PushIfNotDone(ctx, socket.samplesOutput, metrics.Sample{ Metric: socket.builtinMetrics.WSMessagesReceived, Time: time.Now(), Tags: socket.sampleTags, @@ -421,7 +420,7 @@ func (s *Socket) Send(message string) { s.handleEvent("error", s.rt.ToValue(err)) } - stats.PushIfNotDone(s.ctx, s.samplesOutput, stats.Sample{ + metrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{ Metric: s.builtinMetrics.WSMessagesSent, Time: time.Now(), Tags: s.sampleTags, @@ -451,7 +450,7 @@ func (s *Socket) SendBinary(message goja.Value) { common.Throw(s.rt, fmt.Errorf("expected ArrayBuffer as argument, received: %s", jsType)) } - stats.PushIfNotDone(s.ctx, s.samplesOutput, stats.Sample{ + metrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{ Metric: s.builtinMetrics.WSMessagesSent, Time: time.Now(), Tags: s.sampleTags, @@ -484,11 +483,11 @@ func (s *Socket) trackPong(pingID string) { } pingTimestamp := s.pingSendTimestamps[pingID] - stats.PushIfNotDone(s.ctx, s.samplesOutput, stats.Sample{ + metrics.PushIfNotDone(s.ctx, s.samplesOutput, metrics.Sample{ Metric: s.builtinMetrics.WSPing, Time: pongTimestamp, Tags: s.sampleTags, - Value: stats.D(pongTimestamp.Sub(pingTimestamp)), + Value: metrics.D(pongTimestamp.Sub(pingTimestamp)), }) } diff --git a/js/modules/k6/ws/ws_test.go b/js/modules/k6/ws/ws_test.go index 84c031461ae..6df83bb506b 100644 --- a/js/modules/k6/ws/ws_test.go +++ b/js/modules/k6/ws/ws_test.go @@ -44,13 +44,11 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils/httpmultibin" "go.k6.io/k6/metrics" - - "go.k6.io/k6/stats" ) const statusProtocolSwitch = 101 -func assertSessionMetricsEmitted(t *testing.T, sampleContainers []stats.SampleContainer, subprotocol, url string, status int, group string) { +func assertSessionMetricsEmitted(t *testing.T, sampleContainers []metrics.SampleContainer, subprotocol, url string, status int, group string) { //nolint:unparam seenSessions := false seenSessionDuration := false seenConnecting := false @@ -79,7 +77,7 @@ func assertSessionMetricsEmitted(t *testing.T, sampleContainers []stats.SampleCo assert.True(t, seenSessionDuration, "url %s didn't emit SessionDuration", url) } -func assertMetricEmittedCount(t *testing.T, metricName string, sampleContainers []stats.SampleContainer, url string, count int) { +func assertMetricEmittedCount(t *testing.T, metricName string, sampleContainers []metrics.SampleContainer, url string, count int) { t.Helper() actualCount := 0 @@ -100,7 +98,7 @@ type testState struct { rt *goja.Runtime tb *httpmultibin.HTTPMultiBin state *lib.State - samples chan stats.SampleContainer + samples chan metrics.SampleContainer } func newTestState(t testing.TB) testState { @@ -112,17 +110,17 @@ func newTestState(t testing.TB) testState { rt := goja.New() rt.SetFieldNameMapper(common.FieldNameMapper{}) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, Options: lib.Options{ - SystemTags: stats.NewSystemTagSet( - stats.TagURL, - stats.TagProto, - stats.TagStatus, - stats.TagSubproto, + SystemTags: metrics.NewSystemTagSet( + metrics.TagURL, + metrics.TagProto, + metrics.TagStatus, + metrics.TagSubproto, ), UserAgent: null.StringFrom("TestUserAgent"), }, @@ -159,16 +157,16 @@ func TestSession(t *testing.T) { rt := goja.New() rt.SetFieldNameMapper(common.FieldNameMapper{}) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, Options: lib.Options{ - SystemTags: stats.NewSystemTagSet( - stats.TagURL, - stats.TagProto, - stats.TagStatus, - stats.TagSubproto, + SystemTags: metrics.NewSystemTagSet( + metrics.TagURL, + metrics.TagProto, + metrics.TagStatus, + metrics.TagSubproto, ), }, Samples: samples, @@ -194,7 +192,7 @@ func TestSession(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") t.Run("connect_wss", func(t *testing.T) { _, err := rt.RunString(sr(` @@ -205,7 +203,7 @@ func TestSession(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSSBIN_URL/ws-echo"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSSBIN_URL/ws-echo"), statusProtocolSwitch, "") t.Run("open", func(t *testing.T) { _, err := rt.RunString(sr(` @@ -220,7 +218,7 @@ func TestSession(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") t.Run("send_receive", func(t *testing.T) { _, err := rt.RunString(sr(` @@ -239,7 +237,7 @@ func TestSession(t *testing.T) { require.NoError(t, err) }) - samplesBuf := stats.GetBufferedSamples(samples) + samplesBuf := metrics.GetBufferedSamples(samples) assertSessionMetricsEmitted(t, samplesBuf, "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") assertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr("WSBIN_URL/ws-echo"), 1) assertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr("WSBIN_URL/ws-echo"), 1) @@ -257,7 +255,7 @@ func TestSession(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") t.Run("bad interval", func(t *testing.T) { _, err := rt.RunString(sr(` var counter = 0; @@ -303,7 +301,7 @@ func TestSession(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "setTimeout requires a >0 timeout parameter, received 0.00 ") }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") t.Run("ping", func(t *testing.T) { _, err := rt.RunString(sr(` @@ -325,7 +323,7 @@ func TestSession(t *testing.T) { require.NoError(t, err) }) - samplesBuf = stats.GetBufferedSamples(samples) + samplesBuf = metrics.GetBufferedSamples(samples) assertSessionMetricsEmitted(t, samplesBuf, "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") assertMetricEmittedCount(t, metrics.WSPingName, samplesBuf, sr("WSBIN_URL/ws-echo"), 1) @@ -359,7 +357,7 @@ func TestSession(t *testing.T) { require.NoError(t, err) }) - samplesBuf = stats.GetBufferedSamples(samples) + samplesBuf = metrics.GetBufferedSamples(samples) assertSessionMetricsEmitted(t, samplesBuf, "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") assertMetricEmittedCount(t, metrics.WSPingName, samplesBuf, sr("WSBIN_URL/ws-echo"), 1) @@ -378,7 +376,7 @@ func TestSession(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo"), statusProtocolSwitch, "") serverCloseTests := []struct { name string @@ -469,7 +467,7 @@ func TestSession(t *testing.T) { require.NoError(t, err) }) - samplesBuf = stats.GetBufferedSamples(samples) + samplesBuf = metrics.GetBufferedSamples(samples) assertSessionMetricsEmitted(t, samplesBuf, "", sr("WSBIN_URL/ws-echo-multi"), statusProtocolSwitch, "") assertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr("WSBIN_URL/ws-echo-multi"), 3) assertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr("WSBIN_URL/ws-echo-multi"), 3) @@ -501,7 +499,7 @@ func TestSession(t *testing.T) { require.NoError(t, err) }) - samplesBuf = stats.GetBufferedSamples(samples) + samplesBuf = metrics.GetBufferedSamples(samples) assertSessionMetricsEmitted(t, samplesBuf, "", sr("WSSBIN_URL/ws-echo-multi"), statusProtocolSwitch, "") assertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr("WSSBIN_URL/ws-echo-multi"), 2) assertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr("WSSBIN_URL/ws-echo-multi"), 2) @@ -536,7 +534,7 @@ func TestSession(t *testing.T) { require.NoError(t, err) }) - samplesBuf = stats.GetBufferedSamples(samples) + samplesBuf = metrics.GetBufferedSamples(samples) assertSessionMetricsEmitted(t, samplesBuf, "", sr("WSBIN_URL/ws-echo-multi"), statusProtocolSwitch, "") assertMetricEmittedCount(t, metrics.WSMessagesSentName, samplesBuf, sr("WSBIN_URL/ws-echo-multi"), 2) assertMetricEmittedCount(t, metrics.WSMessagesReceivedName, samplesBuf, sr("WSBIN_URL/ws-echo-multi"), 2) @@ -553,16 +551,16 @@ func TestSocketSendBinary(t *testing.T) { //nolint: tparallel rt := goja.New() rt.SetFieldNameMapper(common.FieldNameMapper{}) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ //nolint: exhaustivestruct Group: root, Dialer: tb.Dialer, Options: lib.Options{ //nolint: exhaustivestruct - SystemTags: stats.NewSystemTagSet( - stats.TagURL, - stats.TagProto, - stats.TagStatus, - stats.TagSubproto, + SystemTags: metrics.NewSystemTagSet( + metrics.TagURL, + metrics.TagProto, + metrics.TagStatus, + metrics.TagSubproto, ), }, Samples: samples, @@ -651,12 +649,12 @@ func TestErrors(t *testing.T) { rt := goja.New() rt.SetFieldNameMapper(common.FieldNameMapper{}) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, Options: lib.Options{ - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, Samples: samples, BuiltinMetrics: metrics.RegisterBuiltinMetrics(metrics.NewRegistry()), @@ -719,7 +717,7 @@ func TestErrors(t *testing.T) { } `)) require.NoError(t, err) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo-invalid"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo-invalid"), statusProtocolSwitch, "") }) t.Run("error on close", func(t *testing.T) { @@ -748,7 +746,7 @@ func TestErrors(t *testing.T) { }); `)) require.NoError(t, err) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-close"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-close"), statusProtocolSwitch, "") }) } @@ -767,11 +765,11 @@ func TestSystemTags(t *testing.T) { // external service demos.kaazing.com (https://github.com/k6io/k6/issues/537) testedSystemTags := []string{"group", "status", "subproto", "url", "ip"} - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, - Options: lib.Options{SystemTags: stats.ToSystemTagSet(testedSystemTags)}, + Options: lib.Options{SystemTags: metrics.ToSystemTagSet(testedSystemTags)}, Samples: samples, TLSConfig: tb.TLSClientConfig, BuiltinMetrics: metrics.RegisterBuiltinMetrics(metrics.NewRegistry()), @@ -789,7 +787,7 @@ func TestSystemTags(t *testing.T) { for _, expectedTag := range testedSystemTags { expectedTag := expectedTag t.Run("only "+expectedTag, func(t *testing.T) { - state.Options.SystemTags = stats.ToSystemTagSet([]string{expectedTag}) + state.Options.SystemTags = metrics.ToSystemTagSet([]string{expectedTag}) _, err := rt.RunString(sr(` var res = ws.connect("WSBIN_URL/ws-echo", function(socket){ socket.on("open", function() { @@ -805,7 +803,7 @@ func TestSystemTags(t *testing.T) { `)) require.NoError(t, err) - for _, sampleContainer := range stats.GetBufferedSamples(samples) { + for _, sampleContainer := range metrics.GetBufferedSamples(samples) { for _, sample := range sampleContainer.GetSamples() { for emittedTag := range sample.Tags.CloneTags() { assert.Equal(t, expectedTag, emittedTag) @@ -826,17 +824,17 @@ func TestTLSConfig(t *testing.T) { rt := goja.New() rt.SetFieldNameMapper(common.FieldNameMapper{}) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, Options: lib.Options{ - SystemTags: stats.NewSystemTagSet( - stats.TagURL, - stats.TagProto, - stats.TagStatus, - stats.TagSubproto, - stats.TagIP, + SystemTags: metrics.NewSystemTagSet( + metrics.TagURL, + metrics.TagProto, + metrics.TagStatus, + metrics.TagSubproto, + metrics.TagIP, ), }, Samples: samples, @@ -865,7 +863,7 @@ func TestTLSConfig(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSSBIN_URL/ws-close"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSSBIN_URL/ws-close"), statusProtocolSwitch, "") t.Run("custom certificates", func(t *testing.T) { state.TLSConfig = tb.TLSClientConfig @@ -880,7 +878,7 @@ func TestTLSConfig(t *testing.T) { `)) require.NoError(t, err) }) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSSBIN_URL/ws-close"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSSBIN_URL/ws-close"), statusProtocolSwitch, "") } func TestReadPump(t *testing.T) { @@ -967,16 +965,16 @@ func TestUserAgent(t *testing.T) { rt := goja.New() rt.SetFieldNameMapper(common.FieldNameMapper{}) - samples := make(chan stats.SampleContainer, 1000) + samples := make(chan metrics.SampleContainer, 1000) state := &lib.State{ Group: root, Dialer: tb.Dialer, Options: lib.Options{ - SystemTags: stats.NewSystemTagSet( - stats.TagURL, - stats.TagProto, - stats.TagStatus, - stats.TagSubproto, + SystemTags: metrics.NewSystemTagSet( + metrics.TagURL, + metrics.TagProto, + metrics.TagStatus, + metrics.TagSubproto, ), UserAgent: null.StringFrom("TestUserAgent"), }, @@ -1009,7 +1007,7 @@ func TestUserAgent(t *testing.T) { `)) require.NoError(t, err) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo-useragent"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(samples), "", sr("WSBIN_URL/ws-echo-useragent"), statusProtocolSwitch, "") } func TestCompression(t *testing.T) { @@ -1072,7 +1070,7 @@ func TestCompression(t *testing.T) { `)) require.NoError(t, err) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(ts.samples), "", sr("WSBIN_URL/ws-compression"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(ts.samples), "", sr("WSBIN_URL/ws-compression"), statusProtocolSwitch, "") }) t.Run("params", func(t *testing.T) { @@ -1146,7 +1144,7 @@ func TestCompression(t *testing.T) { }) } -func clearSamples(tb *httpmultibin.HTTPMultiBin, samples chan stats.SampleContainer) { +func clearSamples(tb *httpmultibin.HTTPMultiBin, samples chan metrics.SampleContainer) { ctxDone := tb.Context.Done() for { select { @@ -1288,5 +1286,5 @@ func TestCookieJar(t *testing.T) { `)) require.NoError(t, err) - assertSessionMetricsEmitted(t, stats.GetBufferedSamples(ts.samples), "", sr("WSBIN_URL/ws-echo-someheader"), statusProtocolSwitch, "") + assertSessionMetricsEmitted(t, metrics.GetBufferedSamples(ts.samples), "", sr("WSBIN_URL/ws-echo-someheader"), statusProtocolSwitch, "") } diff --git a/js/runner.go b/js/runner.go index a8e56588d23..d26e1477704 100644 --- a/js/runner.go +++ b/js/runner.go @@ -53,7 +53,6 @@ import ( "go.k6.io/k6/lib/types" "go.k6.io/k6/loader" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // Ensure Runner implements the lib.Runner interface @@ -145,7 +144,7 @@ func (r *Runner) MakeArchive() *lib.Archive { } // NewVU returns a new initialized VU. -func (r *Runner) NewVU(idLocal, idGlobal uint64, samplesOut chan<- stats.SampleContainer) (lib.InitializedVU, error) { +func (r *Runner) NewVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.SampleContainer) (lib.InitializedVU, error) { vu, err := r.newVU(idLocal, idGlobal, samplesOut) if err != nil { return nil, err @@ -154,7 +153,7 @@ func (r *Runner) NewVU(idLocal, idGlobal uint64, samplesOut chan<- stats.SampleC } // nolint:funlen -func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- stats.SampleContainer) (*VU, error) { +func (r *Runner) newVU(idLocal, idGlobal uint64, samplesOut chan<- metrics.SampleContainer) (*VU, error) { // Instantiate a new bundle, make a VU out of it. moduleVUImpl := newModuleVUImpl() bi, err := r.Bundle.Instantiate(r.Logger, idLocal, moduleVUImpl) @@ -305,7 +304,7 @@ func forceHTTP1() bool { } // Setup runs the setup function if there is one and sets the setupData to the returned value -func (r *Runner) Setup(ctx context.Context, out chan<- stats.SampleContainer) error { +func (r *Runner) Setup(ctx context.Context, out chan<- metrics.SampleContainer) error { setupCtx, setupCancel := context.WithTimeout(ctx, r.getTimeoutFor(consts.SetupFn)) defer setupCancel() @@ -337,7 +336,8 @@ func (r *Runner) SetSetupData(data []byte) { r.setupData = data } -func (r *Runner) Teardown(ctx context.Context, out chan<- stats.SampleContainer) error { +// Teardown runs the teardown function if there is one. +func (r *Runner) Teardown(ctx context.Context, out chan<- metrics.SampleContainer) error { teardownCtx, teardownCancel := context.WithTimeout(ctx, r.getTimeoutFor(consts.TeardownFn)) defer teardownCancel() @@ -372,7 +372,7 @@ func (r *Runner) IsExecutable(name string) bool { func (r *Runner) HandleSummary(ctx context.Context, summary *lib.Summary) (map[string]io.Reader, error) { summaryDataForJS := summarizeMetricsToObject(summary, r.Bundle.Options, r.setupData) - out := make(chan stats.SampleContainer, 100) + out := make(chan metrics.SampleContainer, 100) defer close(out) go func() { // discard all metrics @@ -516,7 +516,12 @@ func parseTTL(ttlS string) (time.Duration, error) { // Runs an exported function in its own temporary VU, optionally with an argument. Execution is // interrupted if the context expires. No error is returned if the part does not exist. -func (r *Runner) runPart(ctx context.Context, out chan<- stats.SampleContainer, name string, arg interface{}) (goja.Value, error) { +func (r *Runner) runPart( + ctx context.Context, + out chan<- metrics.SampleContainer, + name string, + arg interface{}, +) (goja.Value, error) { vu, err := r.newVU(0, 0, out) if err != nil { return goja.Undefined(), err @@ -543,7 +548,7 @@ func (r *Runner) runPart(ctx context.Context, out chan<- stats.SampleContainer, return goja.Undefined(), err } - if r.Bundle.Options.SystemTags.Has(stats.TagGroup) { + if r.Bundle.Options.SystemTags.Has(metrics.TagGroup) { vu.state.Tags.Set("group", group.Path) } vu.state.Group = group @@ -592,7 +597,7 @@ type VU struct { Console *console BPool *bpool.BufferPool - Samples chan<- stats.SampleContainer + Samples chan<- metrics.SampleContainer setupData goja.Value @@ -649,16 +654,16 @@ func (u *VU) Activate(params *lib.VUActivationParams) lib.ActiveVU { for k, v := range params.Tags { u.state.Tags.Set(k, v) } - if opts.SystemTags.Has(stats.TagVU) { + if opts.SystemTags.Has(metrics.TagVU) { u.state.Tags.Set("vu", strconv.FormatUint(u.ID, 10)) } - if opts.SystemTags.Has(stats.TagIter) { + if opts.SystemTags.Has(metrics.TagIter) { u.state.Tags.Set("iter", strconv.FormatInt(u.iteration, 10)) } - if opts.SystemTags.Has(stats.TagGroup) { + if opts.SystemTags.Has(metrics.TagGroup) { u.state.Tags.Set("group", u.state.Group.Path) } - if opts.SystemTags.Has(stats.TagScenario) { + if opts.SystemTags.Has(metrics.TagScenario) { u.state.Tags.Set("scenario", params.Scenario) } @@ -783,7 +788,7 @@ func (u *VU) runFn( } opts := &u.Runner.Bundle.Options - if opts.SystemTags.Has(stats.TagIter) { + if opts.SystemTags.Has(metrics.TagIter) { u.state.Tags.Set("iter", strconv.FormatInt(u.state.Iteration, 10)) } @@ -820,7 +825,7 @@ func (u *VU) runFn( u.Transport.CloseIdleConnections() } - sampleTags := stats.NewSampleTags(u.state.CloneTags()) + sampleTags := metrics.NewSampleTags(u.state.CloneTags()) u.state.Samples <- u.Dialer.GetTrail( startTime, endTime, isFullIteration, isDefault, sampleTags, u.Runner.builtinMetrics) diff --git a/js/runner_test.go b/js/runner_test.go index 111d4f61725..7d6d5342478 100644 --- a/js/runner_test.go +++ b/js/runner_test.go @@ -63,7 +63,6 @@ import ( "go.k6.io/k6/loader" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) func TestRunnerNew(t *testing.T) { @@ -78,7 +77,7 @@ func TestRunnerNew(t *testing.T) { t.Run("NewVU", func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) assert.NoError(t, err) vuc, ok := initVU.(*VU) assert.True(t, ok) @@ -176,7 +175,7 @@ func TestOptionsSettingToScript(t *testing.T) { r.SetOptions(newOptions) require.Equal(t, newOptions, r.GetOptions()) - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.NewVU(1, 1, samples) if assert.NoError(t, err) { ctx, cancel := context.WithCancel(context.Background()) @@ -228,7 +227,7 @@ func TestOptionsPropagationToScript(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.NewVU(1, 1, samples) if assert.NoError(t, err) { @@ -364,7 +363,7 @@ func testSetupDataHelper(t *testing.T, data string) { t.Parallel() ctx, cancel := context.WithCancel(context.Background()) defer cancel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) if !assert.NoError(t, r.Setup(ctx, samples)) { return @@ -431,7 +430,7 @@ func TestConsoleInInitContext(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.NewVU(1, 1, samples) if assert.NoError(t, err) { ctx, cancel := context.WithCancel(context.Background()) @@ -517,7 +516,7 @@ func TestRunnerIntegrationImports(t *testing.T) { for name, r := range testdata { r := r t.Run(name, func(t *testing.T) { - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -550,7 +549,7 @@ func TestVURunContext(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - vu, err := r.newVU(1, 1, make(chan stats.SampleContainer, 100)) + vu, err := r.newVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) fnCalled := false @@ -595,7 +594,7 @@ func TestVURunInterrupt(t *testing.T) { name, r := name, r t.Run(name, func(t *testing.T) { t.Parallel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) defer close(samples) go func() { for range samples { @@ -634,7 +633,7 @@ func TestVURunInterruptDoesntPanic(t *testing.T) { t.Parallel() ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) defer close(samples) go func() { for range samples { @@ -693,7 +692,7 @@ func TestVUIntegrationGroups(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - vu, err := r.newVU(1, 1, make(chan stats.SampleContainer, 100)) + vu, err := r.newVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) fnOuterCalled := false @@ -748,7 +747,7 @@ func TestVUIntegrationMetrics(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) defer close(samples) vu, err := r.newVU(1, 1, samples) require.NoError(t, err) @@ -759,14 +758,14 @@ func TestVUIntegrationMetrics(t *testing.T) { err = activeVU.RunOnce() assert.NoError(t, err) sampleCount := 0 - for i, sampleC := range stats.GetBufferedSamples(samples) { + for i, sampleC := range metrics.GetBufferedSamples(samples) { for j, s := range sampleC.GetSamples() { sampleCount++ switch i + j { case 0: assert.Equal(t, 5.0, s.Value) assert.Equal(t, "my_metric", s.Metric.Name) - assert.Equal(t, stats.Trend, s.Metric.Type) + assert.Equal(t, metrics.Trend, s.Metric.Type) case 1: assert.Equal(t, 0.0, s.Value) assert.Equal(t, builtinMetrics.DataSent, s.Metric, "`data_sent` sample is before `data_received` and `iteration_duration`") @@ -827,7 +826,7 @@ func TestVUIntegrationInsecureRequests(t *testing.T) { t.Parallel() r.Logger, _ = logtest.NewNullLogger() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -872,7 +871,7 @@ func TestVUIntegrationBlacklistOption(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -909,7 +908,7 @@ func TestVUIntegrationBlacklistScript(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -947,7 +946,7 @@ func TestVUIntegrationBlockHostnamesOption(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVu, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVu, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -985,7 +984,7 @@ func TestVUIntegrationBlockHostnamesScript(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVu, err := r.NewVU(0, 0, make(chan stats.SampleContainer, 100)) + initVu, err := r.NewVU(0, 0, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1033,7 +1032,7 @@ func TestVUIntegrationHosts(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -1106,7 +1105,7 @@ func TestVUIntegrationTLSConfig(t *testing.T) { t.Parallel() r.Logger, _ = logtest.NewNullLogger() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1131,7 +1130,7 @@ func TestVUIntegrationOpenFunctionError(t *testing.T) { `) assert.NoError(t, err) - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) assert.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1149,7 +1148,7 @@ func TestVUIntegrationOpenFunctionErrorWhenSneaky(t *testing.T) { `) assert.NoError(t, err) - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) assert.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1179,7 +1178,7 @@ func TestVUDoesOpenUnderV0Condition(t *testing.T) { r, err := getSimpleRunner(t, "/script.js", data, fs) require.NoError(t, err) - _, err = r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + _, err = r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) assert.NoError(t, err) } @@ -1203,7 +1202,7 @@ func TestVUDoesNotOpenUnderConditions(t *testing.T) { r, err := getSimpleRunner(t, "/script.js", data, fs) require.NoError(t, err) - _, err = r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + _, err = r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) assert.Error(t, err) assert.Contains(t, err.Error(), "open() can't be used with files that weren't previously opened during initialization (__VU==0)") } @@ -1227,7 +1226,7 @@ func TestVUDoesNonExistingPathnUnderConditions(t *testing.T) { r, err := getSimpleRunner(t, "/script.js", data, fs) require.NoError(t, err) - _, err = r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + _, err = r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) assert.Error(t, err) assert.Contains(t, err.Error(), "open() can't be used with files that weren't previously opened during initialization (__VU==0)") } @@ -1270,7 +1269,7 @@ func TestVUIntegrationCookiesReset(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1326,7 +1325,7 @@ func TestVUIntegrationCookiesNoReset(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -1361,7 +1360,7 @@ func TestVUIntegrationVUID(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1234, 1234, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1234, 1234, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -1513,7 +1512,7 @@ func TestVUIntegrationClientCerts(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() r.Logger, _ = logtest.NewNullLogger() - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) if assert.NoError(t, err) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1676,7 +1675,7 @@ func TestArchiveRunningIntegrity(t *testing.T) { t.Run(name, func(t *testing.T) { t.Parallel() var err error - ch := make(chan stats.SampleContainer, 100) + ch := make(chan metrics.SampleContainer, 100) ctx, cancel := context.WithCancel(context.Background()) defer cancel() err = r.Setup(ctx, ch) @@ -1759,7 +1758,7 @@ func TestStuffNotPanicking(t *testing.T) { `)) require.NoError(t, err) - ch := make(chan stats.SampleContainer, 1000) + ch := make(chan metrics.SampleContainer, 1000) initVU, err := r.NewVU(1, 1, ch) require.NoError(t, err) @@ -1793,7 +1792,7 @@ func TestPanicOnSimpleHTML(t *testing.T) { `) require.NoError(t, err) - ch := make(chan stats.SampleContainer, 1000) + ch := make(chan metrics.SampleContainer, 1000) initVU, err := r.NewVU(1, 1, ch) require.NoError(t, err) @@ -1850,7 +1849,7 @@ func TestSystemTags(t *testing.T) { num, tc := num, tc t.Run(fmt.Sprintf("TC %d with only %s", num, tc.tag), func(t *testing.T) { t.Parallel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) r, err := getSimpleRunner(t, "/script.js", tb.Replacer.Replace(` var http = require("k6/http"); @@ -1869,7 +1868,7 @@ func TestSystemTags(t *testing.T) { require.NoError(t, r.SetOptions(r.GetOptions().Apply(lib.Options{ Throw: null.BoolFrom(false), TLSVersion: &lib.TLSVersions{Max: tls.VersionTLS13}, - SystemTags: stats.ToSystemTagSet([]string{tc.tag}), + SystemTags: metrics.ToSystemTagSet([]string{tc.tag}), InsecureSkipTLSVerify: null.BoolFrom(true), }))) @@ -1885,7 +1884,7 @@ func TestSystemTags(t *testing.T) { }) require.NoError(t, activeVU.RunOnce()) - bufSamples := stats.GetBufferedSamples(samples) + bufSamples := metrics.GetBufferedSamples(samples) require.NotEmpty(t, bufSamples) for _, sample := range bufSamples[0].GetSamples() { assert.NotEmpty(t, sample.Tags) @@ -1923,7 +1922,7 @@ func TestVUPanic(t *testing.T) { r := r t.Run(name, func(t *testing.T) { t.Parallel() - initVU, err := r.NewVU(1, 1234, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1234, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) logger := logrus.New() @@ -1970,7 +1969,7 @@ type multiFileTestCase struct { script string expInitErr bool expVUErr bool - samples chan stats.SampleContainer + samples chan metrics.SampleContainer } func runMultiFileTestCase(t *testing.T, tc multiFileTestCase, tb *httpmultibin.HTTPMultiBin) { @@ -2084,7 +2083,7 @@ func TestComplicatedFileImportsForGRPC(t *testing.T) { return multiFileTestCase{ fses: map[string]afero.Fs{"file": fs, "https": afero.NewMemMapFs()}, rtOpts: lib.RuntimeOptions{CompatibilityMode: null.NewString("base", true)}, - samples: make(chan stats.SampleContainer, 100), + samples: make(chan metrics.SampleContainer, 100), cwd: cwd, expInitErr: expInitErr, expVUErr: expVUErr, script: script, } } @@ -2155,7 +2154,7 @@ func TestMinIterationDurationIsCancellable(t *testing.T) { `) require.NoError(t, err) - ch := make(chan stats.SampleContainer, 1000) + ch := make(chan metrics.SampleContainer, 1000) initVU, err := r.NewVU(1, 1, ch) require.NoError(t, err) @@ -2244,7 +2243,7 @@ func TestForceHTTP1Feature(t *testing.T) { for name, r := range runners { r := r t.Run(name, func(t *testing.T) { - initVU, err := r.NewVU(1, 1, make(chan stats.SampleContainer, 100)) + initVU, err := r.NewVU(1, 1, make(chan metrics.SampleContainer, 100)) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) @@ -2324,8 +2323,8 @@ func TestExecutionInfo(t *testing.T) { } require.NoError(t, err) - r.Bundle.Options.SystemTags = stats.NewSystemTagSet(stats.DefaultSystemTagSet) - samples := make(chan stats.SampleContainer, 100) + r.Bundle.Options.SystemTags = metrics.NewSystemTagSet(metrics.DefaultSystemTagSet) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.NewVU(1, 10, samples) require.NoError(t, err) diff --git a/js/share_test.go b/js/share_test.go index fadfe122436..2978c34b07b 100644 --- a/js/share_test.go +++ b/js/share_test.go @@ -32,7 +32,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestNewSharedArrayIntegration(t *testing.T) { @@ -97,7 +96,7 @@ exports.default = function() { r := r t.Run(name, func(t *testing.T) { t.Parallel() - samples := make(chan stats.SampleContainer, 100) + samples := make(chan metrics.SampleContainer, 100) initVU, err := r.NewVU(1, 1, samples) require.NoError(t, err) diff --git a/js/summary.go b/js/summary.go index 405006cbfb9..44b743e4788 100644 --- a/js/summary.go +++ b/js/summary.go @@ -30,7 +30,7 @@ import ( "github.com/dop251/goja" "go.k6.io/k6/js/common" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // Copied from https://github.com/k6io/jslib.k6.io/tree/master/lib/k6-summary @@ -42,32 +42,32 @@ var summaryWrapperLambdaCode string //nolint:gochecknoglobals // TODO: figure out something saner... refactor the sinks and how we deal with // metrics in general... so much pain and misery... :sob: -func metricValueGetter(summaryTrendStats []string) func(stats.Sink, time.Duration) map[string]float64 { - trendResolvers, err := stats.GetResolversForTrendColumns(summaryTrendStats) +func metricValueGetter(summaryTrendStats []string) func(metrics.Sink, time.Duration) map[string]float64 { + trendResolvers, err := metrics.GetResolversForTrendColumns(summaryTrendStats) if err != nil { panic(err.Error()) // this should have been validated already } - return func(sink stats.Sink, t time.Duration) (result map[string]float64) { + return func(sink metrics.Sink, t time.Duration) (result map[string]float64) { sink.Calc() switch sink := sink.(type) { - case *stats.CounterSink: + case *metrics.CounterSink: result = sink.Format(t) rate := 0.0 if t > 0 { rate = sink.Value / (float64(t) / float64(time.Second)) } result["rate"] = rate - case *stats.GaugeSink: + case *metrics.GaugeSink: result = sink.Format(t) result["min"] = sink.Min result["max"] = sink.Max - case *stats.RateSink: + case *metrics.RateSink: result = sink.Format(t) result["passes"] = float64(sink.Trues) result["fails"] = float64(sink.Total - sink.Trues) - case *stats.TrendSink: + case *metrics.TrendSink: result = make(map[string]float64, len(summaryTrendStats)) for _, col := range summaryTrendStats { result[col] = trendResolvers[col](sink) diff --git a/js/summary_test.go b/js/summary_test.go index 335847270fc..cf3bc52efed 100644 --- a/js/summary_test.go +++ b/js/summary_test.go @@ -36,7 +36,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) const ( @@ -100,23 +99,23 @@ func TestTextSummaryWithSubMetrics(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - parentMetric, err := registry.NewMetric("my_parent", stats.Counter) + parentMetric, err := registry.NewMetric("my_parent", metrics.Counter) require.NoError(t, err) - parentMetric.Sink.Add(stats.Sample{Value: 11}) + parentMetric.Sink.Add(metrics.Sample{Value: 11}) - parentMetricPost, err := registry.NewMetric("my_parent_post", stats.Counter) + parentMetricPost, err := registry.NewMetric("my_parent_post", metrics.Counter) require.NoError(t, err) - parentMetricPost.Sink.Add(stats.Sample{Value: 22}) + parentMetricPost.Sink.Add(metrics.Sample{Value: 22}) subMetric, err := parentMetric.AddSubmetric("sub:1") require.NoError(t, err) - subMetric.Metric.Sink.Add(stats.Sample{Value: 1}) + subMetric.Metric.Sink.Add(metrics.Sample{Value: 1}) subMetricPost, err := parentMetricPost.AddSubmetric("sub:2") require.NoError(t, err) - subMetricPost.Metric.Sink.Add(stats.Sample{Value: 2}) + subMetricPost.Metric.Sink.Add(metrics.Sample{Value: 2}) - metrics := map[string]*stats.Metric{ + metrics := map[string]*metrics.Metric{ parentMetric.Name: parentMetric, parentMetricPost.Name: parentMetricPost, subMetric.Name: subMetric.Metric, @@ -154,42 +153,42 @@ func TestTextSummaryWithSubMetrics(t *testing.T) { assert.Equal(t, "\n"+expected+"\n", string(summaryOut)) } -func createTestMetrics(t *testing.T) (map[string]*stats.Metric, *lib.Group) { +func createTestMetrics(t *testing.T) (map[string]*metrics.Metric, *lib.Group) { registry := metrics.NewRegistry() - metrics := make(map[string]*stats.Metric) + testMetrics := make(map[string]*metrics.Metric) - gaugeMetric, err := registry.NewMetric("vus", stats.Gauge) + gaugeMetric, err := registry.NewMetric("vus", metrics.Gauge) require.NoError(t, err) - gaugeMetric.Sink.Add(stats.Sample{Value: 1}) + gaugeMetric.Sink.Add(metrics.Sample{Value: 1}) - countMetric, err := registry.NewMetric("http_reqs", stats.Counter) + countMetric, err := registry.NewMetric("http_reqs", metrics.Counter) require.NoError(t, err) countMetric.Tainted = null.BoolFrom(true) - countMetric.Thresholds = stats.Thresholds{Thresholds: []*stats.Threshold{{Source: "rate<100", LastFailed: true}}} + countMetric.Thresholds = metrics.Thresholds{Thresholds: []*metrics.Threshold{{Source: "rate<100", LastFailed: true}}} - checksMetric, err := registry.NewMetric("checks", stats.Rate) + checksMetric, err := registry.NewMetric("checks", metrics.Rate) require.NoError(t, err) checksMetric.Tainted = null.BoolFrom(false) - checksMetric.Thresholds = stats.Thresholds{Thresholds: []*stats.Threshold{{Source: "rate>70", LastFailed: false}}} - sink := &stats.TrendSink{} + checksMetric.Thresholds = metrics.Thresholds{Thresholds: []*metrics.Threshold{{Source: "rate>70", LastFailed: false}}} + sink := &metrics.TrendSink{} samples := []float64{10.0, 15.0, 20.0} for _, s := range samples { - sink.Add(stats.Sample{Value: s}) - countMetric.Sink.Add(stats.Sample{Value: 1}) + sink.Add(metrics.Sample{Value: s}) + countMetric.Sink.Add(metrics.Sample{Value: 1}) } - metrics["vus"] = gaugeMetric - metrics["http_reqs"] = countMetric - metrics["checks"] = checksMetric - metrics["my_trend"] = &stats.Metric{ + testMetrics["vus"] = gaugeMetric + testMetrics["http_reqs"] = countMetric + testMetrics["checks"] = checksMetric + testMetrics["my_trend"] = &metrics.Metric{ Name: "my_trend", - Type: stats.Trend, - Contains: stats.Time, + Type: metrics.Trend, + Contains: metrics.Time, Sink: sink, Tainted: null.BoolFrom(true), - Thresholds: stats.Thresholds{ - Thresholds: []*stats.Threshold{ + Thresholds: metrics.Thresholds{ + Thresholds: []*metrics.Threshold{ { Source: "my_trend<1000", LastFailed: true, @@ -217,13 +216,13 @@ func createTestMetrics(t *testing.T) (map[string]*stats.Metric, *lib.Group) { check2.Fails = 10 for i := 0; i < int(check1.Passes+check2.Passes+check3.Passes); i++ { - checksMetric.Sink.Add(stats.Sample{Value: 1}) + checksMetric.Sink.Add(metrics.Sample{Value: 1}) } for i := 0; i < int(check1.Fails+check2.Fails+check3.Fails); i++ { - checksMetric.Sink.Add(stats.Sample{Value: 0}) + checksMetric.Sink.Add(metrics.Sample{Value: 0}) } - return metrics, rootG + return testMetrics, rootG } func createTestSummary(t *testing.T) *lib.Summary { diff --git a/lib/archive_test.go b/lib/archive_test.go index 67faf13e950..40b8fc78cf1 100644 --- a/lib/archive_test.go +++ b/lib/archive_test.go @@ -37,7 +37,7 @@ import ( "go.k6.io/k6/lib/consts" "go.k6.io/k6/lib/fsext" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func TestNormalizeAndAnonymizePath(t *testing.T) { @@ -142,7 +142,7 @@ func TestArchiveReadWrite(t *testing.T) { K6Version: consts.Version, Options: Options{ VUs: null.IntFrom(12345), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, FilenameURL: &url.URL{Scheme: "file", Path: "/path/to/a.js"}, Data: []byte(`// a contents`), @@ -192,7 +192,7 @@ func TestArchiveReadWrite(t *testing.T) { Type: "js", Options: Options{ VUs: null.IntFrom(12345), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, FilenameURL: &url.URL{Scheme: "file", Path: fmt.Sprintf("%s/a.js", entry.Pwd)}, K6Version: consts.Version, @@ -215,7 +215,7 @@ func TestArchiveReadWrite(t *testing.T) { Type: "js", Options: Options{ VUs: null.IntFrom(12345), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, FilenameURL: &url.URL{Scheme: "file", Path: fmt.Sprintf("%s/a.js", entry.PwdNormAnon)}, K6Version: consts.Version, @@ -344,7 +344,7 @@ func TestStrangePaths(t *testing.T) { K6Version: consts.Version, Options: Options{ VUs: null.IntFrom(12345), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, FilenameURL: &url.URL{Scheme: "file", Path: pathToChange}, Data: []byte(`// ` + pathToChange + ` contents`), diff --git a/lib/execution.go b/lib/execution.go index 69c8b6c4dc3..dd8959b5828 100644 --- a/lib/execution.go +++ b/lib/execution.go @@ -31,7 +31,6 @@ import ( "github.com/sirupsen/logrus" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // An ExecutionScheduler is in charge of initializing executors and using them @@ -58,11 +57,11 @@ type ExecutionScheduler interface { GetExecutors() []Executor // Init initializes all executors, including all of their needed VUs. - Init(ctx context.Context, samplesOut chan<- stats.SampleContainer) error + Init(ctx context.Context, samplesOut chan<- metrics.SampleContainer) error // Run the ExecutionScheduler, funneling the generated metric samples // through the supplied out channel. - Run(globalCtx, runCtx context.Context, samplesOut chan<- stats.SampleContainer) error + Run(globalCtx, runCtx context.Context, samplesOut chan<- metrics.SampleContainer) error // Pause a test, or start/resume it. To check if a test is paused, use // GetState().IsPaused(). diff --git a/lib/executor/base_executor.go b/lib/executor/base_executor.go index 9a65d4e5e9b..830abf234f7 100644 --- a/lib/executor/base_executor.go +++ b/lib/executor/base_executor.go @@ -28,7 +28,7 @@ import ( "github.com/sirupsen/logrus" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -92,13 +92,13 @@ func (bs *BaseExecutor) GetProgress() *pb.ProgressBar { // getMetricTags returns a tag set that can be used to emit metrics by the // executor. The VU ID is optional. -func (bs *BaseExecutor) getMetricTags(vuID *uint64) *stats.SampleTags { +func (bs *BaseExecutor) getMetricTags(vuID *uint64) *metrics.SampleTags { tags := bs.executionState.Options.RunTags.CloneTags() - if bs.executionState.Options.SystemTags.Has(stats.TagScenario) { + if bs.executionState.Options.SystemTags.Has(metrics.TagScenario) { tags["scenario"] = bs.config.GetName() } - if vuID != nil && bs.executionState.Options.SystemTags.Has(stats.TagVU) { + if vuID != nil && bs.executionState.Options.SystemTags.Has(metrics.TagVU) { tags["vu"] = strconv.FormatUint(*vuID, 10) } - return stats.IntoSampleTags(&tags) + return metrics.IntoSampleTags(&tags) } diff --git a/lib/executor/common_test.go b/lib/executor/common_test.go index 8e876dd6b08..60783cdfe96 100644 --- a/lib/executor/common_test.go +++ b/lib/executor/common_test.go @@ -31,12 +31,12 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/minirunner" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func simpleRunner(vuFn func(context.Context, *lib.State) error) lib.Runner { return &minirunner.MiniRunner{ - Fn: func(ctx context.Context, state *lib.State, _ chan<- stats.SampleContainer) error { + Fn: func(ctx context.Context, state *lib.State, _ chan<- metrics.SampleContainer) error { return vuFn(ctx, state) }, } @@ -46,7 +46,7 @@ func setupExecutor(t testing.TB, config lib.ExecutorConfig, es *lib.ExecutionSta context.Context, context.CancelFunc, lib.Executor, *testutils.SimpleLogrusHook, ) { ctx, cancel := context.WithCancel(context.Background()) - engineOut := make(chan stats.SampleContainer, 100) // TODO: return this for more complicated tests? + engineOut := make(chan metrics.SampleContainer, 100) // TODO: return this for more complicated tests? logHook := &testutils.SimpleLogrusHook{HookedLevels: []logrus.Level{logrus.WarnLevel}} testLog := logrus.New() diff --git a/lib/executor/constant_arrival_rate.go b/lib/executor/constant_arrival_rate.go index 2e5000c63f5..925d6feab06 100644 --- a/lib/executor/constant_arrival_rate.go +++ b/lib/executor/constant_arrival_rate.go @@ -34,7 +34,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -211,7 +211,7 @@ func (car *ConstantArrivalRate) Init(ctx context.Context) error { // This will allow us to implement https://github.com/k6io/k6/issues/1386 // and things like all of the TODOs below in one place only. //nolint:funlen,cyclop -func (car ConstantArrivalRate) Run(parentCtx context.Context, out chan<- stats.SampleContainer) (err error) { +func (car ConstantArrivalRate) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) { gracefulStop := car.config.GetGracefulStop() duration := car.config.Duration.TimeDuration() preAllocatedVUs := car.config.GetPreAllocatedVUs(car.executionState.ExecutionTuple) @@ -344,7 +344,7 @@ func (car ConstantArrivalRate) Run(parentCtx context.Context, out chan<- stats.S // Since there aren't any free VUs available, consider this iteration // dropped - we aren't going to try to recover it, but - stats.PushIfNotDone(parentCtx, out, stats.Sample{ + metrics.PushIfNotDone(parentCtx, out, metrics.Sample{ Value: 1, Metric: droppedIterationMetric, Tags: metricTags, Time: time.Now(), }) diff --git a/lib/executor/constant_arrival_rate_test.go b/lib/executor/constant_arrival_rate_test.go index 563789aaf4c..7bca39fa9d8 100644 --- a/lib/executor/constant_arrival_rate_test.go +++ b/lib/executor/constant_arrival_rate_test.go @@ -37,7 +37,6 @@ import ( "go.k6.io/k6/lib/testutils/minirunner" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func newExecutionSegmentFromString(str string) *lib.ExecutionSegment { @@ -83,7 +82,7 @@ func TestConstantArrivalRateRunNotEnoughAllocatedVUsWarn(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) entries := logHook.Drain() @@ -125,7 +124,7 @@ func TestConstantArrivalRateRunCorrectRate(t *testing.T) { require.InDelta(t, 50, currentCount, 1) } }() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) wg.Wait() require.NoError(t, err) @@ -248,7 +247,7 @@ func TestConstantArrivalRateRunCorrectTiming(t *testing.T) { } }() startTime = time.Now() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) wg.Wait() require.NoError(t, err) @@ -291,7 +290,7 @@ func TestArrivalRateCancel(t *testing.T) { go func() { defer wg.Done() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) errCh <- executor.Run(ctx, engineOut) close(weAreDoneCh) }() @@ -341,7 +340,7 @@ func TestConstantArrivalRateDroppedIterations(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) logs := logHook.Drain() @@ -392,14 +391,14 @@ func TestConstantArrivalRateGlobalIters(t *testing.T) { gotIters := []uint64{} var mx sync.Mutex - runner.Fn = func(ctx context.Context, state *lib.State, _ chan<- stats.SampleContainer) error { + runner.Fn = func(ctx context.Context, state *lib.State, _ chan<- metrics.SampleContainer) error { mx.Lock() gotIters = append(gotIters, state.GetScenarioGlobalVUIter()) mx.Unlock() return nil } - engineOut := make(chan stats.SampleContainer, 100) + engineOut := make(chan metrics.SampleContainer, 100) err = executor.Run(ctx, engineOut) require.NoError(t, err) assert.Equal(t, tc.expIters, gotIters) diff --git a/lib/executor/constant_vus.go b/lib/executor/constant_vus.go index a32f2ca75cd..84a40c9aa71 100644 --- a/lib/executor/constant_vus.go +++ b/lib/executor/constant_vus.go @@ -31,7 +31,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -142,7 +142,7 @@ var _ lib.Executor = &ConstantVUs{} // Run constantly loops through as many iterations as possible on a fixed number // of VUs for the specified duration. -func (clv ConstantVUs) Run(parentCtx context.Context, out chan<- stats.SampleContainer) (err error) { +func (clv ConstantVUs) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) { numVUs := clv.config.GetVUs(clv.executionState.ExecutionTuple) duration := clv.config.Duration.TimeDuration() gracefulStop := clv.config.GetGracefulStop() diff --git a/lib/executor/externally_controlled.go b/lib/executor/externally_controlled.go index 972564ded2b..1e9ed0e5881 100644 --- a/lib/executor/externally_controlled.go +++ b/lib/executor/externally_controlled.go @@ -34,7 +34,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -499,7 +499,7 @@ func (rs *externallyControlledRunState) handleConfigChange(oldCfg, newCfg Extern // dynamically controlled number of VUs either for the specified duration, or // until the test is manually stopped. // nolint:funlen,gocognit,cyclop -func (mex *ExternallyControlled) Run(parentCtx context.Context, out chan<- stats.SampleContainer) (err error) { +func (mex *ExternallyControlled) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) { mex.configLock.RLock() // Safely get the current config - it's important that the close of the // hasStarted channel is inside of the lock, so that there are no data races diff --git a/lib/executor/helpers_test.go b/lib/executor/helpers_test.go index 6fbf99194fc..f3a872bdd83 100644 --- a/lib/executor/helpers_test.go +++ b/lib/executor/helpers_test.go @@ -20,10 +20,10 @@ package executor -import "go.k6.io/k6/stats" +import "go.k6.io/k6/metrics" -func sumMetricValues(samples chan stats.SampleContainer, metricName string) (sum float64) { - for _, sc := range stats.GetBufferedSamples(samples) { +func sumMetricValues(samples chan metrics.SampleContainer, metricName string) (sum float64) { // nolint: unparam + for _, sc := range metrics.GetBufferedSamples(samples) { samples := sc.GetSamples() for _, s := range samples { if s.Metric.Name == metricName { diff --git a/lib/executor/per_vu_iterations.go b/lib/executor/per_vu_iterations.go index 494f13b474c..fd38a22a82b 100644 --- a/lib/executor/per_vu_iterations.go +++ b/lib/executor/per_vu_iterations.go @@ -32,7 +32,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -151,7 +151,7 @@ var _ lib.Executor = &PerVUIterations{} // Run executes a specific number of iterations with each configured VU. // nolint:funlen -func (pvi PerVUIterations) Run(parentCtx context.Context, out chan<- stats.SampleContainer) (err error) { +func (pvi PerVUIterations) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) { numVUs := pvi.config.GetVUs(pvi.executionState.ExecutionTuple) iterations := pvi.config.GetIterations() duration := pvi.config.MaxDuration.TimeDuration() @@ -225,7 +225,7 @@ func (pvi PerVUIterations) Run(parentCtx context.Context, out chan<- stats.Sampl for i := int64(0); i < iterations; i++ { select { case <-regDurationDone: - stats.PushIfNotDone(parentCtx, out, stats.Sample{ + metrics.PushIfNotDone(parentCtx, out, metrics.Sample{ Value: float64(iterations - i), Metric: droppedIterationMetric, Tags: pvi.getMetricTags(&vuID), Time: time.Now(), }) diff --git a/lib/executor/per_vu_iterations_test.go b/lib/executor/per_vu_iterations_test.go index f00d2cae38e..517b76a49ea 100644 --- a/lib/executor/per_vu_iterations_test.go +++ b/lib/executor/per_vu_iterations_test.go @@ -34,7 +34,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func getTestPerVUIterationsConfig() PerVUIterationsConfig { @@ -64,7 +63,7 @@ func TestPerVUIterationsRun(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) @@ -103,7 +102,7 @@ func TestPerVUIterationsRunVariableVU(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) @@ -150,7 +149,7 @@ func TestPerVuIterationsEmitDroppedIterations(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) assert.Empty(t, logHook.Drain()) diff --git a/lib/executor/ramping_arrival_rate.go b/lib/executor/ramping_arrival_rate.go index 7b83d640da8..301ec550a34 100644 --- a/lib/executor/ramping_arrival_rate.go +++ b/lib/executor/ramping_arrival_rate.go @@ -33,7 +33,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -319,7 +319,7 @@ func noNegativeSqrt(f float64) float64 { // This will allow us to implement https://github.com/k6io/k6/issues/1386 // and things like all of the TODOs below in one place only. //nolint:funlen,cyclop -func (varr RampingArrivalRate) Run(parentCtx context.Context, out chan<- stats.SampleContainer) (err error) { +func (varr RampingArrivalRate) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) { segment := varr.executionState.ExecutionTuple.Segment gracefulStop := varr.config.GetGracefulStop() duration := sumStagesDuration(varr.config.Stages) @@ -479,7 +479,7 @@ func (varr RampingArrivalRate) Run(parentCtx context.Context, out chan<- stats.S // Since there aren't any free VUs available, consider this iteration // dropped - we aren't going to try to recover it, but - stats.PushIfNotDone(parentCtx, out, droppedIterationMetric.Sample(time.Now(), metricTags, 1)) + metrics.PushIfNotDone(parentCtx, out, droppedIterationMetric.Sample(time.Now(), metricTags, 1)) // We'll try to start allocating another VU in the background, // non-blockingly, if we have remainingUnplannedVUs... diff --git a/lib/executor/ramping_arrival_rate_test.go b/lib/executor/ramping_arrival_rate_test.go index 980303f0272..13ce6100de5 100644 --- a/lib/executor/ramping_arrival_rate_test.go +++ b/lib/executor/ramping_arrival_rate_test.go @@ -38,7 +38,6 @@ import ( "go.k6.io/k6/lib/testutils/minirunner" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func getTestRampingArrivalRateConfig() *RampingArrivalRateConfig { @@ -80,7 +79,7 @@ func TestRampingArrivalRateRunNotEnoughAllocatedVUsWarn(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) entries := logHook.Drain() @@ -128,7 +127,7 @@ func TestRampingArrivalRateRunCorrectRate(t *testing.T) { currentCount = atomic.SwapInt64(&count, 0) assert.InDelta(t, 50, currentCount, 3) }() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) wg.Wait() require.NoError(t, err) @@ -171,7 +170,7 @@ func TestRampingArrivalRateRunUnplannedVUs(t *testing.T) { }, es, runner) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) es.SetInitVUFunc(func(_ context.Context, logger *logrus.Entry) (lib.InitializedVU, error) { cur := atomic.LoadInt64(&count) require.Equal(t, cur, int64(1)) @@ -234,7 +233,7 @@ func TestRampingArrivalRateRunCorrectRateWithSlowRate(t *testing.T) { }, es, runner) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) es.SetInitVUFunc(func(_ context.Context, logger *logrus.Entry) (lib.InitializedVU, error) { t.Log("init") cur := atomic.LoadInt64(&count) @@ -287,7 +286,7 @@ func TestRampingArrivalRateRunGracefulStop(t *testing.T) { es, runner) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) defer close(engineOut) err = executor.Run(ctx, engineOut) @@ -309,7 +308,7 @@ func BenchmarkRampingArrivalRateRun(b *testing.B) { for _, tc := range tests { b.Run(fmt.Sprintf("VUs%d", tc.prealloc.ValueOrZero()), func(b *testing.B) { - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) defer close(engineOut) go func() { for range engineOut { @@ -757,14 +756,14 @@ func TestRampingArrivalRateGlobalIters(t *testing.T) { gotIters := []uint64{} var mx sync.Mutex - runner.Fn = func(ctx context.Context, state *lib.State, _ chan<- stats.SampleContainer) error { + runner.Fn = func(ctx context.Context, state *lib.State, _ chan<- metrics.SampleContainer) error { mx.Lock() gotIters = append(gotIters, state.GetScenarioGlobalVUIter()) mx.Unlock() return nil } - engineOut := make(chan stats.SampleContainer, 100) + engineOut := make(chan metrics.SampleContainer, 100) err = executor.Run(ctx, engineOut) require.NoError(t, err) assert.Equal(t, tc.expIters, gotIters) diff --git a/lib/executor/ramping_vus.go b/lib/executor/ramping_vus.go index 9b7b81f3e44..2c235a2695d 100644 --- a/lib/executor/ramping_vus.go +++ b/lib/executor/ramping_vus.go @@ -32,7 +32,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -506,7 +506,7 @@ func (vlv *RampingVUs) Init(_ context.Context) error { // Run constantly loops through as many iterations as possible on a variable // number of VUs for the specified stages. -func (vlv *RampingVUs) Run(ctx context.Context, _ chan<- stats.SampleContainer) error { +func (vlv *RampingVUs) Run(ctx context.Context, _ chan<- metrics.SampleContainer) error { regularDuration, isFinal := lib.GetEndOffset(vlv.rawSteps) if !isFinal { return fmt.Errorf("%s expected raw end offset at %s to be final", vlv.config.GetName(), regularDuration) diff --git a/lib/executor/shared_iterations.go b/lib/executor/shared_iterations.go index 86d749b04b0..31e17e59886 100644 --- a/lib/executor/shared_iterations.go +++ b/lib/executor/shared_iterations.go @@ -32,7 +32,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -183,7 +183,7 @@ func (si *SharedIterations) Init(ctx context.Context) error { // Run executes a specific total number of iterations, which are all shared by // the configured VUs. // nolint:funlen -func (si SharedIterations) Run(parentCtx context.Context, out chan<- stats.SampleContainer) (err error) { +func (si SharedIterations) Run(parentCtx context.Context, out chan<- metrics.SampleContainer) (err error) { numVUs := si.config.GetVUs(si.executionState.ExecutionTuple) iterations := si.et.ScaleInt64(si.config.Iterations.Int64) duration := si.config.MaxDuration.TimeDuration() @@ -223,7 +223,7 @@ func (si SharedIterations) Run(parentCtx context.Context, out chan<- stats.Sampl defer func() { activeVUs.Wait() if attemptedIters < totalIters { - stats.PushIfNotDone(parentCtx, out, stats.Sample{ + metrics.PushIfNotDone(parentCtx, out, metrics.Sample{ Value: float64(totalIters - attemptedIters), Metric: si.executionState.BuiltinMetrics.DroppedIterations, Tags: si.getMetricTags(nil), Time: time.Now(), diff --git a/lib/executor/shared_iterations_test.go b/lib/executor/shared_iterations_test.go index 7220d8d1d92..f4e65f6aa6a 100644 --- a/lib/executor/shared_iterations_test.go +++ b/lib/executor/shared_iterations_test.go @@ -37,7 +37,6 @@ import ( "go.k6.io/k6/lib/testutils/minirunner" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func getTestSharedIterationsConfig() SharedIterationsConfig { @@ -142,7 +141,7 @@ func TestSharedIterationsEmitDroppedIterations(t *testing.T) { }), ) defer cancel() - engineOut := make(chan stats.SampleContainer, 1000) + engineOut := make(chan metrics.SampleContainer, 1000) err = executor.Run(ctx, engineOut) require.NoError(t, err) assert.Empty(t, logHook.Drain()) @@ -188,14 +187,14 @@ func TestSharedIterationsGlobalIters(t *testing.T) { gotIters := []uint64{} var mx sync.Mutex - runner.Fn = func(ctx context.Context, state *lib.State, _ chan<- stats.SampleContainer) error { + runner.Fn = func(ctx context.Context, state *lib.State, _ chan<- metrics.SampleContainer) error { mx.Lock() gotIters = append(gotIters, state.GetScenarioGlobalVUIter()) mx.Unlock() return nil } - engineOut := make(chan stats.SampleContainer, 100) + engineOut := make(chan metrics.SampleContainer, 100) err = executor.Run(ctx, engineOut) require.NoError(t, err) sort.Slice(gotIters, func(i, j int) bool { return gotIters[i] < gotIters[j] }) diff --git a/lib/executor/vu_handle_test.go b/lib/executor/vu_handle_test.go index e3485a30e6e..a6169c33b05 100644 --- a/lib/executor/vu_handle_test.go +++ b/lib/executor/vu_handle_test.go @@ -34,7 +34,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/minirunner" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func mockNextIterations() (uint64, uint64) { @@ -55,7 +55,7 @@ func TestVUHandleRace(t *testing.T) { logEntry := logrus.NewEntry(testLog) runner := &minirunner.MiniRunner{} - runner.Fn = func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + runner.Fn = func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { return nil } @@ -144,7 +144,7 @@ func TestVUHandleStartStopRace(t *testing.T) { logEntry := logrus.NewEntry(testLog) runner := &minirunner.MiniRunner{} - runner.Fn = func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + runner.Fn = func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { return nil } @@ -387,7 +387,7 @@ func BenchmarkVUHandleIterations(b *testing.B) { } runner := &minirunner.MiniRunner{} - runner.Fn = func(ctx context.Context, _ *lib.State, out chan<- stats.SampleContainer) error { + runner.Fn = func(ctx context.Context, _ *lib.State, out chan<- metrics.SampleContainer) error { return nil } getVU := func() (lib.InitializedVU, error) { diff --git a/lib/executors.go b/lib/executors.go index e8ef95f49aa..f0d39afa4f7 100644 --- a/lib/executors.go +++ b/lib/executors.go @@ -31,7 +31,7 @@ import ( "github.com/sirupsen/logrus" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "go.k6.io/k6/ui/pb" ) @@ -128,7 +128,7 @@ type Executor interface { GetLogger() *logrus.Entry Init(ctx context.Context) error - Run(ctx context.Context, engineOut chan<- stats.SampleContainer) error + Run(ctx context.Context, engineOut chan<- metrics.SampleContainer) error } // PausableExecutor should be implemented by the executors that can be paused diff --git a/lib/netext/dialer.go b/lib/netext/dialer.go index 2f94178623d..578d0e88b86 100644 --- a/lib/netext/dialer.go +++ b/lib/netext/dialer.go @@ -31,7 +31,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // Dialer wraps net.Dialer and provides k6 specific functionality - @@ -95,12 +94,12 @@ func (d *Dialer) DialContext(ctx context.Context, proto, addr string) (net.Conn, // TODO: Refactor this according to // https://github.com/k6io/k6/pull/1203#discussion_r337938370 func (d *Dialer) GetTrail( - startTime, endTime time.Time, fullIteration bool, emitIterations bool, tags *stats.SampleTags, + startTime, endTime time.Time, fullIteration bool, emitIterations bool, tags *metrics.SampleTags, builtinMetrics *metrics.BuiltinMetrics, ) *NetTrail { bytesWritten := atomic.SwapInt64(&d.BytesWritten, 0) bytesRead := atomic.SwapInt64(&d.BytesRead, 0) - samples := []stats.Sample{ + samples := []metrics.Sample{ { Time: endTime, Metric: builtinMetrics.DataSent, @@ -115,14 +114,14 @@ func (d *Dialer) GetTrail( }, } if fullIteration { - samples = append(samples, stats.Sample{ + samples = append(samples, metrics.Sample{ Time: endTime, Metric: builtinMetrics.IterationDuration, - Value: stats.D(endTime.Sub(startTime)), + Value: metrics.D(endTime.Sub(startTime)), Tags: tags, }) if emitIterations { - samples = append(samples, stats.Sample{ + samples = append(samples, metrics.Sample{ Time: endTime, Metric: builtinMetrics.Iterations, Value: 1, @@ -223,24 +222,24 @@ type NetTrail struct { FullIteration bool StartTime time.Time EndTime time.Time - Tags *stats.SampleTags - Samples []stats.Sample + Tags *metrics.SampleTags + Samples []metrics.Sample } // Ensure that interfaces are implemented correctly -var _ stats.ConnectedSampleContainer = &NetTrail{} +var _ metrics.ConnectedSampleContainer = &NetTrail{} -// GetSamples implements the stats.SampleContainer interface. -func (ntr *NetTrail) GetSamples() []stats.Sample { +// GetSamples implements the metrics.SampleContainer interface. +func (ntr *NetTrail) GetSamples() []metrics.Sample { return ntr.Samples } -// GetTags implements the stats.ConnectedSampleContainer interface. -func (ntr *NetTrail) GetTags() *stats.SampleTags { +// GetTags implements the metrics.ConnectedSampleContainer interface. +func (ntr *NetTrail) GetTags() *metrics.SampleTags { return ntr.Tags } -// GetTime implements the stats.ConnectedSampleContainer interface. +// GetTime implements the metrics.ConnectedSampleContainer interface. func (ntr *NetTrail) GetTime() time.Time { return ntr.EndTime } diff --git a/lib/netext/httpext/request.go b/lib/netext/httpext/request.go index 44ef0622644..47ce4c03518 100644 --- a/lib/netext/httpext/request.go +++ b/lib/netext/httpext/request.go @@ -39,7 +39,7 @@ import ( "gopkg.in/guregu/null.v3" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // HTTPRequestCookie is a representation of a cookie used for request objects @@ -117,13 +117,13 @@ func updateK6Response(k6Response *Response, finishedReq *finishedRequest) { k6Response.RemotePort = remotePort } k6Response.Timings = ResponseTimings{ - Duration: stats.D(trail.Duration), - Blocked: stats.D(trail.Blocked), - Connecting: stats.D(trail.Connecting), - TLSHandshaking: stats.D(trail.TLSHandshaking), - Sending: stats.D(trail.Sending), - Waiting: stats.D(trail.Waiting), - Receiving: stats.D(trail.Receiving), + Duration: metrics.D(trail.Duration), + Blocked: metrics.D(trail.Blocked), + Connecting: metrics.D(trail.Connecting), + TLSHandshaking: metrics.D(trail.TLSHandshaking), + Sending: metrics.D(trail.Sending), + Waiting: metrics.D(trail.Waiting), + Receiving: metrics.D(trail.Receiving), } } @@ -195,7 +195,7 @@ func MakeRequest(ctx context.Context, state *lib.State, preq *ParsedHTTPRequest) // Only set the name system tag if the user didn't explicitly set it beforehand, // and the Name was generated from a tagged template string (via http.url). - if _, ok := tags["name"]; !ok && state.Options.SystemTags.Has(stats.TagName) && + if _, ok := tags["name"]; !ok && state.Options.SystemTags.Has(metrics.TagName) && preq.URL.Name != "" && preq.URL.Name != preq.URL.Clean() { tags["name"] = preq.URL.Name } diff --git a/lib/netext/httpext/request_test.go b/lib/netext/httpext/request_test.go index 1b93383db41..5c6f3b0227d 100644 --- a/lib/netext/httpext/request_test.go +++ b/lib/netext/httpext/request_test.go @@ -43,7 +43,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) type reader func([]byte) (int, error) @@ -119,7 +118,7 @@ func TestMakeRequestError(t *testing.T) { Compressions: []CompressionType{badCompressionType}, } state := &lib.State{ - Options: lib.Options{RunTags: &stats.SampleTags{}}, + Options: lib.Options{RunTags: &metrics.SampleTags{}}, Transport: http.DefaultTransport, Logger: logrus.New(), Tags: lib.NewTagMap(nil), @@ -142,7 +141,7 @@ func TestMakeRequestError(t *testing.T) { logger := logrus.New() logger.Level = logrus.DebugLevel state := &lib.State{ - Options: lib.Options{RunTags: &stats.SampleTags{}}, + Options: lib.Options{RunTags: &metrics.SampleTags{}}, Transport: srv.Client().Transport, Logger: logger, Tags: lib.NewTagMap(nil), @@ -190,10 +189,10 @@ func TestResponseStatus(t *testing.T) { defer server.Close() logger := logrus.New() logger.Level = logrus.DebugLevel - samples := make(chan<- stats.SampleContainer, 1) + samples := make(chan<- metrics.SampleContainer, 1) registry := metrics.NewRegistry() state := &lib.State{ - Options: lib.Options{RunTags: &stats.SampleTags{}}, + Options: lib.Options{RunTags: &metrics.SampleTags{}}, Transport: server.Client().Transport, Logger: logger, Samples: samples, @@ -266,14 +265,14 @@ func TestMakeRequestTimeoutInTheMiddle(t *testing.T) { defer srv.Close() ctx, cancel := context.WithCancel(context.Background()) defer cancel() - samples := make(chan stats.SampleContainer, 10) + samples := make(chan metrics.SampleContainer, 10) logger := logrus.New() logger.Level = logrus.DebugLevel registry := metrics.NewRegistry() state := &lib.State{ Options: lib.Options{ - RunTags: &stats.SampleTags{}, - SystemTags: &stats.DefaultSystemTagSet, + RunTags: &metrics.SampleTags{}, + SystemTags: &metrics.DefaultSystemTagSet, }, Transport: srv.Client().Transport, Samples: samples, @@ -343,14 +342,14 @@ func TestTrailFailed(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - samples := make(chan stats.SampleContainer, 10) + samples := make(chan metrics.SampleContainer, 10) logger := logrus.New() logger.Level = logrus.DebugLevel registry := metrics.NewRegistry() state := &lib.State{ Options: lib.Options{ - RunTags: &stats.SampleTags{}, - SystemTags: &stats.DefaultSystemTagSet, + RunTags: &metrics.SampleTags{}, + SystemTags: &metrics.DefaultSystemTagSet, }, Transport: srv.Client().Transport, Samples: samples, @@ -405,14 +404,14 @@ func TestMakeRequestDialTimeout(t *testing.T) { }() ctx, cancel := context.WithCancel(context.Background()) defer cancel() - samples := make(chan stats.SampleContainer, 10) + samples := make(chan metrics.SampleContainer, 10) logger := logrus.New() logger.Level = logrus.DebugLevel registry := metrics.NewRegistry() state := &lib.State{ Options: lib.Options{ - RunTags: &stats.SampleTags{}, - SystemTags: &stats.DefaultSystemTagSet, + RunTags: &metrics.SampleTags{}, + SystemTags: &metrics.DefaultSystemTagSet, }, Transport: &http.Transport{ DialContext: (&net.Dialer{ @@ -464,14 +463,14 @@ func TestMakeRequestTimeoutInTheBegining(t *testing.T) { defer srv.Close() ctx, cancel := context.WithCancel(context.Background()) defer cancel() - samples := make(chan stats.SampleContainer, 10) + samples := make(chan metrics.SampleContainer, 10) logger := logrus.New() logger.Level = logrus.DebugLevel registry := metrics.NewRegistry() state := &lib.State{ Options: lib.Options{ - RunTags: &stats.SampleTags{}, - SystemTags: &stats.DefaultSystemTagSet, + RunTags: &metrics.SampleTags{}, + SystemTags: &metrics.DefaultSystemTagSet, }, Transport: srv.Client().Transport, Samples: samples, diff --git a/lib/netext/httpext/tracer.go b/lib/netext/httpext/tracer.go index 3af2b29015c..d920394e439 100644 --- a/lib/netext/httpext/tracer.go +++ b/lib/netext/httpext/tracer.go @@ -28,7 +28,6 @@ import ( "time" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" "gopkg.in/guregu/null.v3" ) @@ -56,43 +55,43 @@ type Trail struct { Failed null.Bool // Populated by SaveSamples() - Tags *stats.SampleTags - Samples []stats.Sample + Tags *metrics.SampleTags + Samples []metrics.Sample } // SaveSamples populates the Trail's sample slice so they're accesible via GetSamples() -func (tr *Trail) SaveSamples(builtinMetrics *metrics.BuiltinMetrics, tags *stats.SampleTags) { +func (tr *Trail) SaveSamples(builtinMetrics *metrics.BuiltinMetrics, tags *metrics.SampleTags) { tr.Tags = tags - tr.Samples = make([]stats.Sample, 0, 9) // this is with 1 more for a possible HTTPReqFailed - tr.Samples = append(tr.Samples, []stats.Sample{ + tr.Samples = make([]metrics.Sample, 0, 9) // this is with 1 more for a possible HTTPReqFailed + tr.Samples = append(tr.Samples, []metrics.Sample{ {Metric: builtinMetrics.HTTPReqs, Time: tr.EndTime, Tags: tags, Value: 1}, - {Metric: builtinMetrics.HTTPReqDuration, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Duration)}, - {Metric: builtinMetrics.HTTPReqBlocked, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Blocked)}, - {Metric: builtinMetrics.HTTPReqConnecting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Connecting)}, - {Metric: builtinMetrics.HTTPReqTLSHandshaking, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.TLSHandshaking)}, - {Metric: builtinMetrics.HTTPReqSending, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Sending)}, - {Metric: builtinMetrics.HTTPReqWaiting, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Waiting)}, - {Metric: builtinMetrics.HTTPReqReceiving, Time: tr.EndTime, Tags: tags, Value: stats.D(tr.Receiving)}, + {Metric: builtinMetrics.HTTPReqDuration, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.Duration)}, + {Metric: builtinMetrics.HTTPReqBlocked, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.Blocked)}, + {Metric: builtinMetrics.HTTPReqConnecting, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.Connecting)}, + {Metric: builtinMetrics.HTTPReqTLSHandshaking, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.TLSHandshaking)}, + {Metric: builtinMetrics.HTTPReqSending, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.Sending)}, + {Metric: builtinMetrics.HTTPReqWaiting, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.Waiting)}, + {Metric: builtinMetrics.HTTPReqReceiving, Time: tr.EndTime, Tags: tags, Value: metrics.D(tr.Receiving)}, }...) } -// GetSamples implements the stats.SampleContainer interface. -func (tr *Trail) GetSamples() []stats.Sample { +// GetSamples implements the metrics.SampleContainer interface. +func (tr *Trail) GetSamples() []metrics.Sample { return tr.Samples } -// GetTags implements the stats.ConnectedSampleContainer interface. -func (tr *Trail) GetTags() *stats.SampleTags { +// GetTags implements the metrics.ConnectedSampleContainer interface. +func (tr *Trail) GetTags() *metrics.SampleTags { return tr.Tags } -// GetTime implements the stats.ConnectedSampleContainer interface. +// GetTime implements the metrics.ConnectedSampleContainer interface. func (tr *Trail) GetTime() time.Time { return tr.EndTime } // Ensure that interfaces are implemented correctly -var _ stats.ConnectedSampleContainer = &Trail{} +var _ metrics.ConnectedSampleContainer = &Trail{} // A Tracer wraps "net/http/httptrace" to collect granular timings for HTTP requests. // Note that since there is not yet an event for the end of a request (there's a PR to diff --git a/lib/netext/httpext/tracer_test.go b/lib/netext/httpext/tracer_test.go index 049379d9c3d..8112d2b3fb5 100644 --- a/lib/netext/httpext/tracer_test.go +++ b/lib/netext/httpext/tracer_test.go @@ -44,7 +44,6 @@ import ( "go.k6.io/k6/lib/netext" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) const traceDelay = 100 * time.Millisecond @@ -150,7 +149,7 @@ func TestTracer(t *testing.T) { time.Sleep(traceDelay) } trail := tracer.Done() - trail.SaveSamples(builtinMetrics, stats.IntoSampleTags(&map[string]string{"tag": "value"})) + trail.SaveSamples(builtinMetrics, metrics.IntoSampleTags(&map[string]string{"tag": "value"})) samples := trail.GetSamples() assertLaterOrZero(t, tracer.getConn, isReuse) @@ -166,7 +165,7 @@ func TestTracer(t *testing.T) { assert.Equal(t, strings.TrimPrefix(srv.URL, "https://"), trail.ConnRemoteAddr.String()) assert.Len(t, samples, 8) - seenMetrics := map[*stats.Metric]bool{} + seenMetrics := map[*metrics.Metric]bool{} for i, s := range samples { assert.NotContains(t, seenMetrics, s.Metric) seenMetrics[s.Metric] = true diff --git a/lib/netext/httpext/transport.go b/lib/netext/httpext/transport.go index d5cab8ac9d2..67cdb503fc7 100644 --- a/lib/netext/httpext/transport.go +++ b/lib/netext/httpext/transport.go @@ -31,7 +31,7 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/lib/netext" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // transport is an implementation of http.RoundTripper that will measure and emit @@ -106,9 +106,9 @@ func (t *transport) measureAndEmitMetrics(unfReq *unfinishedRequest) *finishedRe } enabledTags := t.state.Options.SystemTags - urlEnabled := enabledTags.Has(stats.TagURL) + urlEnabled := enabledTags.Has(metrics.TagURL) var setName bool - if _, ok := tags["name"]; !ok && enabledTags.Has(stats.TagName) { + if _, ok := tags["name"]; !ok && enabledTags.Has(metrics.TagName) { setName = true } if urlEnabled || setName { @@ -121,49 +121,49 @@ func (t *transport) measureAndEmitMetrics(unfReq *unfinishedRequest) *finishedRe } } - if enabledTags.Has(stats.TagMethod) { + if enabledTags.Has(metrics.TagMethod) { tags["method"] = unfReq.request.Method } if unfReq.err != nil { result.errorCode, result.errorMsg = errorCodeForError(unfReq.err) - if enabledTags.Has(stats.TagError) { + if enabledTags.Has(metrics.TagError) { tags["error"] = result.errorMsg } - if enabledTags.Has(stats.TagErrorCode) { + if enabledTags.Has(metrics.TagErrorCode) { tags["error_code"] = strconv.Itoa(int(result.errorCode)) } - if enabledTags.Has(stats.TagStatus) { + if enabledTags.Has(metrics.TagStatus) { tags["status"] = "0" } } else { - if enabledTags.Has(stats.TagStatus) { + if enabledTags.Has(metrics.TagStatus) { tags["status"] = strconv.Itoa(unfReq.response.StatusCode) } if unfReq.response.StatusCode >= 400 { - if enabledTags.Has(stats.TagErrorCode) { + if enabledTags.Has(metrics.TagErrorCode) { result.errorCode = errCode(1000 + unfReq.response.StatusCode) tags["error_code"] = strconv.Itoa(int(result.errorCode)) } } - if enabledTags.Has(stats.TagProto) { + if enabledTags.Has(metrics.TagProto) { tags["proto"] = unfReq.response.Proto } if unfReq.response.TLS != nil { tlsInfo, oscp := netext.ParseTLSConnState(unfReq.response.TLS) - if enabledTags.Has(stats.TagTLSVersion) { + if enabledTags.Has(metrics.TagTLSVersion) { tags["tls_version"] = tlsInfo.Version } - if enabledTags.Has(stats.TagOCSPStatus) { + if enabledTags.Has(metrics.TagOCSPStatus) { tags["ocsp_status"] = oscp.Status } result.tlsInfo = tlsInfo } } - if enabledTags.Has(stats.TagIP) && trail.ConnRemoteAddr != nil { + if enabledTags.Has(metrics.TagIP) && trail.ConnRemoteAddr != nil { if ip, _, err := net.SplitHostPort(trail.ConnRemoteAddr.String()); err == nil { tags["ip"] = ip } @@ -179,12 +179,12 @@ func (t *transport) measureAndEmitMetrics(unfReq *unfinishedRequest) *finishedRe failed = 1 } - if enabledTags.Has(stats.TagExpectedResponse) { - tags[stats.TagExpectedResponse.String()] = strconv.FormatBool(expected) + if enabledTags.Has(metrics.TagExpectedResponse) { + tags[metrics.TagExpectedResponse.String()] = strconv.FormatBool(expected) } } - finalTags := stats.IntoSampleTags(&tags) + finalTags := metrics.IntoSampleTags(&tags) builtinMetrics := t.state.BuiltinMetrics trail.SaveSamples(builtinMetrics, finalTags) if t.responseCallback != nil { @@ -193,12 +193,12 @@ func (t *transport) measureAndEmitMetrics(unfReq *unfinishedRequest) *finishedRe trail.Failed.Bool = true } trail.Samples = append(trail.Samples, - stats.Sample{ + metrics.Sample{ Metric: builtinMetrics.HTTPReqFailed, Time: trail.EndTime, Tags: finalTags, Value: failed, }, ) } - stats.PushIfNotDone(t.ctx, t.state.Samples, trail) + metrics.PushIfNotDone(t.ctx, t.state.Samples, trail) return result } diff --git a/lib/netext/httpext/transport_test.go b/lib/netext/httpext/transport_test.go index 382eff6a375..3f707809e72 100644 --- a/lib/netext/httpext/transport_test.go +++ b/lib/netext/httpext/transport_test.go @@ -28,13 +28,13 @@ import ( "github.com/sirupsen/logrus" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func BenchmarkMeasureAndEmitMetrics(b *testing.B) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - samples := make(chan stats.SampleContainer, 10) + samples := make(chan metrics.SampleContainer, 10) defer close(samples) go func() { for range samples { @@ -45,8 +45,8 @@ func BenchmarkMeasureAndEmitMetrics(b *testing.B) { state := &lib.State{ Options: lib.Options{ - RunTags: &stats.SampleTags{}, - SystemTags: &stats.DefaultSystemTagSet, + RunTags: &metrics.SampleTags{}, + SystemTags: &metrics.DefaultSystemTagSet, }, Samples: samples, Logger: logger, diff --git a/lib/options.go b/lib/options.go index 86ed96c66b0..c4bbf8e24d7 100644 --- a/lib/options.go +++ b/lib/options.go @@ -29,7 +29,7 @@ import ( "strconv" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" "gopkg.in/guregu/null.v3" ) @@ -335,7 +335,7 @@ type Options struct { // Define thresholds; these take the form of 'metric=["snippet1", "snippet2"]'. // To create a threshold on a derived metric based on tag queries ("submetrics"), create a // metric on a nonexistent metric named 'real_metric{tagA:valueA,tagB:valueB}'. - Thresholds map[string]stats.Thresholds `json:"thresholds" envconfig:"K6_THRESHOLDS"` + Thresholds map[string]metrics.Thresholds `json:"thresholds" envconfig:"K6_THRESHOLDS"` // Blacklist IP ranges that tests may not contact. Mainly useful in hosted setups. BlacklistIPs []*IPNet `json:"blacklistIPs" envconfig:"K6_BLACKLIST_IPS"` @@ -370,10 +370,10 @@ type Options struct { // Which system tags to include with metrics ("method", "vu" etc.) // Use pointer for identifying whether user provide any tag or not. - SystemTags *stats.SystemTagSet `json:"systemTags" envconfig:"K6_SYSTEM_TAGS"` + SystemTags *metrics.SystemTagSet `json:"systemTags" envconfig:"K6_SYSTEM_TAGS"` // Tags to be applied to all samples for this running - RunTags *stats.SampleTags `json:"tags" envconfig:"K6_TAGS"` + RunTags *metrics.SampleTags `json:"tags" envconfig:"K6_TAGS"` // Buffer size of the channel for metric samples; 0 means unbuffered MetricSamplesBufferSize null.Int `json:"metricSamplesBufferSize" envconfig:"K6_METRIC_SAMPLES_BUFFER_SIZE"` diff --git a/lib/options_test.go b/lib/options_test.go index 8f0cab3bf76..f46801d8b1b 100644 --- a/lib/options_test.go +++ b/lib/options_test.go @@ -34,7 +34,7 @@ import ( "gopkg.in/guregu/null.v3" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) func TestOptions(t *testing.T) { @@ -355,9 +355,9 @@ func TestOptions(t *testing.T) { }) t.Run("Thresholds", func(t *testing.T) { - opts := Options{}.Apply(Options{Thresholds: map[string]stats.Thresholds{ + opts := Options{}.Apply(Options{Thresholds: map[string]metrics.Thresholds{ "metric": { - Thresholds: []*stats.Threshold{{}}, + Thresholds: []*metrics.Threshold{{}}, }, }}) assert.NotNil(t, opts.Thresholds) @@ -377,23 +377,23 @@ func TestOptions(t *testing.T) { assert.Equal(t, Options{}, opts) }) t.Run("SystemTags", func(t *testing.T) { - opts := Options{}.Apply(Options{SystemTags: stats.NewSystemTagSet(stats.TagProto)}) + opts := Options{}.Apply(Options{SystemTags: metrics.NewSystemTagSet(metrics.TagProto)}) assert.NotNil(t, opts.SystemTags) assert.NotEmpty(t, opts.SystemTags) - assert.True(t, opts.SystemTags.Has(stats.TagProto)) + assert.True(t, opts.SystemTags.Has(metrics.TagProto)) t.Run("JSON", func(t *testing.T) { t.Run("Array", func(t *testing.T) { var opts Options jsonStr := `{"systemTags":["url"]}` assert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts)) - assert.Equal(t, *stats.NewSystemTagSet(stats.TagURL), *opts.SystemTags) + assert.Equal(t, *metrics.NewSystemTagSet(metrics.TagURL), *opts.SystemTags) t.Run("Roundtrip", func(t *testing.T) { data, err := json.Marshal(opts.SystemTags) assert.NoError(t, err) assert.Equal(t, `["url"]`, string(data)) - var vers2 stats.SystemTagSet + var vers2 metrics.SystemTagSet assert.NoError(t, json.Unmarshal(data, &vers2)) assert.Equal(t, vers2, *opts.SystemTags) }) @@ -402,7 +402,7 @@ func TestOptions(t *testing.T) { var opts Options jsonStr := `{"systemTags":[]}` assert.NoError(t, json.Unmarshal([]byte(jsonStr), &opts)) - assert.Equal(t, stats.SystemTagSet(0), *opts.SystemTags) + assert.Equal(t, metrics.SystemTagSet(0), *opts.SystemTags) }) }) }) @@ -412,7 +412,7 @@ func TestOptions(t *testing.T) { assert.Equal(t, stats, opts.SummaryTrendStats) }) t.Run("RunTags", func(t *testing.T) { - tags := stats.IntoSampleTags(&map[string]string{"myTag": "hello"}) + tags := metrics.IntoSampleTags(&map[string]string{"myTag": "hello"}) opts := Options{}.Apply(Options{RunTags: tags}) assert.Equal(t, tags, opts.RunTags) }) diff --git a/lib/runner.go b/lib/runner.go index 9cad5f6c420..0265ec0d6cd 100644 --- a/lib/runner.go +++ b/lib/runner.go @@ -25,7 +25,7 @@ import ( "io" "time" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // ActiveVU represents an actively running virtual user. @@ -74,10 +74,10 @@ type Runner interface { // Spawns a new VU. It's fine to make this function rather heavy, if it means a performance // improvement at runtime. Remember, this is called once per VU and normally only at the start // of a test - RunOnce() may be called hundreds of thousands of times, and must be fast. - NewVU(idLocal, idGlobal uint64, out chan<- stats.SampleContainer) (InitializedVU, error) + NewVU(idLocal, idGlobal uint64, out chan<- metrics.SampleContainer) (InitializedVU, error) // Runs pre-test setup, if applicable. - Setup(ctx context.Context, out chan<- stats.SampleContainer) error + Setup(ctx context.Context, out chan<- metrics.SampleContainer) error // Returns json representation of the setup data if setup() is specified and run, nil otherwise GetSetupData() []byte @@ -86,7 +86,7 @@ type Runner interface { SetSetupData([]byte) // Runs post-test teardown, if applicable. - Teardown(ctx context.Context, out chan<- stats.SampleContainer) error + Teardown(ctx context.Context, out chan<- metrics.SampleContainer) error // Returns the default (root) Group. GetDefaultGroup() *Group @@ -113,7 +113,7 @@ type UIState struct { // Summary contains all of the data the summary handler gets. type Summary struct { - Metrics map[string]*stats.Metric + Metrics map[string]*metrics.Metric RootGroup *Group TestRunDuration time.Duration // TODO: use lib.ExecutionState-based interface instead? NoColor bool // TODO: drop this when noColor is part of the (runtime) options diff --git a/lib/state.go b/lib/state.go index efa1a27c3f7..89be0af3b17 100644 --- a/lib/state.go +++ b/lib/state.go @@ -33,7 +33,6 @@ import ( "golang.org/x/time/rate" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // DialContexter is an interface that can dial with a context @@ -66,7 +65,7 @@ type State struct { RPSLimit *rate.Limiter // Sample channel, possibly buffered - Samples chan<- stats.SampleContainer + Samples chan<- metrics.SampleContainer // Buffer pool; use instead of allocating fresh buffers when possible. // TODO: maybe use https://golang.org/pkg/sync/#Pool ? diff --git a/lib/testutils/minirunner/minirunner.go b/lib/testutils/minirunner/minirunner.go index b640123dc22..cf606902556 100644 --- a/lib/testutils/minirunner/minirunner.go +++ b/lib/testutils/minirunner/minirunner.go @@ -25,7 +25,7 @@ import ( "io" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // Ensure mock implementations conform to the interfaces. @@ -39,9 +39,9 @@ var ( // using a real JS runtime, it allows us to directly specify the options and // functions with Go code. type MiniRunner struct { - Fn func(ctx context.Context, state *lib.State, out chan<- stats.SampleContainer) error - SetupFn func(ctx context.Context, out chan<- stats.SampleContainer) ([]byte, error) - TeardownFn func(ctx context.Context, out chan<- stats.SampleContainer) error + Fn func(ctx context.Context, state *lib.State, out chan<- metrics.SampleContainer) error + SetupFn func(ctx context.Context, out chan<- metrics.SampleContainer) ([]byte, error) + TeardownFn func(ctx context.Context, out chan<- metrics.SampleContainer) error HandleSummaryFn func(context.Context, *lib.Summary) (map[string]io.Reader, error) SetupData []byte @@ -57,7 +57,7 @@ func (r MiniRunner) MakeArchive() *lib.Archive { } // NewVU returns a new VU with an incremental ID. -func (r *MiniRunner) NewVU(idLocal, idGlobal uint64, out chan<- stats.SampleContainer) (lib.InitializedVU, error) { +func (r *MiniRunner) NewVU(idLocal, idGlobal uint64, out chan<- metrics.SampleContainer) (lib.InitializedVU, error) { state := &lib.State{VUID: idLocal, VUIDGlobal: idGlobal, Iteration: int64(-1)} return &VU{ R: r, @@ -70,7 +70,7 @@ func (r *MiniRunner) NewVU(idLocal, idGlobal uint64, out chan<- stats.SampleCont } // Setup calls the supplied mock setup() function, if present. -func (r *MiniRunner) Setup(ctx context.Context, out chan<- stats.SampleContainer) (err error) { +func (r *MiniRunner) Setup(ctx context.Context, out chan<- metrics.SampleContainer) (err error) { if fn := r.SetupFn; fn != nil { r.SetupData, err = fn(ctx, out) } @@ -89,7 +89,7 @@ func (r *MiniRunner) SetSetupData(data []byte) { } // Teardown calls the supplied mock teardown() function, if present. -func (r MiniRunner) Teardown(ctx context.Context, out chan<- stats.SampleContainer) error { +func (r MiniRunner) Teardown(ctx context.Context, out chan<- metrics.SampleContainer) error { if fn := r.TeardownFn; fn != nil { return fn(ctx, out) } @@ -132,7 +132,7 @@ func (r *MiniRunner) HandleSummary(ctx context.Context, s *lib.Summary) (map[str // VU is a mock VU, spawned by a MiniRunner. type VU struct { R *MiniRunner - Out chan<- stats.SampleContainer + Out chan<- metrics.SampleContainer ID, IDGlobal uint64 Iteration int64 state *lib.State diff --git a/lib/testutils/mockoutput/mockoutput.go b/lib/testutils/mockoutput/mockoutput.go index 23a2dac9c55..096ab3aa77e 100644 --- a/lib/testutils/mockoutput/mockoutput.go +++ b/lib/testutils/mockoutput/mockoutput.go @@ -22,8 +22,8 @@ package mockoutput import ( "go.k6.io/k6/lib" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) // New exists so that the usage from tests avoids repetition, i.e. is @@ -34,8 +34,8 @@ func New() *MockOutput { // MockOutput can be used in tests to mock an actual output. type MockOutput struct { - SampleContainers []stats.SampleContainer - Samples []stats.Sample + SampleContainers []metrics.SampleContainer + Samples []metrics.Sample RunStatus lib.RunStatus DescFn func() string @@ -46,7 +46,7 @@ type MockOutput struct { var _ output.WithRunStatusUpdates = &MockOutput{} // AddMetricSamples just saves the results in memory. -func (mo *MockOutput) AddMetricSamples(scs []stats.SampleContainer) { +func (mo *MockOutput) AddMetricSamples(scs []metrics.SampleContainer) { mo.SampleContainers = append(mo.SampleContainers, scs...) for _, sc := range scs { mo.Samples = append(mo.Samples, sc.GetSamples()...) diff --git a/metrics/builtin.go b/metrics/builtin.go index fde4a9b728b..c53102f31d1 100644 --- a/metrics/builtin.go +++ b/metrics/builtin.go @@ -20,10 +20,6 @@ package metrics -import ( - "go.k6.io/k6/stats" -) - const ( VUsName = "vus" //nolint:revive VUsMaxName = "vus_max" @@ -59,75 +55,75 @@ const ( // BuiltinMetrics represent all the builtin metrics of k6 type BuiltinMetrics struct { - VUs *stats.Metric - VUsMax *stats.Metric - Iterations *stats.Metric - IterationDuration *stats.Metric - DroppedIterations *stats.Metric + VUs *Metric + VUsMax *Metric + Iterations *Metric + IterationDuration *Metric + DroppedIterations *Metric // Runner-emitted. - Checks *stats.Metric - GroupDuration *stats.Metric + Checks *Metric + GroupDuration *Metric // HTTP-related. - HTTPReqs *stats.Metric - HTTPReqFailed *stats.Metric - HTTPReqDuration *stats.Metric - HTTPReqBlocked *stats.Metric - HTTPReqConnecting *stats.Metric - HTTPReqTLSHandshaking *stats.Metric - HTTPReqSending *stats.Metric - HTTPReqWaiting *stats.Metric - HTTPReqReceiving *stats.Metric + HTTPReqs *Metric + HTTPReqFailed *Metric + HTTPReqDuration *Metric + HTTPReqBlocked *Metric + HTTPReqConnecting *Metric + HTTPReqTLSHandshaking *Metric + HTTPReqSending *Metric + HTTPReqWaiting *Metric + HTTPReqReceiving *Metric // Websocket-related - WSSessions *stats.Metric - WSMessagesSent *stats.Metric - WSMessagesReceived *stats.Metric - WSPing *stats.Metric - WSSessionDuration *stats.Metric - WSConnecting *stats.Metric + WSSessions *Metric + WSMessagesSent *Metric + WSMessagesReceived *Metric + WSPing *Metric + WSSessionDuration *Metric + WSConnecting *Metric // gRPC-related - GRPCReqDuration *stats.Metric + GRPCReqDuration *Metric // Network-related; used for future protocols as well. - DataSent *stats.Metric - DataReceived *stats.Metric + DataSent *Metric + DataReceived *Metric } // RegisterBuiltinMetrics register and returns the builtin metrics in the provided registry func RegisterBuiltinMetrics(registry *Registry) *BuiltinMetrics { return &BuiltinMetrics{ - VUs: registry.MustNewMetric(VUsName, stats.Gauge), - VUsMax: registry.MustNewMetric(VUsMaxName, stats.Gauge), - Iterations: registry.MustNewMetric(IterationsName, stats.Counter), - IterationDuration: registry.MustNewMetric(IterationDurationName, stats.Trend, stats.Time), - DroppedIterations: registry.MustNewMetric(DroppedIterationsName, stats.Counter), - - Checks: registry.MustNewMetric(ChecksName, stats.Rate), - GroupDuration: registry.MustNewMetric(GroupDurationName, stats.Trend, stats.Time), - - HTTPReqs: registry.MustNewMetric(HTTPReqsName, stats.Counter), - HTTPReqFailed: registry.MustNewMetric(HTTPReqFailedName, stats.Rate), - HTTPReqDuration: registry.MustNewMetric(HTTPReqDurationName, stats.Trend, stats.Time), - HTTPReqBlocked: registry.MustNewMetric(HTTPReqBlockedName, stats.Trend, stats.Time), - HTTPReqConnecting: registry.MustNewMetric(HTTPReqConnectingName, stats.Trend, stats.Time), - HTTPReqTLSHandshaking: registry.MustNewMetric(HTTPReqTLSHandshakingName, stats.Trend, stats.Time), - HTTPReqSending: registry.MustNewMetric(HTTPReqSendingName, stats.Trend, stats.Time), - HTTPReqWaiting: registry.MustNewMetric(HTTPReqWaitingName, stats.Trend, stats.Time), - HTTPReqReceiving: registry.MustNewMetric(HTTPReqReceivingName, stats.Trend, stats.Time), - - WSSessions: registry.MustNewMetric(WSSessionsName, stats.Counter), - WSMessagesSent: registry.MustNewMetric(WSMessagesSentName, stats.Counter), - WSMessagesReceived: registry.MustNewMetric(WSMessagesReceivedName, stats.Counter), - WSPing: registry.MustNewMetric(WSPingName, stats.Trend, stats.Time), - WSSessionDuration: registry.MustNewMetric(WSSessionDurationName, stats.Trend, stats.Time), - WSConnecting: registry.MustNewMetric(WSConnectingName, stats.Trend, stats.Time), - - GRPCReqDuration: registry.MustNewMetric(GRPCReqDurationName, stats.Trend, stats.Time), - - DataSent: registry.MustNewMetric(DataSentName, stats.Counter, stats.Data), - DataReceived: registry.MustNewMetric(DataReceivedName, stats.Counter, stats.Data), + VUs: registry.MustNewMetric(VUsName, Gauge), + VUsMax: registry.MustNewMetric(VUsMaxName, Gauge), + Iterations: registry.MustNewMetric(IterationsName, Counter), + IterationDuration: registry.MustNewMetric(IterationDurationName, Trend, Time), + DroppedIterations: registry.MustNewMetric(DroppedIterationsName, Counter), + + Checks: registry.MustNewMetric(ChecksName, Rate), + GroupDuration: registry.MustNewMetric(GroupDurationName, Trend, Time), + + HTTPReqs: registry.MustNewMetric(HTTPReqsName, Counter), + HTTPReqFailed: registry.MustNewMetric(HTTPReqFailedName, Rate), + HTTPReqDuration: registry.MustNewMetric(HTTPReqDurationName, Trend, Time), + HTTPReqBlocked: registry.MustNewMetric(HTTPReqBlockedName, Trend, Time), + HTTPReqConnecting: registry.MustNewMetric(HTTPReqConnectingName, Trend, Time), + HTTPReqTLSHandshaking: registry.MustNewMetric(HTTPReqTLSHandshakingName, Trend, Time), + HTTPReqSending: registry.MustNewMetric(HTTPReqSendingName, Trend, Time), + HTTPReqWaiting: registry.MustNewMetric(HTTPReqWaitingName, Trend, Time), + HTTPReqReceiving: registry.MustNewMetric(HTTPReqReceivingName, Trend, Time), + + WSSessions: registry.MustNewMetric(WSSessionsName, Counter), + WSMessagesSent: registry.MustNewMetric(WSMessagesSentName, Counter), + WSMessagesReceived: registry.MustNewMetric(WSMessagesReceivedName, Counter), + WSPing: registry.MustNewMetric(WSPingName, Trend, Time), + WSSessionDuration: registry.MustNewMetric(WSSessionDurationName, Trend, Time), + WSConnecting: registry.MustNewMetric(WSConnectingName, Trend, Time), + + GRPCReqDuration: registry.MustNewMetric(GRPCReqDurationName, Trend, Time), + + DataSent: registry.MustNewMetric(DataSentName, Counter, Data), + DataReceived: registry.MustNewMetric(DataReceivedName, Counter, Data), } } diff --git a/metrics/engine/engine.go b/metrics/engine/engine.go index e5ce9944b04..3c64e11b074 100644 --- a/metrics/engine/engine.go +++ b/metrics/engine/engine.go @@ -11,7 +11,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" "gopkg.in/guregu/null.v3" ) @@ -26,7 +25,7 @@ type MetricsEngine struct { logger logrus.FieldLogger // These can be both top-level metrics or sub-metrics - metricsWithThresholds []*stats.Metric + metricsWithThresholds []*metrics.Metric // TODO: completely refactor: // - make these private, @@ -34,7 +33,7 @@ type MetricsEngine struct { // - have one lock per metric instead of a a global one, when // the metrics are decoupled from their types MetricsLock sync.Mutex - ObservedMetrics map[string]*stats.Metric + ObservedMetrics map[string]*metrics.Metric } // NewMetricsEngine creates a new metrics Engine with the given parameters. @@ -49,7 +48,7 @@ func NewMetricsEngine( runtimeOptions: rtOpts, logger: logger.WithField("component", "metrics-engine"), - ObservedMetrics: make(map[string]*stats.Metric), + ObservedMetrics: make(map[string]*metrics.Metric), } if !(me.runtimeOptions.NoSummary.Bool && me.runtimeOptions.NoThresholds.Bool) { @@ -71,7 +70,7 @@ func (me *MetricsEngine) GetIngester() output.Output { } } -func (me *MetricsEngine) getThresholdMetricOrSubmetric(name string) (*stats.Metric, error) { +func (me *MetricsEngine) getThresholdMetricOrSubmetric(name string) (*metrics.Metric, error) { // TODO: replace with strings.Cut after Go 1.18 nameParts := strings.SplitN(name, "{", 2) @@ -94,7 +93,7 @@ func (me *MetricsEngine) getThresholdMetricOrSubmetric(name string) (*stats.Metr return sm.Metric, nil } -func (me *MetricsEngine) markObserved(metric *stats.Metric) { +func (me *MetricsEngine) markObserved(metric *metrics.Metric) { if !metric.Observed { metric.Observed = true me.ObservedMetrics[metric.Name] = metric @@ -130,7 +129,7 @@ func (me *MetricsEngine) initSubMetricsAndThresholds() error { // TODO: refactor out of here when https://github.com/grafana/k6/issues/1321 // lands and there is a better way to enable a metric with tag - if me.options.SystemTags.Has(stats.TagExpectedResponse) { + if me.options.SystemTags.Has(metrics.TagExpectedResponse) { _, err := me.getThresholdMetricOrSubmetric("http_req_duration{expected_response:true}") if err != nil { return err // shouldn't happen, but ¯\_(ツ)_/¯ diff --git a/metrics/engine/ingester.go b/metrics/engine/ingester.go index 87bdceeadf2..83a514552a0 100644 --- a/metrics/engine/ingester.go +++ b/metrics/engine/ingester.go @@ -58,7 +58,7 @@ func (oi *outputIngester) flushMetrics() { oi.metricsEngine.MetricsLock.Lock() defer oi.metricsEngine.MetricsLock.Unlock() - // TODO: split metric samples in buckets with a *stats.Metric key; this will + // TODO: split metric samples in buckets with a *metrics.Metric key; this will // allow us to have a per-bucket lock, instead of one global one, and it // will allow us to split apart the metric Name and Type from its Sink and // Observed fields... diff --git a/metrics/metric.go b/metrics/metric.go new file mode 100644 index 00000000000..0165991419e --- /dev/null +++ b/metrics/metric.go @@ -0,0 +1,123 @@ +package metrics + +import ( + "fmt" + "strings" + "time" + + "gopkg.in/guregu/null.v3" +) + +// A Metric defines the shape of a set of data. +type Metric struct { + Name string `json:"name"` + Type MetricType `json:"type"` + Contains ValueType `json:"contains"` + + // TODO: decouple the metrics from the sinks and thresholds... have them + // linked, but not in the same struct? + Tainted null.Bool `json:"tainted"` + Thresholds Thresholds `json:"thresholds"` + Submetrics []*Submetric `json:"submetrics"` + Sub *Submetric `json:"-"` + Sink Sink `json:"-"` + Observed bool `json:"-"` +} + +// Sample samples the metric at the given time, with the provided tags and value +func (m *Metric) Sample(t time.Time, tags *SampleTags, value float64) Sample { + return Sample{ + Time: t, + Tags: tags, + Value: value, + Metric: m, + } +} + +// newMetric instantiates a new Metric +func newMetric(name string, mt MetricType, vt ...ValueType) *Metric { + valueType := Default + if len(vt) > 0 { + valueType = vt[0] + } + var sink Sink + switch mt { + case Counter: + sink = &CounterSink{} + case Gauge: + sink = &GaugeSink{} + case Trend: + sink = &TrendSink{} + case Rate: + sink = &RateSink{} + default: + return nil + } + return &Metric{ + Name: name, + Type: mt, + Contains: valueType, + Sink: sink, + } +} + +// A Submetric represents a filtered dataset based on a parent metric. +type Submetric struct { + Name string `json:"name"` + Suffix string `json:"suffix"` // TODO: rename? + Tags *SampleTags `json:"tags"` + + Metric *Metric `json:"-"` + Parent *Metric `json:"-"` +} + +// AddSubmetric creates a new submetric from the key:value threshold definition +// and adds it to the metric's submetrics list. +func (m *Metric) AddSubmetric(keyValues string) (*Submetric, error) { + keyValues = strings.TrimSpace(keyValues) + if len(keyValues) == 0 { + return nil, fmt.Errorf("submetric criteria for metric '%s' cannot be empty", m.Name) + } + kvs := strings.Split(keyValues, ",") + rawTags := make(map[string]string, len(kvs)) + for _, kv := range kvs { + if kv == "" { + continue + } + parts := strings.SplitN(kv, ":", 2) + + key := strings.Trim(strings.TrimSpace(parts[0]), `"'`) + if len(parts) != 2 { + rawTags[key] = "" + continue + } + + value := strings.Trim(strings.TrimSpace(parts[1]), `"'`) + rawTags[key] = value + } + + tags := IntoSampleTags(&rawTags) + + for _, sm := range m.Submetrics { + if sm.Tags.IsEqual(tags) { + return nil, fmt.Errorf( + "sub-metric with params '%s' already exists for metric %s: %s", + keyValues, m.Name, sm.Name, + ) + } + } + + subMetric := &Submetric{ + Name: m.Name + "{" + keyValues + "}", + Suffix: keyValues, + Tags: tags, + Parent: m, + } + subMetricMetric := newMetric(subMetric.Name, m.Type, m.Contains) + subMetricMetric.Sub = subMetric // sigh + subMetric.Metric = subMetricMetric + + m.Submetrics = append(m.Submetrics, subMetric) + + return subMetric, nil +} diff --git a/metrics/metric_test.go b/metrics/metric_test.go new file mode 100644 index 00000000000..7db2239b76d --- /dev/null +++ b/metrics/metric_test.go @@ -0,0 +1,68 @@ +package metrics + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewMetric(t *testing.T) { + t.Parallel() + testdata := map[string]struct { + Type MetricType + SinkType Sink + }{ + "Counter": {Counter, &CounterSink{}}, + "Gauge": {Gauge, &GaugeSink{}}, + "Trend": {Trend, &TrendSink{}}, + "Rate": {Rate, &RateSink{}}, + } + + for name, data := range testdata { + name, data := name, data + t.Run(name, func(t *testing.T) { + t.Parallel() + m := newMetric("my_metric", data.Type) + assert.Equal(t, "my_metric", m.Name) + assert.IsType(t, data.SinkType, m.Sink) + }) + } +} + +func TestAddSubmetric(t *testing.T) { + t.Parallel() + testdata := map[string]struct { + err bool + tags map[string]string + }{ + "": {true, nil}, + " ": {true, nil}, + "a": {false, map[string]string{"a": ""}}, + "a:1": {false, map[string]string{"a": "1"}}, + " a : 1 ": {false, map[string]string{"a": "1"}}, + "a,b": {false, map[string]string{"a": "", "b": ""}}, + ` a:"",b: ''`: {false, map[string]string{"a": "", "b": ""}}, + `a:1,b:2`: {false, map[string]string{"a": "1", "b": "2"}}, + ` a : 1, b : 2 `: {false, map[string]string{"a": "1", "b": "2"}}, + `a : '1' , b : "2"`: {false, map[string]string{"a": "1", "b": "2"}}, + `" a" : ' 1' , b : "2 " `: {false, map[string]string{" a": " 1", "b": "2 "}}, //nolint:gocritic + } + + for name, expected := range testdata { + name, expected := name, expected + t.Run(name, func(t *testing.T) { + t.Parallel() + + m := newMetric("metric", Trend) + sm, err := m.AddSubmetric(name) + if expected.err { + require.Error(t, err) + return + } + require.NoError(t, err) + require.NotNil(t, sm) + assert.EqualValues(t, expected.tags, sm.Tags.tags) + }) + } +} diff --git a/metrics/metric_type.go b/metrics/metric_type.go new file mode 100644 index 00000000000..ce0b9f4b8c3 --- /dev/null +++ b/metrics/metric_type.go @@ -0,0 +1,86 @@ +package metrics + +import "errors" + +// A MetricType specifies the type of a metric. +type MetricType int + +// Possible values for MetricType. +const ( + Counter = MetricType(iota) // A counter that sums its data points + Gauge // A gauge that displays the latest value + Trend // A trend, min/max/avg/med are interesting + Rate // A rate, displays % of values that aren't 0 +) + +// ErrInvalidMetricType indicates the serialized metric type is invalid. +var ErrInvalidMetricType = errors.New("invalid metric type") + +const ( + counterString = "counter" + gaugeString = "gauge" + trendString = "trend" + rateString = "rate" + + defaultString = "default" + timeString = "time" + dataString = "data" +) + +// MarshalJSON serializes a MetricType as a human readable string. +func (t MetricType) MarshalJSON() ([]byte, error) { + txt, err := t.MarshalText() + if err != nil { + return nil, err + } + return []byte(`"` + string(txt) + `"`), nil +} + +// MarshalText serializes a MetricType as a human readable string. +func (t MetricType) MarshalText() ([]byte, error) { + switch t { + case Counter: + return []byte(counterString), nil + case Gauge: + return []byte(gaugeString), nil + case Trend: + return []byte(trendString), nil + case Rate: + return []byte(rateString), nil + default: + return nil, ErrInvalidMetricType + } +} + +// UnmarshalText deserializes a MetricType from a string representation. +func (t *MetricType) UnmarshalText(data []byte) error { + switch string(data) { + case counterString: + *t = Counter + case gaugeString: + *t = Gauge + case trendString: + *t = Trend + case rateString: + *t = Rate + default: + return ErrInvalidMetricType + } + + return nil +} + +func (t MetricType) String() string { + switch t { + case Counter: + return counterString + case Gauge: + return gaugeString + case Trend: + return trendString + case Rate: + return rateString + default: + return "[INVALID]" + } +} diff --git a/metrics/registry.go b/metrics/registry.go index bfc28a44290..1d40c615bdc 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -24,20 +24,18 @@ import ( "fmt" "regexp" "sync" - - "go.k6.io/k6/stats" ) // Registry is what can create metrics type Registry struct { - metrics map[string]*stats.Metric + metrics map[string]*Metric l sync.RWMutex } // NewRegistry returns a new registry func NewRegistry() *Registry { return &Registry{ - metrics: make(map[string]*stats.Metric), + metrics: make(map[string]*Metric), } } @@ -51,7 +49,7 @@ func checkName(name string) bool { // NewMetric returns new metric registered to this registry // TODO have multiple versions returning specific metric types when we have such things -func (r *Registry) NewMetric(name string, typ stats.MetricType, t ...stats.ValueType) (*stats.Metric, error) { +func (r *Registry) NewMetric(name string, typ MetricType, t ...ValueType) (*Metric, error) { r.l.Lock() defer r.l.Unlock() @@ -78,7 +76,7 @@ func (r *Registry) NewMetric(name string, typ stats.MetricType, t ...stats.Value } // MustNewMetric is like NewMetric, but will panic if there is an error -func (r *Registry) MustNewMetric(name string, typ stats.MetricType, t ...stats.ValueType) *stats.Metric { +func (r *Registry) MustNewMetric(name string, typ MetricType, t ...ValueType) *Metric { m, err := r.NewMetric(name, typ, t...) if err != nil { panic(err) @@ -88,32 +86,6 @@ func (r *Registry) MustNewMetric(name string, typ stats.MetricType, t ...stats.V // Get returns the Metric with the given name. If that metric doesn't exist, // Get() will return a nil value. -func (r *Registry) Get(name string) *stats.Metric { +func (r *Registry) Get(name string) *Metric { return r.metrics[name] } - -func newMetric(name string, mt stats.MetricType, vt ...stats.ValueType) *stats.Metric { - valueType := stats.Default - if len(vt) > 0 { - valueType = vt[0] - } - var sink stats.Sink - switch mt { - case stats.Counter: - sink = &stats.CounterSink{} - case stats.Gauge: - sink = &stats.GaugeSink{} - case stats.Trend: - sink = &stats.TrendSink{} - case stats.Rate: - sink = &stats.RateSink{} - default: - return nil - } - return &stats.Metric{ - Name: name, - Type: mt, - Contains: valueType, - Sink: sink, - } -} diff --git a/metrics/registry_test.go b/metrics/registry_test.go index 890b84d3fdf..820df0a7e73 100644 --- a/metrics/registry_test.go +++ b/metrics/registry_test.go @@ -25,26 +25,25 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "go.k6.io/k6/stats" ) func TestRegistryNewMetric(t *testing.T) { t.Parallel() r := NewRegistry() - somethingCounter, err := r.NewMetric("something", stats.Counter) + somethingCounter, err := r.NewMetric("something", Counter) require.NoError(t, err) require.Equal(t, "something", somethingCounter.Name) - somethingCounterAgain, err := r.NewMetric("something", stats.Counter) + somethingCounterAgain, err := r.NewMetric("something", Counter) require.NoError(t, err) require.Equal(t, "something", somethingCounterAgain.Name) require.Same(t, somethingCounter, somethingCounterAgain) - _, err = r.NewMetric("something", stats.Gauge) + _, err = r.NewMetric("something", Gauge) require.Error(t, err) - _, err = r.NewMetric("something", stats.Counter, stats.Time) + _, err = r.NewMetric("something", Counter, Time) require.Error(t, err) } diff --git a/stats/stats.go b/metrics/sample.go similarity index 54% rename from stats/stats.go rename to metrics/sample.go index eaae2bf0967..cf9cf723205 100644 --- a/stats/stats.go +++ b/metrics/sample.go @@ -1,184 +1,175 @@ -/* - * - * k6 - a next-generation load testing tool - * Copyright (C) 2016 Load Impact - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -package stats +package metrics import ( "context" "encoding/json" - "errors" "fmt" "strconv" "strings" "time" "github.com/mailru/easyjson/jwriter" - "gopkg.in/guregu/null.v3" ) -const ( - counterString = "counter" - gaugeString = "gauge" - trendString = "trend" - rateString = "rate" +// A Sample is a single measurement. +type Sample struct { + Metric *Metric + Time time.Time + Tags *SampleTags + Value float64 +} - defaultString = "default" - timeString = "time" - dataString = "data" -) +// SampleContainer is a simple abstraction that allows sample +// producers to attach extra information to samples they return +type SampleContainer interface { + GetSamples() []Sample +} -// Possible values for MetricType. -const ( - Counter = MetricType(iota) // A counter that sums its data points - Gauge // A gauge that displays the latest value - Trend // A trend, min/max/avg/med are interesting - Rate // A rate, displays % of values that aren't 0 -) +// Samples is just the simplest SampleContainer implementation +// that will be used when there's no need for extra information +type Samples []Sample -// Possible values for ValueType. -const ( - Default = ValueType(iota) // Values are presented as-is - Time // Values are timestamps (nanoseconds) - Data // Values are data amounts (bytes) -) +// GetSamples just implements the SampleContainer interface +func (s Samples) GetSamples() []Sample { + return s +} -// The serialized metric type is invalid. -var ErrInvalidMetricType = errors.New("invalid metric type") +// ConnectedSampleContainer is an extension of the SampleContainer +// interface that should be implemented when emitted samples +// are connected and share the same time and tags. +type ConnectedSampleContainer interface { + SampleContainer + GetTags() *SampleTags + GetTime() time.Time +} -// The serialized value type is invalid. -var ErrInvalidValueType = errors.New("invalid value type") +// ConnectedSamples is the simplest ConnectedSampleContainer +// implementation that will be used when there's no need for +// extra information +type ConnectedSamples struct { + Samples []Sample + Tags *SampleTags + Time time.Time +} -// A MetricType specifies the type of a metric. -type MetricType int +// GetSamples implements the SampleContainer and ConnectedSampleContainer +// interfaces and returns the stored slice with samples. +func (cs ConnectedSamples) GetSamples() []Sample { + return cs.Samples +} -// MarshalJSON serializes a MetricType as a human readable string. -func (t MetricType) MarshalJSON() ([]byte, error) { - txt, err := t.MarshalText() - if err != nil { - return nil, err - } - return []byte(`"` + string(txt) + `"`), nil +// GetTags implements ConnectedSampleContainer interface and returns stored tags. +func (cs ConnectedSamples) GetTags() *SampleTags { + return cs.Tags } -// MarshalText serializes a MetricType as a human readable string. -func (t MetricType) MarshalText() ([]byte, error) { - switch t { - case Counter: - return []byte(counterString), nil - case Gauge: - return []byte(gaugeString), nil - case Trend: - return []byte(trendString), nil - case Rate: - return []byte(rateString), nil - default: - return nil, ErrInvalidMetricType - } +// GetTime implements ConnectedSampleContainer interface and returns stored time. +func (cs ConnectedSamples) GetTime() time.Time { + return cs.Time } -// UnmarshalText deserializes a MetricType from a string representation. -func (t *MetricType) UnmarshalText(data []byte) error { - switch string(data) { - case counterString: - *t = Counter - case gaugeString: - *t = Gauge - case trendString: - *t = Trend - case rateString: - *t = Rate - default: - return ErrInvalidMetricType - } +// GetSamples implement the ConnectedSampleContainer interface +// for a single Sample, since it's obviously connected with itself :) +func (s Sample) GetSamples() []Sample { + return []Sample{s} +} - return nil +// GetTags implements ConnectedSampleContainer interface +// and returns the sample's tags. +func (s Sample) GetTags() *SampleTags { + return s.Tags } -func (t MetricType) String() string { - switch t { - case Counter: - return counterString - case Gauge: - return gaugeString - case Trend: - return trendString - case Rate: - return rateString - default: - return "[INVALID]" - } +// GetTime just implements ConnectedSampleContainer interface +// and returns the sample's time. +func (s Sample) GetTime() time.Time { + return s.Time } -// The type of values a metric contains. -type ValueType int +// Ensure that interfaces are implemented correctly +var ( + _ SampleContainer = Sample{} + _ SampleContainer = Samples{} +) -// MarshalJSON serializes a ValueType to a JSON string. -func (t ValueType) MarshalJSON() ([]byte, error) { - txt, err := t.MarshalText() - if err != nil { - return nil, err +var ( + _ ConnectedSampleContainer = Sample{} + _ ConnectedSampleContainer = ConnectedSamples{} +) + +// GetBufferedSamples will read all present (i.e. buffered or currently being pushed) +// values in the input channel and return them as a slice. +func GetBufferedSamples(input <-chan SampleContainer) (result []SampleContainer) { + for { + select { + case val, ok := <-input: + if !ok { + return + } + result = append(result, val) + default: + return + } } - return []byte(`"` + string(txt) + `"`), nil } -// MarshalText serializes a ValueType as a human readable string. -func (t ValueType) MarshalText() ([]byte, error) { - switch t { - case Default: - return []byte(defaultString), nil - case Time: - return []byte(timeString), nil - case Data: - return []byte(dataString), nil - default: - return nil, ErrInvalidValueType +// PushIfNotDone first checks if the supplied context is done and doesn't push +// the sample container if it is. +func PushIfNotDone(ctx context.Context, output chan<- SampleContainer, sample SampleContainer) bool { + if ctx.Err() != nil { + return false } + output <- sample + return true } -// UnmarshalText deserializes a ValueType from a string representation. -func (t *ValueType) UnmarshalText(data []byte) error { - switch string(data) { - case defaultString: - *t = Default - case timeString: - *t = Time - case dataString: - *t = Data - default: - return ErrInvalidValueType +// GetResolversForTrendColumns checks if passed trend columns are valid for use in +// the summary output and then returns a map of the corresponding resolvers. +func GetResolversForTrendColumns(trendColumns []string) (map[string]func(s *TrendSink) float64, error) { + staticResolvers := map[string]func(s *TrendSink) float64{ + "avg": func(s *TrendSink) float64 { return s.Avg }, + "min": func(s *TrendSink) float64 { return s.Min }, + "med": func(s *TrendSink) float64 { return s.Med }, + "max": func(s *TrendSink) float64 { return s.Max }, + "count": func(s *TrendSink) float64 { return float64(s.Count) }, } + dynamicResolver := func(percentile float64) func(s *TrendSink) float64 { + return func(s *TrendSink) float64 { + return s.P(percentile / 100) + } + } + + result := make(map[string]func(s *TrendSink) float64, len(trendColumns)) - return nil + for _, stat := range trendColumns { + if staticStat, ok := staticResolvers[stat]; ok { + result[stat] = staticStat + continue + } + + percentile, err := parsePercentile(stat) + if err != nil { + return nil, err + } + result[stat] = dynamicResolver(percentile) + } + + return result, nil } -func (t ValueType) String() string { - switch t { - case Default: - return defaultString - case Time: - return timeString - case Data: - return dataString - default: - return "[INVALID]" +// parsePercentile is a helper function to parse and validate percentile notations +func parsePercentile(stat string) (float64, error) { + if !strings.HasPrefix(stat, "p(") || !strings.HasSuffix(stat, ")") { + return 0, fmt.Errorf("invalid trend stat '%s', unknown format", stat) } + + percentile, err := strconv.ParseFloat(stat[2:len(stat)-1], 64) + + if err != nil || (percentile < 0) || (percentile > 100) { + return 0, fmt.Errorf("invalid percentile trend stat value '%s', provide a number between 0 and 100", stat) + } + + return percentile, nil } // SampleTags is an immutable string[string] map for tags. Once a tag @@ -325,277 +316,3 @@ func IntoSampleTags(data *map[string]string) *SampleTags { *data = nil return &res } - -// A Sample is a single measurement. -type Sample struct { - Metric *Metric - Time time.Time - Tags *SampleTags - Value float64 -} - -// SampleContainer is a simple abstraction that allows sample -// producers to attach extra information to samples they return -type SampleContainer interface { - GetSamples() []Sample -} - -// Samples is just the simplest SampleContainer implementation -// that will be used when there's no need for extra information -type Samples []Sample - -// GetSamples just implements the SampleContainer interface -func (s Samples) GetSamples() []Sample { - return s -} - -// ConnectedSampleContainer is an extension of the SampleContainer -// interface that should be implemented when emitted samples -// are connected and share the same time and tags. -type ConnectedSampleContainer interface { - SampleContainer - GetTags() *SampleTags - GetTime() time.Time -} - -// ConnectedSamples is the simplest ConnectedSampleContainer -// implementation that will be used when there's no need for -// extra information -type ConnectedSamples struct { - Samples []Sample - Tags *SampleTags - Time time.Time -} - -// GetSamples implements the SampleContainer and ConnectedSampleContainer -// interfaces and returns the stored slice with samples. -func (cs ConnectedSamples) GetSamples() []Sample { - return cs.Samples -} - -// GetTags implements ConnectedSampleContainer interface and returns stored tags. -func (cs ConnectedSamples) GetTags() *SampleTags { - return cs.Tags -} - -// GetTime implements ConnectedSampleContainer interface and returns stored time. -func (cs ConnectedSamples) GetTime() time.Time { - return cs.Time -} - -// GetSamples implement the ConnectedSampleContainer interface -// for a single Sample, since it's obviously connected with itself :) -func (s Sample) GetSamples() []Sample { - return []Sample{s} -} - -// GetTags implements ConnectedSampleContainer interface -// and returns the sample's tags. -func (s Sample) GetTags() *SampleTags { - return s.Tags -} - -// GetTime just implements ConnectedSampleContainer interface -// and returns the sample's time. -func (s Sample) GetTime() time.Time { - return s.Time -} - -// Ensure that interfaces are implemented correctly -var ( - _ SampleContainer = Sample{} - _ SampleContainer = Samples{} -) - -var ( - _ ConnectedSampleContainer = Sample{} - _ ConnectedSampleContainer = ConnectedSamples{} -) - -// GetBufferedSamples will read all present (i.e. buffered or currently being pushed) -// values in the input channel and return them as a slice. -func GetBufferedSamples(input <-chan SampleContainer) (result []SampleContainer) { - for { - select { - case val, ok := <-input: - if !ok { - return - } - result = append(result, val) - default: - return - } - } -} - -// PushIfNotDone first checks if the supplied context is done and doesn't push -// the sample container if it is. -func PushIfNotDone(ctx context.Context, output chan<- SampleContainer, sample SampleContainer) bool { - if ctx.Err() != nil { - return false - } - output <- sample - return true -} - -// TODO: move to the metrics/ package - -// A Metric defines the shape of a set of data. -type Metric struct { - Name string `json:"name"` - Type MetricType `json:"type"` - Contains ValueType `json:"contains"` - - // TODO: decouple the metrics from the sinks and thresholds... have them - // linked, but not in the same struct? - Tainted null.Bool `json:"tainted"` - Thresholds Thresholds `json:"thresholds"` - Submetrics []*Submetric `json:"submetrics"` - Sub *Submetric `json:"-"` - Sink Sink `json:"-"` - Observed bool `json:"-"` -} - -// Sample samples the metric at the given time, with the provided tags and value -func (m *Metric) Sample(t time.Time, tags *SampleTags, value float64) Sample { - return Sample{ - Time: t, - Tags: tags, - Value: value, - Metric: m, - } -} - -// newMetric instantiates a new Metric -func newMetric(name string, mt MetricType, vt ...ValueType) *Metric { - contains := Default - if len(vt) > 0 { - contains = vt[0] - } - - var sink Sink - switch mt { - case Counter: - sink = &CounterSink{} - case Gauge: - sink = &GaugeSink{} - case Trend: - sink = &TrendSink{} - case Rate: - sink = &RateSink{} - default: - return nil - } - - return &Metric{Name: name, Type: mt, Contains: contains, Sink: sink} -} - -// A Submetric represents a filtered dataset based on a parent metric. -type Submetric struct { - Name string `json:"name"` - Suffix string `json:"suffix"` // TODO: rename? - Tags *SampleTags `json:"tags"` - - Metric *Metric `json:"-"` - Parent *Metric `json:"-"` -} - -// AddSubmetric creates a new submetric from the key:value threshold definition -// and adds it to the metric's submetrics list. -func (m *Metric) AddSubmetric(keyValues string) (*Submetric, error) { - keyValues = strings.TrimSpace(keyValues) - if len(keyValues) == 0 { - return nil, fmt.Errorf("submetric criteria for metric '%s' cannot be empty", m.Name) - } - kvs := strings.Split(keyValues, ",") - rawTags := make(map[string]string, len(kvs)) - for _, kv := range kvs { - if kv == "" { - continue - } - parts := strings.SplitN(kv, ":", 2) - - key := strings.Trim(strings.TrimSpace(parts[0]), `"'`) - if len(parts) != 2 { - rawTags[key] = "" - continue - } - - value := strings.Trim(strings.TrimSpace(parts[1]), `"'`) - rawTags[key] = value - } - - tags := IntoSampleTags(&rawTags) - - for _, sm := range m.Submetrics { - if sm.Tags.IsEqual(tags) { - return nil, fmt.Errorf( - "sub-metric with params '%s' already exists for metric %s: %s", - keyValues, m.Name, sm.Name, - ) - } - } - - subMetric := &Submetric{ - Name: m.Name + "{" + keyValues + "}", - Suffix: keyValues, - Tags: tags, - Parent: m, - } - subMetricMetric := newMetric(subMetric.Name, m.Type, m.Contains) - subMetricMetric.Sub = subMetric // sigh - subMetric.Metric = subMetricMetric - - m.Submetrics = append(m.Submetrics, subMetric) - - return subMetric, nil -} - -// parsePercentile is a helper function to parse and validate percentile notations -func parsePercentile(stat string) (float64, error) { - if !strings.HasPrefix(stat, "p(") || !strings.HasSuffix(stat, ")") { - return 0, fmt.Errorf("invalid trend stat '%s', unknown format", stat) - } - - percentile, err := strconv.ParseFloat(stat[2:len(stat)-1], 64) - - if err != nil || (percentile < 0) || (percentile > 100) { - return 0, fmt.Errorf("invalid percentile trend stat value '%s', provide a number between 0 and 100", stat) - } - - return percentile, nil -} - -// GetResolversForTrendColumns checks if passed trend columns are valid for use in -// the summary output and then returns a map of the corresponding resolvers. -func GetResolversForTrendColumns(trendColumns []string) (map[string]func(s *TrendSink) float64, error) { - staticResolvers := map[string]func(s *TrendSink) float64{ - "avg": func(s *TrendSink) float64 { return s.Avg }, - "min": func(s *TrendSink) float64 { return s.Min }, - "med": func(s *TrendSink) float64 { return s.Med }, - "max": func(s *TrendSink) float64 { return s.Max }, - "count": func(s *TrendSink) float64 { return float64(s.Count) }, - } - dynamicResolver := func(percentile float64) func(s *TrendSink) float64 { - return func(s *TrendSink) float64 { - return s.P(percentile / 100) - } - } - - result := make(map[string]func(s *TrendSink) float64, len(trendColumns)) - - for _, stat := range trendColumns { - if staticStat, ok := staticResolvers[stat]; ok { - result[stat] = staticStat - continue - } - - percentile, err := parsePercentile(stat) - if err != nil { - return nil, err - } - result[stat] = dynamicResolver(percentile) - } - - return result, nil -} diff --git a/stats/stats_test.go b/metrics/sample_test.go similarity index 63% rename from stats/stats_test.go rename to metrics/sample_test.go index 7ec7ae3887c..fddd5383226 100644 --- a/stats/stats_test.go +++ b/metrics/sample_test.go @@ -1,24 +1,4 @@ -/* - * - * k6 - a next-generation load testing tool - * Copyright (C) 2016 Load Impact - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - * - */ - -package stats +package metrics import ( "encoding/json" @@ -27,69 +7,8 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) -func TestNewMetric(t *testing.T) { - t.Parallel() - testdata := map[string]struct { - Type MetricType - SinkType Sink - }{ - "Counter": {Counter, &CounterSink{}}, - "Gauge": {Gauge, &GaugeSink{}}, - "Trend": {Trend, &TrendSink{}}, - "Rate": {Rate, &RateSink{}}, - } - - for name, data := range testdata { - name, data := name, data - t.Run(name, func(t *testing.T) { - t.Parallel() - m := newMetric("my_metric", data.Type) - assert.Equal(t, "my_metric", m.Name) - assert.IsType(t, data.SinkType, m.Sink) - }) - } -} - -func TestAddSubmetric(t *testing.T) { - t.Parallel() - testdata := map[string]struct { - err bool - tags map[string]string - }{ - "": {true, nil}, - " ": {true, nil}, - "a": {false, map[string]string{"a": ""}}, - "a:1": {false, map[string]string{"a": "1"}}, - " a : 1 ": {false, map[string]string{"a": "1"}}, - "a,b": {false, map[string]string{"a": "", "b": ""}}, - ` a:"",b: ''`: {false, map[string]string{"a": "", "b": ""}}, - `a:1,b:2`: {false, map[string]string{"a": "1", "b": "2"}}, - ` a : 1, b : 2 `: {false, map[string]string{"a": "1", "b": "2"}}, - `a : '1' , b : "2"`: {false, map[string]string{"a": "1", "b": "2"}}, - `" a" : ' 1' , b : "2 " `: {false, map[string]string{" a": " 1", "b": "2 "}}, //nolint:gocritic - } - - for name, expected := range testdata { - name, expected := name, expected - t.Run(name, func(t *testing.T) { - t.Parallel() - - m := newMetric("metric", Trend) - sm, err := m.AddSubmetric(name) - if expected.err { - require.Error(t, err) - return - } - require.NoError(t, err) - require.NotNil(t, sm) - assert.EqualValues(t, expected.tags, sm.Tags.tags) - }) - } -} - func TestSampleTags(t *testing.T) { t.Parallel() @@ -208,17 +127,9 @@ func TestGetResolversForTrendColumnsValidation(t *testing.T) { } } -func createTestTrendSink(count int) *TrendSink { - sink := TrendSink{} - - for i := 0; i < count; i++ { - sink.Add(Sample{Value: float64(i)}) - } - - return &sink -} +func TestGetResolversForTrendColumnsCalculation(t *testing.T) { + t.Parallel() -func TestResolversForTrendColumnsCalculation(t *testing.T) { customResolversTests := []struct { stats string percentile float64 @@ -230,11 +141,12 @@ func TestResolversForTrendColumnsCalculation(t *testing.T) { {"p(99.999)", 0.99999}, } - sink := createTestTrendSink(100) - for _, tc := range customResolversTests { tc := tc t.Run(fmt.Sprintf("%v", tc.stats), func(t *testing.T) { + t.Parallel() + sink := createTestTrendSink(100) + res, err := GetResolversForTrendColumns([]string{tc.stats}) assert.NoError(t, err) assert.Len(t, res, 1) @@ -244,3 +156,13 @@ func TestResolversForTrendColumnsCalculation(t *testing.T) { }) } } + +func createTestTrendSink(count int) *TrendSink { + sink := TrendSink{} + + for i := 0; i < count; i++ { + sink.Add(Sample{Value: float64(i)}) + } + + return &sink +} diff --git a/stats/sink.go b/metrics/sink.go similarity index 99% rename from stats/sink.go rename to metrics/sink.go index 8834454ada3..01b5d5263a9 100644 --- a/stats/sink.go +++ b/metrics/sink.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "errors" diff --git a/stats/sink_test.go b/metrics/sink_test.go similarity index 99% rename from stats/sink_test.go rename to metrics/sink_test.go index 6c629da3f86..585a2950acb 100644 --- a/stats/sink_test.go +++ b/metrics/sink_test.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "testing" diff --git a/stats/system_tag.go b/metrics/system_tag.go similarity index 99% rename from stats/system_tag.go rename to metrics/system_tag.go index d68a905caf4..6a9d0513935 100644 --- a/stats/system_tag.go +++ b/metrics/system_tag.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "bytes" diff --git a/stats/system_tag_set_gen.go b/metrics/system_tag_set_gen.go similarity index 99% rename from stats/system_tag_set_gen.go rename to metrics/system_tag_set_gen.go index b65604d01ec..08ae3fc19df 100644 --- a/stats/system_tag_set_gen.go +++ b/metrics/system_tag_set_gen.go @@ -1,7 +1,7 @@ // Code generated by "enumer -type=SystemTagSet -transform=snake -trimprefix=Tag -output system_tag_set_gen.go"; DO NOT EDIT. // -package stats +package metrics import ( "fmt" diff --git a/stats/system_tag_test.go b/metrics/system_tag_test.go similarity index 97% rename from stats/system_tag_test.go rename to metrics/system_tag_test.go index 86f91e53974..623b822fb6c 100644 --- a/stats/system_tag_test.go +++ b/metrics/system_tag_test.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "encoding/json" @@ -29,6 +29,8 @@ import ( ) func TestSystemTagSetMarshalJSON(t *testing.T) { + t.Parallel() + tests := []struct { tagset SystemTagSet expected string @@ -47,6 +49,8 @@ func TestSystemTagSetMarshalJSON(t *testing.T) { } func TestSystemTagSet_UnmarshalJSON(t *testing.T) { + t.Parallel() + tests := []struct { tags []byte sets []SystemTagSet @@ -65,6 +69,8 @@ func TestSystemTagSet_UnmarshalJSON(t *testing.T) { } func TestSystemTagSetTextUnmarshal(t *testing.T) { + t.Parallel() + testMatrix := map[string]SystemTagSet{ "": 0, "ip": TagIP, @@ -83,6 +89,8 @@ func TestSystemTagSetTextUnmarshal(t *testing.T) { } func TestTagSetMarshalJSON(t *testing.T) { + t.Parallel() + tests := []struct { tagset TagSet expected string @@ -100,6 +108,8 @@ func TestTagSetMarshalJSON(t *testing.T) { } func TestTagSet_UnmarshalJSON(t *testing.T) { + t.Parallel() + tests := []struct { tags []byte sets TagSet @@ -118,6 +128,8 @@ func TestTagSet_UnmarshalJSON(t *testing.T) { } func TestTagSetTextUnmarshal(t *testing.T) { + t.Parallel() + testMatrix := map[string]TagSet{ "": make(TagSet), "ip": {"ip": true}, diff --git a/stats/thresholds.go b/metrics/thresholds.go similarity index 97% rename from stats/thresholds.go rename to metrics/thresholds.go index 3b513dc57b0..90e5f816389 100644 --- a/stats/thresholds.go +++ b/metrics/thresholds.go @@ -17,7 +17,7 @@ * along with this program. If not, see . * */ -package stats +package metrics import ( "bytes" @@ -188,10 +188,10 @@ func (ts *Thresholds) Run(sink Sink, duration time.Duration) (bool, error) { // Initialize the sinks store ts.sinked = make(map[string]float64) - // FIXME: Remove this comment as soon as the stats.Sink does not expose Format anymore. + // FIXME: Remove this comment as soon as the metrics.Sink does not expose Format anymore. // // As of December 2021, this block reproduces the behavior of the - // stats.Sink.Format behavior. As we intend to try to get away from it, + // metrics.Sink.Format behavior. As we intend to try to get away from it, // we instead implement the behavior directly here. // // For more details, see https://github.com/grafana/k6/issues/2320 diff --git a/stats/thresholds_parser.go b/metrics/thresholds_parser.go similarity index 99% rename from stats/thresholds_parser.go rename to metrics/thresholds_parser.go index cdb0a28190b..cd9c7b2e531 100644 --- a/stats/thresholds_parser.go +++ b/metrics/thresholds_parser.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "fmt" diff --git a/stats/thresholds_parser_test.go b/metrics/thresholds_parser_test.go similarity index 99% rename from stats/thresholds_parser_test.go rename to metrics/thresholds_parser_test.go index 25120684d6e..ac751cbf57b 100644 --- a/stats/thresholds_parser_test.go +++ b/metrics/thresholds_parser_test.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "testing" diff --git a/stats/thresholds_test.go b/metrics/thresholds_test.go similarity index 99% rename from stats/thresholds_test.go rename to metrics/thresholds_test.go index 91ff5cf89c4..f1bcfe1ff35 100644 --- a/stats/thresholds_test.go +++ b/metrics/thresholds_test.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "encoding/json" diff --git a/stats/units.go b/metrics/units.go similarity index 98% rename from stats/units.go rename to metrics/units.go index e414f8d20d7..8a7bcb8315b 100644 --- a/stats/units.go +++ b/metrics/units.go @@ -18,7 +18,7 @@ * */ -package stats +package metrics import ( "time" diff --git a/metrics/value_type.go b/metrics/value_type.go new file mode 100644 index 00000000000..59cd49cab77 --- /dev/null +++ b/metrics/value_type.go @@ -0,0 +1,68 @@ +package metrics + +import "errors" + +// Possible values for ValueType. +const ( + Default = ValueType(iota) // Values are presented as-is + Time // Values are timestamps (nanoseconds) + Data // Values are data amounts (bytes) +) + +// ErrInvalidValueType indicates the serialized value type is invalid. +var ErrInvalidValueType = errors.New("invalid value type") + +// ValueType holds the type of values a metric contains. +type ValueType int + +// MarshalJSON serializes a ValueType to a JSON string. +func (t ValueType) MarshalJSON() ([]byte, error) { + txt, err := t.MarshalText() + if err != nil { + return nil, err + } + return []byte(`"` + string(txt) + `"`), nil +} + +// MarshalText serializes a ValueType as a human readable string. +func (t ValueType) MarshalText() ([]byte, error) { + switch t { + case Default: + return []byte(defaultString), nil + case Time: + return []byte(timeString), nil + case Data: + return []byte(dataString), nil + default: + return nil, ErrInvalidValueType + } +} + +// UnmarshalText deserializes a ValueType from a string representation. +func (t *ValueType) UnmarshalText(data []byte) error { + switch string(data) { + case defaultString: + *t = Default + case timeString: + *t = Time + case dataString: + *t = Data + default: + return ErrInvalidValueType + } + + return nil +} + +func (t ValueType) String() string { + switch t { + case Default: + return defaultString + case Time: + return timeString + case Data: + return dataString + default: + return "[INVALID]" + } +} diff --git a/output/cloud/bench_test.go b/output/cloud/bench_test.go index 04b6a291dbe..f18d6d3d7d7 100644 --- a/output/cloud/bench_test.go +++ b/output/cloud/bench_test.go @@ -42,8 +42,8 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/testutils/httpmultibin" "go.k6.io/k6/lib/types" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) func BenchmarkAggregateHTTP(b *testing.B) { @@ -52,7 +52,7 @@ func BenchmarkAggregateHTTP(b *testing.B) { JSONConfig: json.RawMessage(`{"noCompress": true, "aggregationCalcInterval": "200ms","aggregationPeriod": "200ms"}`), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "/script.js"}, }) @@ -67,7 +67,7 @@ func BenchmarkAggregateHTTP(b *testing.B) { b.ResetTimer() for s := 0; s < b.N; s++ { b.StopTimer() - container := make([]stats.SampleContainer, containersCount) + container := make([]metrics.SampleContainer, containersCount) for i := 1; i <= containersCount; i++ { status := "200" if i%tagCount%7 == 6 { @@ -88,7 +88,7 @@ func BenchmarkAggregateHTTP(b *testing.B) { } } -func generateTags(i, tagCount int, additionals ...map[string]string) *stats.SampleTags { +func generateTags(i, tagCount int, additionals ...map[string]string) *metrics.SampleTags { res := map[string]string{ "test": "mest", "a": "b", "custom": fmt.Sprintf("group%d", i%tagCount%9), @@ -102,7 +102,7 @@ func generateTags(i, tagCount int, additionals ...map[string]string) *stats.Samp } } - return stats.IntoSampleTags(&res) + return metrics.IntoSampleTags(&res) } func BenchmarkMetricMarshal(b *testing.B) { @@ -241,7 +241,7 @@ func generateSamples(count int) []*Sample { Metric: "something", Data: &SampleDataSingle{ Time: toMicroSecond(now), - Type: stats.Counter, + Type: metrics.Counter, Tags: tags, Value: float64(i), }, @@ -273,7 +273,7 @@ func generateSamples(count int) []*Sample { return samples } -func generateHTTPExtTrail(now time.Time, i time.Duration, tags *stats.SampleTags) *httpext.Trail { +func generateHTTPExtTrail(now time.Time, i time.Duration, tags *metrics.SampleTags) *httpext.Trail { return &httpext.Trail{ Blocked: i % 200 * 100 * time.Millisecond, Connecting: i % 200 * 200 * time.Millisecond, @@ -313,7 +313,7 @@ func BenchmarkHTTPPush(b *testing.B) { }`, tb.ServerHTTP.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "/script.js"}, }) diff --git a/output/cloud/cloud_easyjson.go b/output/cloud/cloud_easyjson.go index a62045d5f63..cd13c2b2bbd 100644 --- a/output/cloud/cloud_easyjson.go +++ b/output/cloud/cloud_easyjson.go @@ -7,7 +7,7 @@ import ( easyjson "github.com/mailru/easyjson" jlexer "github.com/mailru/easyjson/jlexer" jwriter "github.com/mailru/easyjson/jwriter" - stats "go.k6.io/k6/stats" + metrics "go.k6.io/k6/metrics" ) // suppress unused package warning @@ -113,7 +113,7 @@ func easyjson9def2ecdDecodeGoK6IoK6OutputCloud1(in *jlexer.Lexer, out *SampleDat out.Tags = nil } else { if out.Tags == nil { - out.Tags = new(stats.SampleTags) + out.Tags = new(metrics.SampleTags) } if data := in.Raw(); in.Ok() { in.AddError((*out.Tags).UnmarshalJSON(data)) @@ -198,7 +198,7 @@ func easyjson9def2ecdDecodeGoK6IoK6OutputCloud2(in *jlexer.Lexer, out *SampleDat out.Tags = nil } else { if out.Tags == nil { - out.Tags = new(stats.SampleTags) + out.Tags = new(metrics.SampleTags) } if data := in.Raw(); in.Ok() { in.AddError((*out.Tags).UnmarshalJSON(data)) @@ -315,7 +315,7 @@ func easyjson9def2ecdDecodeGoK6IoK6OutputCloud3(in *jlexer.Lexer, out *SampleDat out.Tags = nil } else { if out.Tags == nil { - out.Tags = new(stats.SampleTags) + out.Tags = new(metrics.SampleTags) } if data := in.Raw(); in.Ok() { in.AddError((*out.Tags).UnmarshalJSON(data)) diff --git a/output/cloud/data.go b/output/cloud/data.go index 1178ddaf8fc..2bd98968628 100644 --- a/output/cloud/data.go +++ b/output/cloud/data.go @@ -29,7 +29,6 @@ import ( "go.k6.io/k6/lib/netext/httpext" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // DataType constants @@ -90,10 +89,10 @@ func (ct *Sample) UnmarshalJSON(p []byte) error { // SampleDataSingle is used in all simple un-aggregated single-value samples. //easyjson:json type SampleDataSingle struct { - Time int64 `json:"time,string"` - Type stats.MetricType `json:"type"` - Tags *stats.SampleTags `json:"tags,omitempty"` - Value float64 `json:"value"` + Time int64 `json:"time,string"` + Type metrics.MetricType `json:"type"` + Tags *metrics.SampleTags `json:"tags,omitempty"` + Value float64 `json:"value"` } // SampleDataMap is used by samples that contain multiple values, currently @@ -101,10 +100,10 @@ type SampleDataSingle struct { // requests (`http_req_li_all`). //easyjson:json type SampleDataMap struct { - Time int64 `json:"time,string"` - Type stats.MetricType `json:"type"` - Tags *stats.SampleTags `json:"tags,omitempty"` - Values map[string]float64 `json:"values,omitempty"` + Time int64 `json:"time,string"` + Type metrics.MetricType `json:"type"` + Tags *metrics.SampleTags `json:"tags,omitempty"` + Values map[string]float64 `json:"values,omitempty"` } // NewSampleFromTrail just creates a ready-to-send Sample instance @@ -117,15 +116,15 @@ func NewSampleFromTrail(trail *httpext.Trail) *Sample { values := make(map[string]float64, length) values[metrics.HTTPReqsName] = 1 - values[metrics.HTTPReqDurationName] = stats.D(trail.Duration) - values[metrics.HTTPReqBlockedName] = stats.D(trail.Blocked) - values[metrics.HTTPReqConnectingName] = stats.D(trail.Connecting) - values[metrics.HTTPReqTLSHandshakingName] = stats.D(trail.TLSHandshaking) - values[metrics.HTTPReqSendingName] = stats.D(trail.Sending) - values[metrics.HTTPReqWaitingName] = stats.D(trail.Waiting) - values[metrics.HTTPReqReceivingName] = stats.D(trail.Receiving) + values[metrics.HTTPReqDurationName] = metrics.D(trail.Duration) + values[metrics.HTTPReqBlockedName] = metrics.D(trail.Blocked) + values[metrics.HTTPReqConnectingName] = metrics.D(trail.Connecting) + values[metrics.HTTPReqTLSHandshakingName] = metrics.D(trail.TLSHandshaking) + values[metrics.HTTPReqSendingName] = metrics.D(trail.Sending) + values[metrics.HTTPReqWaitingName] = metrics.D(trail.Waiting) + values[metrics.HTTPReqReceivingName] = metrics.D(trail.Receiving) if trail.Failed.Valid { // this is done so the adding of 1 map element doesn't reexpand the map as this is a hotpath - values[metrics.HTTPReqFailedName] = stats.B(trail.Failed.Bool) + values[metrics.HTTPReqFailedName] = metrics.B(trail.Failed.Bool) } return &Sample{ Type: DataTypeMap, @@ -141,10 +140,10 @@ func NewSampleFromTrail(trail *httpext.Trail) *Sample { // SampleDataAggregatedHTTPReqs is used in aggregated samples for HTTP requests. //easyjson:json type SampleDataAggregatedHTTPReqs struct { - Time int64 `json:"time,string"` - Type string `json:"type"` - Count uint64 `json:"count"` - Tags *stats.SampleTags `json:"tags,omitempty"` + Time int64 `json:"time,string"` + Type string `json:"type"` + Count uint64 `json:"count"` + Tags *metrics.SampleTags `json:"tags,omitempty"` Values struct { Duration AggregatedMetric `json:"http_req_duration"` Blocked AggregatedMetric `json:"http_req_blocked"` @@ -229,12 +228,12 @@ func (am *AggregatedMetric) Add(t time.Duration) { // Calc populates the float fields for min and max and calculates the average value func (am *AggregatedMetric) Calc(count float64) { - am.Min = stats.D(am.minD) - am.Max = stats.D(am.maxD) - am.Avg = stats.D(am.sumD) / count + am.Min = metrics.D(am.minD) + am.Max = metrics.D(am.maxD) + am.Avg = metrics.D(am.sumD) / count } -type aggregationBucket map[*stats.SampleTags][]*httpext.Trail +type aggregationBucket map[*metrics.SampleTags][]*httpext.Trail type durations []time.Duration diff --git a/output/cloud/data_test.go b/output/cloud/data_test.go index 8e614dad2ac..3b1fd5c4608 100644 --- a/output/cloud/data_test.go +++ b/output/cloud/data_test.go @@ -33,7 +33,6 @@ import ( "go.k6.io/k6/lib/netext/httpext" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestSampleMarshaling(t *testing.T) { @@ -54,7 +53,7 @@ func TestSampleMarshaling(t *testing.T) { Data: &SampleDataSingle{ Type: builtinMetrics.VUs.Type, Time: toMicroSecond(now), - Tags: stats.IntoSampleTags(&map[string]string{"aaa": "bbb", "ccc": "123"}), + Tags: metrics.IntoSampleTags(&map[string]string{"aaa": "bbb", "ccc": "123"}), Value: 999, }, }, @@ -66,11 +65,11 @@ func TestSampleMarshaling(t *testing.T) { Metric: "iter_li_all", Data: &SampleDataMap{ Time: toMicroSecond(now), - Tags: stats.IntoSampleTags(&map[string]string{"test": "mest"}), + Tags: metrics.IntoSampleTags(&map[string]string{"test": "mest"}), Values: map[string]float64{ metrics.DataSentName: 1234.5, metrics.DataReceivedName: 6789.1, - metrics.IterationDurationName: stats.D(10 * time.Second), + metrics.IterationDurationName: metrics.D(10 * time.Second), }, }, }, @@ -108,7 +107,7 @@ func TestSampleMarshaling(t *testing.T) { aggrData := &SampleDataAggregatedHTTPReqs{ Time: exptoMicroSecond, Type: "aggregated_trend", - Tags: stats.IntoSampleTags(&map[string]string{"test": "mest"}), + Tags: metrics.IntoSampleTags(&map[string]string{"test": "mest"}), } aggrData.Add( &httpext.Trail{ @@ -150,7 +149,7 @@ func TestSampleMarshaling(t *testing.T) { aggrData := &SampleDataAggregatedHTTPReqs{ Time: exptoMicroSecond, Type: "aggregated_trend", - Tags: stats.IntoSampleTags(&map[string]string{"test": "mest"}), + Tags: metrics.IntoSampleTags(&map[string]string{"test": "mest"}), } aggrData.Add( &httpext.Trail{ @@ -218,9 +217,9 @@ func TestMetricAggregation(t *testing.T) { m.Add(5 * time.Second) m.Add(10 * time.Second) m.Calc(5) - assert.Equal(t, m.Min, stats.D(1*time.Second)) - assert.Equal(t, m.Max, stats.D(10*time.Second)) - assert.Equal(t, m.Avg, stats.D(4*time.Second)) + assert.Equal(t, m.Min, metrics.D(1*time.Second)) + assert.Equal(t, m.Max, metrics.D(10*time.Second)) + assert.Equal(t, m.Avg, metrics.D(4*time.Second)) } // For more realistic request time distributions, import diff --git a/output/cloud/output.go b/output/cloud/output.go index 2da3baadb21..22bcc8229aa 100644 --- a/output/cloud/output.go +++ b/output/cloud/output.go @@ -40,7 +40,6 @@ import ( "go.k6.io/k6/lib/netext" "go.k6.io/k6/lib/netext/httpext" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // TestName is the default Load Impact Cloud test name @@ -53,7 +52,7 @@ type Output struct { executionPlan []lib.ExecutionStep duration int64 // in seconds - thresholds map[string][]*stats.Threshold + thresholds map[string][]*metrics.Threshold client *MetricsClient runStatus lib.RunStatus @@ -110,7 +109,7 @@ func newOutput(params output.Params) (*Output, error) { logger := params.Logger.WithFields(logrus.Fields{"output": "cloud"}) if conf.AggregationPeriod.Duration > 0 && - (params.ScriptOptions.SystemTags.Has(stats.TagVU) || params.ScriptOptions.SystemTags.Has(stats.TagIter)) { + (params.ScriptOptions.SystemTags.Has(metrics.TagVU) || params.ScriptOptions.SystemTags.Has(metrics.TagIter)) { return nil, errors.New("aggregation cannot be enabled if the 'vu' or 'iter' system tag is also enabled") } @@ -163,10 +162,15 @@ func newOutput(params output.Params) (*Output, error) { } // validateRequiredSystemTags checks if all required tags are present. -func validateRequiredSystemTags(scriptTags *stats.SystemTagSet) error { +func validateRequiredSystemTags(scriptTags *metrics.SystemTagSet) error { missingRequiredTags := []string{} - requiredTags := stats.TagName | stats.TagMethod | stats.TagStatus | stats.TagError | stats.TagCheck | stats.TagGroup - for _, tag := range stats.SystemTagSetValues() { + requiredTags := metrics.TagName | + metrics.TagMethod | + metrics.TagStatus | + metrics.TagError | + metrics.TagCheck | + metrics.TagGroup + for _, tag := range metrics.SystemTagSetValues() { if requiredTags.Has(tag) && !scriptTags.Has(tag) { missingRequiredTags = append(missingRequiredTags, tag.String()) } @@ -309,8 +313,8 @@ func (out *Output) SetRunStatus(status lib.RunStatus) { } // SetThresholds receives the thresholds before the output is Start()-ed. -func (out *Output) SetThresholds(scriptThresholds map[string]stats.Thresholds) { - thresholds := make(map[string][]*stats.Threshold) +func (out *Output) SetThresholds(scriptThresholds map[string]metrics.Thresholds) { + thresholds := make(map[string][]*metrics.Threshold) for name, t := range scriptThresholds { thresholds[name] = append(thresholds[name], t.Thresholds...) } @@ -334,7 +338,7 @@ func useCloudTags(source *httpext.Trail) *httpext.Trail { dest := new(httpext.Trail) *dest = *source - dest.Tags = stats.IntoSampleTags(&newTags) + dest.Tags = metrics.IntoSampleTags(&newTags) dest.Samples = nil return dest @@ -343,7 +347,7 @@ func useCloudTags(source *httpext.Trail) *httpext.Trail { // AddMetricSamples receives a set of metric samples. This method is never // called concurrently, so it defers as much of the work as possible to the // asynchronous goroutines initialized in Start(). -func (out *Output) AddMetricSamples(sampleContainers []stats.SampleContainer) { +func (out *Output) AddMetricSamples(sampleContainers []metrics.SampleContainer) { select { case <-out.stopSendingMetrics: return @@ -375,7 +379,7 @@ func (out *Output) AddMetricSamples(sampleContainers []stats.SampleContainer) { } if sc.FullIteration { - values[metrics.IterationDurationName] = stats.D(sc.EndTime.Sub(sc.StartTime)) + values[metrics.IterationDurationName] = metrics.D(sc.EndTime.Sub(sc.StartTime)) values[metrics.IterationsName] = 1 } diff --git a/output/cloud/output_test.go b/output/cloud/output_test.go index 17637397b23..9643d72478d 100644 --- a/output/cloud/output_test.go +++ b/output/cloud/output_test.go @@ -50,10 +50,9 @@ import ( "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) -func tagEqual(expected, got *stats.SampleTags) bool { +func tagEqual(expected, got *metrics.SampleTags) bool { expectedMap := expected.CloneTags() gotMap := got.CloneTags() @@ -185,7 +184,7 @@ func runCloudOutputTestCase(t *testing.T, minSamples int) { JSONConfig: json.RawMessage(fmt.Sprintf(`{"host": "%s", "noCompress": true}`, tb.ServerHTTP.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "/script.js"}, }) @@ -210,10 +209,10 @@ func runCloudOutputTestCase(t *testing.T, minSamples int) { now := time.Now() tagMap := map[string]string{"test": "mest", "a": "b", "name": "name", "url": "url"} - tags := stats.IntoSampleTags(&tagMap) + tags := metrics.IntoSampleTags(&tagMap) expectedTagMap := tags.CloneTags() expectedTagMap["url"], _ = tags.Get("name") - expectedTags := stats.IntoSampleTags(&expectedTagMap) + expectedTags := metrics.IntoSampleTags(&expectedTagMap) expSamples := make(chan []Sample) defer close(expSamples) @@ -222,7 +221,7 @@ func runCloudOutputTestCase(t *testing.T, minSamples int) { rw.WriteHeader(http.StatusOK) // silence a test warning }) - out.AddMetricSamples([]stats.SampleContainer{stats.Sample{ + out.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{ Time: now, Metric: builtinMetrics.VUs, Tags: tags, @@ -252,12 +251,12 @@ func runCloudOutputTestCase(t *testing.T, minSamples int) { Duration: 1500 * time.Millisecond, Tags: tags, } - out.AddMetricSamples([]stats.SampleContainer{&simpleTrail}) + out.AddMetricSamples([]metrics.SampleContainer{&simpleTrail}) expSamples <- []Sample{*NewSampleFromTrail(&simpleTrail)} smallSkew := 0.02 - trails := []stats.SampleContainer{} + trails := []metrics.SampleContainer{} durations := make([]time.Duration, len(trails)) for i := int64(0); i < out.config.AggregationMinSamples.Int64; i++ { similarTrail := skewTrail(r, simpleTrail, 1.0, 1.0+smallSkew) @@ -270,9 +269,9 @@ func runCloudOutputTestCase(t *testing.T, minSamples int) { checkAggrMetric := func(normal time.Duration, aggr AggregatedMetric) { assert.True(t, aggr.Min <= aggr.Avg) assert.True(t, aggr.Avg <= aggr.Max) - assert.InEpsilon(t, normal, stats.ToD(aggr.Min), smallSkew) - assert.InEpsilon(t, normal, stats.ToD(aggr.Avg), smallSkew) - assert.InEpsilon(t, normal, stats.ToD(aggr.Max), smallSkew) + assert.InEpsilon(t, normal, metrics.ToD(aggr.Min), smallSkew) + assert.InEpsilon(t, normal, metrics.ToD(aggr.Avg), smallSkew) + assert.InEpsilon(t, normal, metrics.ToD(aggr.Max), smallSkew) } outlierTrail := skewTrail(r, simpleTrail, 2.0+smallSkew, 3.0+smallSkew) @@ -330,14 +329,14 @@ func TestCloudOutputMaxPerPacket(t *testing.T) { JSONConfig: json.RawMessage(fmt.Sprintf(`{"host": "%s", "noCompress": true}`, tb.ServerHTTP.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "/script.js"}, }) require.NoError(t, err) require.NoError(t, err) now := time.Now() - tags := stats.IntoSampleTags(&map[string]string{"test": "mest", "a": "b"}) + tags := metrics.IntoSampleTags(&map[string]string{"test": "mest", "a": "b"}) gotTheLimit := false var m sync.Mutex @@ -357,14 +356,14 @@ func TestCloudOutputMaxPerPacket(t *testing.T) { require.NoError(t, out.Start()) - out.AddMetricSamples([]stats.SampleContainer{stats.Sample{ + out.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{ Time: now, Metric: builtinMetrics.VUs, - Tags: stats.NewSampleTags(tags.CloneTags()), + Tags: metrics.NewSampleTags(tags.CloneTags()), Value: 1.0, }}) for j := time.Duration(1); j <= 200; j++ { - container := make([]stats.SampleContainer, 0, 500) + container := make([]metrics.SampleContainer, 0, 500) for i := time.Duration(1); i <= 50; i++ { container = append(container, &httpext.Trail{ Blocked: i % 200 * 100 * time.Millisecond, @@ -377,7 +376,7 @@ func TestCloudOutputMaxPerPacket(t *testing.T) { EndTime: now.Add(i * 100), ConnDuration: 500 * time.Millisecond, Duration: j * i * 1500 * time.Millisecond, - Tags: stats.NewSampleTags(tags.CloneTags()), + Tags: metrics.NewSampleTags(tags.CloneTags()), }) } out.AddMetricSamples(container) @@ -435,7 +434,7 @@ func testCloudOutputStopSendingMetric(t *testing.T, stopOnError bool) { }`, tb.ServerHTTP.URL, stopOnError)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, External: map[string]json.RawMessage{ "loadimpact": json.RawMessage(`{"name": "my-custom-name"}`), }, @@ -452,7 +451,7 @@ func testCloudOutputStopSendingMetric(t *testing.T, stopOnError bool) { } require.NoError(t, err) now := time.Now() - tags := stats.IntoSampleTags(&map[string]string{"test": "mest", "a": "b"}) + tags := metrics.IntoSampleTags(&map[string]string{"test": "mest", "a": "b"}) count := 1 max := 5 @@ -482,14 +481,14 @@ func testCloudOutputStopSendingMetric(t *testing.T, stopOnError bool) { require.NoError(t, out.Start()) - out.AddMetricSamples([]stats.SampleContainer{stats.Sample{ + out.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{ Time: now, Metric: builtinMetrics.VUs, - Tags: stats.NewSampleTags(tags.CloneTags()), + Tags: metrics.NewSampleTags(tags.CloneTags()), Value: 1.0, }}) for j := time.Duration(1); j <= 200; j++ { - container := make([]stats.SampleContainer, 0, 500) + container := make([]metrics.SampleContainer, 0, 500) for i := time.Duration(1); i <= 50; i++ { container = append(container, &httpext.Trail{ Blocked: i % 200 * 100 * time.Millisecond, @@ -502,7 +501,7 @@ func testCloudOutputStopSendingMetric(t *testing.T, stopOnError bool) { EndTime: now.Add(i * 100), ConnDuration: 500 * time.Millisecond, Duration: j * i * 1500 * time.Millisecond, - Tags: stats.NewSampleTags(tags.CloneTags()), + Tags: metrics.NewSampleTags(tags.CloneTags()), }) } out.AddMetricSamples(container) @@ -522,10 +521,10 @@ func testCloudOutputStopSendingMetric(t *testing.T, stopOnError bool) { nBufferSamples := len(out.bufferSamples) nBufferHTTPTrails := len(out.bufferHTTPTrails) - out.AddMetricSamples([]stats.SampleContainer{stats.Sample{ + out.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{ Time: now, Metric: builtinMetrics.VUs, - Tags: stats.NewSampleTags(tags.CloneTags()), + Tags: metrics.NewSampleTags(tags.CloneTags()), Value: 1.0, }}) if nBufferSamples != len(out.bufferSamples) || nBufferHTTPTrails != len(out.bufferHTTPTrails) { @@ -539,7 +538,7 @@ func TestCloudOutputRequireScriptName(t *testing.T) { Logger: testutils.NewLogger(t), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: ""}, }) @@ -572,7 +571,7 @@ func TestCloudOutputAggregationPeriodZeroNoBlock(t *testing.T) { }`, tb.ServerHTTP.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "/script.js"}, }) @@ -627,7 +626,7 @@ func TestCloudOutputPushRefID(t *testing.T) { }`, tb.ServerHTTP.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "/script.js"}, }) @@ -638,9 +637,9 @@ func TestCloudOutputPushRefID(t *testing.T) { assert.Equal(t, "333", out.referenceID) now := time.Now() - tags := stats.IntoSampleTags(&map[string]string{"test": "mest", "a": "b"}) + tags := metrics.IntoSampleTags(&map[string]string{"test": "mest", "a": "b"}) - out.AddMetricSamples([]stats.SampleContainer{stats.Sample{ + out.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{ Time: now, Metric: builtinMetrics.HTTPReqDuration, Tags: tags, @@ -691,7 +690,7 @@ func TestCloudOutputRecvIterLIAllIterations(t *testing.T) { }`, tb.ServerHTTP.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "path/to/script.js"}, }) @@ -735,7 +734,7 @@ func TestCloudOutputRecvIterLIAllIterations(t *testing.T) { FullIteration: true, StartTime: now.Add(-time.Minute), EndTime: now, - Samples: []stats.Sample{ + Samples: []metrics.Sample{ { Time: now, Metric: builtinMetrics.DataSent, @@ -754,7 +753,7 @@ func TestCloudOutputRecvIterLIAllIterations(t *testing.T) { }, } - out.AddMetricSamples([]stats.SampleContainer{&simpleNetTrail}) + out.AddMetricSamples([]metrics.SampleContainer{&simpleNetTrail}) require.NoError(t, out.Stop()) require.True(t, gotIterations) } @@ -799,7 +798,7 @@ func TestNewName(t *testing.T) { Logger: testutils.NewLogger(t), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: testCase.url, }) @@ -838,7 +837,7 @@ func TestPublishMetric(t *testing.T) { JSONConfig: json.RawMessage(fmt.Sprintf(`{"host": "%s", "noCompress": false}`, server.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "script.js"}, }) @@ -872,7 +871,7 @@ func TestNewOutputClientTimeout(t *testing.T) { JSONConfig: json.RawMessage(fmt.Sprintf(`{"host": "%s", "timeout": "2ms"}`, ts.URL)), ScriptOptions: lib.Options{ Duration: types.NullDurationFrom(1 * time.Second), - SystemTags: &stats.DefaultSystemTagSet, + SystemTags: &metrics.DefaultSystemTagSet, }, ScriptPath: &url.URL{Path: "script.js"}, }) diff --git a/output/csv/output.go b/output/csv/output.go index 1a3f754a0c0..bfba60fba28 100644 --- a/output/csv/output.go +++ b/output/csv/output.go @@ -33,8 +33,8 @@ import ( "github.com/sirupsen/logrus" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) // Output implements the lib.Output interface for saving to CSV files. @@ -200,7 +200,7 @@ func MakeHeader(tags []string) []string { } // SampleToRow converts sample into array of strings -func SampleToRow(sample *stats.Sample, resTags []string, ignoredTags []string, row []string) []string { +func SampleToRow(sample *metrics.Sample, resTags []string, ignoredTags []string, row []string) []string { row[0] = sample.Metric.Name row[1] = fmt.Sprintf("%d", sample.Time.Unix()) row[2] = fmt.Sprintf("%f", sample.Value) diff --git a/output/csv/output_test.go b/output/csv/output_test.go index 0a60bbf9bcf..d0fa3c13bcc 100644 --- a/output/csv/output_test.go +++ b/output/csv/output_test.go @@ -39,7 +39,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) func TestMakeHeader(t *testing.T) { @@ -66,22 +65,22 @@ func TestMakeHeader(t *testing.T) { } func TestSampleToRow(t *testing.T) { - testMetric, err := metrics.NewRegistry().NewMetric("my_metric", stats.Gauge) + testMetric, err := metrics.NewRegistry().NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) testData := []struct { testname string - sample *stats.Sample + sample *metrics.Sample resTags []string ignoredTags []string }{ { testname: "One res tag, one ignored tag, one extra tag", - sample: &stats.Sample{ + sample: &metrics.Sample{ Time: time.Unix(1562324644, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "tag1": "val1", "tag2": "val2", "tag3": "val3", @@ -92,11 +91,11 @@ func TestSampleToRow(t *testing.T) { }, { testname: "Two res tags, three extra tags", - sample: &stats.Sample{ + sample: &metrics.Sample{ Time: time.Unix(1562324644, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "tag1": "val1", "tag2": "val2", "tag3": "val3", @@ -109,11 +108,11 @@ func TestSampleToRow(t *testing.T) { }, { testname: "Two res tags, two ignored", - sample: &stats.Sample{ + sample: &metrics.Sample{ Time: time.Unix(1562324644, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "tag1": "val1", "tag2": "val2", "tag3": "val3", @@ -219,32 +218,32 @@ func readCompressedFile(fileName string, fs afero.Fs) string { func TestRun(t *testing.T) { t.Parallel() - testMetric, err := metrics.NewRegistry().NewMetric("my_metric", stats.Gauge) + testMetric, err := metrics.NewRegistry().NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) testData := []struct { - samples []stats.SampleContainer + samples []metrics.SampleContainer fileName string fileReaderFunc func(fileName string, fs afero.Fs) string outputContent string }{ { - samples: []stats.SampleContainer{ - stats.Sample{ + samples: []metrics.SampleContainer{ + metrics.Sample{ Time: time.Unix(1562324643, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "check": "val1", "url": "val2", "error": "val3", }), }, - stats.Sample{ + metrics.Sample{ Time: time.Unix(1562324644, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "check": "val1", "url": "val2", "error": "val3", @@ -257,22 +256,22 @@ func TestRun(t *testing.T) { outputContent: "metric_name,timestamp,metric_value,check,error,extra_tags\n" + "my_metric,1562324643,1.000000,val1,val3,url=val2\n" + "my_metric,1562324644,1.000000,val1,val3,tag4=val4&url=val2\n", }, { - samples: []stats.SampleContainer{ - stats.Sample{ + samples: []metrics.SampleContainer{ + metrics.Sample{ Time: time.Unix(1562324643, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "check": "val1", "url": "val2", "error": "val3", }), }, - stats.Sample{ + metrics.Sample{ Time: time.Unix(1562324644, 0), Metric: testMetric, Value: 1, - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "check": "val1", "url": "val2", "error": "val3", @@ -293,7 +292,7 @@ func TestRun(t *testing.T) { FS: mem, ConfigArgument: data.fileName, ScriptOptions: lib.Options{ - SystemTags: stats.NewSystemTagSet(stats.TagError | stats.TagCheck), + SystemTags: metrics.NewSystemTagSet(metrics.TagError | metrics.TagCheck), }, }) require.NoError(t, err) diff --git a/output/helpers.go b/output/helpers.go index 52376c883df..91d46bd69e6 100644 --- a/output/helpers.go +++ b/output/helpers.go @@ -25,7 +25,7 @@ import ( "sync" "time" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // SampleBuffer is a simple thread-safe buffer for metric samples. It should be @@ -34,12 +34,12 @@ import ( // and we don't want to block the Engine in the meantime. type SampleBuffer struct { sync.Mutex - buffer []stats.SampleContainer + buffer []metrics.SampleContainer maxLen int } // AddMetricSamples adds the given metric samples to the internal buffer. -func (sc *SampleBuffer) AddMetricSamples(samples []stats.SampleContainer) { +func (sc *SampleBuffer) AddMetricSamples(samples []metrics.SampleContainer) { if len(samples) == 0 { return } @@ -51,7 +51,7 @@ func (sc *SampleBuffer) AddMetricSamples(samples []stats.SampleContainer) { // GetBufferedSamples returns the currently buffered metric samples and makes a // new internal buffer with some hopefully realistic size. If the internal // buffer is empty, it will return nil. -func (sc *SampleBuffer) GetBufferedSamples() []stats.SampleContainer { +func (sc *SampleBuffer) GetBufferedSamples() []metrics.SampleContainer { sc.Lock() defer sc.Unlock() @@ -64,7 +64,7 @@ func (sc *SampleBuffer) GetBufferedSamples() []stats.SampleContainer { } // Make the new buffer halfway between the previously allocated size and the // maximum buffer size we've seen so far, to hopefully reduce copying a bit. - sc.buffer = make([]stats.SampleContainer, 0, (bufferedLen+sc.maxLen)/2) + sc.buffer = make([]metrics.SampleContainer, 0, (bufferedLen+sc.maxLen)/2) return buffered } diff --git a/output/helpers_test.go b/output/helpers_test.go index 0200c5f5769..626ec7e7600 100644 --- a/output/helpers_test.go +++ b/output/helpers_test.go @@ -30,41 +30,40 @@ import ( "github.com/stretchr/testify/require" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func TestSampleBufferBasics(t *testing.T) { t.Parallel() registry := metrics.NewRegistry() - metric, err := registry.NewMetric("my_metric", stats.Rate) + metric, err := registry.NewMetric("my_metric", metrics.Rate) require.NoError(t, err) - single := stats.Sample{ + single := metrics.Sample{ Time: time.Now(), Metric: metric, Value: float64(123), - Tags: stats.NewSampleTags(map[string]string{"tag1": "val1"}), + Tags: metrics.NewSampleTags(map[string]string{"tag1": "val1"}), } - connected := stats.ConnectedSamples{Samples: []stats.Sample{single, single}, Time: single.Time} + connected := metrics.ConnectedSamples{Samples: []metrics.Sample{single, single}, Time: single.Time} buffer := SampleBuffer{} assert.Empty(t, buffer.GetBufferedSamples()) - buffer.AddMetricSamples([]stats.SampleContainer{single, single}) - buffer.AddMetricSamples([]stats.SampleContainer{single, connected, single}) - assert.Equal(t, []stats.SampleContainer{single, single, single, connected, single}, buffer.GetBufferedSamples()) + buffer.AddMetricSamples([]metrics.SampleContainer{single, single}) + buffer.AddMetricSamples([]metrics.SampleContainer{single, connected, single}) + assert.Equal(t, []metrics.SampleContainer{single, single, single, connected, single}, buffer.GetBufferedSamples()) assert.Empty(t, buffer.GetBufferedSamples()) // Verify some internals assert.Equal(t, cap(buffer.buffer), 5) - buffer.AddMetricSamples([]stats.SampleContainer{single, connected}) + buffer.AddMetricSamples([]metrics.SampleContainer{single, connected}) buffer.AddMetricSamples(nil) - buffer.AddMetricSamples([]stats.SampleContainer{}) - buffer.AddMetricSamples([]stats.SampleContainer{single}) - assert.Equal(t, []stats.SampleContainer{single, connected, single}, buffer.GetBufferedSamples()) + buffer.AddMetricSamples([]metrics.SampleContainer{}) + buffer.AddMetricSamples([]metrics.SampleContainer{single}) + assert.Equal(t, []metrics.SampleContainer{single, connected, single}, buffer.GetBufferedSamples()) assert.Equal(t, cap(buffer.buffer), 4) - buffer.AddMetricSamples([]stats.SampleContainer{single}) - assert.Equal(t, []stats.SampleContainer{single}, buffer.GetBufferedSamples()) + buffer.AddMetricSamples([]metrics.SampleContainer{single}) + assert.Equal(t, []metrics.SampleContainer{single}, buffer.GetBufferedSamples()) assert.Equal(t, cap(buffer.buffer), 3) assert.Empty(t, buffer.GetBufferedSamples()) } @@ -77,7 +76,7 @@ func TestSampleBufferConcurrently(t *testing.T) { t.Logf("Random source seeded with %d\n", seed) registry := metrics.NewRegistry() - metric, err := registry.NewMetric("my_metric", stats.Gauge) + metric, err := registry.NewMetric("my_metric", metrics.Gauge) require.NoError(t, err) producersCount := 50 + r.Intn(50) @@ -88,11 +87,11 @@ func TestSampleBufferConcurrently(t *testing.T) { wg := make(chan struct{}) fillBuffer := func() { for i := 0; i < sampleCount; i++ { - buffer.AddMetricSamples([]stats.SampleContainer{stats.Sample{ + buffer.AddMetricSamples([]metrics.SampleContainer{metrics.Sample{ Time: time.Unix(1562324644, 0), Metric: metric, Value: float64(i), - Tags: stats.NewSampleTags(map[string]string{"tag1": "val1"}), + Tags: metrics.NewSampleTags(map[string]string{"tag1": "val1"}), }}) time.Sleep(time.Duration(i*sleepModifier) * time.Microsecond) } @@ -105,7 +104,7 @@ func TestSampleBufferConcurrently(t *testing.T) { timer := time.NewTicker(5 * time.Millisecond) timeout := time.After(5 * time.Second) defer timer.Stop() - readSamples := make([]stats.SampleContainer, 0, sampleCount*producersCount) + readSamples := make([]metrics.SampleContainer, 0, sampleCount*producersCount) finishedProducers := 0 loop: for { diff --git a/output/influxdb/bench_test.go b/output/influxdb/bench_test.go index 2b8a20552d1..99093df09b4 100644 --- a/output/influxdb/bench_test.go +++ b/output/influxdb/bench_test.go @@ -29,11 +29,10 @@ import ( "github.com/stretchr/testify/require" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) func benchmarkInfluxdb(b *testing.B, t time.Duration) { - metric, err := metrics.NewRegistry().NewMetric("test_gauge", stats.Gauge) + metric, err := metrics.NewRegistry().NewMetric("test_gauge", metrics.Gauge) require.NoError(b, err) testOutputCycle(b, func(rw http.ResponseWriter, r *http.Request) { @@ -49,12 +48,12 @@ func benchmarkInfluxdb(b *testing.B, t time.Duration) { b = tb.(*testing.B) b.ResetTimer() - samples := make(stats.Samples, 10) + samples := make(metrics.Samples, 10) for i := 0; i < len(samples); i++ { - samples[i] = stats.Sample{ + samples[i] = metrics.Sample{ Metric: metric, Time: time.Now(), - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "something": "else", "VU": "21", "else": "something", @@ -65,7 +64,7 @@ func benchmarkInfluxdb(b *testing.B, t time.Duration) { b.ResetTimer() for i := 0; i < b.N; i++ { - c.AddMetricSamples([]stats.SampleContainer{samples}) + c.AddMetricSamples([]metrics.SampleContainer{samples}) time.Sleep(time.Nanosecond * 20) } }) diff --git a/output/influxdb/output.go b/output/influxdb/output.go index f322933c69f..8b71111c1fc 100644 --- a/output/influxdb/output.go +++ b/output/influxdb/output.go @@ -31,8 +31,8 @@ import ( client "github.com/influxdata/influxdb1-client/v2" "github.com/sirupsen/logrus" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) // FieldKind defines Enum for tag-to-field type conversion @@ -124,7 +124,7 @@ func (o *Output) extractTagsToValues(tags map[string]string, values map[string]i return values } -func (o *Output) batchFromSamples(containers []stats.SampleContainer) (client.BatchPoints, error) { +func (o *Output) batchFromSamples(containers []metrics.SampleContainer) (client.BatchPoints, error) { batch, err := client.NewBatchPoints(o.BatchConf) if err != nil { return nil, fmt.Errorf("couldn't make a batch: %w", err) @@ -134,7 +134,7 @@ func (o *Output) batchFromSamples(containers []stats.SampleContainer) (client.Ba tags map[string]string values map[string]interface{} } - cache := map[*stats.SampleTags]cacheItem{} + cache := map[*metrics.SampleTags]cacheItem{} for _, container := range containers { samples := container.GetSamples() for _, sample := range samples { diff --git a/output/influxdb/output_test.go b/output/influxdb/output_test.go index 6708cd7ccfe..830e85790ee 100644 --- a/output/influxdb/output_test.go +++ b/output/influxdb/output_test.go @@ -38,7 +38,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) func TestBadConcurrentWrites(t *testing.T) { @@ -109,7 +108,7 @@ func testOutputCycle(t testing.TB, handler http.HandlerFunc, body func(testing.T func TestOutput(t *testing.T) { t.Parallel() - metric, err := metrics.NewRegistry().NewMetric("test_gauge", stats.Gauge) + metric, err := metrics.NewRegistry().NewMetric("test_gauge", metrics.Gauge) require.NoError(t, err) var samplesRead int @@ -132,12 +131,12 @@ func TestOutput(t *testing.T) { rw.WriteHeader(204) }, func(tb testing.TB, c *Output) { - samples := make(stats.Samples, 10) + samples := make(metrics.Samples, 10) for i := 0; i < len(samples); i++ { - samples[i] = stats.Sample{ + samples[i] = metrics.Sample{ Metric: metric, Time: time.Now(), - Tags: stats.NewSampleTags(map[string]string{ + Tags: metrics.NewSampleTags(map[string]string{ "something": "else", "VU": "21", "else": "something", @@ -145,8 +144,8 @@ func TestOutput(t *testing.T) { Value: 2.0, } } - c.AddMetricSamples([]stats.SampleContainer{samples}) - c.AddMetricSamples([]stats.SampleContainer{samples}) + c.AddMetricSamples([]metrics.SampleContainer{samples}) + c.AddMetricSamples([]metrics.SampleContainer{samples}) }) } @@ -176,7 +175,7 @@ func TestOutputFlushMetricsConcurrency(t *testing.T) { ts.Close() }() - metric, err := metrics.NewRegistry().NewMetric("test_gauge", stats.Gauge) + metric, err := metrics.NewRegistry().NewMetric("test_gauge", metrics.Gauge) require.NoError(t, err) o, err := newOutput(output.Params{ @@ -190,8 +189,8 @@ func TestOutputFlushMetricsConcurrency(t *testing.T) { case o.semaphoreCh <- struct{}{}: <-o.semaphoreCh wg.Add(1) - o.AddMetricSamples([]stats.SampleContainer{stats.Samples{ - stats.Sample{ + o.AddMetricSamples([]metrics.SampleContainer{metrics.Samples{ + metrics.Sample{ Metric: metric, Value: 2.0, }, diff --git a/output/json/json.go b/output/json/json.go index b0f190d93e9..928056ec9c5 100644 --- a/output/json/json.go +++ b/output/json/json.go @@ -33,8 +33,8 @@ import ( "github.com/sirupsen/logrus" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) // TODO: add option for emitting proper JSON files (https://github.com/k6io/k6/issues/737) @@ -52,7 +52,7 @@ type Output struct { out io.Writer closeFn func() error seenMetrics map[string]struct{} - thresholds map[string][]*stats.Threshold + thresholds map[string][]*metrics.Threshold } // New returns a new JSON output. @@ -131,8 +131,8 @@ func (o *Output) Stop() error { } // SetThresholds receives the thresholds before the output is Start()-ed. -func (o *Output) SetThresholds(thresholds map[string]stats.Thresholds) { - ths := make(map[string][]*stats.Threshold) +func (o *Output) SetThresholds(thresholds map[string]metrics.Thresholds) { + ths := make(map[string][]*metrics.Threshold) for name, t := range thresholds { ths[name] = append(ths[name], t.Thresholds...) } @@ -165,7 +165,7 @@ func (o *Output) flushMetrics() { } } -func (o *Output) handleMetric(m *stats.Metric, jw *jwriter.Writer) { +func (o *Output) handleMetric(m *metrics.Metric, jw *jwriter.Writer) { if _, ok := o.seenMetrics[m.Name]; ok { return } diff --git a/output/json/json_easyjson.go b/output/json/json_easyjson.go index 85210d84a77..e35f1b7452f 100644 --- a/output/json/json_easyjson.go +++ b/output/json/json_easyjson.go @@ -7,7 +7,7 @@ import ( easyjson "github.com/mailru/easyjson" jlexer "github.com/mailru/easyjson/jlexer" jwriter "github.com/mailru/easyjson/jwriter" - stats "go.k6.io/k6/stats" + metrics "go.k6.io/k6/metrics" time "time" ) @@ -86,9 +86,9 @@ func (v *sampleEnvelope) UnmarshalEasyJSON(l *jlexer.Lexer) { easyjson42239ddeDecodeGoK6IoK6OutputJson(l, v) } func easyjson42239ddeDecode(in *jlexer.Lexer, out *struct { - Time time.Time `json:"time"` - Value float64 `json:"value"` - Tags *stats.SampleTags `json:"tags"` + Time time.Time `json:"time"` + Value float64 `json:"value"` + Tags *metrics.SampleTags `json:"tags"` }) { isTopLevel := in.IsStart() if in.IsNull() { @@ -120,7 +120,7 @@ func easyjson42239ddeDecode(in *jlexer.Lexer, out *struct { out.Tags = nil } else { if out.Tags == nil { - out.Tags = new(stats.SampleTags) + out.Tags = new(metrics.SampleTags) } if data := in.Raw(); in.Ok() { in.AddError((*out.Tags).UnmarshalJSON(data)) @@ -137,9 +137,9 @@ func easyjson42239ddeDecode(in *jlexer.Lexer, out *struct { } } func easyjson42239ddeEncode(out *jwriter.Writer, in struct { - Time time.Time `json:"time"` - Value float64 `json:"value"` - Tags *stats.SampleTags `json:"tags"` + Time time.Time `json:"time"` + Value float64 `json:"value"` + Tags *metrics.SampleTags `json:"tags"` }) { out.RawByte('{') first := true @@ -192,9 +192,9 @@ func easyjson42239ddeDecodeGoK6IoK6OutputJson1(in *jlexer.Lexer, out *metricEnve out.Data = nil } else { if out.Data == nil { - out.Data = new(stats.Metric) + out.Data = new(metrics.Metric) } - easyjson42239ddeDecodeGoK6IoK6Stats(in, out.Data) + easyjson42239ddeDecodeGoK6IoK6Metrics(in, out.Data) } case "metric": out.Metric = string(in.String()) @@ -223,7 +223,7 @@ func easyjson42239ddeEncodeGoK6IoK6OutputJson1(out *jwriter.Writer, in metricEnv if in.Data == nil { out.RawString("null") } else { - easyjson42239ddeEncodeGoK6IoK6Stats(out, *in.Data) + easyjson42239ddeEncodeGoK6IoK6Metrics(out, *in.Data) } } { @@ -243,7 +243,7 @@ func (v metricEnvelope) MarshalEasyJSON(w *jwriter.Writer) { func (v *metricEnvelope) UnmarshalEasyJSON(l *jlexer.Lexer) { easyjson42239ddeDecodeGoK6IoK6OutputJson1(l, v) } -func easyjson42239ddeDecodeGoK6IoK6Stats(in *jlexer.Lexer, out *stats.Metric) { +func easyjson42239ddeDecodeGoK6IoK6Metrics(in *jlexer.Lexer, out *metrics.Metric) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -288,23 +288,23 @@ func easyjson42239ddeDecodeGoK6IoK6Stats(in *jlexer.Lexer, out *stats.Metric) { in.Delim('[') if out.Submetrics == nil { if !in.IsDelim(']') { - out.Submetrics = make([]*stats.Submetric, 0, 8) + out.Submetrics = make([]*metrics.Submetric, 0, 8) } else { - out.Submetrics = []*stats.Submetric{} + out.Submetrics = []*metrics.Submetric{} } } else { out.Submetrics = (out.Submetrics)[:0] } for !in.IsDelim(']') { - var v1 *stats.Submetric + var v1 *metrics.Submetric if in.IsNull() { in.Skip() v1 = nil } else { if v1 == nil { - v1 = new(stats.Submetric) + v1 = new(metrics.Submetric) } - easyjson42239ddeDecodeGoK6IoK6Stats1(in, v1) + easyjson42239ddeDecodeGoK6IoK6Metrics1(in, v1) } out.Submetrics = append(out.Submetrics, v1) in.WantComma() @@ -321,7 +321,7 @@ func easyjson42239ddeDecodeGoK6IoK6Stats(in *jlexer.Lexer, out *stats.Metric) { in.Consumed() } } -func easyjson42239ddeEncodeGoK6IoK6Stats(out *jwriter.Writer, in stats.Metric) { +func easyjson42239ddeEncodeGoK6IoK6Metrics(out *jwriter.Writer, in metrics.Metric) { out.RawByte('{') first := true _ = first @@ -364,7 +364,7 @@ func easyjson42239ddeEncodeGoK6IoK6Stats(out *jwriter.Writer, in stats.Metric) { if v3 == nil { out.RawString("null") } else { - easyjson42239ddeEncodeGoK6IoK6Stats1(out, *v3) + easyjson42239ddeEncodeGoK6IoK6Metrics1(out, *v3) } } out.RawByte(']') @@ -372,7 +372,7 @@ func easyjson42239ddeEncodeGoK6IoK6Stats(out *jwriter.Writer, in stats.Metric) { } out.RawByte('}') } -func easyjson42239ddeDecodeGoK6IoK6Stats1(in *jlexer.Lexer, out *stats.Submetric) { +func easyjson42239ddeDecodeGoK6IoK6Metrics1(in *jlexer.Lexer, out *metrics.Submetric) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -401,7 +401,7 @@ func easyjson42239ddeDecodeGoK6IoK6Stats1(in *jlexer.Lexer, out *stats.Submetric out.Tags = nil } else { if out.Tags == nil { - out.Tags = new(stats.SampleTags) + out.Tags = new(metrics.SampleTags) } if data := in.Raw(); in.Ok() { in.AddError((*out.Tags).UnmarshalJSON(data)) @@ -417,7 +417,7 @@ func easyjson42239ddeDecodeGoK6IoK6Stats1(in *jlexer.Lexer, out *stats.Submetric in.Consumed() } } -func easyjson42239ddeEncodeGoK6IoK6Stats1(out *jwriter.Writer, in stats.Submetric) { +func easyjson42239ddeEncodeGoK6IoK6Metrics1(out *jwriter.Writer, in metrics.Submetric) { out.RawByte('{') first := true _ = first diff --git a/output/json/json_test.go b/output/json/json_test.go index 49da4037740..af0ca08f20b 100644 --- a/output/json/json_test.go +++ b/output/json/json_test.go @@ -35,7 +35,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) func getValidator(t testing.TB, expected []string) func(io.Reader) { @@ -55,28 +54,29 @@ func getValidator(t testing.TB, expected []string) func(io.Reader) { } } -func generateTestMetricSamples(t testing.TB) ([]stats.SampleContainer, func(io.Reader)) { +func generateTestMetricSamples(t testing.TB) ([]metrics.SampleContainer, func(io.Reader)) { registry := metrics.NewRegistry() - metric1, err := registry.NewMetric("my_metric1", stats.Gauge) + metric1, err := registry.NewMetric("my_metric1", metrics.Gauge) require.NoError(t, err) - metric2, err := registry.NewMetric("my_metric2", stats.Counter, stats.Data) + metric2, err := registry.NewMetric("my_metric2", metrics.Counter, metrics.Data) require.NoError(t, err) time1 := time.Date(2021, time.February, 24, 13, 37, 10, 0, time.UTC) time2 := time1.Add(10 * time.Second) time3 := time2.Add(10 * time.Second) - connTags := stats.NewSampleTags(map[string]string{"key": "val"}) - samples := []stats.SampleContainer{ - stats.Sample{Time: time1, Metric: metric1, Value: float64(1), Tags: stats.NewSampleTags(map[string]string{"tag1": "val1"})}, - stats.Sample{Time: time1, Metric: metric1, Value: float64(2), Tags: stats.NewSampleTags(map[string]string{"tag2": "val2"})}, - stats.ConnectedSamples{Samples: []stats.Sample{ + connTags := metrics.NewSampleTags(map[string]string{"key": "val"}) + + samples := []metrics.SampleContainer{ + metrics.Sample{Time: time1, Metric: metric1, Value: float64(1), Tags: metrics.NewSampleTags(map[string]string{"tag1": "val1"})}, + metrics.Sample{Time: time1, Metric: metric1, Value: float64(2), Tags: metrics.NewSampleTags(map[string]string{"tag2": "val2"})}, + metrics.ConnectedSamples{Samples: []metrics.Sample{ {Time: time2, Metric: metric2, Value: float64(3), Tags: connTags}, {Time: time2, Metric: metric1, Value: float64(4), Tags: connTags}, }, Time: time2, Tags: connTags}, - stats.Sample{Time: time3, Metric: metric2, Value: float64(5), Tags: stats.NewSampleTags(map[string]string{"tag3": "val3"})}, + metrics.Sample{Time: time3, Metric: metric2, Value: float64(5), Tags: metrics.NewSampleTags(map[string]string{"tag3": "val3"})}, } expected := []string{ `{"type":"Metric","data":{"name":"my_metric1","type":"gauge","contains":"default","tainted":null,"thresholds":["rate<0.01","p(99)<250"],"submetrics":null},"metric":"my_metric1"}`, @@ -186,15 +186,15 @@ func TestJsonOutputFileGzipped(t *testing.T) { func TestWrapSampleWithSamplePointer(t *testing.T) { t.Parallel() - out := wrapSample(stats.Sample{ - Metric: &stats.Metric{}, + out := wrapSample(metrics.Sample{ + Metric: &metrics.Metric{}, }) assert.NotEqual(t, out, (*sampleEnvelope)(nil)) } func TestWrapMetricWithMetricPointer(t *testing.T) { t.Parallel() - out := wrapMetric(&stats.Metric{}) + out := wrapMetric(&metrics.Metric{}) assert.NotEqual(t, out, (*metricEnvelope)(nil)) } @@ -204,7 +204,7 @@ func setThresholds(t *testing.T, out output.Output) { jout, ok := out.(*Output) require.True(t, ok) - ts := stats.NewThresholds([]string{"rate<0.01", "p(99)<250"}) + ts := metrics.NewThresholds([]string{"rate<0.01", "p(99)<250"}) - jout.SetThresholds(map[string]stats.Thresholds{"my_metric1": ts}) + jout.SetThresholds(map[string]metrics.Thresholds{"my_metric1": ts}) } diff --git a/output/json/wrapper.go b/output/json/wrapper.go index 61fa649c90c..3410ea9b00a 100644 --- a/output/json/wrapper.go +++ b/output/json/wrapper.go @@ -23,7 +23,7 @@ package json import ( "time" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) //go:generate easyjson -pkg -no_std_marshalers -gen_build_flags -mod=mod . @@ -34,14 +34,14 @@ type sampleEnvelope struct { Data struct { Time time.Time `json:"time"` Value float64 `json:"value"` - Tags *stats.SampleTags `json:"tags"` + Tags *metrics.SampleTags `json:"tags"` } `json:"data"` Metric string `json:"metric"` } // wrapSample is used to package a metric sample in a way that's nice to export // to JSON. -func wrapSample(sample stats.Sample) sampleEnvelope { +func wrapSample(sample metrics.Sample) sampleEnvelope { s := sampleEnvelope{ Type: "Point", Metric: sample.Metric.Name, @@ -55,11 +55,11 @@ func wrapSample(sample stats.Sample) sampleEnvelope { //easyjson:json type metricEnvelope struct { Type string `json:"type"` - Data *stats.Metric `json:"data"` + Data *metrics.Metric `json:"data"` Metric string `json:"metric"` } -func wrapMetric(metric *stats.Metric) metricEnvelope { +func wrapMetric(metric *metrics.Metric) metricEnvelope { return metricEnvelope{ Type: "Metric", Metric: metric.Name, diff --git a/output/manager.go b/output/manager.go index fdb88743e19..38d72e53b78 100644 --- a/output/manager.go +++ b/output/manager.go @@ -3,7 +3,7 @@ package output import ( "github.com/sirupsen/logrus" "go.k6.io/k6/lib" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // Manager can be used to manage multiple outputs at the same time. @@ -70,7 +70,7 @@ func (om *Manager) SetRunStatus(status lib.RunStatus) { // current Engine. It needs to be replaced with the full metric pump. // // TODO: refactor -func (om *Manager) AddMetricSamples(sampleContainers []stats.SampleContainer) { +func (om *Manager) AddMetricSamples(sampleContainers []metrics.SampleContainer) { if len(sampleContainers) == 0 { return } diff --git a/output/statsd/config.go b/output/statsd/config.go index e7f2a8b3bf1..cff9dabd449 100644 --- a/output/statsd/config.go +++ b/output/statsd/config.go @@ -28,7 +28,7 @@ import ( "gopkg.in/guregu/null.v3" "go.k6.io/k6/lib/types" - "go.k6.io/k6/stats" + "go.k6.io/k6/metrics" ) // config defines the StatsD configuration. @@ -37,11 +37,11 @@ type config struct { BufferSize null.Int `json:"bufferSize,omitempty" envconfig:"K6_STATSD_BUFFER_SIZE"` Namespace null.String `json:"namespace,omitempty" envconfig:"K6_STATSD_NAMESPACE"` PushInterval types.NullDuration `json:"pushInterval,omitempty" envconfig:"K6_STATSD_PUSH_INTERVAL"` - TagBlocklist stats.TagSet `json:"tagBlocklist,omitempty" envconfig:"K6_STATSD_TAG_BLOCKLIST"` + TagBlocklist metrics.TagSet `json:"tagBlocklist,omitempty" envconfig:"K6_STATSD_TAG_BLOCKLIST"` EnableTags null.Bool `json:"enableTags,omitempty" envconfig:"K6_STATSD_ENABLE_TAGS"` } -func processTags(t stats.TagSet, tags map[string]string) []string { +func processTags(t metrics.TagSet, tags map[string]string) []string { var res []string for key, value := range tags { if value != "" && !t[key] { @@ -82,7 +82,7 @@ func newConfig() config { BufferSize: null.NewInt(20, false), Namespace: null.NewString("k6.", false), PushInterval: types.NewNullDuration(1*time.Second, false), - TagBlocklist: (stats.TagVU | stats.TagIter | stats.TagURL).Map(), + TagBlocklist: (metrics.TagVU | metrics.TagIter | metrics.TagURL).Map(), EnableTags: null.NewBool(false, false), } } diff --git a/output/statsd/output.go b/output/statsd/output.go index d21fd4c460f..10e6b097cf9 100644 --- a/output/statsd/output.go +++ b/output/statsd/output.go @@ -27,8 +27,8 @@ import ( "github.com/DataDog/datadog-go/statsd" "github.com/sirupsen/logrus" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) // New creates a new statsd connector client @@ -63,20 +63,20 @@ type Output struct { client *statsd.Client } -func (o *Output) dispatch(entry stats.Sample) error { +func (o *Output) dispatch(entry metrics.Sample) error { var tagList []string if o.config.EnableTags.Bool { tagList = processTags(o.config.TagBlocklist, entry.Tags.CloneTags()) } switch entry.Metric.Type { - case stats.Counter: + case metrics.Counter: return o.client.Count(entry.Metric.Name, int64(entry.Value), tagList, 1) - case stats.Trend: + case metrics.Trend: return o.client.TimeInMilliseconds(entry.Metric.Name, entry.Value, tagList, 1) - case stats.Gauge: + case metrics.Gauge: return o.client.Gauge(entry.Metric.Name, entry.Value, tagList, 1) - case stats.Rate: + case metrics.Rate: if check, ok := entry.Tags.Get("check"); ok { return o.client.Count( checkToString(check, entry.Value), diff --git a/output/statsd/output_test.go b/output/statsd/output_test.go index 3b3fea75cfa..2b73855fe53 100644 --- a/output/statsd/output_test.go +++ b/output/statsd/output_test.go @@ -33,8 +33,8 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/types" + "go.k6.io/k6/metrics" "go.k6.io/k6/output" - "go.k6.io/k6/stats" ) func getOutput( @@ -55,14 +55,14 @@ func getOutput( func TestStatsdOutput(t *testing.T) { t.Parallel() baseTest(t, getOutput, - func(t *testing.T, _ []stats.SampleContainer, expectedOutput, output string) { + func(t *testing.T, _ []metrics.SampleContainer, expectedOutput, output string) { assert.Equal(t, expectedOutput, output) }) } func TestStatsdEnabledTags(t *testing.T) { t.Parallel() - tagMap := stats.TagSet{"tag1": true, "tag2": true} + tagMap := metrics.TagSet{"tag1": true, "tag2": true} baseTest(t, func( logger logrus.FieldLogger, addr, namespace null.String, bufferSize null.Int, pushInterval types.NullDuration, @@ -79,7 +79,7 @@ func TestStatsdEnabledTags(t *testing.T) { "enableTags": true }`, addr.String, namespace.String, bufferSize.Int64, pushInterval.Duration.String())), }) - }, func(t *testing.T, containers []stats.SampleContainer, expectedOutput, output string) { + }, func(t *testing.T, containers []metrics.SampleContainer, expectedOutput, output string) { outputLines := strings.Split(output, "\n") expectedOutputLines := strings.Split(expectedOutput, "\n") var lines int diff --git a/output/statsd/test_helper.go b/output/statsd/test_helper.go index 3e1cf72e064..2cbd763ea4b 100644 --- a/output/statsd/test_helper.go +++ b/output/statsd/test_helper.go @@ -32,7 +32,6 @@ import ( "go.k6.io/k6/lib/testutils" "go.k6.io/k6/lib/types" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) type getOutputFn func( @@ -45,7 +44,7 @@ type getOutputFn func( //nolint:funlen func baseTest(t *testing.T, getOutput getOutputFn, - checkResult func(t *testing.T, samples []stats.SampleContainer, expectedOutput, output string), + checkResult func(t *testing.T, samples []metrics.SampleContainer, expectedOutput, output string), ) { t.Helper() testNamespace := "testing.things." // to be dynamic @@ -86,31 +85,31 @@ func baseTest(t *testing.T, defer func() { require.NoError(t, collector.Stop()) }() - newSample := func(m *stats.Metric, value float64, tags map[string]string) stats.Sample { - return stats.Sample{ + newSample := func(m *metrics.Metric, value float64, tags map[string]string) metrics.Sample { + return metrics.Sample{ Time: time.Now(), - Metric: m, Value: value, Tags: stats.IntoSampleTags(&tags), + Metric: m, Value: value, Tags: metrics.IntoSampleTags(&tags), } } registry := metrics.NewRegistry() - myCounter, err := registry.NewMetric("my_counter", stats.Counter) + myCounter, err := registry.NewMetric("my_counter", metrics.Counter) require.NoError(t, err) - myGauge, err := registry.NewMetric("my_gauge", stats.Gauge) + myGauge, err := registry.NewMetric("my_gauge", metrics.Gauge) require.NoError(t, err) - myTrend, err := registry.NewMetric("my_trend", stats.Trend) + myTrend, err := registry.NewMetric("my_trend", metrics.Trend) require.NoError(t, err) - myRate, err := registry.NewMetric("my_rate", stats.Rate) + myRate, err := registry.NewMetric("my_rate", metrics.Rate) require.NoError(t, err) - myCheck, err := registry.NewMetric("my_check", stats.Rate) + myCheck, err := registry.NewMetric("my_check", metrics.Rate) require.NoError(t, err) testMatrix := []struct { - input []stats.SampleContainer + input []metrics.SampleContainer output string }{ { - input: []stats.SampleContainer{ + input: []metrics.SampleContainer{ newSample(myCounter, 12, map[string]string{ "tag1": "value1", "tag3": "value3", @@ -119,7 +118,7 @@ func baseTest(t *testing.T, output: "testing.things.my_counter:12|c", }, { - input: []stats.SampleContainer{ + input: []metrics.SampleContainer{ newSample(myGauge, 13, map[string]string{ "tag1": "value1", "tag3": "value3", @@ -128,7 +127,7 @@ func baseTest(t *testing.T, output: "testing.things.my_gauge:13.000000|g", }, { - input: []stats.SampleContainer{ + input: []metrics.SampleContainer{ newSample(myTrend, 14, map[string]string{ "tag1": "value1", "tag3": "value3", @@ -137,7 +136,7 @@ func baseTest(t *testing.T, output: "testing.things.my_trend:14.000000|ms", }, { - input: []stats.SampleContainer{ + input: []metrics.SampleContainer{ newSample(myRate, 15, map[string]string{ "tag1": "value1", "tag3": "value3", @@ -146,7 +145,7 @@ func baseTest(t *testing.T, output: "testing.things.my_rate:15|c", }, { - input: []stats.SampleContainer{ + input: []metrics.SampleContainer{ newSample(myCheck, 16, map[string]string{ "tag1": "value1", "tag3": "value3", diff --git a/output/types.go b/output/types.go index 42227e9e8f1..dce2da702aa 100644 --- a/output/types.go +++ b/output/types.go @@ -33,7 +33,6 @@ import ( "go.k6.io/k6/lib" "go.k6.io/k6/metrics" - "go.k6.io/k6/stats" ) // Params contains all possible constructor parameters an output may need. @@ -74,7 +73,7 @@ type Output interface { // method is never called concurrently, so do not do anything blocking here // that might take a long time. Preferably, just use the SampleBuffer or // something like it to buffer metrics until they are flushed. - AddMetricSamples(samples []stats.SampleContainer) + AddMetricSamples(samples []metrics.SampleContainer) // Flush all remaining metrics and finalize the test run. Stop() error @@ -84,7 +83,7 @@ type Output interface { // thresholds before it can be started. type WithThresholds interface { Output - SetThresholds(map[string]stats.Thresholds) + SetThresholds(map[string]metrics.Thresholds) } // WithTestRunStop is an output that can stop the Engine mid-test, interrupting