allow escaping the dot character in paths using a backslash

Occasionally expvar output contains keys that are hostnames,
IP addresses, or filenames that contain the "." character.  For
example:

{
  "bleve": {
    "bootDuration": 16559,
    "indexes": {
      "bench.bleve": {
        "index": {
          "analysis_time": 10889841135,
          "batches": 145,
          "deletes": 0,
          "errors": 0,
          "index_time": 21277401883,
          "lookup_queue_len": 0,
          "updates": 14500
        },
        "search_time": 0,
        "searches": 0
      }
    }
  }
...
}

I can now chart the lookup_queue_len value using the var:

bleve.indexes.bench\.bleve.index.lookup_queue_len

This partially addresses #11 (still does not escape colon character).
This commit is contained in:
Marty Schoch 2015-12-01 16:53:13 -05:00
parent 383ee494c1
commit e7f60e5a45
2 changed files with 90 additions and 1 deletions

46
var.go
View File

@ -38,7 +38,7 @@ const (
// Example: "mem:memstats.Alloc" => []string{"memstats", "Alloc"}
func (v VarName) ToSlice() []string {
start := strings.IndexRune(string(v), ':') + 1
slice := strings.FieldsFunc(string(v)[start:], func(r rune) bool { return r == '.' })
slice := DottedFieldsToSliceEscaped(string(v)[start:])
return slice
}
@ -128,3 +128,47 @@ func roundDuration(d time.Duration) time.Duration {
}
return d
}
func DottedFieldsToSliceEscaped(s string) []string {
rv := make([]string, 0)
lastSlash := false
curr := ""
for _, r := range s {
// base case, dot not after slash
if !lastSlash && r == '.' {
if len(curr) > 0 {
rv = append(rv, curr)
curr = ""
}
continue
} else if !lastSlash {
// any character not after slash
curr += string(r)
if r == '\\' {
lastSlash = true
} else {
lastSlash = false
}
continue
} else if r == '\\' {
// last was slash, and so is this
lastSlash = false // 2 slashes = 0
// we already appended a single slash on first
continue
} else if r == '.' {
// we see \. but already appended \ last time
// replace it with .
curr = curr[:len(curr)-1] + "."
lastSlash = false
} else {
// \ and any other character, ignore
curr += string(r)
lastSlash = false
continue
}
}
if len(curr) > 0 {
rv = append(rv, curr)
}
return rv
}

View File

@ -44,4 +44,49 @@ func TestVarName(t *testing.T) {
if kind != KindDuration {
t.Fatalf("Expecting kind to be %v, but got: %v", KindDuration, kind)
}
// single \. escapes the dot
v = VarName(`bleve.indexes.bench\.bleve.index.lookup_queue_len`)
slice = v.ToSlice()
if len(slice) != 5 || slice[0] != "bleve" || slice[1] != "indexes" || slice[2] != "bench.bleve" ||
slice[3] != "index" || slice[4] != "lookup_queue_len" {
t.Fatalf("ToSlice failed: %v", slice)
}
// double \\. escapes backslash, not dot
v = VarName(`bleve.indexes.bench\\.bleve.index.lookup_queue_len`)
slice = v.ToSlice()
if len(slice) != 6 || slice[0] != "bleve" || slice[1] != "indexes" || slice[2] != "bench\\" ||
slice[3] != "bleve" || slice[4] != "index" || slice[5] != "lookup_queue_len" {
t.Fatalf("ToSlice failed: %v", slice)
}
// triple \\\. escapes backslash then dot
v = VarName(`bleve.indexes.bench\\\.bleve.index.lookup_queue_len`)
slice = v.ToSlice()
if len(slice) != 5 || slice[0] != "bleve" || slice[1] != "indexes" || slice[2] != "bench\\.bleve" ||
slice[3] != "index" || slice[4] != "lookup_queue_len" {
t.Fatalf("ToSlice failed: %v", slice)
}
// quadruple \\\\. escapes two backslashes, not dot
v = VarName(`bleve.indexes.bench\\\\.bleve.index.lookup_queue_len`)
slice = v.ToSlice()
if len(slice) != 6 || slice[0] != "bleve" || slice[1] != "indexes" || slice[2] != "bench\\\\" ||
slice[3] != "bleve" || slice[4] != "index" || slice[5] != "lookup_queue_len" {
t.Fatalf("ToSlice failed: %v", slice)
}
// unsupported \x passes through unaltered
v = VarName(`bleve.indexes.bench\xbleve.index.lookup_queue_len`)
slice = v.ToSlice()
if len(slice) != 5 || slice[0] != "bleve" || slice[1] != "indexes" || slice[2] != "bench\\xbleve" ||
slice[3] != "index" || slice[4] != "lookup_queue_len" {
t.Fatalf("ToSlice failed: %v", slice)
}
}