{"action":"created","comment":{"url":"https://api.github.com/repos/ManageIQ/manageiq/pulls/comments/57689813","id":57689813,"diff_hunk":"@@ -0,0 +1,135 @@\n+module ManageIQ::Providers\n+  class Hawkular::MiddlewareManager::LiveMetricsCapture\n+    class TargetValidationError < RuntimeError; end\n+    class MetricValidationError < RuntimeError; end\n+\n+    def initialize(target)\n+      @target = target\n+      unless @target.kind_of?(MiddlewareServer)\n+        raise TargetValidationError, \"Validation error: unknown target\"\n+      end\n+      @ems = @target.ext_management_system\n+    end\n+\n+    def metrics_available\n+      resource = Struct.new(:id, :feed).new\n+      resource.id = @target.nativeid\n+      resource.feed = @target.feed\n+      available = []\n+      @ems.metrics_resource(resource).each do |metric|\n+        available << {\n+          :id   => metric.id,\n+          :name => @target.class::METRICS_HWK_MIQ[metric.name],\n+          :type => metric.type,\n+          :unit => metric.unit\n+        }\n+      end\n+      available\n+    end\n+\n+    def validate_metric(metric)\n+      if metric.nil?\n+        false\n+      elsif metric[:id].nil?\n+        false\n+      elsif metric[:name].nil?\n+        false\n+      elsif metric[:type].nil?\n+        false\n+      elsif metric[:unit].nil?\n+        false\n+      else\n+        true\n+      end\n+    end\n+\n+    def metric(metric, start_time, end_time, interval)\n+      unless validate_metric(metric)\n+        raise MetricValidationError, \"Validation error: metric must be defined\"\n+      end\n+      starts = (start_time - interval).to_i.in_milliseconds\n+      ends = end_time.to_i.in_milliseconds\n+      bucket_duration = \"#{interval}s\"\n+      metrics = collect_metrics(metric[:id], metric[:type], starts, ends, bucket_duration)\n+      process_data(metric, metrics)\n+    end\n+\n+    def first_and_last_capture(metric)\n+      unless validate_metric(metric)\n+        raise MetricValidationError, \"Validation error: metric must be defined\"\n+      end\n+      case metric[:type]\n+      when \"GAUGE\" then\n+        min = @ems.metrics_connect.gauges.get_data(metric[:id], starts: 0, limit: 1, order: 'ASC')\n+        max = @ems.metrics_connect.gauges.get_data(metric[:id], starts: 0, limit: 1, order: 'DESC')\n+      when \"COUNTER\" then\n+        min = @ems.metrics_connect.counters.get_data(metric[:id], starts: 0, limit: 1, order: 'ASC')\n+        max = @ems.metrics_connect.counters.get_data(metric[:id], starts: 0, limit: 1, order: 'DESC')\n+      when \"AVAILABILITY\" then\n+        min = @ems.metrics_connect.avail.get_data(metric[:id], starts: 0, limit: 1, order: 'ASC')\n+        max = @ems.metrics_connect.avail.get_data(metric[:id], starts: 0, limit: 1, order: 'DESC')\n+      else raise MetricValidationError, \"Validation error: unknown type #{metric_type}\"\n+      end\n+      [min[0]['timestamp'], max[0]['timestamp']]\n+    end\n+\n+    def collect_metrics(metric_id, metric_type, starts, ends, bucket_duration)\n+      case metric_type\n+      when \"GAUGE\" then gauges(metric_id, starts, ends, bucket_duration)\n+      when \"COUNTER\" then counters(metric_id, starts, ends, bucket_duration)\n+      when \"AVAILABILITY\" then availabilities(metric_id, starts, ends, bucket_duration)\n+      else raise MetricValidationError, \"Validation error: unknown type #{metric_type}\"\n+      end\n+    end\n+\n+    def gauges(metric_id, starts, ends, bucket_duration)\n+      sort_and_normalize(\n+        @ems.metrics_connect.gauges.get_data(metric_id, :starts => starts, :ends => ends,\n+                                             :bucketDuration => bucket_duration))\n+    end\n+\n+    def counters(metric_id, starts, ends, bucket_duration)\n+      compute_derivates(\n+        sort_and_normalize(\n+          @ems.metrics_connect.counters.get_data(metric_id, :starts => starts, :ends => ends,\n+                                                 :bucketDuration => bucket_duration)))\n+    end\n+\n+    def availabilities(metric_id, starts, ends, bucket_duration)\n+      sort_and_normalize(\n+        @ems.metrics_connect.avail.get_data(metric_id, :starts => starts, :ends => ends,\n+                                            :bucketDuration => bucket_duration))\n+    end\n+\n+    def sort_and_normalize(data)\n+      # Sorting and removing last entry because always incomplete\n+      # as it's still in progress.\n+      norm_data = (data.sort_by { |x| x['start'] }).slice(0..-2)","path":"app/models/manageiq/providers/hawkular/middleware_manager/live_metrics_capture.rb","position":107,"original_position":107,"commit_id":"c954c7cd4b938f4003f1acbf7d5efda572d30651","original_commit_id":"c954c7cd4b938f4003f1acbf7d5efda572d30651","user":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"body":"NaN values are discarded inside sort_and_normalize method.\r\nValues are strings for availability type of metrics and integers for counters and gauges.\r\nNot sure if it is ok to maintain this or we should add specific strong typing on that.\r\nStill experimenting on the handling part of the metrics.","created_at":"2016-03-29T08:46:47Z","updated_at":"2016-03-29T08:46:47Z","html_url":"https://github.com/ManageIQ/manageiq/pull/7365#discussion_r57689813","pull_request_url":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365","_links":{"self":{"href":"https://api.github.com/repos/ManageIQ/manageiq/pulls/comments/57689813"},"html":{"href":"https://github.com/ManageIQ/manageiq/pull/7365#discussion_r57689813"},"pull_request":{"href":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365"}}},"pull_request":{"url":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365","id":63262554,"html_url":"https://github.com/ManageIQ/manageiq/pull/7365","diff_url":"https://github.com/ManageIQ/manageiq/pull/7365.diff","patch_url":"https://github.com/ManageIQ/manageiq/pull/7365.patch","issue_url":"https://api.github.com/repos/ManageIQ/manageiq/issues/7365","number":7365,"state":"open","locked":false,"title":"[WIP][PoC]Hawkular live metrics mixins","user":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"body":"@miq-bot add_label providers/hawkular","created_at":"2016-03-17T17:36:14Z","updated_at":"2016-03-29T08:46:47Z","closed_at":null,"merged_at":null,"merge_commit_sha":"cfaf2d1fb8e8aaedaa5593dd32bee2b9b6144462","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365/commits","review_comments_url":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365/comments","review_comment_url":"https://api.github.com/repos/ManageIQ/manageiq/pulls/comments{/number}","comments_url":"https://api.github.com/repos/ManageIQ/manageiq/issues/7365/comments","statuses_url":"https://api.github.com/repos/ManageIQ/manageiq/statuses/c954c7cd4b938f4003f1acbf7d5efda572d30651","head":{"label":"lucasponce:hawkular-live-metrics-mixins","ref":"hawkular-live-metrics-mixins","sha":"c954c7cd4b938f4003f1acbf7d5efda572d30651","user":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"repo":{"id":52009210,"name":"manageiq","full_name":"lucasponce/manageiq","owner":{"login":"lucasponce","id":1662329,"avatar_url":"https://avatars.githubusercontent.com/u/1662329?v=3","gravatar_id":"","url":"https://api.github.com/users/lucasponce","html_url":"https://github.com/lucasponce","followers_url":"https://api.github.com/users/lucasponce/followers","following_url":"https://api.github.com/users/lucasponce/following{/other_user}","gists_url":"https://api.github.com/users/lucasponce/gists{/gist_id}","starred_url":"https://api.github.com/users/lucasponce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/lucasponce/subscriptions","organizations_url":"https://api.github.com/users/lucasponce/orgs","repos_url":"https://api.github.com/users/lucasponce/repos","events_url":"https://api.github.com/users/lucasponce/events{/privacy}","received_events_url":"https://api.github.com/users/lucasponce/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/lucasponce/manageiq","description":"ManageIQ Cloud Management Platform","fork":true,"url":"https://api.github.com/repos/lucasponce/manageiq","forks_url":"https://api.github.com/repos/lucasponce/manageiq/forks","keys_url":"https://api.github.com/repos/lucasponce/manageiq/keys{/key_id}","collaborators_url":"https://api.github.com/repos/lucasponce/manageiq/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/lucasponce/manageiq/teams","hooks_url":"https://api.github.com/repos/lucasponce/manageiq/hooks","issue_events_url":"https://api.github.com/repos/lucasponce/manageiq/issues/events{/number}","events_url":"https://api.github.com/repos/lucasponce/manageiq/events","assignees_url":"https://api.github.com/repos/lucasponce/manageiq/assignees{/user}","branches_url":"https://api.github.com/repos/lucasponce/manageiq/branches{/branch}","tags_url":"https://api.github.com/repos/lucasponce/manageiq/tags","blobs_url":"https://api.github.com/repos/lucasponce/manageiq/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/lucasponce/manageiq/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/lucasponce/manageiq/git/refs{/sha}","trees_url":"https://api.github.com/repos/lucasponce/manageiq/git/trees{/sha}","statuses_url":"https://api.github.com/repos/lucasponce/manageiq/statuses/{sha}","languages_url":"https://api.github.com/repos/lucasponce/manageiq/languages","stargazers_url":"https://api.github.com/repos/lucasponce/manageiq/stargazers","contributors_url":"https://api.github.com/repos/lucasponce/manageiq/contributors","subscribers_url":"https://api.github.com/repos/lucasponce/manageiq/subscribers","subscription_url":"https://api.github.com/repos/lucasponce/manageiq/subscription","commits_url":"https://api.github.com/repos/lucasponce/manageiq/commits{/sha}","git_commits_url":"https://api.github.com/repos/lucasponce/manageiq/git/commits{/sha}","comments_url":"https://api.github.com/repos/lucasponce/manageiq/comments{/number}","issue_comment_url":"https://api.github.com/repos/lucasponce/manageiq/issues/comments{/number}","contents_url":"https://api.github.com/repos/lucasponce/manageiq/contents/{+path}","compare_url":"https://api.github.com/repos/lucasponce/manageiq/compare/{base}...{head}","merges_url":"https://api.github.com/repos/lucasponce/manageiq/merges","archive_url":"https://api.github.com/repos/lucasponce/manageiq/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/lucasponce/manageiq/downloads","issues_url":"https://api.github.com/repos/lucasponce/manageiq/issues{/number}","pulls_url":"https://api.github.com/repos/lucasponce/manageiq/pulls{/number}","milestones_url":"https://api.github.com/repos/lucasponce/manageiq/milestones{/number}","notifications_url":"https://api.github.com/repos/lucasponce/manageiq/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/lucasponce/manageiq/labels{/name}","releases_url":"https://api.github.com/repos/lucasponce/manageiq/releases{/id}","deployments_url":"https://api.github.com/repos/lucasponce/manageiq/deployments","created_at":"2016-02-18T13:31:38Z","updated_at":"2016-02-18T13:31:56Z","pushed_at":"2016-03-23T17:37:59Z","git_url":"git://github.com/lucasponce/manageiq.git","ssh_url":"git@github.com:lucasponce/manageiq.git","clone_url":"https://github.com/lucasponce/manageiq.git","svn_url":"https://github.com/lucasponce/manageiq","homepage":"manageiq.org","size":110224,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"ManageIQ:master","ref":"master","sha":"b5457635ee3e0feb34828875cf0d51a70ea99d73","user":{"login":"ManageIQ","id":1125575,"avatar_url":"https://avatars.githubusercontent.com/u/1125575?v=3","gravatar_id":"","url":"https://api.github.com/users/ManageIQ","html_url":"https://github.com/ManageIQ","followers_url":"https://api.github.com/users/ManageIQ/followers","following_url":"https://api.github.com/users/ManageIQ/following{/other_user}","gists_url":"https://api.github.com/users/ManageIQ/gists{/gist_id}","starred_url":"https://api.github.com/users/ManageIQ/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ManageIQ/subscriptions","organizations_url":"https://api.github.com/users/ManageIQ/orgs","repos_url":"https://api.github.com/users/ManageIQ/repos","events_url":"https://api.github.com/users/ManageIQ/events{/privacy}","received_events_url":"https://api.github.com/users/ManageIQ/received_events","type":"Organization","site_admin":false},"repo":{"id":20789757,"name":"manageiq","full_name":"ManageIQ/manageiq","owner":{"login":"ManageIQ","id":1125575,"avatar_url":"https://avatars.githubusercontent.com/u/1125575?v=3","gravatar_id":"","url":"https://api.github.com/users/ManageIQ","html_url":"https://github.com/ManageIQ","followers_url":"https://api.github.com/users/ManageIQ/followers","following_url":"https://api.github.com/users/ManageIQ/following{/other_user}","gists_url":"https://api.github.com/users/ManageIQ/gists{/gist_id}","starred_url":"https://api.github.com/users/ManageIQ/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ManageIQ/subscriptions","organizations_url":"https://api.github.com/users/ManageIQ/orgs","repos_url":"https://api.github.com/users/ManageIQ/repos","events_url":"https://api.github.com/users/ManageIQ/events{/privacy}","received_events_url":"https://api.github.com/users/ManageIQ/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/ManageIQ/manageiq","description":"ManageIQ Cloud Management Platform","fork":false,"url":"https://api.github.com/repos/ManageIQ/manageiq","forks_url":"https://api.github.com/repos/ManageIQ/manageiq/forks","keys_url":"https://api.github.com/repos/ManageIQ/manageiq/keys{/key_id}","collaborators_url":"https://api.github.com/repos/ManageIQ/manageiq/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/ManageIQ/manageiq/teams","hooks_url":"https://api.github.com/repos/ManageIQ/manageiq/hooks","issue_events_url":"https://api.github.com/repos/ManageIQ/manageiq/issues/events{/number}","events_url":"https://api.github.com/repos/ManageIQ/manageiq/events","assignees_url":"https://api.github.com/repos/ManageIQ/manageiq/assignees{/user}","branches_url":"https://api.github.com/repos/ManageIQ/manageiq/branches{/branch}","tags_url":"https://api.github.com/repos/ManageIQ/manageiq/tags","blobs_url":"https://api.github.com/repos/ManageIQ/manageiq/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/ManageIQ/manageiq/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/ManageIQ/manageiq/git/refs{/sha}","trees_url":"https://api.github.com/repos/ManageIQ/manageiq/git/trees{/sha}","statuses_url":"https://api.github.com/repos/ManageIQ/manageiq/statuses/{sha}","languages_url":"https://api.github.com/repos/ManageIQ/manageiq/languages","stargazers_url":"https://api.github.com/repos/ManageIQ/manageiq/stargazers","contributors_url":"https://api.github.com/repos/ManageIQ/manageiq/contributors","subscribers_url":"https://api.github.com/repos/ManageIQ/manageiq/subscribers","subscription_url":"https://api.github.com/repos/ManageIQ/manageiq/subscription","commits_url":"https://api.github.com/repos/ManageIQ/manageiq/commits{/sha}","git_commits_url":"https://api.github.com/repos/ManageIQ/manageiq/git/commits{/sha}","comments_url":"https://api.github.com/repos/ManageIQ/manageiq/comments{/number}","issue_comment_url":"https://api.github.com/repos/ManageIQ/manageiq/issues/comments{/number}","contents_url":"https://api.github.com/repos/ManageIQ/manageiq/contents/{+path}","compare_url":"https://api.github.com/repos/ManageIQ/manageiq/compare/{base}...{head}","merges_url":"https://api.github.com/repos/ManageIQ/manageiq/merges","archive_url":"https://api.github.com/repos/ManageIQ/manageiq/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/ManageIQ/manageiq/downloads","issues_url":"https://api.github.com/repos/ManageIQ/manageiq/issues{/number}","pulls_url":"https://api.github.com/repos/ManageIQ/manageiq/pulls{/number}","milestones_url":"https://api.github.com/repos/ManageIQ/manageiq/milestones{/number}","notifications_url":"https://api.github.com/repos/ManageIQ/manageiq/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/ManageIQ/manageiq/labels{/name}","releases_url":"https://api.github.com/repos/ManageIQ/manageiq/releases{/id}","deployments_url":"https://api.github.com/repos/ManageIQ/manageiq/deployments","created_at":"2014-06-13T02:31:26Z","updated_at":"2016-03-28T18:53:33Z","pushed_at":"2016-03-29T08:43:08Z","git_url":"git://github.com/ManageIQ/manageiq.git","ssh_url":"git@github.com:ManageIQ/manageiq.git","clone_url":"https://github.com/ManageIQ/manageiq.git","svn_url":"https://github.com/ManageIQ/manageiq","homepage":"manageiq.org","size":151161,"stargazers_count":245,"watchers_count":245,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":262,"mirror_url":null,"open_issues_count":614,"forks":262,"open_issues":614,"watchers":245,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365"},"html":{"href":"https://github.com/ManageIQ/manageiq/pull/7365"},"issue":{"href":"https://api.github.com/repos/ManageIQ/manageiq/issues/7365"},"comments":{"href":"https://api.github.com/repos/ManageIQ/manageiq/issues/7365/comments"},"review_comments":{"href":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365/comments"},"review_comment":{"href":"https://api.github.com/repos/ManageIQ/manageiq/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/ManageIQ/manageiq/pulls/7365/commits"},"statuses":{"href":"https://api.github.com/repos/ManageIQ/manageiq/statuses/c954c7cd4b938f4003f1acbf7d5efda572d30651"}}}}