Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 79 additions & 7 deletions stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,73 @@ import (
"unsafe"
)

// Semantics represents the semantics of a counter ('c', 'g', 'b', 'q', '?').
type Semantics int

const (
SemanticsUnknown Semantics = iota
SemanticsCounter // 'c'
SemanticsGauge // 'g'
SemanticsBitmap // 'b'
SemanticsBoolean // 'q'
)

// Flags represents the display format of a counter ('i', 'B', 'b', 'q', 'd', '?').
type Flags int

const (
FlagsUnknown Flags = iota
FlagsInteger // 'i'
FlagsBytes // 'B'
FlagsBitmap // 'b'
FlagsBoolean // 'q'
FlagsDuration // 'd'
)

func semanticsFromC(c C.int) Semantics {
switch c {
case 'c':
return SemanticsCounter
case 'g':
return SemanticsGauge
case 'b':
return SemanticsBitmap
case 'q':
return SemanticsBoolean
default:
return SemanticsUnknown
}
}

func flagsFromC(c C.int) Flags {
switch c {
case 'i':
return FlagsInteger
case 'B':
return FlagsBytes
case 'b':
return FlagsBitmap
case 'q':
return FlagsBoolean
case 'd':
return FlagsDuration
default:
return FlagsUnknown
}
}

// Counter represents a Varnish statistic counter with metadata.
type Counter struct {
SDesc string `json:"description"`
LDesc string `json:"ldesc"`
Value uint64 `json:"value"`
Semantics Semantics `json:"semantics"`
Flags Flags `json:"flags"`
}

// Stats returns a map with all stat counters and their values.
func (v *Varnish) Stats() map[string]uint64 {
items := make(map[string]uint64)
func (v *Varnish) Stats() map[string]Counter {
items := make(map[string]Counter)
handle := ptrHandles.track(items)
defer ptrHandles.untrack(handle)
C.VSC_Iter(v.vsc, v.vsm,
Expand All @@ -36,8 +100,11 @@ func (v *Varnish) Stats() map[string]uint64 {
// 0 and false otherwise.
func (v *Varnish) Stat(s string) (uint64, bool) {
stats := v.Stats()
value, ok := stats[s]
return value, ok
c, ok := stats[s]
if !ok {
return 0, false
}
return c.Value, true
}

// do_list_cb()
Expand All @@ -49,11 +116,16 @@ func listCallback(handle unsafe.Pointer, pt *C.struct_VSC_point) C.int {
return 1
}
name := C.GoString(pt.name)
value := *(*uint64)(unsafe.Pointer(pt.ptr))
items, ok := priv.(map[string]uint64)
items, ok := priv.(map[string]Counter)
if !ok {
return 1
}
items[name] = value
items[name] = Counter{
SDesc: C.GoString(pt.sdesc),
LDesc: C.GoString(pt.ldesc),
Value: *(*uint64)(unsafe.Pointer(pt.ptr)),
Semantics: semanticsFromC(pt.semantics),
Flags: flagsFromC(pt.format),
}
return 0
}
29 changes: 27 additions & 2 deletions vago_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package vago

import (
"fmt"
"strings"
"sync"
"testing"
Expand Down Expand Up @@ -112,6 +113,15 @@ func TestStats(t *testing.T) {
if len(items) == 0 {
t.Fatal("Expected map with elements")
}
for name, counter := range items {
if counter.SDesc == "" {
t.Errorf("%s: expected non-empty SDesc", name)
}
if counter.LDesc == "" {
t.Errorf("%s: expected non-empty LDesc", name)
}
break
}
}

func TestStatFail(t *testing.T) {
Expand All @@ -133,7 +143,22 @@ func TestStatOK(t *testing.T) {
t.Fatal("Expected nil")
}
defer v.Close()
if _, ok := v.Stat("MAIN.uptime"); !ok {
t.Fatal("Expected some value")
stats := v.Stats()
fmt.Printf("Stats: %v\n", stats)
counter, ok := stats["MAIN.uptime"]
if !ok {
t.Fatal("Expected MAIN.uptime")
}
if counter.SDesc == "" {
t.Error("Expected non-empty SDesc")
}
if counter.LDesc == "" {
t.Error("Expected non-empty LDesc")
}
if counter.Semantics != SemanticsCounter {
t.Errorf("Expected SemanticsCounter, got %v", counter.Semantics)
}
if counter.Flags != FlagsDuration {
t.Errorf("Expected FlagsDuration, got %v", counter.Flags)
}
}