{"action":"created","comment":{"url":"https://api.github.com/repos/Clever/kayvee-go/pulls/comments/81663727","pull_request_review_id":2627520,"id":81663727,"diff_hunk":"@@ -0,0 +1,188 @@\n+package router\n+\n+import (\n+\t\"fmt\"\n+\t\"reflect\"\n+\t\"strings\"\n+\n+\t\"github.com/Clever/go-utils/stringset\"\n+)\n+\n+// UnmarshalYAML unmarshals the `matchers` section of a log-routing\n+// configuration. It ensures that this section is a map from strings to either\n+// a single string or a list of strings and that:\n+// - Keys and values contain no special characters -- $, %, {, or } -- and\n+//   hence no substitutions\n+// - If value is a list, there are no repeated elements\n+func (m *RuleMatchers) UnmarshalYAML(unmarshal func(interface{}) error) error {\n+\tvar data map[string]interface{}\n+\n+\terr := unmarshal(&data)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\t*m = RuleMatchers(make(map[string][]string))\n+\n+\tfor field, value := range data {\n+\t\terr := ensureNoSpecials(field)\n+\t\tif err != nil {\n+\t\t\treturn fmt.Errorf(\"Invalid matcher field name '%s': %s\", field, err.Error())\n+\t\t}\n+\n+\t\ttypeErr := fmt.Errorf(\"Invalid type for matcher value on field '%s': %+v.\\n\\tShould be string or slice of strings.\", field, value)\n+\t\tswitch value := value.(type) {\n+\t\tcase string:\n+\t\t\terr := ensureNoSpecials(value)\n+\t\t\tif err != nil {\n+\t\t\t\treturn fmt.Errorf(\"Invalid matcher value '%s' on field '%s': %s\",\n+\t\t\t\t\tvalue, field, err.Error())\n+\t\t\t}\n+\t\t\t(*m)[field] = []string{value}\n+\t\tcase []interface{}:\n+\t\t\tstrValue := make([]string, len(value))\n+\t\t\tfor i, v := range value {\n+\t\t\t\tif str, ok := v.(string); ok {\n+\t\t\t\t\terr := ensureNoSpecials(str)\n+\t\t\t\t\tif err != nil {\n+\t\t\t\t\t\treturn fmt.Errorf(\"Invalid matcher value '%s' on field '%s': %s\",\n+\t\t\t\t\t\t\tstr, field, err.Error())\n+\t\t\t\t\t}\n+\t\t\t\t\tstrValue[i] = str\n+\t\t\t\t} else {\n+\t\t\t\t\treturn typeErr\n+\t\t\t\t}\n+\t\t\t}\n+\t\t\terr := ensureNoRepeats(strValue)\n+\t\t\tif err != nil {\n+\t\t\t\treturn fmt.Errorf(\"Invalid matcher value on field '%s': %s\", field, err.Error())\n+\t\t\t}\n+\t\t\t(*m)[field] = strValue\n+\t\tdefault:\n+\t\t\treturn typeErr\n+\t\t}\n+\t}\n+\n+\treturn nil\n+}\n+\n+// UnmarshalYAML unmarshals the `output` section of a log-routing\n+// configuration. It ultimately just unmarshals into a map[string]interface{}\n+// but before doing so it uses the WhateverOutput structs defined in rule.go to\n+// validate the format are correct for whatever type of output is specified.\n+func (o *RuleOutput) UnmarshalYAML(unmarshal func(interface{}) error) error {\n+\tvar obj struct {\n+\t\tType string\n+\t}\n+\terr := unmarshal(&obj)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tswitch obj.Type {\n+\tcase \"metrics\":\n+\t\tvar metrics metricsOutput\n+\t\terr := validateStrict(&metrics, unmarshal)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\tcase \"alert\":\n+\t\tvar alert alertOutput\n+\t\terr := validateStrict(&alert, unmarshal)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\tcase \"analytics\":\n+\t\tvar analytics analyticsOutput\n+\t\terr := validateStrict(&analytics, unmarshal)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\tcase \"notification\":\n+\t\tvar notification notificationOutput\n+\t\terr := validateStrict(&notification, unmarshal)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\tdefault:\n+\t\treturn fmt.Errorf(\"Unknown output type: %s\", obj.Type)\n+\t}\n+\n+\tvar result map[string]interface{}\n+\terr = unmarshal(&result)\n+\t*o = result\n+\treturn err","path":"router/parse.go","position":114,"original_position":114,"commit_id":"6e000ac46fed3ee12cbb46bcdd5ec4514916294c","original_commit_id":"6e000ac46fed3ee12cbb46bcdd5ec4514916294c","user":{"login":"nathanleiby","id":102242,"avatar_url":"https://avatars.githubusercontent.com/u/102242?v=3","gravatar_id":"","url":"https://api.github.com/users/nathanleiby","html_url":"https://github.com/nathanleiby","followers_url":"https://api.github.com/users/nathanleiby/followers","following_url":"https://api.github.com/users/nathanleiby/following{/other_user}","gists_url":"https://api.github.com/users/nathanleiby/gists{/gist_id}","starred_url":"https://api.github.com/users/nathanleiby/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nathanleiby/subscriptions","organizations_url":"https://api.github.com/users/nathanleiby/orgs","repos_url":"https://api.github.com/users/nathanleiby/repos","events_url":"https://api.github.com/users/nathanleiby/events{/privacy}","received_events_url":"https://api.github.com/users/nathanleiby/received_events","type":"User","site_admin":false},"body":"+1 to only supporting this in notification msg body.","created_at":"2016-10-03T23:45:16Z","updated_at":"2016-10-03T23:45:16Z","html_url":"https://github.com/Clever/kayvee-go/pull/31#discussion_r81663727","pull_request_url":"https://api.github.com/repos/Clever/kayvee-go/pulls/31","_links":{"self":{"href":"https://api.github.com/repos/Clever/kayvee-go/pulls/comments/81663727"},"html":{"href":"https://github.com/Clever/kayvee-go/pull/31#discussion_r81663727"},"pull_request":{"href":"https://api.github.com/repos/Clever/kayvee-go/pulls/31"}}},"pull_request":{"url":"https://api.github.com/repos/Clever/kayvee-go/pulls/31","id":87255859,"html_url":"https://github.com/Clever/kayvee-go/pull/31","diff_url":"https://github.com/Clever/kayvee-go/pull/31.diff","patch_url":"https://github.com/Clever/kayvee-go/pull/31.patch","issue_url":"https://api.github.com/repos/Clever/kayvee-go/issues/31","number":31,"state":"open","locked":false,"title":"Log Routing","user":{"login":"samfishman","id":184140,"avatar_url":"https://avatars.githubusercontent.com/u/184140?v=3","gravatar_id":"","url":"https://api.github.com/users/samfishman","html_url":"https://github.com/samfishman","followers_url":"https://api.github.com/users/samfishman/followers","following_url":"https://api.github.com/users/samfishman/following{/other_user}","gists_url":"https://api.github.com/users/samfishman/gists{/gist_id}","starred_url":"https://api.github.com/users/samfishman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samfishman/subscriptions","organizations_url":"https://api.github.com/users/samfishman/orgs","repos_url":"https://api.github.com/users/samfishman/repos","events_url":"https://api.github.com/users/samfishman/events{/privacy}","received_events_url":"https://api.github.com/users/samfishman/received_events","type":"User","site_admin":false},"body":"**Jira:** https://clever.atlassian.net/browse/INFRA-1960\r\n\r\n**Overview:**\r\nAdds log matching/routing to kayvee. This consists of two main parts:\r\n- Parsing and validating the config file – see router/parse.go\r\n- Process log lines as they are emitted by the app and augment them with the routing rules that match the log line – see router/match.go\r\n\r\n**Testing:**\r\nAdded unit tests.","created_at":"2016-09-29T06:55:55Z","updated_at":"2016-10-03T23:45:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5da2e4a2556d67f8a4049cbd799df5224d83ec9b","assignee":{"login":"xavi-","id":75434,"avatar_url":"https://avatars.githubusercontent.com/u/75434?v=3","gravatar_id":"","url":"https://api.github.com/users/xavi-","html_url":"https://github.com/xavi-","followers_url":"https://api.github.com/users/xavi-/followers","following_url":"https://api.github.com/users/xavi-/following{/other_user}","gists_url":"https://api.github.com/users/xavi-/gists{/gist_id}","starred_url":"https://api.github.com/users/xavi-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xavi-/subscriptions","organizations_url":"https://api.github.com/users/xavi-/orgs","repos_url":"https://api.github.com/users/xavi-/repos","events_url":"https://api.github.com/users/xavi-/events{/privacy}","received_events_url":"https://api.github.com/users/xavi-/received_events","type":"User","site_admin":false},"assignees":[{"login":"xavi-","id":75434,"avatar_url":"https://avatars.githubusercontent.com/u/75434?v=3","gravatar_id":"","url":"https://api.github.com/users/xavi-","html_url":"https://github.com/xavi-","followers_url":"https://api.github.com/users/xavi-/followers","following_url":"https://api.github.com/users/xavi-/following{/other_user}","gists_url":"https://api.github.com/users/xavi-/gists{/gist_id}","starred_url":"https://api.github.com/users/xavi-/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xavi-/subscriptions","organizations_url":"https://api.github.com/users/xavi-/orgs","repos_url":"https://api.github.com/users/xavi-/repos","events_url":"https://api.github.com/users/xavi-/events{/privacy}","received_events_url":"https://api.github.com/users/xavi-/received_events","type":"User","site_admin":false},{"login":"samfishman","id":184140,"avatar_url":"https://avatars.githubusercontent.com/u/184140?v=3","gravatar_id":"","url":"https://api.github.com/users/samfishman","html_url":"https://github.com/samfishman","followers_url":"https://api.github.com/users/samfishman/followers","following_url":"https://api.github.com/users/samfishman/following{/other_user}","gists_url":"https://api.github.com/users/samfishman/gists{/gist_id}","starred_url":"https://api.github.com/users/samfishman/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/samfishman/subscriptions","organizations_url":"https://api.github.com/users/samfishman/orgs","repos_url":"https://api.github.com/users/samfishman/repos","events_url":"https://api.github.com/users/samfishman/events{/privacy}","received_events_url":"https://api.github.com/users/samfishman/received_events","type":"User","site_admin":false}],"milestone":null,"commits_url":"https://api.github.com/repos/Clever/kayvee-go/pulls/31/commits","review_comments_url":"https://api.github.com/repos/Clever/kayvee-go/pulls/31/comments","review_comment_url":"https://api.github.com/repos/Clever/kayvee-go/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Clever/kayvee-go/issues/31/comments","statuses_url":"https://api.github.com/repos/Clever/kayvee-go/statuses/6e000ac46fed3ee12cbb46bcdd5ec4514916294c","head":{"label":"Clever:log-routing","ref":"log-routing","sha":"6e000ac46fed3ee12cbb46bcdd5ec4514916294c","user":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"repo":{"id":24740201,"name":"kayvee-go","full_name":"Clever/kayvee-go","owner":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Clever/kayvee-go","description":"Logs for human and machine readability","fork":false,"url":"https://api.github.com/repos/Clever/kayvee-go","forks_url":"https://api.github.com/repos/Clever/kayvee-go/forks","keys_url":"https://api.github.com/repos/Clever/kayvee-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Clever/kayvee-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Clever/kayvee-go/teams","hooks_url":"https://api.github.com/repos/Clever/kayvee-go/hooks","issue_events_url":"https://api.github.com/repos/Clever/kayvee-go/issues/events{/number}","events_url":"https://api.github.com/repos/Clever/kayvee-go/events","assignees_url":"https://api.github.com/repos/Clever/kayvee-go/assignees{/user}","branches_url":"https://api.github.com/repos/Clever/kayvee-go/branches{/branch}","tags_url":"https://api.github.com/repos/Clever/kayvee-go/tags","blobs_url":"https://api.github.com/repos/Clever/kayvee-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Clever/kayvee-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Clever/kayvee-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/Clever/kayvee-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Clever/kayvee-go/statuses/{sha}","languages_url":"https://api.github.com/repos/Clever/kayvee-go/languages","stargazers_url":"https://api.github.com/repos/Clever/kayvee-go/stargazers","contributors_url":"https://api.github.com/repos/Clever/kayvee-go/contributors","subscribers_url":"https://api.github.com/repos/Clever/kayvee-go/subscribers","subscription_url":"https://api.github.com/repos/Clever/kayvee-go/subscription","commits_url":"https://api.github.com/repos/Clever/kayvee-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/Clever/kayvee-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/Clever/kayvee-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/Clever/kayvee-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/Clever/kayvee-go/contents/{+path}","compare_url":"https://api.github.com/repos/Clever/kayvee-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Clever/kayvee-go/merges","archive_url":"https://api.github.com/repos/Clever/kayvee-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Clever/kayvee-go/downloads","issues_url":"https://api.github.com/repos/Clever/kayvee-go/issues{/number}","pulls_url":"https://api.github.com/repos/Clever/kayvee-go/pulls{/number}","milestones_url":"https://api.github.com/repos/Clever/kayvee-go/milestones{/number}","notifications_url":"https://api.github.com/repos/Clever/kayvee-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Clever/kayvee-go/labels{/name}","releases_url":"https://api.github.com/repos/Clever/kayvee-go/releases{/id}","deployments_url":"https://api.github.com/repos/Clever/kayvee-go/deployments","created_at":"2014-10-02T23:11:24Z","updated_at":"2016-03-04T02:38:13Z","pushed_at":"2016-09-30T00:29:01Z","git_url":"git://github.com/Clever/kayvee-go.git","ssh_url":"git@github.com:Clever/kayvee-go.git","clone_url":"https://github.com/Clever/kayvee-go.git","svn_url":"https://github.com/Clever/kayvee-go","homepage":"","size":127,"stargazers_count":1,"watchers_count":1,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"master"}},"base":{"label":"Clever:master","ref":"master","sha":"98255d50fcf3814080f5c66d47acaba8866e7900","user":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"repo":{"id":24740201,"name":"kayvee-go","full_name":"Clever/kayvee-go","owner":{"login":"Clever","id":1885509,"avatar_url":"https://avatars.githubusercontent.com/u/1885509?v=3","gravatar_id":"","url":"https://api.github.com/users/Clever","html_url":"https://github.com/Clever","followers_url":"https://api.github.com/users/Clever/followers","following_url":"https://api.github.com/users/Clever/following{/other_user}","gists_url":"https://api.github.com/users/Clever/gists{/gist_id}","starred_url":"https://api.github.com/users/Clever/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Clever/subscriptions","organizations_url":"https://api.github.com/users/Clever/orgs","repos_url":"https://api.github.com/users/Clever/repos","events_url":"https://api.github.com/users/Clever/events{/privacy}","received_events_url":"https://api.github.com/users/Clever/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Clever/kayvee-go","description":"Logs for human and machine readability","fork":false,"url":"https://api.github.com/repos/Clever/kayvee-go","forks_url":"https://api.github.com/repos/Clever/kayvee-go/forks","keys_url":"https://api.github.com/repos/Clever/kayvee-go/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Clever/kayvee-go/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Clever/kayvee-go/teams","hooks_url":"https://api.github.com/repos/Clever/kayvee-go/hooks","issue_events_url":"https://api.github.com/repos/Clever/kayvee-go/issues/events{/number}","events_url":"https://api.github.com/repos/Clever/kayvee-go/events","assignees_url":"https://api.github.com/repos/Clever/kayvee-go/assignees{/user}","branches_url":"https://api.github.com/repos/Clever/kayvee-go/branches{/branch}","tags_url":"https://api.github.com/repos/Clever/kayvee-go/tags","blobs_url":"https://api.github.com/repos/Clever/kayvee-go/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Clever/kayvee-go/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Clever/kayvee-go/git/refs{/sha}","trees_url":"https://api.github.com/repos/Clever/kayvee-go/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Clever/kayvee-go/statuses/{sha}","languages_url":"https://api.github.com/repos/Clever/kayvee-go/languages","stargazers_url":"https://api.github.com/repos/Clever/kayvee-go/stargazers","contributors_url":"https://api.github.com/repos/Clever/kayvee-go/contributors","subscribers_url":"https://api.github.com/repos/Clever/kayvee-go/subscribers","subscription_url":"https://api.github.com/repos/Clever/kayvee-go/subscription","commits_url":"https://api.github.com/repos/Clever/kayvee-go/commits{/sha}","git_commits_url":"https://api.github.com/repos/Clever/kayvee-go/git/commits{/sha}","comments_url":"https://api.github.com/repos/Clever/kayvee-go/comments{/number}","issue_comment_url":"https://api.github.com/repos/Clever/kayvee-go/issues/comments{/number}","contents_url":"https://api.github.com/repos/Clever/kayvee-go/contents/{+path}","compare_url":"https://api.github.com/repos/Clever/kayvee-go/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Clever/kayvee-go/merges","archive_url":"https://api.github.com/repos/Clever/kayvee-go/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Clever/kayvee-go/downloads","issues_url":"https://api.github.com/repos/Clever/kayvee-go/issues{/number}","pulls_url":"https://api.github.com/repos/Clever/kayvee-go/pulls{/number}","milestones_url":"https://api.github.com/repos/Clever/kayvee-go/milestones{/number}","notifications_url":"https://api.github.com/repos/Clever/kayvee-go/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Clever/kayvee-go/labels{/name}","releases_url":"https://api.github.com/repos/Clever/kayvee-go/releases{/id}","deployments_url":"https://api.github.com/repos/Clever/kayvee-go/deployments","created_at":"2014-10-02T23:11:24Z","updated_at":"2016-03-04T02:38:13Z","pushed_at":"2016-09-30T00:29:01Z","git_url":"git://github.com/Clever/kayvee-go.git","ssh_url":"git@github.com:Clever/kayvee-go.git","clone_url":"https://github.com/Clever/kayvee-go.git","svn_url":"https://github.com/Clever/kayvee-go","homepage":"","size":127,"stargazers_count":1,"watchers_count":1,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Clever/kayvee-go/pulls/31"},"html":{"href":"https://github.com/Clever/kayvee-go/pull/31"},"issue":{"href":"https://api.github.com/repos/Clever/kayvee-go/issues/31"},"comments":{"href":"https://api.github.com/repos/Clever/kayvee-go/issues/31/comments"},"review_comments":{"href":"https://api.github.com/repos/Clever/kayvee-go/pulls/31/comments"},"review_comment":{"href":"https://api.github.com/repos/Clever/kayvee-go/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Clever/kayvee-go/pulls/31/commits"},"statuses":{"href":"https://api.github.com/repos/Clever/kayvee-go/statuses/6e000ac46fed3ee12cbb46bcdd5ec4514916294c"}}}}
{"actor":{"display_login":"nathanleiby"}}