Skip to content

Commit

Permalink
Move the path simplification library into its own package
Browse files Browse the repository at this point in the history
Signed-off-by: Steve Kuznetsov <skuznets@redhat.com>
  • Loading branch information
stevekuznetsov committed Sep 19, 2019
1 parent 5b3409d commit 8116730
Show file tree
Hide file tree
Showing 8 changed files with 385 additions and 186 deletions.
1 change: 1 addition & 0 deletions ghproxy/ghmetrics/BUILD.bazel
Expand Up @@ -9,6 +9,7 @@ go_library(
importpath = "k8s.io/test-infra/ghproxy/ghmetrics",
visibility = ["//visibility:public"],
deps = [
"//prow/simplifypath:go_default_library",
"@com_github_prometheus_client_golang//prometheus:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
],
Expand Down
2 changes: 1 addition & 1 deletion ghproxy/ghmetrics/ghmetrics.go
Expand Up @@ -95,7 +95,7 @@ func CollectGitHubTokenMetrics(tokenHash, apiVersion string, headers http.Header
// CollectGitHubRequestMetrics publishes the number of requests by API path to
// `github_requests` on prometheus.
func CollectGitHubRequestMetrics(tokenHash, path, statusCode string, roundTripTime float64) {
ghRequestDurationHistVec.With(prometheus.Labels{"token_hash": tokenHash, "path": GetSimplifiedPath(path), "status": statusCode}).Observe(roundTripTime)
ghRequestDurationHistVec.With(prometheus.Labels{"token_hash": tokenHash, "path": simplifier.Simplify(path), "status": statusCode}).Observe(roundTripTime)
}

// timestampStringToTime takes a unix timestamp and returns a `time.Time`
Expand Down
291 changes: 112 additions & 179 deletions ghproxy/ghmetrics/ghpath.go
Expand Up @@ -17,191 +17,124 @@ limitations under the License.
package ghmetrics

import (
"strings"

"github.com/sirupsen/logrus"
"k8s.io/test-infra/prow/simplifypath"
)

const unmatchedPath = "unmatched"

// GetSimplifiedPath returns a variable-free path that can be used as label for prometheus metrics
func GetSimplifiedPath(path string) string {
tree := l("", // shadow element mimicing the root
l("repos",
v("owner",
v("repo",
l("branches", v("branch", l("protection",
l("restrictions", l("users"), l("teams")),
l("required_status_checks", l("contexts")),
l("required_pull_request_reviews"),
l("required_signatures"),
l("enforce_admins")))),
l("issues",
l("comments", v("commentId")),
l("events", v("eventId")),
v("issueId",
l("lock"),
l("comments"),
l("events"),
l("assignees"),
l("reactions"),
l("labels", v("labelId")))),
l("keys", v("keyId")),
l("labels", v("labelId")),
l("milestones", v("milestone")),
l("pulls", v("pullId")),
l("releases", v("releaseId")),
l("statuses", v("statusId")),
l("subscribers", v("subscriberId")),
l("assignees", v("assigneeId")),
l("archive", v("zip")),
l("collaborators", v("collaboratorId")),
var simplifier = simplifypath.NewSimplifier(l("", // shadow element mimicing the root
l("repos",
v("owner",
v("repo",
l("branches", v("branch", l("protection",
l("restrictions", l("users"), l("teams")),
l("required_status_checks", l("contexts")),
l("required_pull_request_reviews"),
l("required_signatures"),
l("enforce_admins")))),
l("issues",
l("comments", v("commentId")),
l("compare", v("sha")),
l("contents", v("contentId")),
l("events", v("eventId")),
v("issueId",
l("lock"),
l("comments"),
l("events"),
l("assignees"),
l("reactions"),
l("labels", v("labelId")))),
l("keys", v("keyId")),
l("labels", v("labelId")),
l("milestones", v("milestone")),
l("pulls", v("pullId")),
l("releases", v("releaseId")),
l("statuses", v("statusId")),
l("subscribers", v("subscriberId")),
l("assignees", v("assigneeId")),
l("archive", v("zip")),
l("collaborators", v("collaboratorId")),
l("comments", v("commentId")),
l("compare", v("sha")),
l("contents", v("contentId")),
l("commits", v("sha")),
l("git",
l("commits", v("sha")),
l("git",
l("commits", v("sha")),
l("ref", v("refId")),
l("tags", v("tagId")),
l("trees", v("sha")),
l("refs", l("heads", v("ref")))),
l("stars"),
l("merges"),
l("stargazers"),
l("notifications"),
l("hooks"),
l("deployments"),
l("downloads"),
l("events"),
l("forks"),
l("topics"),
l("vulnerability-alerts"),
l("automated-security-fixes"),
l("contributors"),
l("languages"),
l("teams"),
l("tags"),
l("transfer")))),
l("user",
l("following", v("userId")),
l("keys", v("keyId")),
l("email", l("visibility")),
l("emails"),
l("public_emails"),
l("followers"),
l("starred"),
l("issues")),
l("users",
v("username",
l("followers", v("username")),
l("repos"),
l("hovercard"),
l("following"))),
l("orgs",
v("orgname",
l("credential-authorizations", v("credentialId")),
l("repos"),
l("issues"),
l("invitations"),
l("members", v("login")),
l("teams"))),
l("organizations",
v("orgId",
l("members"),
l("repos"),
l("teams"))),
l("issues", v("issueId")),
l("search",
l("repositories"),
l("commits"),
l("code"),
l("ref", v("refId")),
l("tags", v("tagId")),
l("trees", v("sha")),
l("refs", l("heads", v("ref")))),
l("stars"),
l("merges"),
l("stargazers"),
l("notifications"),
l("hooks"),
l("deployments"),
l("downloads"),
l("events"),
l("forks"),
l("topics"),
l("vulnerability-alerts"),
l("automated-security-fixes"),
l("contributors"),
l("languages"),
l("teams"),
l("tags"),
l("transfer")))),
l("user",
l("following", v("userId")),
l("keys", v("keyId")),
l("email", l("visibility")),
l("emails"),
l("public_emails"),
l("followers"),
l("starred"),
l("issues")),
l("users",
v("username",
l("followers", v("username")),
l("repos"),
l("hovercard"),
l("following"))),
l("orgs",
v("orgname",
l("credential-authorizations", v("credentialId")),
l("repos"),
l("issues"),
l("users"),
l("topics"),
l("labels")),
l("gists",
l("public"),
l("starred")),
l("notifications", l("threads", v("threadId", l("subscription")))),
l("invitations"),
l("members", v("login")),
l("teams"))),
l("organizations",
v("orgId",
l("members"),
l("repos"),
l("teams"))),
l("issues", v("issueId")),
l("search",
l("repositories"),
l("emojis"),
l("events"),
l("feeds"),
l("hub"),
l("rate_limit"),
l("teams"),
// end point for gh api v4
l("graphql"),
l("licenses"))

splitPath := strings.Split(path, "/")
resolvedPath, matches := resolve(tree, splitPath)
if !matches {
logrus.WithField("path", path).Debug("Path not handled. This is a bug in GHProxy, please open an issue against the kubernetes/test-infra repository with this error message.")
return unmatchedPath
}
return resolvedPath
}

type node struct {
PathFragment
children []node
}

// PathFragment Interface for tree leafs to help resolve paths
type PathFragment interface {
Matches(part string) bool
Represent() string
}

type literal string

func (l literal) Matches(part string) bool {
return string(l) == part
}

func (l literal) Represent() string {
return string(l)
}

type variable string

func (v variable) Matches(part string) bool {
return true
}

func (v variable) Represent() string {
return ":" + string(v)
}

func l(fragment string, children ...node) node {
return node{
PathFragment: literal(fragment),
children: children,
}
}

func v(fragment string, children ...node) node {
return node{
PathFragment: variable(fragment),
children: children,
}
l("commits"),
l("code"),
l("issues"),
l("users"),
l("topics"),
l("labels")),
l("gists",
l("public"),
l("starred")),
l("notifications", l("threads", v("threadId", l("subscription")))),
l("repositories"),
l("emojis"),
l("events"),
l("feeds"),
l("hub"),
l("rate_limit"),
l("teams"),
// end point for gh api v4
l("graphql"),
l("licenses")))

// l and v keep the tree legible

func l(fragment string, children ...simplifypath.Node) simplifypath.Node {
return simplifypath.L(fragment, children...)
}

func resolve(parent node, path []string) (string, bool) {
if !parent.Matches(path[0]) {
return "", false
}
representation := parent.Represent()
if len(path) == 1 || len(parent.children) == 0 {
return representation, true
}
for _, child := range parent.children {
suffix, matched := resolve(child, path[1:])
if matched {
return strings.Join([]string{representation, suffix}, "/"), true
}
}
return "", false
func v(fragment string, children ...simplifypath.Node) simplifypath.Node {
return simplifypath.V(fragment, children...)
}
12 changes: 6 additions & 6 deletions ghproxy/ghmetrics/ghpath_test.go
Expand Up @@ -63,7 +63,7 @@ func Test_GetSimplifiedPath(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetSimplifiedPath(tt.args.path); got != tt.want {
if got := simplifier.Simplify(tt.args.path); got != tt.want {
t.Errorf("GetSimplifiedPath(%s) = %v, want %v", tt.args.path, got, tt.want)
}
})
Expand Down Expand Up @@ -196,7 +196,7 @@ func Test_GetSimplifiedPathRepos(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetSimplifiedPath(tt.args.path); got != tt.want {
if got := simplifier.Simplify(tt.args.path); got != tt.want {
t.Errorf("GetSimplifiedPath(%s) = %v, want %v", tt.args.path, got, tt.want)
}
})
Expand Down Expand Up @@ -233,7 +233,7 @@ func Test_GetSimplifiedPathUser(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetSimplifiedPath(tt.args.path); got != tt.want {
if got := simplifier.Simplify(tt.args.path); got != tt.want {
t.Errorf("GetSimplifiedPath(%s) = %v, want %v", tt.args.path, got, tt.want)
}
})
Expand Down Expand Up @@ -263,7 +263,7 @@ func Test_GetSimplifiedPathUsers(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetSimplifiedPath(tt.args.path); got != tt.want {
if got := simplifier.Simplify(tt.args.path); got != tt.want {
t.Errorf("GetSimplifiedPath() = %v, want %v", got, tt.want)
}
})
Expand Down Expand Up @@ -300,7 +300,7 @@ func Test_GetSimplifiedPathOrgs(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetSimplifiedPath(tt.args.path); got != tt.want {
if got := simplifier.Simplify(tt.args.path); got != tt.want {
t.Errorf("GetSimplifiedPath(%s) = %v, want %v", tt.args.path, got, tt.want)
}
})
Expand All @@ -323,7 +323,7 @@ func Test_GetSimplifiedPathNotifications(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := GetSimplifiedPath(tt.args.path); got != tt.want {
if got := simplifier.Simplify(tt.args.path); got != tt.want {
t.Errorf("GetSimplifiedPath(%s) = %v, want %v", tt.args.path, got, tt.want)
}
})
Expand Down
1 change: 1 addition & 0 deletions prow/BUILD.bazel
Expand Up @@ -150,6 +150,7 @@ filegroup(
"//prow/pubsub/subscriber:all-srcs",
"//prow/repoowners:all-srcs",
"//prow/sidecar:all-srcs",
"//prow/simplifypath:all-srcs",
"//prow/slack:all-srcs",
"//prow/spyglass:all-srcs",
"//prow/statusreconciler:all-srcs",
Expand Down

0 comments on commit 8116730

Please sign in to comment.