{"action":"created","comment":{"url":"https://api.github.com/repos/prometheus/procfs/pulls/comments/39446022","id":39446022,"diff_hunk":"@@ -0,0 +1,164 @@\n+package procfs\n+\n+import (\n+\t\"fmt\"\n+\t\"io/ioutil\"\n+\t\"regexp\"\n+\t\"strconv\"\n+\t\"strings\"\n+\t\"path\"\n+\n+)\n+\n+var (\n+\tstatuslineRE = regexp.MustCompile(`(\\d+) blocks .*\\[(\\d+)/(\\d+)\\] \\[[U_]+\\]`)\n+\tbuildlineRE  = regexp.MustCompile(`\\((\\d+)/\\d+\\)`)\n+)\n+\n+// MDStatus holds info parsed from /proc/mdstat.\n+type MDStatus struct {\n+\t// Name of the device.\n+\tMDName       string\n+\t// activity-state of the device.\n+\tIsActive     bool\n+\t// Number of active disks.\n+\tDisksActive  int64\n+\t// Total number of disks the device consists of.\n+\tDisksTotal   int64\n+\t// Number of blocks the device holds.\n+\tBlocksTotal  int64\n+\t// Number of blocks on the device that are in sync.\n+\tBlocksSynced int64\n+}\n+\n+func evalStatusline(statusline string) (active, total, size int64, err error) {\n+\tmatches := statuslineRE.FindStringSubmatch(statusline)\n+\n+\t// +1 to make it more obvious that the whole string containing the info is also returned as matches[0].\n+\tif len(matches) < 3+1 {\n+\t\treturn 0, 0, 0, fmt.Errorf(\"too few matches found in statusline: %s\", statusline)\n+\t} else {\n+\t\tif len(matches) > 3+1 {\n+\t\t\treturn 0, 0, 0, fmt.Errorf(\"too many matches found in statusline: %s\", statusline)\n+\t\t}\n+\t}\n+\n+\tsize, err = strconv.ParseInt(matches[1], 10, 64)\n+\tif err != nil {\n+\t\treturn 0, 0, 0, fmt.Errorf(\"%s in statusline: %s\", err, statusline)\n+\t}\n+\n+\ttotal, err = strconv.ParseInt(matches[2], 10, 64)\n+\tif err != nil {\n+\t\treturn 0, 0, 0, fmt.Errorf(\"%s in statusline: %s\", err, statusline)\n+\t}\n+\tactive, err = strconv.ParseInt(matches[3], 10, 64)\n+\tif err != nil {\n+\t\treturn 0, 0, 0, fmt.Errorf(\"%s in statusline: %s\", err, statusline)\n+\t}\n+\n+\treturn active, total, size, nil\n+}\n+\n+// Gets the size that has already been synced out of the sync-line.\n+func evalBuildline(buildline string) (int64, error) {\n+\tmatches := buildlineRE.FindStringSubmatch(buildline)\n+\n+\t// +1 to make it more obvious that the whole string containing the info is also returned as matches[0].\n+\tif len(matches) < 1+1 {\n+\t\treturn 0, fmt.Errorf(\"too few matches found in buildline: %s\", buildline)\n+\t}\n+\n+\tif len(matches) > 1+1 {\n+\t\treturn 0, fmt.Errorf(\"too many matches found in buildline: %s\", buildline)\n+\t}\n+\n+\tsyncedSize, err := strconv.ParseInt(matches[1], 10, 64)\n+\n+\tif err != nil {\n+\t\treturn 0, fmt.Errorf(\"%s in buildline: %s\", err, buildline)\n+\t}\n+\n+\treturn syncedSize, nil\n+}\n+\n+// ParseMdstat parses an mdstat-file and returns a struct with the relevant infos.\n+func (fs FS) ParseMdstat() (mdstates []MDStatus, err error) {\n+\tmdStatusFilePath := path.Join(string(fs), \"mdstat\")\n+\tcontent, err := ioutil.ReadFile(mdStatusFilePath)\n+\tif err != nil {\n+\t\treturn []MDStatus{}, fmt.Errorf(\"error parsing %s: %s\", mdStatusFilePath, err)\n+\t}\n+\n+\tmdStatusFile := string(content)\n+\n+\tlines := strings.Split(mdStatusFile, \"\\n\")\n+\tvar currentMD string\n+\n+\t// Each md has at least the deviceline, statusline and one empty line afterwards\n+\t// so we will have probably something of the order len(lines)/3 devices\n+\t// so we use that for preallocation.\n+\testimateMDs := len(lines) / 3\n+\tmdStates := make([]MDStatus, 0, estimateMDs)\n+\n+\tfor i, l := range lines {\n+\t\tif l == \"\" {\n+\t\t\t// Skip entirely empty lines.\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tif l[0] == ' ' {\n+\t\t\t// Those lines are not the beginning of a md-section.\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tif strings.HasPrefix(l, \"Personalities\") || strings.HasPrefix(l, \"unused\") {\n+\t\t\t// We aren't interested in lines with general info.\n+\t\t\tcontinue\n+\t\t}\n+\n+\t\tmainLine := strings.Split(l, \" \")\n+\t\tif len(mainLine) < 3 {\n+\t\t\treturn mdStates, fmt.Errorf(\"error parsing mdline: %s\", l)\n+\t\t}\n+\t\tcurrentMD = mainLine[0]               // name of md-device\n+\t\tisActive := (mainLine[2] == \"active\") // activity status of said md-device\n+\n+\t\tif len(lines) <= i+3 {\n+\t\t\treturn mdStates, fmt.Errorf(\"error parsing %s: entry for %s has fewer lines than expected\", mdStatusFilePath, currentMD)\n+\t\t}\n+\n+\t\tactive, total, size, err := evalStatusline(lines[i+1]) // parse statusline, always present\n+\n+\t\tif err != nil {\n+\t\t\treturn mdStates, fmt.Errorf(\"error parsing %s: %s\", mdStatusFilePath, err)\n+\t\t}\n+\n+\t\t// Now get the number of synced blocks.\n+\t\tvar syncedBlocks int64\n+\n+\t\t// Get the line number of the syncing-line.\n+\t\tvar j int\n+\t\tif strings.Contains(lines[i+2], \"bitmap\") { // then skip the bitmap line\n+\t\t\tj = i + 3\n+\t\t} else {\n+\t\t\tj = i + 2\n+\t\t}\n+\n+\t\t// If device is syncing at the moment, get the number of currently synced bytes,\n+\t\t// otherwise that number equals the size of the device.\n+\t\tif strings.Contains(lines[j], \"recovery\") || strings.Contains(lines[j], \"resync\") {\n+\t\t\tsyncedBlocks, err = evalBuildline(lines[j])\n+\t\t\tif err != nil {\n+\t\t\t\treturn mdStates, fmt.Errorf(\"error parsing %s: %s\", mdStatusFilePath, err)\n+\t\t\t}\n+\t\t} else {\n+\t\t\tsyncedBlocks = size","path":"mdstat.go","position":null,"original_position":156,"commit_id":"c3fd71350b4fd9adc0a104a4023b4889252bc343","original_commit_id":"73d89ecef7c287bcad359135d45fe0d6efeab92c","user":{"login":"cherti","id":6452205,"avatar_url":"https://avatars.githubusercontent.com/u/6452205?v=3","gravatar_id":"","url":"https://api.github.com/users/cherti","html_url":"https://github.com/cherti","followers_url":"https://api.github.com/users/cherti/followers","following_url":"https://api.github.com/users/cherti/following{/other_user}","gists_url":"https://api.github.com/users/cherti/gists{/gist_id}","starred_url":"https://api.github.com/users/cherti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cherti/subscriptions","organizations_url":"https://api.github.com/users/cherti/orgs","repos_url":"https://api.github.com/users/cherti/repos","events_url":"https://api.github.com/users/cherti/events{/privacy}","received_events_url":"https://api.github.com/users/cherti/received_events","type":"User","site_admin":false},"body":"done","created_at":"2015-09-14T20:57:03Z","updated_at":"2015-09-14T20:57:03Z","html_url":"https://github.com/prometheus/procfs/pull/12#discussion_r39446022","pull_request_url":"https://api.github.com/repos/prometheus/procfs/pulls/12","_links":{"self":{"href":"https://api.github.com/repos/prometheus/procfs/pulls/comments/39446022"},"html":{"href":"https://github.com/prometheus/procfs/pull/12#discussion_r39446022"},"pull_request":{"href":"https://api.github.com/repos/prometheus/procfs/pulls/12"}}},"pull_request":{"url":"https://api.github.com/repos/prometheus/procfs/pulls/12","id":44963140,"html_url":"https://github.com/prometheus/procfs/pull/12","diff_url":"https://github.com/prometheus/procfs/pull/12.diff","patch_url":"https://github.com/prometheus/procfs/pull/12.patch","issue_url":"https://api.github.com/repos/prometheus/procfs/issues/12","number":12,"state":"open","locked":false,"title":"adding mdstat-parser to procfs","user":{"login":"cherti","id":6452205,"avatar_url":"https://avatars.githubusercontent.com/u/6452205?v=3","gravatar_id":"","url":"https://api.github.com/users/cherti","html_url":"https://github.com/cherti","followers_url":"https://api.github.com/users/cherti/followers","following_url":"https://api.github.com/users/cherti/following{/other_user}","gists_url":"https://api.github.com/users/cherti/gists{/gist_id}","starred_url":"https://api.github.com/users/cherti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cherti/subscriptions","organizations_url":"https://api.github.com/users/cherti/orgs","repos_url":"https://api.github.com/users/cherti/repos","events_url":"https://api.github.com/users/cherti/events{/privacy}","received_events_url":"https://api.github.com/users/cherti/received_events","type":"User","site_admin":false},"body":"Adding functionality used in node_exporter's mdadm-exporter to procfs, including unittest for the parsing-functionality.","created_at":"2015-09-14T18:22:36Z","updated_at":"2015-09-14T20:57:03Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bbb228a300192422d0a234cf07b91f4f6fd3f082","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/prometheus/procfs/pulls/12/commits","review_comments_url":"https://api.github.com/repos/prometheus/procfs/pulls/12/comments","review_comment_url":"https://api.github.com/repos/prometheus/procfs/pulls/comments{/number}","comments_url":"https://api.github.com/repos/prometheus/procfs/issues/12/comments","statuses_url":"https://api.github.com/repos/prometheus/procfs/statuses/c3fd71350b4fd9adc0a104a4023b4889252bc343","head":{"label":"cherti:mdstat","ref":"mdstat","sha":"c3fd71350b4fd9adc0a104a4023b4889252bc343","user":{"login":"cherti","id":6452205,"avatar_url":"https://avatars.githubusercontent.com/u/6452205?v=3","gravatar_id":"","url":"https://api.github.com/users/cherti","html_url":"https://github.com/cherti","followers_url":"https://api.github.com/users/cherti/followers","following_url":"https://api.github.com/users/cherti/following{/other_user}","gists_url":"https://api.github.com/users/cherti/gists{/gist_id}","starred_url":"https://api.github.com/users/cherti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cherti/subscriptions","organizations_url":"https://api.github.com/users/cherti/orgs","repos_url":"https://api.github.com/users/cherti/repos","events_url":"https://api.github.com/users/cherti/events{/privacy}","received_events_url":"https://api.github.com/users/cherti/received_events","type":"User","site_admin":false},"repo":{"id":42374954,"name":"procfs","full_name":"cherti/procfs","owner":{"login":"cherti","id":6452205,"avatar_url":"https://avatars.githubusercontent.com/u/6452205?v=3","gravatar_id":"","url":"https://api.github.com/users/cherti","html_url":"https://github.com/cherti","followers_url":"https://api.github.com/users/cherti/followers","following_url":"https://api.github.com/users/cherti/following{/other_user}","gists_url":"https://api.github.com/users/cherti/gists{/gist_id}","starred_url":"https://api.github.com/users/cherti/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cherti/subscriptions","organizations_url":"https://api.github.com/users/cherti/orgs","repos_url":"https://api.github.com/users/cherti/repos","events_url":"https://api.github.com/users/cherti/events{/privacy}","received_events_url":"https://api.github.com/users/cherti/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/cherti/procfs","description":"procfs provides functions to retrieve system, kernel and process metrics from the pseudo-filesystem proc.","fork":true,"url":"https://api.github.com/repos/cherti/procfs","forks_url":"https://api.github.com/repos/cherti/procfs/forks","keys_url":"https://api.github.com/repos/cherti/procfs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/cherti/procfs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/cherti/procfs/teams","hooks_url":"https://api.github.com/repos/cherti/procfs/hooks","issue_events_url":"https://api.github.com/repos/cherti/procfs/issues/events{/number}","events_url":"https://api.github.com/repos/cherti/procfs/events","assignees_url":"https://api.github.com/repos/cherti/procfs/assignees{/user}","branches_url":"https://api.github.com/repos/cherti/procfs/branches{/branch}","tags_url":"https://api.github.com/repos/cherti/procfs/tags","blobs_url":"https://api.github.com/repos/cherti/procfs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/cherti/procfs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/cherti/procfs/git/refs{/sha}","trees_url":"https://api.github.com/repos/cherti/procfs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/cherti/procfs/statuses/{sha}","languages_url":"https://api.github.com/repos/cherti/procfs/languages","stargazers_url":"https://api.github.com/repos/cherti/procfs/stargazers","contributors_url":"https://api.github.com/repos/cherti/procfs/contributors","subscribers_url":"https://api.github.com/repos/cherti/procfs/subscribers","subscription_url":"https://api.github.com/repos/cherti/procfs/subscription","commits_url":"https://api.github.com/repos/cherti/procfs/commits{/sha}","git_commits_url":"https://api.github.com/repos/cherti/procfs/git/commits{/sha}","comments_url":"https://api.github.com/repos/cherti/procfs/comments{/number}","issue_comment_url":"https://api.github.com/repos/cherti/procfs/issues/comments{/number}","contents_url":"https://api.github.com/repos/cherti/procfs/contents/{+path}","compare_url":"https://api.github.com/repos/cherti/procfs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/cherti/procfs/merges","archive_url":"https://api.github.com/repos/cherti/procfs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/cherti/procfs/downloads","issues_url":"https://api.github.com/repos/cherti/procfs/issues{/number}","pulls_url":"https://api.github.com/repos/cherti/procfs/pulls{/number}","milestones_url":"https://api.github.com/repos/cherti/procfs/milestones{/number}","notifications_url":"https://api.github.com/repos/cherti/procfs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/cherti/procfs/labels{/name}","releases_url":"https://api.github.com/repos/cherti/procfs/releases{/id}","created_at":"2015-09-12T22:10:28Z","updated_at":"2015-09-12T22:10:30Z","pushed_at":"2015-09-14T20:56:36Z","git_url":"git://github.com/cherti/procfs.git","ssh_url":"git@github.com:cherti/procfs.git","clone_url":"https://github.com/cherti/procfs.git","svn_url":"https://github.com/cherti/procfs","homepage":null,"size":113,"stargazers_count":0,"watchers_count":0,"language":"Go","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":"prometheus:master","ref":"master","sha":"c91d8eefde16bd047416409eb56353ea84a186e4","user":{"login":"prometheus","id":3380462,"avatar_url":"https://avatars.githubusercontent.com/u/3380462?v=3","gravatar_id":"","url":"https://api.github.com/users/prometheus","html_url":"https://github.com/prometheus","followers_url":"https://api.github.com/users/prometheus/followers","following_url":"https://api.github.com/users/prometheus/following{/other_user}","gists_url":"https://api.github.com/users/prometheus/gists{/gist_id}","starred_url":"https://api.github.com/users/prometheus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prometheus/subscriptions","organizations_url":"https://api.github.com/users/prometheus/orgs","repos_url":"https://api.github.com/users/prometheus/repos","events_url":"https://api.github.com/users/prometheus/events{/privacy}","received_events_url":"https://api.github.com/users/prometheus/received_events","type":"Organization","site_admin":false},"repo":{"id":28352089,"name":"procfs","full_name":"prometheus/procfs","owner":{"login":"prometheus","id":3380462,"avatar_url":"https://avatars.githubusercontent.com/u/3380462?v=3","gravatar_id":"","url":"https://api.github.com/users/prometheus","html_url":"https://github.com/prometheus","followers_url":"https://api.github.com/users/prometheus/followers","following_url":"https://api.github.com/users/prometheus/following{/other_user}","gists_url":"https://api.github.com/users/prometheus/gists{/gist_id}","starred_url":"https://api.github.com/users/prometheus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prometheus/subscriptions","organizations_url":"https://api.github.com/users/prometheus/orgs","repos_url":"https://api.github.com/users/prometheus/repos","events_url":"https://api.github.com/users/prometheus/events{/privacy}","received_events_url":"https://api.github.com/users/prometheus/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/prometheus/procfs","description":"procfs provides functions to retrieve system, kernel and process metrics from the pseudo-filesystem proc.","fork":false,"url":"https://api.github.com/repos/prometheus/procfs","forks_url":"https://api.github.com/repos/prometheus/procfs/forks","keys_url":"https://api.github.com/repos/prometheus/procfs/keys{/key_id}","collaborators_url":"https://api.github.com/repos/prometheus/procfs/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/prometheus/procfs/teams","hooks_url":"https://api.github.com/repos/prometheus/procfs/hooks","issue_events_url":"https://api.github.com/repos/prometheus/procfs/issues/events{/number}","events_url":"https://api.github.com/repos/prometheus/procfs/events","assignees_url":"https://api.github.com/repos/prometheus/procfs/assignees{/user}","branches_url":"https://api.github.com/repos/prometheus/procfs/branches{/branch}","tags_url":"https://api.github.com/repos/prometheus/procfs/tags","blobs_url":"https://api.github.com/repos/prometheus/procfs/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/prometheus/procfs/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/prometheus/procfs/git/refs{/sha}","trees_url":"https://api.github.com/repos/prometheus/procfs/git/trees{/sha}","statuses_url":"https://api.github.com/repos/prometheus/procfs/statuses/{sha}","languages_url":"https://api.github.com/repos/prometheus/procfs/languages","stargazers_url":"https://api.github.com/repos/prometheus/procfs/stargazers","contributors_url":"https://api.github.com/repos/prometheus/procfs/contributors","subscribers_url":"https://api.github.com/repos/prometheus/procfs/subscribers","subscription_url":"https://api.github.com/repos/prometheus/procfs/subscription","commits_url":"https://api.github.com/repos/prometheus/procfs/commits{/sha}","git_commits_url":"https://api.github.com/repos/prometheus/procfs/git/commits{/sha}","comments_url":"https://api.github.com/repos/prometheus/procfs/comments{/number}","issue_comment_url":"https://api.github.com/repos/prometheus/procfs/issues/comments{/number}","contents_url":"https://api.github.com/repos/prometheus/procfs/contents/{+path}","compare_url":"https://api.github.com/repos/prometheus/procfs/compare/{base}...{head}","merges_url":"https://api.github.com/repos/prometheus/procfs/merges","archive_url":"https://api.github.com/repos/prometheus/procfs/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/prometheus/procfs/downloads","issues_url":"https://api.github.com/repos/prometheus/procfs/issues{/number}","pulls_url":"https://api.github.com/repos/prometheus/procfs/pulls{/number}","milestones_url":"https://api.github.com/repos/prometheus/procfs/milestones{/number}","notifications_url":"https://api.github.com/repos/prometheus/procfs/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/prometheus/procfs/labels{/name}","releases_url":"https://api.github.com/repos/prometheus/procfs/releases{/id}","created_at":"2014-12-22T18:16:52Z","updated_at":"2015-09-01T09:14:57Z","pushed_at":"2015-09-14T20:56:36Z","git_url":"git://github.com/prometheus/procfs.git","ssh_url":"git@github.com:prometheus/procfs.git","clone_url":"https://github.com/prometheus/procfs.git","svn_url":"https://github.com/prometheus/procfs","homepage":null,"size":349,"stargazers_count":27,"watchers_count":27,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":10,"mirror_url":null,"open_issues_count":1,"forks":10,"open_issues":1,"watchers":27,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/prometheus/procfs/pulls/12"},"html":{"href":"https://github.com/prometheus/procfs/pull/12"},"issue":{"href":"https://api.github.com/repos/prometheus/procfs/issues/12"},"comments":{"href":"https://api.github.com/repos/prometheus/procfs/issues/12/comments"},"review_comments":{"href":"https://api.github.com/repos/prometheus/procfs/pulls/12/comments"},"review_comment":{"href":"https://api.github.com/repos/prometheus/procfs/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/prometheus/procfs/pulls/12/commits"},"statuses":{"href":"https://api.github.com/repos/prometheus/procfs/statuses/c3fd71350b4fd9adc0a104a4023b4889252bc343"}}}}