{"action":"created","comment":{"url":"https://api.github.com/repos/Yelp/fullerite/pulls/comments/45886322","id":45886322,"diff_hunk":"@@ -0,0 +1,132 @@\n+package collector\n+\n+import (\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"fullerite/config\"\n+\t\"fullerite/metric\"\n+\t\"fullerite/util\"\n+\t\"io/ioutil\"\n+\t\"net/http\"\n+\t\"strings\"\n+\t\"time\"\n+\n+\tl \"github.com/Sirupsen/logrus\"\n+)\n+\n+// DI\n+var (\n+\texternalIP = util.ExternalIP\n+\n+\tsendMetrics = (*MesosStats).sendMetrics\n+\tgetMetrics  = (*MesosStats).getMetrics\n+\n+\tnewMLE        = func() MesosLeaderElectInterface { return new(MesosLeaderElect) }\n+\tgetMetricsURL = func(ip string) string { return fmt.Sprintf(\"http://%s:5050/metrics/snapshot\", ip) }\n+)\n+\n+const (\n+\tcacheTimeout = 5 * time.Minute\n+\tgetTimeout   = 10 * time.Second\n+)\n+\n+// MesosStats Collector for mesos leader stats.\n+type MesosStats struct {\n+\tbaseCollector\n+\tIP         string\n+\tclient     http.Client\n+\tmesosCache MesosLeaderElectInterface\n+}\n+\n+// NewMesosStats Simple constructor to set properties for the embedded baseCollector.\n+func NewMesosStats(channel chan metric.Metric, intialInterval int, log *l.Entry) *MesosStats {\n+\tm := new(MesosStats)\n+\n+\tm.log = log\n+\tm.channel = channel\n+\tm.interval = intialInterval\n+\tm.name = \"MesosStats\"\n+\tm.client = http.Client{Timeout: getTimeout}\n+\n+\tif ip, err := externalIP(); err != nil {\n+\t\tm.log.Error(\"Cannot determine internal IP\")\n+\t} else {\n+\t\tm.IP = ip\n+\t}\n+\n+\treturn m\n+}\n+\n+// Configure Override *baseCollector.Configure(). Will create the required MesosLeaderElect instance.\n+func (m *MesosStats) Configure(configMap map[string]interface{}) {\n+\tm.configureCommonParams(configMap)\n+\n+\tc := config.GetAsMap(configMap)\n+\tmesosNodes, exists := c[\"mesosNodes\"]\n+\n+\tif !exists || len(mesosNodes) == 0 {\n+\t\tm.log.Error(\"Require configuration not found: mesosNodes\")\n+\t\treturn\n+\t}\n+\n+\tm.mesosCache = newMLE()\n+\tm.mesosCache.Configure(mesosNodes, cacheTimeout)\n+}\n+\n+// Collect Compares box IP against leader IP and if true, sends data.\n+func (m *MesosStats) Collect() {\n+\tswitch m.mesosCache {\n+\tcase nil:\n+\t\tm.log.Error(\"No mesosCache, Configure() probably failed.\")\n+\t\treturn\n+\tdefault:\n+\t\tif m.mesosCache.Get() != m.IP {\n+\t\t\tm.log.Warn(\"Not the leader; skipping.\")\n+\t\t\treturn","path":"src/fullerite/collector/mesos.go","position":85,"original_position":85,"commit_id":"ecf5e1e1eaae50bb7f17942913a676a44a17d183","original_commit_id":"ecf5e1e1eaae50bb7f17942913a676a44a17d183","user":{"login":"tsheasha","id":941429,"avatar_url":"https://avatars.githubusercontent.com/u/941429?v=3","gravatar_id":"","url":"https://api.github.com/users/tsheasha","html_url":"https://github.com/tsheasha","followers_url":"https://api.github.com/users/tsheasha/followers","following_url":"https://api.github.com/users/tsheasha/following{/other_user}","gists_url":"https://api.github.com/users/tsheasha/gists{/gist_id}","starred_url":"https://api.github.com/users/tsheasha/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tsheasha/subscriptions","organizations_url":"https://api.github.com/users/tsheasha/orgs","repos_url":"https://api.github.com/users/tsheasha/repos","events_url":"https://api.github.com/users/tsheasha/events{/privacy}","received_events_url":"https://api.github.com/users/tsheasha/received_events","type":"User","site_admin":false},"body":"I don't get this... doesn't this mean that our current IP here is not that of the leader? .. if so then why are we just logging  and skipping, shouldn't we in this case re-assign m.IP to match that of m.mesosCache and call send metrics on this updated value. Since this current implementation will only report as long as the leader does not change, but once a change happens it will skip forever.","created_at":"2015-11-25T16:20:44Z","updated_at":"2015-11-25T16:20:44Z","html_url":"https://github.com/Yelp/fullerite/pull/94#discussion_r45886322","pull_request_url":"https://api.github.com/repos/Yelp/fullerite/pulls/94","_links":{"self":{"href":"https://api.github.com/repos/Yelp/fullerite/pulls/comments/45886322"},"html":{"href":"https://github.com/Yelp/fullerite/pull/94#discussion_r45886322"},"pull_request":{"href":"https://api.github.com/repos/Yelp/fullerite/pulls/94"}}},"pull_request":{"url":"https://api.github.com/repos/Yelp/fullerite/pulls/94","id":51784445,"html_url":"https://github.com/Yelp/fullerite/pull/94","diff_url":"https://github.com/Yelp/fullerite/pull/94.diff","patch_url":"https://github.com/Yelp/fullerite/pull/94.patch","issue_url":"https://api.github.com/repos/Yelp/fullerite/issues/94","number":94,"state":"open","locked":false,"title":"Mesos collector","user":{"login":"avadhutp","id":244408,"avatar_url":"https://avatars.githubusercontent.com/u/244408?v=3","gravatar_id":"","url":"https://api.github.com/users/avadhutp","html_url":"https://github.com/avadhutp","followers_url":"https://api.github.com/users/avadhutp/followers","following_url":"https://api.github.com/users/avadhutp/following{/other_user}","gists_url":"https://api.github.com/users/avadhutp/gists{/gist_id}","starred_url":"https://api.github.com/users/avadhutp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/avadhutp/subscriptions","organizations_url":"https://api.github.com/users/avadhutp/orgs","repos_url":"https://api.github.com/users/avadhutp/repos","events_url":"https://api.github.com/users/avadhutp/events{/privacy}","received_events_url":"https://api.github.com/users/avadhutp/received_events","type":"User","site_admin":false},"body":"## What?\r\n1. New collector for stats from mesos\r\n1. Could not use the old mesos.py collector because it does not identify leader masters (mesos can have multiple masters and one of them is elected as a *leader*; we are interested in metrics only from this instance)\r\n1. We will poll the masters for the leader every 5 mins only. Once we identify the leader, we will cache this value for the next 5 mins. And the collector instance running on that box will send stats. I am yet to confirm the efficacy of this 5 min threshold. I will speak to kwa and figure it out before the review is closed. \r\n1. Will be primarily enabled on PaaSTA masters to enable capacity tracking\r\n\r\n## How?\r\n1. The collector is tolerant enough to not panic in case of malformed config. It will simply log errors and move on.\r\n1. Working config example:\r\n```json\r\n\"collectors\": {\r\n    \"MesosStats\":{\"mesosNodes\":\"http://10.40.1.51:5050/,http://10.40.1.49:5050/,http://10.40.1.50:5050/\"}\r\n},\r\n```\r\n\r\n## How do I know this works?\r\n1. Scores of tests added for all code included in the pull request.\r\n1. Tested this version on devc mesos masters to make sure that the correct metrics are being sent to SignalFx from the correct mesos  master (*leader*).","created_at":"2015-11-25T11:50:47Z","updated_at":"2015-11-25T16:20:44Z","closed_at":null,"merged_at":null,"merge_commit_sha":"61bfdae2f760cbb2a9cd15cba32cee46a4f97cea","assignee":{"login":"zachm","id":229114,"avatar_url":"https://avatars.githubusercontent.com/u/229114?v=3","gravatar_id":"","url":"https://api.github.com/users/zachm","html_url":"https://github.com/zachm","followers_url":"https://api.github.com/users/zachm/followers","following_url":"https://api.github.com/users/zachm/following{/other_user}","gists_url":"https://api.github.com/users/zachm/gists{/gist_id}","starred_url":"https://api.github.com/users/zachm/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/zachm/subscriptions","organizations_url":"https://api.github.com/users/zachm/orgs","repos_url":"https://api.github.com/users/zachm/repos","events_url":"https://api.github.com/users/zachm/events{/privacy}","received_events_url":"https://api.github.com/users/zachm/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/Yelp/fullerite/pulls/94/commits","review_comments_url":"https://api.github.com/repos/Yelp/fullerite/pulls/94/comments","review_comment_url":"https://api.github.com/repos/Yelp/fullerite/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Yelp/fullerite/issues/94/comments","statuses_url":"https://api.github.com/repos/Yelp/fullerite/statuses/ecf5e1e1eaae50bb7f17942913a676a44a17d183","head":{"label":"Yelp:avadhutp_mesos_leader_collector","ref":"avadhutp_mesos_leader_collector","sha":"ecf5e1e1eaae50bb7f17942913a676a44a17d183","user":{"login":"Yelp","id":49071,"avatar_url":"https://avatars.githubusercontent.com/u/49071?v=3","gravatar_id":"","url":"https://api.github.com/users/Yelp","html_url":"https://github.com/Yelp","followers_url":"https://api.github.com/users/Yelp/followers","following_url":"https://api.github.com/users/Yelp/following{/other_user}","gists_url":"https://api.github.com/users/Yelp/gists{/gist_id}","starred_url":"https://api.github.com/users/Yelp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Yelp/subscriptions","organizations_url":"https://api.github.com/users/Yelp/orgs","repos_url":"https://api.github.com/users/Yelp/repos","events_url":"https://api.github.com/users/Yelp/events{/privacy}","received_events_url":"https://api.github.com/users/Yelp/received_events","type":"Organization","site_admin":false},"repo":{"id":39368384,"name":"fullerite","full_name":"Yelp/fullerite","owner":{"login":"Yelp","id":49071,"avatar_url":"https://avatars.githubusercontent.com/u/49071?v=3","gravatar_id":"","url":"https://api.github.com/users/Yelp","html_url":"https://github.com/Yelp","followers_url":"https://api.github.com/users/Yelp/followers","following_url":"https://api.github.com/users/Yelp/following{/other_user}","gists_url":"https://api.github.com/users/Yelp/gists{/gist_id}","starred_url":"https://api.github.com/users/Yelp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Yelp/subscriptions","organizations_url":"https://api.github.com/users/Yelp/orgs","repos_url":"https://api.github.com/users/Yelp/repos","events_url":"https://api.github.com/users/Yelp/events{/privacy}","received_events_url":"https://api.github.com/users/Yelp/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Yelp/fullerite","description":"Fullerite is a daemon which collect metrics periodically from various sources and sends them to different metric stores","fork":false,"url":"https://api.github.com/repos/Yelp/fullerite","forks_url":"https://api.github.com/repos/Yelp/fullerite/forks","keys_url":"https://api.github.com/repos/Yelp/fullerite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Yelp/fullerite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Yelp/fullerite/teams","hooks_url":"https://api.github.com/repos/Yelp/fullerite/hooks","issue_events_url":"https://api.github.com/repos/Yelp/fullerite/issues/events{/number}","events_url":"https://api.github.com/repos/Yelp/fullerite/events","assignees_url":"https://api.github.com/repos/Yelp/fullerite/assignees{/user}","branches_url":"https://api.github.com/repos/Yelp/fullerite/branches{/branch}","tags_url":"https://api.github.com/repos/Yelp/fullerite/tags","blobs_url":"https://api.github.com/repos/Yelp/fullerite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Yelp/fullerite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Yelp/fullerite/git/refs{/sha}","trees_url":"https://api.github.com/repos/Yelp/fullerite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Yelp/fullerite/statuses/{sha}","languages_url":"https://api.github.com/repos/Yelp/fullerite/languages","stargazers_url":"https://api.github.com/repos/Yelp/fullerite/stargazers","contributors_url":"https://api.github.com/repos/Yelp/fullerite/contributors","subscribers_url":"https://api.github.com/repos/Yelp/fullerite/subscribers","subscription_url":"https://api.github.com/repos/Yelp/fullerite/subscription","commits_url":"https://api.github.com/repos/Yelp/fullerite/commits{/sha}","git_commits_url":"https://api.github.com/repos/Yelp/fullerite/git/commits{/sha}","comments_url":"https://api.github.com/repos/Yelp/fullerite/comments{/number}","issue_comment_url":"https://api.github.com/repos/Yelp/fullerite/issues/comments{/number}","contents_url":"https://api.github.com/repos/Yelp/fullerite/contents/{+path}","compare_url":"https://api.github.com/repos/Yelp/fullerite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Yelp/fullerite/merges","archive_url":"https://api.github.com/repos/Yelp/fullerite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Yelp/fullerite/downloads","issues_url":"https://api.github.com/repos/Yelp/fullerite/issues{/number}","pulls_url":"https://api.github.com/repos/Yelp/fullerite/pulls{/number}","milestones_url":"https://api.github.com/repos/Yelp/fullerite/milestones{/number}","notifications_url":"https://api.github.com/repos/Yelp/fullerite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Yelp/fullerite/labels{/name}","releases_url":"https://api.github.com/repos/Yelp/fullerite/releases{/id}","created_at":"2015-07-20T07:01:49Z","updated_at":"2015-11-24T13:41:38Z","pushed_at":"2015-11-25T11:50:47Z","git_url":"git://github.com/Yelp/fullerite.git","ssh_url":"git@github.com:Yelp/fullerite.git","clone_url":"https://github.com/Yelp/fullerite.git","svn_url":"https://github.com/Yelp/fullerite","homepage":"","size":6836,"stargazers_count":101,"watchers_count":101,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":21,"mirror_url":null,"open_issues_count":19,"forks":21,"open_issues":19,"watchers":101,"default_branch":"master"}},"base":{"label":"Yelp:master","ref":"master","sha":"16e458c63332900476a14afb0193acdc69a70555","user":{"login":"Yelp","id":49071,"avatar_url":"https://avatars.githubusercontent.com/u/49071?v=3","gravatar_id":"","url":"https://api.github.com/users/Yelp","html_url":"https://github.com/Yelp","followers_url":"https://api.github.com/users/Yelp/followers","following_url":"https://api.github.com/users/Yelp/following{/other_user}","gists_url":"https://api.github.com/users/Yelp/gists{/gist_id}","starred_url":"https://api.github.com/users/Yelp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Yelp/subscriptions","organizations_url":"https://api.github.com/users/Yelp/orgs","repos_url":"https://api.github.com/users/Yelp/repos","events_url":"https://api.github.com/users/Yelp/events{/privacy}","received_events_url":"https://api.github.com/users/Yelp/received_events","type":"Organization","site_admin":false},"repo":{"id":39368384,"name":"fullerite","full_name":"Yelp/fullerite","owner":{"login":"Yelp","id":49071,"avatar_url":"https://avatars.githubusercontent.com/u/49071?v=3","gravatar_id":"","url":"https://api.github.com/users/Yelp","html_url":"https://github.com/Yelp","followers_url":"https://api.github.com/users/Yelp/followers","following_url":"https://api.github.com/users/Yelp/following{/other_user}","gists_url":"https://api.github.com/users/Yelp/gists{/gist_id}","starred_url":"https://api.github.com/users/Yelp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Yelp/subscriptions","organizations_url":"https://api.github.com/users/Yelp/orgs","repos_url":"https://api.github.com/users/Yelp/repos","events_url":"https://api.github.com/users/Yelp/events{/privacy}","received_events_url":"https://api.github.com/users/Yelp/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Yelp/fullerite","description":"Fullerite is a daemon which collect metrics periodically from various sources and sends them to different metric stores","fork":false,"url":"https://api.github.com/repos/Yelp/fullerite","forks_url":"https://api.github.com/repos/Yelp/fullerite/forks","keys_url":"https://api.github.com/repos/Yelp/fullerite/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Yelp/fullerite/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Yelp/fullerite/teams","hooks_url":"https://api.github.com/repos/Yelp/fullerite/hooks","issue_events_url":"https://api.github.com/repos/Yelp/fullerite/issues/events{/number}","events_url":"https://api.github.com/repos/Yelp/fullerite/events","assignees_url":"https://api.github.com/repos/Yelp/fullerite/assignees{/user}","branches_url":"https://api.github.com/repos/Yelp/fullerite/branches{/branch}","tags_url":"https://api.github.com/repos/Yelp/fullerite/tags","blobs_url":"https://api.github.com/repos/Yelp/fullerite/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Yelp/fullerite/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Yelp/fullerite/git/refs{/sha}","trees_url":"https://api.github.com/repos/Yelp/fullerite/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Yelp/fullerite/statuses/{sha}","languages_url":"https://api.github.com/repos/Yelp/fullerite/languages","stargazers_url":"https://api.github.com/repos/Yelp/fullerite/stargazers","contributors_url":"https://api.github.com/repos/Yelp/fullerite/contributors","subscribers_url":"https://api.github.com/repos/Yelp/fullerite/subscribers","subscription_url":"https://api.github.com/repos/Yelp/fullerite/subscription","commits_url":"https://api.github.com/repos/Yelp/fullerite/commits{/sha}","git_commits_url":"https://api.github.com/repos/Yelp/fullerite/git/commits{/sha}","comments_url":"https://api.github.com/repos/Yelp/fullerite/comments{/number}","issue_comment_url":"https://api.github.com/repos/Yelp/fullerite/issues/comments{/number}","contents_url":"https://api.github.com/repos/Yelp/fullerite/contents/{+path}","compare_url":"https://api.github.com/repos/Yelp/fullerite/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Yelp/fullerite/merges","archive_url":"https://api.github.com/repos/Yelp/fullerite/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Yelp/fullerite/downloads","issues_url":"https://api.github.com/repos/Yelp/fullerite/issues{/number}","pulls_url":"https://api.github.com/repos/Yelp/fullerite/pulls{/number}","milestones_url":"https://api.github.com/repos/Yelp/fullerite/milestones{/number}","notifications_url":"https://api.github.com/repos/Yelp/fullerite/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Yelp/fullerite/labels{/name}","releases_url":"https://api.github.com/repos/Yelp/fullerite/releases{/id}","created_at":"2015-07-20T07:01:49Z","updated_at":"2015-11-24T13:41:38Z","pushed_at":"2015-11-25T11:50:47Z","git_url":"git://github.com/Yelp/fullerite.git","ssh_url":"git@github.com:Yelp/fullerite.git","clone_url":"https://github.com/Yelp/fullerite.git","svn_url":"https://github.com/Yelp/fullerite","homepage":"","size":6836,"stargazers_count":101,"watchers_count":101,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":21,"mirror_url":null,"open_issues_count":19,"forks":21,"open_issues":19,"watchers":101,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Yelp/fullerite/pulls/94"},"html":{"href":"https://github.com/Yelp/fullerite/pull/94"},"issue":{"href":"https://api.github.com/repos/Yelp/fullerite/issues/94"},"comments":{"href":"https://api.github.com/repos/Yelp/fullerite/issues/94/comments"},"review_comments":{"href":"https://api.github.com/repos/Yelp/fullerite/pulls/94/comments"},"review_comment":{"href":"https://api.github.com/repos/Yelp/fullerite/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Yelp/fullerite/pulls/94/commits"},"statuses":{"href":"https://api.github.com/repos/Yelp/fullerite/statuses/ecf5e1e1eaae50bb7f17942913a676a44a17d183"}}}}