From 415d68ecba9e897e06c756ce6b4679dda4a1ab03 Mon Sep 17 00:00:00 2001 From: Daniel Turner Date: Mon, 26 Nov 2018 21:13:28 -0800 Subject: [PATCH 01/18] Replace measure with distribution --- lib/kubernetes-deploy/deploy_task.rb | 6 +++--- lib/kubernetes-deploy/kubernetes_resource.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/kubernetes-deploy/deploy_task.rb b/lib/kubernetes-deploy/deploy_task.rb index 22ab0e1ca..fcf60ece9 100644 --- a/lib/kubernetes-deploy/deploy_task.rb +++ b/lib/kubernetes-deploy/deploy_task.rb @@ -162,14 +162,14 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) ::StatsD.event("Deployment of #{@namespace} succeeded", "Successfully deployed all #{@namespace} resources to #{@context}", alert_type: "success", tags: statsd_tags << "status:success") - ::StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success") + ::StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success") @logger.print_summary(:success) rescue DeploymentTimeoutError @logger.print_summary(:timed_out) ::StatsD.event("Deployment of #{@namespace} timed out", "One or more #{@namespace} resources failed to deploy to #{@context} in time", alert_type: "error", tags: statsd_tags << "status:timeout") - ::StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout") + ::StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout") raise rescue FatalDeploymentError => error @logger.summary.add_action(error.message) if error.message != error.class.to_s @@ -177,7 +177,7 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) ::StatsD.event("Deployment of #{@namespace} failed", "One or more #{@namespace} resources failed to deploy to #{@context}", alert_type: "error", tags: statsd_tags << "status:failed") - ::StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed") + ::StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed") raise end diff --git a/lib/kubernetes-deploy/kubernetes_resource.rb b/lib/kubernetes-deploy/kubernetes_resource.rb index 95bef8df9..50d2f328c 100644 --- a/lib/kubernetes-deploy/kubernetes_resource.rb +++ b/lib/kubernetes-deploy/kubernetes_resource.rb @@ -293,7 +293,7 @@ def pretty_status def report_status_to_statsd(watch_time) unless @statsd_report_done - ::StatsD.measure('resource.duration', watch_time, tags: statsd_tags) + ::StatsD.distribution('resource.duration', watch_time, tags: statsd_tags) @statsd_report_done = true end end From 4074d6ac55fa321cc460445ae613b68e7c87e408 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 26 Nov 2018 15:13:16 -0500 Subject: [PATCH 02/18] Wrapped statsd --- lib/kubernetes-deploy/deploy_task.rb | 17 +++++++------ lib/kubernetes-deploy/kubernetes_resource.rb | 2 +- lib/kubernetes-deploy/restart_task.rb | 6 ++--- lib/kubernetes-deploy/runner_task.rb | 6 ++--- lib/kubernetes-deploy/statsd.rb | 25 ++++++++++++++----- .../serial_task_run_test.rb | 5 +++- test/integration/kubernetes_deploy_test.rb | 21 ++++++++++++++++ test/unit/kubernetes-deploy/statsd_test.rb | 2 +- 8 files changed, 62 insertions(+), 22 deletions(-) diff --git a/lib/kubernetes-deploy/deploy_task.rb b/lib/kubernetes-deploy/deploy_task.rb index 40900b94d..12c8d2f51 100644 --- a/lib/kubernetes-deploy/deploy_task.rb +++ b/lib/kubernetes-deploy/deploy_task.rb @@ -135,6 +135,7 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) if deploy_has_priority_resources?(resources) @logger.phase_heading("Predeploying priority resources") predeploy_priority_resources(resources) + StatsD.measure('priority_resources.duration', StatsD.duration(start_priority_resource), tags: statsd_tags) end @logger.phase_heading("Deploying all resources") @@ -143,7 +144,9 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) end if verify_result - deploy_all_resources(resources, prune: prune, verify: true) + start_normal_resource = Time.now.utc + deploy_resources(resources, prune: prune, verify: true) + StatsD.measure('normal_resources.duration', StatsD.duration(start_normal_resource), tags: statsd_tags) failed_resources = resources.reject(&:deploy_succeeded?) success = failed_resources.empty? if !success && failed_resources.all?(&:deploy_timed_out?) @@ -159,25 +162,25 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) MSG @logger.summary.add_paragraph(ColorizedString.new(warning).yellow) end - ::StatsD.event("Deployment of #{@namespace} succeeded", + StatsD.event("Deployment of #{@namespace} succeeded", "Successfully deployed all #{@namespace} resources to #{@context}", alert_type: "success", tags: statsd_tags << "status:success") - ::StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success") + StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success") @logger.print_summary(:success) rescue DeploymentTimeoutError @logger.print_summary(:timed_out) - ::StatsD.event("Deployment of #{@namespace} timed out", + StatsD.event("Deployment of #{@namespace} timed out", "One or more #{@namespace} resources failed to deploy to #{@context} in time", alert_type: "error", tags: statsd_tags << "status:timeout") - ::StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout") + StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout") raise rescue FatalDeploymentError => error @logger.summary.add_action(error.message) if error.message != error.class.to_s @logger.print_summary(:failure) - ::StatsD.event("Deployment of #{@namespace} failed", + StatsD.event("Deployment of #{@namespace} failed", "One or more #{@namespace} resources failed to deploy to #{@context}", alert_type: "error", tags: statsd_tags << "status:failed") - ::StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed") + StatsD.measure('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed") raise end diff --git a/lib/kubernetes-deploy/kubernetes_resource.rb b/lib/kubernetes-deploy/kubernetes_resource.rb index f1784974c..ecab66785 100644 --- a/lib/kubernetes-deploy/kubernetes_resource.rb +++ b/lib/kubernetes-deploy/kubernetes_resource.rb @@ -293,7 +293,7 @@ def pretty_status def report_status_to_statsd(watch_time) unless @statsd_report_done - ::StatsD.measure('resource.duration', watch_time, tags: statsd_tags) + StatsD.measure('resource.duration', watch_time, tags: statsd_tags) @statsd_report_done = true end end diff --git a/lib/kubernetes-deploy/restart_task.rb b/lib/kubernetes-deploy/restart_task.rb index c59af25b7..0861e36c1 100644 --- a/lib/kubernetes-deploy/restart_task.rb +++ b/lib/kubernetes-deploy/restart_task.rb @@ -57,14 +57,14 @@ def perform!(deployments_names = nil) raise DeploymentTimeoutError end raise FatalDeploymentError unless success - ::StatsD.distribution('restart.duration', StatsD.duration(start), tags: tags('success', deployments)) + StatsD.distribution('restart.duration', StatsD.duration(start), tags: tags('success', deployments)) @logger.print_summary(:success) rescue DeploymentTimeoutError - ::StatsD.distribution('restart.duration', StatsD.duration(start), tags: tags('timeout', deployments)) + StatsD.distribution('restart.duration', StatsD.duration(start), tags: tags('timeout', deployments)) @logger.print_summary(:timed_out) raise rescue FatalDeploymentError => error - ::StatsD.distribution('restart.duration', StatsD.duration(start), tags: tags('failure', deployments)) + StatsD.distribution('restart.duration', StatsD.duration(start), tags: tags('failure', deployments)) @logger.summary.add_action(error.message) if error.message != error.class.to_s @logger.print_summary(:failure) raise diff --git a/lib/kubernetes-deploy/runner_task.rb b/lib/kubernetes-deploy/runner_task.rb index 36bc2ed3b..cae06ad67 100644 --- a/lib/kubernetes-deploy/runner_task.rb +++ b/lib/kubernetes-deploy/runner_task.rb @@ -45,14 +45,14 @@ def run!(task_template:, entrypoint:, args:, env_vars: [], verify_result: true) else record_status_once(pod) end - ::StatsD.distribution('task_runner.duration', StatsD.duration(start), tags: statsd_tags('success')) + StatsD.distribution('task_runner.duration', StatsD.duration(start), tags: statsd_tags('success')) @logger.print_summary(:success) rescue DeploymentTimeoutError - ::StatsD.distribution('task_runner.duration', StatsD.duration(start), tags: statsd_tags('timeout')) + StatsD.distribution('task_runner.duration', StatsD.duration(start), tags: statsd_tags('timeout')) @logger.print_summary(:timed_out) raise rescue FatalDeploymentError - ::StatsD.distribution('task_runner.duration', StatsD.duration(start), tags: statsd_tags('failure')) + StatsD.distribution('task_runner.duration', StatsD.duration(start), tags: statsd_tags('failure')) @logger.print_summary(:failure) raise end diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index 9ccfe8b0b..d4d284dad 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -4,23 +4,36 @@ module KubernetesDeploy class StatsD + extend ::StatsD def self.duration(start_time) (Time.now.utc - start_time).round(1) end def self.build - ::StatsD.default_sample_rate = 1.0 - ::StatsD.prefix = "KubernetesDeploy" + self.default_sample_rate = 1.0 + self.prefix = "KubernetesDeploy" if ENV['STATSD_DEV'].present? - ::StatsD.backend = ::StatsD::Instrument::Backends::LoggerBackend.new(Logger.new($stderr)) + self.backend = ::StatsD::Instrument::Backends::LoggerBackend.new(Logger.new($stderr)) elsif ENV['STATSD_ADDR'].present? statsd_impl = ENV['STATSD_IMPLEMENTATION'].present? ? ENV['STATSD_IMPLEMENTATION'] : "datadog" - ::StatsD.backend = ::StatsD::Instrument::Backends::UDPBackend.new(ENV['STATSD_ADDR'], statsd_impl) + self.backend = ::StatsD::Instrument::Backends::UDPBackend.new(ENV['STATSD_ADDR'], statsd_impl) else - ::StatsD.backend = ::StatsD::Instrument::Backends::NullBackend.new + self.backend = ::StatsD::Instrument::Backends::NullBackend.new end - ::StatsD.backend + end + + def self.capture_statsd_calls(&block) + mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new + old_backend, self.backend = self.backend, mock_backend + block.call + mock_backend.collected_metrics + ensure + if old_backend.kind_of?(::StatsD::Instrument::Backends::CaptureBackend) + old_backend.collected_metrics.concat(mock_backend.collected_metrics) + end + + self.backend = old_backend end module MeasureMethods diff --git a/test/integration-serial/serial_task_run_test.rb b/test/integration-serial/serial_task_run_test.rb index ea95ea58d..2918f7e38 100644 --- a/test/integration-serial/serial_task_run_test.rb +++ b/test/integration-serial/serial_task_run_test.rb @@ -29,12 +29,13 @@ def test_run_without_verify_result_fails_if_pod_was_not_created ], in_order: true) end - # Run statsd tests in serial because capture_statsd_calls modifies global state in a way + # Run statsd tests in serial because KubernetesDeploy::StatsD.capture_statsd_calls modifies global state in a way # that makes capturing metrics across parrallel runs unreliable def test_failure_statsd_metric_emitted bad_ns = "missing" task_runner = build_task_runner(ns: bad_ns) + result = false metrics = capture_statsd_calls do result = task_runner.run(run_params) assert_task_run_failure(result) @@ -52,6 +53,7 @@ def test_success_statsd_metric_emitted deploy_task_template task_runner = build_task_runner + result = false metrics = capture_statsd_calls do result = task_runner.run(run_params.merge(verify_result: false)) assert_task_run_success(result) @@ -69,6 +71,7 @@ def test_timedout_statsd_metric_emitted deploy_task_template task_runner = build_task_runner(max_watch_seconds: 0) + result = false metrics = capture_statsd_calls do result = task_runner.run(run_params.merge(args: ["sleep 5"])) assert_task_run_failure(result, :timed_out) diff --git a/test/integration/kubernetes_deploy_test.rb b/test/integration/kubernetes_deploy_test.rb index cb6148230..3f49cb48c 100644 --- a/test/integration/kubernetes_deploy_test.rb +++ b/test/integration/kubernetes_deploy_test.rb @@ -1029,6 +1029,27 @@ def test_friendly_error_on_misidentified_erb_file ], in_order: true) end + def test_adds_namespace_labels_to_statsd_tags + desired_tags = %W(context:#{KubeclientHelper::TEST_CONTEXT} namespace:#{@namespace} foo:bar) + hello_cloud = FixtureSetAssertions::HelloCloud.new(@namespace) + kubeclient.patch_namespace(hello_cloud.namespace, metadata: { labels: { foo: 'bar' } }) + metrics = KubernetesDeploy::StatsD.capture_statsd_calls do + assert_deploy_success deploy_fixtures("hello-cloud", subset: ["configmap-data.yml"]) + end + + # We can't ensure that all the metrics we grab are from this specific test because they are running in parallel + metrics = metrics.select { |m| m.tags.include? "namespace:#{@namespace}" } + assert_equal 5, metrics.count + + event_metrics = metrics.find_all { |m| m.type == :_e } + assert event_metrics.any? + assert_equal 1, event_metrics.count + + metrics.each do |metric| + assert_empty desired_tags - metric.tags + end + end + def test_raise_on_yaml_missing_kind result = deploy_fixtures("invalid-resources", subset: ["missing_kind.yml"]) assert_deploy_failure(result) diff --git a/test/unit/kubernetes-deploy/statsd_test.rb b/test/unit/kubernetes-deploy/statsd_test.rb index 99cd7d011..d5bf3e8df 100644 --- a/test/unit/kubernetes-deploy/statsd_test.rb +++ b/test/unit/kubernetes-deploy/statsd_test.rb @@ -40,7 +40,7 @@ def test_build_when_statsd_addr_env_present_but_statsd_implementation_is_not KubernetesDeploy::StatsD.build - assert_equal :datadog, StatsD.backend.implementation + assert_equal :datadog, KubernetesDeploy::StatsD.backend.implementation ensure ENV['STATSD_ADDR'] = original_addr ENV['STATSD_IMPLEMENTATION'] = original_impl From 57f9bfc6d93612d92f0ff8703b7f90afd8b4ccc8 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 08:01:53 -0500 Subject: [PATCH 03/18] Move capture_statsd_calls to test helper --- lib/kubernetes-deploy/statsd.rb | 47 ------------------- test/helpers/statsd_helper.rb | 17 +++++++ .../serial_task_run_test.rb | 2 +- test/integration/kubernetes_deploy_test.rb | 2 +- 4 files changed, 19 insertions(+), 49 deletions(-) create mode 100644 test/helpers/statsd_helper.rb diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index d4d284dad..af1ff218c 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -22,52 +22,5 @@ def self.build self.backend = ::StatsD::Instrument::Backends::NullBackend.new end end - - def self.capture_statsd_calls(&block) - mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new - old_backend, self.backend = self.backend, mock_backend - block.call - mock_backend.collected_metrics - ensure - if old_backend.kind_of?(::StatsD::Instrument::Backends::CaptureBackend) - old_backend.collected_metrics.concat(mock_backend.collected_metrics) - end - - self.backend = old_backend - end - - module MeasureMethods - def measure_method(method_name, metric = nil) - unless method_defined?(method_name) || private_method_defined?(method_name) - raise NotImplementedError, "Cannot instrument undefined method #{method_name}" - end - - unless const_defined?("InstrumentationProxy") - const_set("InstrumentationProxy", Module.new) - should_prepend = true - end - - metric ||= "#{method_name}.duration" - self::InstrumentationProxy.send(:define_method, method_name) do |*args, &block| - begin - start_time = Time.now.utc - super(*args, &block) - rescue - error = true - raise - ensure - dynamic_tags = send(:statsd_tags) if respond_to?(:statsd_tags, true) - dynamic_tags ||= {} - if error - dynamic_tags[:error] = error if dynamic_tags.is_a?(Hash) - dynamic_tags << "error:#{error}" if dynamic_tags.is_a?(Array) - end - ::StatsD.distribution(metric, KubernetesDeploy::StatsD.duration(start_time), tags: dynamic_tags) - end - end - - prepend(self::InstrumentationProxy) if should_prepend - end - end end end diff --git a/test/helpers/statsd_helper.rb b/test/helpers/statsd_helper.rb new file mode 100644 index 000000000..5c0ad8b9b --- /dev/null +++ b/test/helpers/statsd_helper.rb @@ -0,0 +1,17 @@ +module StatsDHelper + extend self + + def capture_statsd_calls(&block) + binding.pry + mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new + old_backend, KubernetesDeploy::StatsD.backend = KubernetesDeploy::StatsD.backend, mock_backend + block.call + mock_backend.collected_metrics + ensure + if old_backend.kind_of?(::StatsD::Instrument::Backends::CaptureBackend) + old_backend.collected_metrics.concat(mock_backend.collected_metrics) + end + + KubernetesDeploy::StatsD.backend = old_backend + end +end \ No newline at end of file diff --git a/test/integration-serial/serial_task_run_test.rb b/test/integration-serial/serial_task_run_test.rb index 2918f7e38..c1690c402 100644 --- a/test/integration-serial/serial_task_run_test.rb +++ b/test/integration-serial/serial_task_run_test.rb @@ -29,7 +29,7 @@ def test_run_without_verify_result_fails_if_pod_was_not_created ], in_order: true) end - # Run statsd tests in serial because KubernetesDeploy::StatsD.capture_statsd_calls modifies global state in a way + # Run statsd tests in serial because StatsDHelper.capture_statsd_calls modifies global state in a way # that makes capturing metrics across parrallel runs unreliable def test_failure_statsd_metric_emitted bad_ns = "missing" diff --git a/test/integration/kubernetes_deploy_test.rb b/test/integration/kubernetes_deploy_test.rb index 3f49cb48c..0f733ea05 100644 --- a/test/integration/kubernetes_deploy_test.rb +++ b/test/integration/kubernetes_deploy_test.rb @@ -1033,7 +1033,7 @@ def test_adds_namespace_labels_to_statsd_tags desired_tags = %W(context:#{KubeclientHelper::TEST_CONTEXT} namespace:#{@namespace} foo:bar) hello_cloud = FixtureSetAssertions::HelloCloud.new(@namespace) kubeclient.patch_namespace(hello_cloud.namespace, metadata: { labels: { foo: 'bar' } }) - metrics = KubernetesDeploy::StatsD.capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do assert_deploy_success deploy_fixtures("hello-cloud", subset: ["configmap-data.yml"]) end From cfa0080e323fe8b04a8af8fd8e330a1ea97dff37 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 08:04:37 -0500 Subject: [PATCH 04/18] doi, remove pry --- test/helpers/statsd_helper.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/helpers/statsd_helper.rb b/test/helpers/statsd_helper.rb index 5c0ad8b9b..feda6b593 100644 --- a/test/helpers/statsd_helper.rb +++ b/test/helpers/statsd_helper.rb @@ -1,8 +1,7 @@ module StatsDHelper extend self - + def capture_statsd_calls(&block) - binding.pry mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new old_backend, KubernetesDeploy::StatsD.backend = KubernetesDeploy::StatsD.backend, mock_backend block.call @@ -11,7 +10,6 @@ def capture_statsd_calls(&block) if old_backend.kind_of?(::StatsD::Instrument::Backends::CaptureBackend) old_backend.collected_metrics.concat(mock_backend.collected_metrics) end - KubernetesDeploy::StatsD.backend = old_backend end -end \ No newline at end of file +end From 3d11b1ec9cc559221a2edd9bc3f76cf1d8c649b2 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 08:53:26 -0500 Subject: [PATCH 05/18] add test --- test/unit/kubernetes-deploy/statsd_test.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/unit/kubernetes-deploy/statsd_test.rb b/test/unit/kubernetes-deploy/statsd_test.rb index d5bf3e8df..4374a4311 100644 --- a/test/unit/kubernetes-deploy/statsd_test.rb +++ b/test/unit/kubernetes-deploy/statsd_test.rb @@ -109,5 +109,12 @@ def test_measure_method_that_raises_with_array_tags assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" assert_equal "KubernetesDeploy.measured_method_raises.duration", metrics.first.name assert_equal ["test:true", "error:true"], metrics.first.tags + def test_kubernetes_statsd_does_not_override_global_config + KubernetesDeploy::StatsD.build + ::StatsD.prefix = "test" + ::StatsD.default_sample_rate = 2.0 + refute_equal KubernetesDeploy::StatsD.prefix, ::StatsD.prefix + refute_equal KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate + refute_equal KubernetesDeploy::StatsD.backend, ::StatsD.backend end end From 042dd727d1dc31baa1adfb10aea92671d75f1c1e Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 09:08:03 -0500 Subject: [PATCH 06/18] policial --- test/helpers/statsd_helper.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/helpers/statsd_helper.rb b/test/helpers/statsd_helper.rb index feda6b593..74dc94d6f 100644 --- a/test/helpers/statsd_helper.rb +++ b/test/helpers/statsd_helper.rb @@ -1,13 +1,17 @@ +# frozen_string_literal: true module StatsDHelper extend self def capture_statsd_calls(&block) mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new - old_backend, KubernetesDeploy::StatsD.backend = KubernetesDeploy::StatsD.backend, mock_backend - block.call + old_backend = KubernetesDeploy::StatsD.backend + KubernetesDeploy::StatsD.backend = mock_backend + + yield + mock_backend.collected_metrics ensure - if old_backend.kind_of?(::StatsD::Instrument::Backends::CaptureBackend) + if old_backend.is_a?(::StatsD::Instrument::Backends::CaptureBackend) old_backend.collected_metrics.concat(mock_backend.collected_metrics) end KubernetesDeploy::StatsD.backend = old_backend From dc5dbec12a03ed9563c98fc6e55eed0bfa4665c6 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 11:13:35 -0500 Subject: [PATCH 07/18] stash --- lib/kubernetes-deploy/kubectl.rb | 2 +- lib/kubernetes-deploy/statsd.rb | 35 +++++++ lib/kubernetes-deploy/sync_mediator.rb | 91 +++++++++++++++++++ test/helpers/statsd_helper.rb | 2 +- test/integration-serial/serial_deploy_test.rb | 4 +- .../serial_task_run_test.rb | 2 +- test/test_helper.rb | 1 + test/unit/kubernetes-deploy/kubectl_test.rb | 2 +- test/unit/kubernetes-deploy/statsd_test.rb | 24 ++++- 9 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 lib/kubernetes-deploy/sync_mediator.rb diff --git a/lib/kubernetes-deploy/kubectl.rb b/lib/kubernetes-deploy/kubectl.rb index ac36626e6..44bf38ef2 100644 --- a/lib/kubernetes-deploy/kubectl.rb +++ b/lib/kubernetes-deploy/kubectl.rb @@ -45,7 +45,7 @@ def run(*args, log_failure: nil, use_context: true, use_namespace: true, raise_i raise(ResourceNotFoundError, err) if raise_if_not_found else @logger.debug("Kubectl err: #{err}") unless output_is_sensitive? - ::StatsD.increment('kubectl.error', 1, tags: { context: @context, namespace: @namespace, cmd: args[1] }) + StatsD.increment('kubectl.error', 1, tags: { context: @context, namespace: @namespace, cmd: args[1] }) end sleep retry_delay(attempt) unless attempt == attempts end diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index af1ff218c..c354c0438 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -22,5 +22,40 @@ def self.build self.backend = ::StatsD::Instrument::Backends::NullBackend.new end end + + module MeasureMethods + def measure_method(method_name, metric = nil) + unless method_defined?(method_name) || private_method_defined?(method_name) + raise NotImplementedError, "Cannot instrument undefined method #{method_name}" + end + + unless const_defined?("InstrumentationProxy") + const_set("InstrumentationProxy", Module.new) + should_prepend = true + end + + metric ||= "#{method_name}.duration" + self::InstrumentationProxy.send(:define_method, method_name) do |*args, &block| + begin + start_time = Time.now.utc + super(*args, &block) + rescue + error = true + raise + ensure + dynamic_tags = send(:statsd_tags) if respond_to?(:statsd_tags, true) + dynamic_tags ||= {} + if error + dynamic_tags[:error] = error if dynamic_tags.is_a?(Hash) + dynamic_tags << "error:#{error}" if dynamic_tags.is_a?(Array) + end + + StatsD.distribution(metric, StatsD.duration(start_time), tags: dynamic_tags) + end + end + + prepend(self::InstrumentationProxy) if should_prepend + end + end end end diff --git a/lib/kubernetes-deploy/sync_mediator.rb b/lib/kubernetes-deploy/sync_mediator.rb new file mode 100644 index 000000000..0c905f369 --- /dev/null +++ b/lib/kubernetes-deploy/sync_mediator.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true +module KubernetesDeploy + class SyncMediator + extend KubernetesDeploy::StatsD::MeasureMethods + + def initialize(namespace:, context:, logger:) + @namespace = namespace + @context = context + @logger = logger + clear_cache + end + + def get_instance(kind, resource_name, raise_if_not_found: false) + unless @cache.key?(kind) + StatsD.increment("sync.cache_miss", tags: statsd_tags.merge(type: kind)) + @logger.debug("Could not use the cache to fetch #{kind} instance #{resource_name}. "\ + "Cached kinds: #{@cache.keys.join(',')}") + return request_instance(kind, resource_name, raise_if_not_found: raise_if_not_found) + end + + cached_instance = @cache[kind].fetch(resource_name, {}) + if cached_instance.blank? && raise_if_not_found + raise KubernetesDeploy::Kubectl::ResourceNotFoundError, "Resource does not exist (used cache for kind #{kind})" + end + cached_instance + end + + def get_all(kind, selector = nil) + unless @cache.key?(kind) + StatsD.increment("sync.cache_miss", tags: statsd_tags.merge(type: kind)) + @logger.debug("Kind #{kind} not cached. Cached kinds: #{@cache.keys.join(',')}") + fetch_by_kind(kind) + end + instances = @cache.fetch(kind, {}).values + return instances unless selector + + instances.select do |r| + labels = r.dig("metadata", "labels") || {} + labels >= selector + end + end + + def sync(resources) + clear_cache + + dependencies = resources.map(&:class).uniq.flat_map do |c| + c::SYNC_DEPENDENCIES if c.const_defined?('SYNC_DEPENDENCIES') + end + kinds = (resources.map(&:kubectl_resource_type) + dependencies).compact.uniq + @logger.debug("Populating cache for kinds: #{kinds.join(', ')}") + kinds.each { |kind| fetch_by_kind(kind, attempts: 5) } + + KubernetesDeploy::Concurrency.split_across_threads(resources) do |r| + r.sync(dup) + end + end + measure_method(:sync) + + def kubectl + @kubectl ||= Kubectl.new(namespace: @namespace, context: @context, logger: @logger, log_failure_by_default: false) + end + + private + + def statsd_tags + { namespace: @namespace, context: @context } + end + + def clear_cache + @cache = {} + end + + def request_instance(kind, iname, raise_if_not_found:) + raw_json, _err, st = kubectl.run("get", kind, iname, "-a", "--output=json", + raise_if_not_found: raise_if_not_found) + st.success? ? JSON.parse(raw_json) : {} + end + + def fetch_by_kind(kind, attempts: 1) + raw_json, _, st = kubectl.run("get", kind, "-a", "--output=json", attempts: attempts) + return unless st.success? + + instances = {} + JSON.parse(raw_json)["items"].each do |resource| + resource_name = resource.dig("metadata", "name") + instances[resource_name] = resource + end + @cache[kind] = instances + end + end +end diff --git a/test/helpers/statsd_helper.rb b/test/helpers/statsd_helper.rb index 74dc94d6f..ec2e914c4 100644 --- a/test/helpers/statsd_helper.rb +++ b/test/helpers/statsd_helper.rb @@ -7,7 +7,7 @@ def capture_statsd_calls(&block) old_backend = KubernetesDeploy::StatsD.backend KubernetesDeploy::StatsD.backend = mock_backend - yield + block.call mock_backend.collected_metrics ensure diff --git a/test/integration-serial/serial_deploy_test.rb b/test/integration-serial/serial_deploy_test.rb index b654af21f..dbfd01114 100644 --- a/test/integration-serial/serial_deploy_test.rb +++ b/test/integration-serial/serial_deploy_test.rb @@ -185,7 +185,7 @@ def test_crd_pruning def test_stage_related_metrics_include_custom_tags_from_namespace hello_cloud = FixtureSetAssertions::HelloCloud.new(@namespace) kubeclient.patch_namespace(hello_cloud.namespace, metadata: { labels: { foo: 'bar' } }) - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do assert_deploy_success deploy_fixtures("hello-cloud", subset: ["configmap-data.yml"], wait: false) end @@ -207,7 +207,7 @@ def test_stage_related_metrics_include_custom_tags_from_namespace end def test_all_expected_statsd_metrics_emitted_with_essential_tags - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do result = deploy_fixtures('hello-cloud', subset: ['configmap-data.yml'], wait: false) assert_deploy_success(result) end diff --git a/test/integration-serial/serial_task_run_test.rb b/test/integration-serial/serial_task_run_test.rb index c1690c402..c849a5653 100644 --- a/test/integration-serial/serial_task_run_test.rb +++ b/test/integration-serial/serial_task_run_test.rb @@ -29,7 +29,7 @@ def test_run_without_verify_result_fails_if_pod_was_not_created ], in_order: true) end - # Run statsd tests in serial because StatsDHelper.capture_statsd_calls modifies global state in a way + # Run statsd tests in serial because StatsDHelper.StatsDHelper.capture_statsd_calls modifies global state in a way # that makes capturing metrics across parrallel runs unreliable def test_failure_statsd_metric_emitted bad_ns = "missing" diff --git a/test/test_helper.rb b/test/test_helper.rb index cb88418f9..c76229f88 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -67,6 +67,7 @@ def run end def setup + KubernetesDeploy::StatsD.build Kubectl.any_instance.expects(:run).never if ban_net_connect? # can't use mocha in Minitest::Test#run configure_logger end diff --git a/test/unit/kubernetes-deploy/kubectl_test.rb b/test/unit/kubernetes-deploy/kubectl_test.rb index c1960848b..f900b83a5 100644 --- a/test/unit/kubernetes-deploy/kubectl_test.rb +++ b/test/unit/kubernetes-deploy/kubectl_test.rb @@ -90,7 +90,7 @@ def test_run_with_multiple_attempts_retries_and_emits_failure_metrics kubectl = build_kubectl kubectl.expects(:retry_delay).returns(0).times(4) - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do _out, _err, st = kubectl.run("get", "pods", attempts: 5) refute_predicate st, :success? end diff --git a/test/unit/kubernetes-deploy/statsd_test.rb b/test/unit/kubernetes-deploy/statsd_test.rb index 4374a4311..1894f9191 100644 --- a/test/unit/kubernetes-deploy/statsd_test.rb +++ b/test/unit/kubernetes-deploy/statsd_test.rb @@ -26,10 +26,15 @@ def statsd_tags class TestMeasureNoTags extend(KubernetesDeploy::StatsD::MeasureMethods) + def thing_to_measure; end measure_method :thing_to_measure end + def setup + KubernetesDeploy::StatsD.build + end + def test_build_when_statsd_addr_env_present_but_statsd_implementation_is_not original_addr = ENV['STATSD_ADDR'] ENV['STATSD_ADDR'] = '127.0.0.1' @@ -48,6 +53,15 @@ def test_build_when_statsd_addr_env_present_but_statsd_implementation_is_not KubernetesDeploy::StatsD.build end + def test_kubernetes_statsd_does_not_override_global_config + KubernetesDeploy::StatsD.build + ::StatsD.prefix = "test" + ::StatsD.default_sample_rate = 2.0 + refute_equal KubernetesDeploy::StatsD.prefix, ::StatsD.prefix + refute_equal KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate + refute_equal KubernetesDeploy::StatsD.backend, ::StatsD.backend + end + def test_measuring_non_existent_method_raises assert_raises_message(NotImplementedError, "Cannot instrument undefined method bogus_method") do TestMeasureClass.measure_method(:bogus_method) @@ -59,7 +73,7 @@ def test_measure_method_does_not_change_the_return_value end def test_measure_method_uses_expected_name_and_tags - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do TestMeasureClass.new.thing_to_measure end assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" @@ -68,7 +82,7 @@ def test_measure_method_uses_expected_name_and_tags end def test_measure_method_with_custom_metric_name - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do TestMeasureClass.new.measure_with_custom_metric end assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" @@ -77,7 +91,7 @@ def test_measure_method_with_custom_metric_name end def test_measure_method_with_statsd_tags_undefined - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do TestMeasureNoTags.new.thing_to_measure end assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" @@ -86,7 +100,7 @@ def test_measure_method_with_statsd_tags_undefined end def test_measure_method_that_raises_with_hash_tags - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do tester = TestMeasureClass.new tester.expects(:statsd_tags).returns(test: true) assert_raises(ArgumentError) do @@ -99,7 +113,7 @@ def test_measure_method_that_raises_with_hash_tags end def test_measure_method_that_raises_with_array_tags - metrics = capture_statsd_calls do + metrics = StatsDHelper.capture_statsd_calls do tester = TestMeasureClass.new tester.expects(:statsd_tags).returns(["test:true"]) assert_raises(ArgumentError) do From 3ed6e17acc7c812bae0b4d56a437619c96344992 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 14:38:02 -0500 Subject: [PATCH 08/18] working --- lib/kubernetes-deploy/kubectl.rb | 2 +- lib/kubernetes-deploy/statsd.rb | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/kubernetes-deploy/kubectl.rb b/lib/kubernetes-deploy/kubectl.rb index 44bf38ef2..674869648 100644 --- a/lib/kubernetes-deploy/kubectl.rb +++ b/lib/kubernetes-deploy/kubectl.rb @@ -45,7 +45,7 @@ def run(*args, log_failure: nil, use_context: true, use_namespace: true, raise_i raise(ResourceNotFoundError, err) if raise_if_not_found else @logger.debug("Kubectl err: #{err}") unless output_is_sensitive? - StatsD.increment('kubectl.error', 1, tags: { context: @context, namespace: @namespace, cmd: args[1] }) + StatsD.increment('kubectl.error', 1, tags: { context: @context, namespace: @namespace, cmd: args[1] }, prefix: "KubernetesDeploy") end sleep retry_delay(attempt) unless attempt == attempts end diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index c354c0438..6490333b8 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -5,6 +5,7 @@ module KubernetesDeploy class StatsD extend ::StatsD + def self.duration(start_time) (Time.now.utc - start_time).round(1) end @@ -50,7 +51,7 @@ def measure_method(method_name, metric = nil) dynamic_tags << "error:#{error}" if dynamic_tags.is_a?(Array) end - StatsD.distribution(metric, StatsD.duration(start_time), tags: dynamic_tags) + StatsD.distribution(metric, KubernetesDeploy::StatsD.duration(start_time), tags: dynamic_tags, prefix: "KubernetesDeploy") end end From ecfad7e3927c59cc36a82f389e006b29089b3a1c Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Tue, 27 Nov 2018 15:35:56 -0500 Subject: [PATCH 09/18] police --- lib/kubernetes-deploy/kubectl.rb | 7 ++++++- lib/kubernetes-deploy/statsd.rb | 7 ++++++- test/helpers/statsd_helper.rb | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/kubernetes-deploy/kubectl.rb b/lib/kubernetes-deploy/kubectl.rb index 674869648..f7d1ed8e2 100644 --- a/lib/kubernetes-deploy/kubectl.rb +++ b/lib/kubernetes-deploy/kubectl.rb @@ -45,7 +45,12 @@ def run(*args, log_failure: nil, use_context: true, use_namespace: true, raise_i raise(ResourceNotFoundError, err) if raise_if_not_found else @logger.debug("Kubectl err: #{err}") unless output_is_sensitive? - StatsD.increment('kubectl.error', 1, tags: { context: @context, namespace: @namespace, cmd: args[1] }, prefix: "KubernetesDeploy") + StatsD.increment( + 'kubectl.error', + 1, + tags: { context: @context, namespace: @namespace, cmd: args[1] }, + prefix: "KubernetesDeploy" + ) end sleep retry_delay(attempt) unless attempt == attempts end diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index 6490333b8..d202a2369 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -51,7 +51,12 @@ def measure_method(method_name, metric = nil) dynamic_tags << "error:#{error}" if dynamic_tags.is_a?(Array) end - StatsD.distribution(metric, KubernetesDeploy::StatsD.duration(start_time), tags: dynamic_tags, prefix: "KubernetesDeploy") + StatsD.distribution( + metric, + KubernetesDeploy::StatsD.duration(start_time), + tags: dynamic_tags, + prefix: "KubernetesDeploy" + ) end end diff --git a/test/helpers/statsd_helper.rb b/test/helpers/statsd_helper.rb index ec2e914c4..71e3369b2 100644 --- a/test/helpers/statsd_helper.rb +++ b/test/helpers/statsd_helper.rb @@ -2,12 +2,12 @@ module StatsDHelper extend self - def capture_statsd_calls(&block) + def capture_statsd_calls mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new old_backend = KubernetesDeploy::StatsD.backend KubernetesDeploy::StatsD.backend = mock_backend - block.call + yield if block_given? mock_backend.collected_metrics ensure From e9eac5462be3fa78a158f2167f45ba14c650ada5 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Wed, 28 Nov 2018 10:23:22 -0500 Subject: [PATCH 10/18] Rebase + PR comments remove accidental file, fix line length Extract prefix to const simpler scoping for StatsD.build call Don't need to build StatsD in test_helper include StatsDHelper, not class method policial rebase fix rebase fix rebase fix centralize adding prefix more fix more fix --- lib/kubernetes-deploy.rb | 2 +- lib/kubernetes-deploy/deploy_task.rb | 5 +- lib/kubernetes-deploy/kubectl.rb | 7 +- lib/kubernetes-deploy/statsd.rb | 25 ++++- lib/kubernetes-deploy/sync_mediator.rb | 91 ------------------- test/helpers/statsd_helper.rb | 2 - test/integration-serial/serial_deploy_test.rb | 5 +- .../serial_task_run_test.rb | 6 +- test/integration/kubernetes_deploy_test.rb | 21 ----- test/test_helper.rb | 1 - test/unit/kubernetes-deploy/kubectl_test.rb | 3 +- test/unit/kubernetes-deploy/statsd_test.rb | 31 ++----- 12 files changed, 44 insertions(+), 155 deletions(-) delete mode 100644 lib/kubernetes-deploy/sync_mediator.rb diff --git a/lib/kubernetes-deploy.rb b/lib/kubernetes-deploy.rb index 881108466..255b7d34b 100644 --- a/lib/kubernetes-deploy.rb +++ b/lib/kubernetes-deploy.rb @@ -23,5 +23,5 @@ module KubernetesDeploy MIN_KUBE_VERSION = '1.9.0' - KubernetesDeploy::StatsD.build + StatsD.build end diff --git a/lib/kubernetes-deploy/deploy_task.rb b/lib/kubernetes-deploy/deploy_task.rb index 12c8d2f51..54799705a 100644 --- a/lib/kubernetes-deploy/deploy_task.rb +++ b/lib/kubernetes-deploy/deploy_task.rb @@ -135,7 +135,6 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) if deploy_has_priority_resources?(resources) @logger.phase_heading("Predeploying priority resources") predeploy_priority_resources(resources) - StatsD.measure('priority_resources.duration', StatsD.duration(start_priority_resource), tags: statsd_tags) end @logger.phase_heading("Deploying all resources") @@ -144,9 +143,7 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) end if verify_result - start_normal_resource = Time.now.utc - deploy_resources(resources, prune: prune, verify: true) - StatsD.measure('normal_resources.duration', StatsD.duration(start_normal_resource), tags: statsd_tags) + deploy_all_resources(resources, prune: prune, verify: true) failed_resources = resources.reject(&:deploy_succeeded?) success = failed_resources.empty? if !success && failed_resources.all?(&:deploy_timed_out?) diff --git a/lib/kubernetes-deploy/kubectl.rb b/lib/kubernetes-deploy/kubectl.rb index f7d1ed8e2..44bf38ef2 100644 --- a/lib/kubernetes-deploy/kubectl.rb +++ b/lib/kubernetes-deploy/kubectl.rb @@ -45,12 +45,7 @@ def run(*args, log_failure: nil, use_context: true, use_namespace: true, raise_i raise(ResourceNotFoundError, err) if raise_if_not_found else @logger.debug("Kubectl err: #{err}") unless output_is_sensitive? - StatsD.increment( - 'kubectl.error', - 1, - tags: { context: @context, namespace: @namespace, cmd: args[1] }, - prefix: "KubernetesDeploy" - ) + StatsD.increment('kubectl.error', 1, tags: { context: @context, namespace: @namespace, cmd: args[1] }) end sleep retry_delay(attempt) unless attempt == attempts end diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index d202a2369..91f47d479 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -6,6 +6,8 @@ module KubernetesDeploy class StatsD extend ::StatsD + PREFIX = "KubernetesDeploy" + def self.duration(start_time) (Time.now.utc - start_time).round(1) end @@ -24,6 +26,27 @@ def self.build end end + def self.measure(key, value = nil, *metric_options, &block) + if metric_options && metric_options.first.is_a?(Hash) + metric_options.first[:prefix] = PREFIX + end + super + end + + def self.increment(key, value = 1, *metric_options) + if metric_options && metric_options.first.is_a?(Hash) + metric_options.first[:prefix] = PREFIX + end + super + end + + def self.distribution(key, value=nil, *metric_options, &block) + if metric_options && metric_options.first.is_a?(Hash) + metric_options.first[:prefix] = PREFIX + end + super + end + module MeasureMethods def measure_method(method_name, metric = nil) unless method_defined?(method_name) || private_method_defined?(method_name) @@ -55,7 +78,7 @@ def measure_method(method_name, metric = nil) metric, KubernetesDeploy::StatsD.duration(start_time), tags: dynamic_tags, - prefix: "KubernetesDeploy" + prefix: PREFIX ) end end diff --git a/lib/kubernetes-deploy/sync_mediator.rb b/lib/kubernetes-deploy/sync_mediator.rb deleted file mode 100644 index 0c905f369..000000000 --- a/lib/kubernetes-deploy/sync_mediator.rb +++ /dev/null @@ -1,91 +0,0 @@ -# frozen_string_literal: true -module KubernetesDeploy - class SyncMediator - extend KubernetesDeploy::StatsD::MeasureMethods - - def initialize(namespace:, context:, logger:) - @namespace = namespace - @context = context - @logger = logger - clear_cache - end - - def get_instance(kind, resource_name, raise_if_not_found: false) - unless @cache.key?(kind) - StatsD.increment("sync.cache_miss", tags: statsd_tags.merge(type: kind)) - @logger.debug("Could not use the cache to fetch #{kind} instance #{resource_name}. "\ - "Cached kinds: #{@cache.keys.join(',')}") - return request_instance(kind, resource_name, raise_if_not_found: raise_if_not_found) - end - - cached_instance = @cache[kind].fetch(resource_name, {}) - if cached_instance.blank? && raise_if_not_found - raise KubernetesDeploy::Kubectl::ResourceNotFoundError, "Resource does not exist (used cache for kind #{kind})" - end - cached_instance - end - - def get_all(kind, selector = nil) - unless @cache.key?(kind) - StatsD.increment("sync.cache_miss", tags: statsd_tags.merge(type: kind)) - @logger.debug("Kind #{kind} not cached. Cached kinds: #{@cache.keys.join(',')}") - fetch_by_kind(kind) - end - instances = @cache.fetch(kind, {}).values - return instances unless selector - - instances.select do |r| - labels = r.dig("metadata", "labels") || {} - labels >= selector - end - end - - def sync(resources) - clear_cache - - dependencies = resources.map(&:class).uniq.flat_map do |c| - c::SYNC_DEPENDENCIES if c.const_defined?('SYNC_DEPENDENCIES') - end - kinds = (resources.map(&:kubectl_resource_type) + dependencies).compact.uniq - @logger.debug("Populating cache for kinds: #{kinds.join(', ')}") - kinds.each { |kind| fetch_by_kind(kind, attempts: 5) } - - KubernetesDeploy::Concurrency.split_across_threads(resources) do |r| - r.sync(dup) - end - end - measure_method(:sync) - - def kubectl - @kubectl ||= Kubectl.new(namespace: @namespace, context: @context, logger: @logger, log_failure_by_default: false) - end - - private - - def statsd_tags - { namespace: @namespace, context: @context } - end - - def clear_cache - @cache = {} - end - - def request_instance(kind, iname, raise_if_not_found:) - raw_json, _err, st = kubectl.run("get", kind, iname, "-a", "--output=json", - raise_if_not_found: raise_if_not_found) - st.success? ? JSON.parse(raw_json) : {} - end - - def fetch_by_kind(kind, attempts: 1) - raw_json, _, st = kubectl.run("get", kind, "-a", "--output=json", attempts: attempts) - return unless st.success? - - instances = {} - JSON.parse(raw_json)["items"].each do |resource| - resource_name = resource.dig("metadata", "name") - instances[resource_name] = resource - end - @cache[kind] = instances - end - end -end diff --git a/test/helpers/statsd_helper.rb b/test/helpers/statsd_helper.rb index 71e3369b2..1b891fe5f 100644 --- a/test/helpers/statsd_helper.rb +++ b/test/helpers/statsd_helper.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true module StatsDHelper - extend self - def capture_statsd_calls mock_backend = ::StatsD::Instrument::Backends::CaptureBackend.new old_backend = KubernetesDeploy::StatsD.backend diff --git a/test/integration-serial/serial_deploy_test.rb b/test/integration-serial/serial_deploy_test.rb index dbfd01114..b49422a5a 100644 --- a/test/integration-serial/serial_deploy_test.rb +++ b/test/integration-serial/serial_deploy_test.rb @@ -2,6 +2,7 @@ require 'integration_test_helper' class SerialDeployTest < KubernetesDeploy::IntegrationTest + include StatsDHelper # This cannot be run in parallel because it either stubs a constant or operates in a non-exclusive namespace def test_deploying_to_protected_namespace_with_override_does_not_prune KubernetesDeploy::DeployTask.stub_const(:PROTECTED_NAMESPACES, [@namespace]) do @@ -185,7 +186,7 @@ def test_crd_pruning def test_stage_related_metrics_include_custom_tags_from_namespace hello_cloud = FixtureSetAssertions::HelloCloud.new(@namespace) kubeclient.patch_namespace(hello_cloud.namespace, metadata: { labels: { foo: 'bar' } }) - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do assert_deploy_success deploy_fixtures("hello-cloud", subset: ["configmap-data.yml"], wait: false) end @@ -207,7 +208,7 @@ def test_stage_related_metrics_include_custom_tags_from_namespace end def test_all_expected_statsd_metrics_emitted_with_essential_tags - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do result = deploy_fixtures('hello-cloud', subset: ['configmap-data.yml'], wait: false) assert_deploy_success(result) end diff --git a/test/integration-serial/serial_task_run_test.rb b/test/integration-serial/serial_task_run_test.rb index c849a5653..60cba4d06 100644 --- a/test/integration-serial/serial_task_run_test.rb +++ b/test/integration-serial/serial_task_run_test.rb @@ -3,6 +3,7 @@ class SerialTaskRunTest < KubernetesDeploy::IntegrationTest include TaskRunnerTestHelper + include StatsDHelper # Mocha is not thread-safe: https://github.com/freerange/mocha#thread-safety def test_run_without_verify_result_fails_if_pod_was_not_created @@ -29,13 +30,12 @@ def test_run_without_verify_result_fails_if_pod_was_not_created ], in_order: true) end - # Run statsd tests in serial because StatsDHelper.StatsDHelper.capture_statsd_calls modifies global state in a way + # Run statsd tests in serial because capture_statsd_calls modifies global state in a way # that makes capturing metrics across parrallel runs unreliable def test_failure_statsd_metric_emitted bad_ns = "missing" task_runner = build_task_runner(ns: bad_ns) - result = false metrics = capture_statsd_calls do result = task_runner.run(run_params) assert_task_run_failure(result) @@ -53,7 +53,6 @@ def test_success_statsd_metric_emitted deploy_task_template task_runner = build_task_runner - result = false metrics = capture_statsd_calls do result = task_runner.run(run_params.merge(verify_result: false)) assert_task_run_success(result) @@ -71,7 +70,6 @@ def test_timedout_statsd_metric_emitted deploy_task_template task_runner = build_task_runner(max_watch_seconds: 0) - result = false metrics = capture_statsd_calls do result = task_runner.run(run_params.merge(args: ["sleep 5"])) assert_task_run_failure(result, :timed_out) diff --git a/test/integration/kubernetes_deploy_test.rb b/test/integration/kubernetes_deploy_test.rb index 0f733ea05..cb6148230 100644 --- a/test/integration/kubernetes_deploy_test.rb +++ b/test/integration/kubernetes_deploy_test.rb @@ -1029,27 +1029,6 @@ def test_friendly_error_on_misidentified_erb_file ], in_order: true) end - def test_adds_namespace_labels_to_statsd_tags - desired_tags = %W(context:#{KubeclientHelper::TEST_CONTEXT} namespace:#{@namespace} foo:bar) - hello_cloud = FixtureSetAssertions::HelloCloud.new(@namespace) - kubeclient.patch_namespace(hello_cloud.namespace, metadata: { labels: { foo: 'bar' } }) - metrics = StatsDHelper.capture_statsd_calls do - assert_deploy_success deploy_fixtures("hello-cloud", subset: ["configmap-data.yml"]) - end - - # We can't ensure that all the metrics we grab are from this specific test because they are running in parallel - metrics = metrics.select { |m| m.tags.include? "namespace:#{@namespace}" } - assert_equal 5, metrics.count - - event_metrics = metrics.find_all { |m| m.type == :_e } - assert event_metrics.any? - assert_equal 1, event_metrics.count - - metrics.each do |metric| - assert_empty desired_tags - metric.tags - end - end - def test_raise_on_yaml_missing_kind result = deploy_fixtures("invalid-resources", subset: ["missing_kind.yml"]) assert_deploy_failure(result) diff --git a/test/test_helper.rb b/test/test_helper.rb index c76229f88..cb88418f9 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -67,7 +67,6 @@ def run end def setup - KubernetesDeploy::StatsD.build Kubectl.any_instance.expects(:run).never if ban_net_connect? # can't use mocha in Minitest::Test#run configure_logger end diff --git a/test/unit/kubernetes-deploy/kubectl_test.rb b/test/unit/kubernetes-deploy/kubectl_test.rb index f900b83a5..721f0c2c3 100644 --- a/test/unit/kubernetes-deploy/kubectl_test.rb +++ b/test/unit/kubernetes-deploy/kubectl_test.rb @@ -2,6 +2,7 @@ require 'test_helper' class KubectlTest < KubernetesDeploy::TestCase + include StatsDHelper def setup super KubernetesDeploy::Kubectl.any_instance.unstub(:run) @@ -90,7 +91,7 @@ def test_run_with_multiple_attempts_retries_and_emits_failure_metrics kubectl = build_kubectl kubectl.expects(:retry_delay).returns(0).times(4) - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do _out, _err, st = kubectl.run("get", "pods", attempts: 5) refute_predicate st, :success? end diff --git a/test/unit/kubernetes-deploy/statsd_test.rb b/test/unit/kubernetes-deploy/statsd_test.rb index 1894f9191..c54c2ceab 100644 --- a/test/unit/kubernetes-deploy/statsd_test.rb +++ b/test/unit/kubernetes-deploy/statsd_test.rb @@ -3,6 +3,7 @@ require 'test_helper' class StatsDTest < KubernetesDeploy::TestCase + include StatsDHelper class TestMeasureClass extend(KubernetesDeploy::StatsD::MeasureMethods) @@ -26,15 +27,10 @@ def statsd_tags class TestMeasureNoTags extend(KubernetesDeploy::StatsD::MeasureMethods) - def thing_to_measure; end measure_method :thing_to_measure end - def setup - KubernetesDeploy::StatsD.build - end - def test_build_when_statsd_addr_env_present_but_statsd_implementation_is_not original_addr = ENV['STATSD_ADDR'] ENV['STATSD_ADDR'] = '127.0.0.1' @@ -45,7 +41,7 @@ def test_build_when_statsd_addr_env_present_but_statsd_implementation_is_not KubernetesDeploy::StatsD.build - assert_equal :datadog, KubernetesDeploy::StatsD.backend.implementation + assert_equal(:datadog, KubernetesDeploy::StatsD.backend.implementation) ensure ENV['STATSD_ADDR'] = original_addr ENV['STATSD_IMPLEMENTATION'] = original_impl @@ -57,9 +53,9 @@ def test_kubernetes_statsd_does_not_override_global_config KubernetesDeploy::StatsD.build ::StatsD.prefix = "test" ::StatsD.default_sample_rate = 2.0 - refute_equal KubernetesDeploy::StatsD.prefix, ::StatsD.prefix - refute_equal KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate - refute_equal KubernetesDeploy::StatsD.backend, ::StatsD.backend + refute_equal(KubernetesDeploy::StatsD.prefix, ::StatsD.prefix) + refute_equal(KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate) + refute_equal(KubernetesDeploy::StatsD.backend, ::StatsD.backend) end def test_measuring_non_existent_method_raises @@ -73,7 +69,7 @@ def test_measure_method_does_not_change_the_return_value end def test_measure_method_uses_expected_name_and_tags - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do TestMeasureClass.new.thing_to_measure end assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" @@ -82,7 +78,7 @@ def test_measure_method_uses_expected_name_and_tags end def test_measure_method_with_custom_metric_name - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do TestMeasureClass.new.measure_with_custom_metric end assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" @@ -91,7 +87,7 @@ def test_measure_method_with_custom_metric_name end def test_measure_method_with_statsd_tags_undefined - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do TestMeasureNoTags.new.thing_to_measure end assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" @@ -100,7 +96,7 @@ def test_measure_method_with_statsd_tags_undefined end def test_measure_method_that_raises_with_hash_tags - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do tester = TestMeasureClass.new tester.expects(:statsd_tags).returns(test: true) assert_raises(ArgumentError) do @@ -113,7 +109,7 @@ def test_measure_method_that_raises_with_hash_tags end def test_measure_method_that_raises_with_array_tags - metrics = StatsDHelper.capture_statsd_calls do + metrics = capture_statsd_calls do tester = TestMeasureClass.new tester.expects(:statsd_tags).returns(["test:true"]) assert_raises(ArgumentError) do @@ -123,12 +119,5 @@ def test_measure_method_that_raises_with_array_tags assert_predicate metrics, :one?, "Expected 1 metric, got #{metrics.length}" assert_equal "KubernetesDeploy.measured_method_raises.duration", metrics.first.name assert_equal ["test:true", "error:true"], metrics.first.tags - def test_kubernetes_statsd_does_not_override_global_config - KubernetesDeploy::StatsD.build - ::StatsD.prefix = "test" - ::StatsD.default_sample_rate = 2.0 - refute_equal KubernetesDeploy::StatsD.prefix, ::StatsD.prefix - refute_equal KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate - refute_equal KubernetesDeploy::StatsD.backend, ::StatsD.backend end end From 7119eb95699c270974d8bd4af38208aff5c84f04 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 11:31:27 -0500 Subject: [PATCH 11/18] fix --- lib/kubernetes-deploy/statsd.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index 91f47d479..9294287a1 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -40,7 +40,7 @@ def self.increment(key, value = 1, *metric_options) super end - def self.distribution(key, value=nil, *metric_options, &block) + def self.distribution(key, value = nil, *metric_options, &block) if metric_options && metric_options.first.is_a?(Hash) metric_options.first[:prefix] = PREFIX end @@ -77,8 +77,7 @@ def measure_method(method_name, metric = nil) StatsD.distribution( metric, KubernetesDeploy::StatsD.duration(start_time), - tags: dynamic_tags, - prefix: PREFIX + tags: dynamic_tags ) end end From de4e2ad24bcd851f479cafa47c3efcd59dd1397c Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 12:14:23 -0500 Subject: [PATCH 12/18] no need to check if *args is array --- lib/kubernetes-deploy/statsd.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index 9294287a1..4f0e8fbb4 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -27,23 +27,17 @@ def self.build end def self.measure(key, value = nil, *metric_options, &block) - if metric_options && metric_options.first.is_a?(Hash) - metric_options.first[:prefix] = PREFIX - end + metric_options.first[:prefix] = PREFIX if metric_options.first.is_a?(Hash) super end def self.increment(key, value = 1, *metric_options) - if metric_options && metric_options.first.is_a?(Hash) - metric_options.first[:prefix] = PREFIX - end + metric_options.first[:prefix] = PREFIX if metric_options.first.is_a?(Hash) super end def self.distribution(key, value = nil, *metric_options, &block) - if metric_options && metric_options.first.is_a?(Hash) - metric_options.first[:prefix] = PREFIX - end + metric_options.first[:prefix] = PREFIX if metric_options.first.is_a?(Hash) super end From 933dbbac5b481db7369c9084e16ca6491d74cd9e Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 13:16:46 -0500 Subject: [PATCH 13/18] use **args before forwarding measurement calls to ::StatsD --- lib/kubernetes-deploy/statsd.rb | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index 4f0e8fbb4..ce7470269 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -14,7 +14,6 @@ def self.duration(start_time) def self.build self.default_sample_rate = 1.0 - self.prefix = "KubernetesDeploy" if ENV['STATSD_DEV'].present? self.backend = ::StatsD::Instrument::Backends::LoggerBackend.new(Logger.new($stderr)) @@ -26,18 +25,18 @@ def self.build end end - def self.measure(key, value = nil, *metric_options, &block) - metric_options.first[:prefix] = PREFIX if metric_options.first.is_a?(Hash) + def self.measure(key, value = nil, **metric_options, &block) + metric_options.merge!(prefix: PREFIX) super end - def self.increment(key, value = 1, *metric_options) - metric_options.first[:prefix] = PREFIX if metric_options.first.is_a?(Hash) + def self.increment(key, value = 1, **metric_options) + metric_options.merge!(prefix: PREFIX) super end - def self.distribution(key, value = nil, *metric_options, &block) - metric_options.first[:prefix] = PREFIX if metric_options.first.is_a?(Hash) + def self.distribution(key, value = nil, **metric_options, &block) + metric_options.merge!(prefix: PREFIX) super end From 53fbf9187bf4b324eab302623af714344180038b Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 13:24:43 -0500 Subject: [PATCH 14/18] put ::StatsD settings back to defaults after test --- test/unit/kubernetes-deploy/statsd_test.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/unit/kubernetes-deploy/statsd_test.rb b/test/unit/kubernetes-deploy/statsd_test.rb index c54c2ceab..48d76ae91 100644 --- a/test/unit/kubernetes-deploy/statsd_test.rb +++ b/test/unit/kubernetes-deploy/statsd_test.rb @@ -50,12 +50,18 @@ def test_build_when_statsd_addr_env_present_but_statsd_implementation_is_not end def test_kubernetes_statsd_does_not_override_global_config - KubernetesDeploy::StatsD.build + old_prefix = ::StatsD.prefix + old_sample_rate = ::StatsD.default_sample_rate + ::StatsD.prefix = "test" ::StatsD.default_sample_rate = 2.0 + KubernetesDeploy::StatsD.build refute_equal(KubernetesDeploy::StatsD.prefix, ::StatsD.prefix) refute_equal(KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate) refute_equal(KubernetesDeploy::StatsD.backend, ::StatsD.backend) + + ::StatsD.prefix = old_prefix + ::StatsD.default_sample_rate = old_sample_rate end def test_measuring_non_existent_method_raises From 46da762da7e15840801a665ee4f57c750a57a3ee Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 13:28:32 -0500 Subject: [PATCH 15/18] ensure revert global statsd settings --- test/unit/kubernetes-deploy/statsd_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/kubernetes-deploy/statsd_test.rb b/test/unit/kubernetes-deploy/statsd_test.rb index 48d76ae91..de169b619 100644 --- a/test/unit/kubernetes-deploy/statsd_test.rb +++ b/test/unit/kubernetes-deploy/statsd_test.rb @@ -59,7 +59,7 @@ def test_kubernetes_statsd_does_not_override_global_config refute_equal(KubernetesDeploy::StatsD.prefix, ::StatsD.prefix) refute_equal(KubernetesDeploy::StatsD.default_sample_rate, ::StatsD.default_sample_rate) refute_equal(KubernetesDeploy::StatsD.backend, ::StatsD.backend) - + ensure ::StatsD.prefix = old_prefix ::StatsD.default_sample_rate = old_sample_rate end From 761297275795fd332f6b4c343b6aa52cdc2dedcd Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 13:31:06 -0500 Subject: [PATCH 16/18] scope it right --- lib/kubernetes-deploy/deploy_task.rb | 6 +++--- lib/kubernetes-deploy/kubernetes_resource.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/kubernetes-deploy/deploy_task.rb b/lib/kubernetes-deploy/deploy_task.rb index f6037e386..b3e0b966d 100644 --- a/lib/kubernetes-deploy/deploy_task.rb +++ b/lib/kubernetes-deploy/deploy_task.rb @@ -162,14 +162,14 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) StatsD.event("Deployment of #{@namespace} succeeded", "Successfully deployed all #{@namespace} resources to #{@context}", alert_type: "success", tags: statsd_tags << "status:success") - ::StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success") + StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:success") @logger.print_summary(:success) rescue DeploymentTimeoutError @logger.print_summary(:timed_out) StatsD.event("Deployment of #{@namespace} timed out", "One or more #{@namespace} resources failed to deploy to #{@context} in time", alert_type: "error", tags: statsd_tags << "status:timeout") - ::StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout") + StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:timeout") raise rescue FatalDeploymentError => error @logger.summary.add_action(error.message) if error.message != error.class.to_s @@ -177,7 +177,7 @@ def run!(verify_result: true, allow_protected_ns: false, prune: true) StatsD.event("Deployment of #{@namespace} failed", "One or more #{@namespace} resources failed to deploy to #{@context}", alert_type: "error", tags: statsd_tags << "status:failed") - ::StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed") + StatsD.distribution('all_resources.duration', StatsD.duration(start), tags: statsd_tags << "status:failed") raise end diff --git a/lib/kubernetes-deploy/kubernetes_resource.rb b/lib/kubernetes-deploy/kubernetes_resource.rb index 4fdf7155a..a78e77f38 100644 --- a/lib/kubernetes-deploy/kubernetes_resource.rb +++ b/lib/kubernetes-deploy/kubernetes_resource.rb @@ -293,7 +293,7 @@ def pretty_status def report_status_to_statsd(watch_time) unless @statsd_report_done - ::StatsD.distribution('resource.duration', watch_time, tags: statsd_tags) + StatsD.distribution('resource.duration', watch_time, tags: statsd_tags) @statsd_report_done = true end end From 7f77f114db73001b248d8a109169c738907a81cf Mon Sep 17 00:00:00 2001 From: Timothy Smith Date: Mon, 10 Dec 2018 13:33:17 -0500 Subject: [PATCH 17/18] Automatic corrections for lib/kubernetes-deploy/statsd.rb --- lib/kubernetes-deploy/statsd.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index ce7470269..9d975a4f3 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -26,17 +26,17 @@ def self.build end def self.measure(key, value = nil, **metric_options, &block) - metric_options.merge!(prefix: PREFIX) + metric_options[:prefix] = PREFIX super end def self.increment(key, value = 1, **metric_options) - metric_options.merge!(prefix: PREFIX) + metric_options[:prefix] = PREFIX super end def self.distribution(key, value = nil, **metric_options, &block) - metric_options.merge!(prefix: PREFIX) + metric_options[:prefix] = PREFIX super end From 0eefd631fc697d42a21ea3c57c3719811b361062 Mon Sep 17 00:00:00 2001 From: timothysmith0609 Date: Mon, 10 Dec 2018 14:46:00 -0500 Subject: [PATCH 18/18] Remove redundant field, add explanatory comment --- lib/kubernetes-deploy/statsd.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/kubernetes-deploy/statsd.rb b/lib/kubernetes-deploy/statsd.rb index 9d975a4f3..81be3e819 100644 --- a/lib/kubernetes-deploy/statsd.rb +++ b/lib/kubernetes-deploy/statsd.rb @@ -13,8 +13,6 @@ def self.duration(start_time) end def self.build - self.default_sample_rate = 1.0 - if ENV['STATSD_DEV'].present? self.backend = ::StatsD::Instrument::Backends::LoggerBackend.new(Logger.new($stderr)) elsif ENV['STATSD_ADDR'].present? @@ -25,11 +23,10 @@ def self.build end end - def self.measure(key, value = nil, **metric_options, &block) - metric_options[:prefix] = PREFIX - super - end - + # It is not sufficient to set the prefix field on the KubernetesDeploy::StatsD singleton itself, since its value + # is overridden in the underlying calls to the ::StatsD library, hence the need to pass it in as a custom prefix + # via the metric_options hash. This is done since KubernetesDeploy may be included as a library and should not + # change the global StatsD configuration of the importing application. def self.increment(key, value = 1, **metric_options) metric_options[:prefix] = PREFIX super