From b82a1e996c665ca947bae581c1e6030535c9f734 Mon Sep 17 00:00:00 2001 From: Ivan Daniluk Date: Thu, 15 Oct 2015 23:11:48 -0400 Subject: [PATCH] Add customizable endpoints ('/debug/vars') --- expvars.go | 4 +-- main.go | 3 +++ utils.go | 70 ++++++++++++++++++++++++++++++--------------------- utils_test.go | 33 ++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 31 deletions(-) diff --git a/expvars.go b/expvars.go index 5f1d20d..59e23fa 100644 --- a/expvars.go +++ b/expvars.go @@ -11,8 +11,8 @@ import ( "github.com/antonholmquist/jason" ) -// ExpvarsUrl is the default url for fetching expvar info. -const ExpvarsPath = "/debug/vars" +// DefaultEndpoint is the default url for fetching expvar info. +var DefaultEndpoint = "/debug/vars" // Expvar represents fetched expvar variable. type Expvar struct { diff --git a/main.go b/main.go index f5d0196..276d09b 100644 --- a/main.go +++ b/main.go @@ -17,12 +17,15 @@ var ( varsArg = flag.String("vars", "mem:memstats.Alloc,mem:memstats.Sys,mem:memstats.HeapAlloc,mem:memstats.HeapInuse,duration:memstats.PauseNs,duration:memstats.PauseTotalNs", "Vars to monitor (comma-separated)") dummy = flag.Bool("dummy", false, "Use dummy (console) output") self = flag.Bool("self", false, "Monitor itself") + endpoint = flag.String("endpoint", DefaultEndpoint, "URL endpoint for expvars") ) func main() { flag.Usage = Usage flag.Parse() + DefaultEndpoint = *endpoint + // Process ports/urls ports, _ := ParsePorts(*urls) if *self { diff --git a/utils.go b/utils.go index 0d8ba6e..82c1879 100644 --- a/utils.go +++ b/utils.go @@ -53,7 +53,9 @@ func flattenURLs(rawurl string, ports []string) ([]url.URL, error) { if err != nil { return nil, err } - baseUrl.Path = ExpvarsPath + if baseUrl.Path == "" { + baseUrl.Path = DefaultEndpoint + } // Create new URL for each port for _, port := range ports { @@ -69,35 +71,9 @@ func ParsePorts(s string) ([]url.URL, error) { var urls []url.URL fields := strings.FieldsFunc(s, func(r rune) bool { return r == ',' }) for _, field := range fields { - // Try simple 'ports range' mode, ports only ("1234-1235,80") - // Defaults to "localhost" will be used. - ports, err := parseRange(field) - if err == nil { - furls, err := flattenURLs("http://localhost", ports) - if err != nil { - return nil, err - } - urls = append(urls, furls...) - continue - } + rawurl, portsRange := extractUrlAndPorts(field) - // then, try host:ports notation ("localhost:1234-1235,https://remote:2000,2345") - var rawurl, portsRange string - parts := strings.FieldsFunc(field, func(r rune) bool { return r == ':' }) - switch len(parts) { - case 1: - // "1234-234" - rawurl = "http://localhost" - case 2: - // "localhost:1234" - rawurl, portsRange = parts[0], parts[1] - default: - // "https://user:pass@remote.name:1234" - rawurl = strings.Join(parts[:len(parts)-1], ":") - portsRange = parts[len(parts)-1] - } - - ports, err = parseRange(portsRange) + ports, err := parseRange(portsRange) if err != nil { return nil, ErrParsePorts } @@ -113,6 +89,42 @@ func ParsePorts(s string) ([]url.URL, error) { return urls, nil } +// extractUrlAndPorts attempts to split url and extract raw url +// for the single port and range of ports to parse. +// +// i.e. "http://name:1234-1236/_endpoint" would return "http://name/_endpoint" and +// "1234-1236" +func extractUrlAndPorts(s string) (string, string) { + var rawurl, ports string + parts := strings.Split(s, ":") + switch len(parts) { + case 1: + // "1234-234" + rawurl = "http://localhost" + ports = parts[0] + case 2: + // "localhost:1234" + rawurl, ports = parts[0], parts[1] + default: + // "https://user:pass@remote.name:1234" or "http://name:1234-1236/_endpoint" + + // construct endpoint from the first part of URI, before ports appera + rawurl = strings.Join(parts[:len(parts)-1], ":") + + // get either "1234-1235" or "1234-1235/_endpoint" + lastPart := parts[len(parts)-1] + + // try to find endpoint and attach it to rawurl + fields := strings.SplitN(lastPart, "/", 2) + ports = fields[0] + if len(fields) > 1 { + rawurl = fmt.Sprintf("%s/%s", rawurl, fields[1]) + } + } + + return rawurl, ports +} + // parseRange flattens port ranges, such as "1234-1240,1333" func parseRange(s string) ([]string, error) { portsInt, err := ranges.Parse(s) diff --git a/utils_test.go b/utils_test.go index 037ae86..6866e21 100644 --- a/utils_test.go +++ b/utils_test.go @@ -26,6 +26,29 @@ func TestUtils(t *testing.T) { } } +func TestExtractUrlAndPorts(t *testing.T) { + var rawurl, ports string + rawurl, ports = extractUrlAndPorts("40000-40002") + if rawurl != "http://localhost" || ports != "40000-40002" { + t.Fatalf("extract url and ports failed: %v, %v", rawurl, ports) + } + + rawurl, ports = extractUrlAndPorts("https://example.com:1234") + if rawurl != "https://example.com" || ports != "1234" { + t.Fatalf("extract url and ports failed: %v, %v", rawurl, ports) + } + + rawurl, ports = extractUrlAndPorts("http://user:passwd@example.com:1234-1256") + if rawurl != "http://user:passwd@example.com" || ports != "1234-1256" { + t.Fatalf("extract url and ports failed: %v, %v", rawurl, ports) + } + + rawurl, ports = extractUrlAndPorts("https://example.com:1234-1256/_endpoint") + if rawurl != "https://example.com/_endpoint" || ports != "1234-1256" { + t.Fatalf("extract url and ports failed: %v, %v", rawurl, ports) + } +} + func TestPorts(t *testing.T) { arg := "1234,1235" ports, err := ParsePorts(arg) @@ -85,4 +108,14 @@ func TestPorts(t *testing.T) { if err == nil { t.Fatalf("err shouldn't be nil") } + + // Test endpoints + arg = "localhost:2000,https://example.com:1234/_custom_expvars" + ports, err = ParsePorts(arg) + if err != nil { + t.Fatal(err) + } + if ports[0].Path != "/debug/vars" || ports[1].Path != "/_custom_expvars" { + t.Fatalf("ParsePorts returns wrong data: %v", ports) + } }