Skip to content

Commit 20a94f2

Browse files
V2 HdrHistogram Log format (v1.3) (#35)
* [add] V2 HdrHistogram Log format (v1.3) * [fix] Added nolint to the examples * [fix] Fixed error message typo on minimum length on bytes for 7,8,and 9 bytelen * [fix] Fixed ExampleHistogram_PercentilesPrint
1 parent aada4ab commit 20a94f2

15 files changed

+892
-127
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@ coverage.txt
1414
# Test binary, built with `go test -c`
1515
*.test
1616

17+
# Test example output
18+
example.logV2.hlog
19+
1720
# Output of the go coverage tool, specifically when used with LiteIDE
1821
*.out
1922

2023
# Dependency directories (remove the comment below to include it)
2124
# vendor/
25+

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ GOTEST=$(GOCMD) test
77
GOGET=$(GOCMD) get
88
GOMOD=$(GOCMD) mod
99
GOFMT=$(GOCMD) fmt
10+
GODOC=godoc
1011

1112
.PHONY: all test coverage
1213
all: test coverage
@@ -36,3 +37,6 @@ test: get fmt
3637
coverage: get test
3738
$(GOTEST) -race -coverprofile=coverage.txt -covermode=atomic .
3839

40+
godoc:
41+
$(GODOC)
42+

example_hdr_test.go

+52
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,65 @@
11
package hdrhistogram_test
22

33
import (
4+
"fmt"
45
"github.com/HdrHistogram/hdrhistogram-go"
56
"os"
67
)
78

9+
// This latency Histogram could be used to track and analyze the counts of
10+
// observed integer values between 0 us and 30000000 us ( 30 secs )
11+
// while maintaining a value precision of 4 significant digits across that range,
12+
// translating to a value resolution of :
13+
// - 1 microsecond up to 10 milliseconds,
14+
// - 100 microsecond (or better) from 10 milliseconds up to 10 seconds,
15+
// - 300 microsecond (or better) from 10 seconds up to 30 seconds,
16+
// nolint
17+
func ExampleNew() {
18+
lH := hdrhistogram.New(1, 30000000, 4)
19+
input := []int64{
20+
459876, 669187, 711612, 816326, 931423, 1033197, 1131895, 2477317,
21+
3964974, 12718782,
22+
}
23+
24+
for _, sample := range input {
25+
lH.RecordValue(sample)
26+
}
27+
28+
fmt.Printf("Percentile 50: %d\n", lH.ValueAtQuantile(50.0))
29+
30+
// Output:
31+
// Percentile 50: 931423
32+
}
33+
34+
// This latency Histogram could be used to track and analyze the counts of
35+
// observed integer values between 0 us and 30000000 us ( 30 secs )
36+
// while maintaining a value precision of 3 significant digits across that range,
37+
// translating to a value resolution of :
38+
// - 1 microsecond up to 1 millisecond,
39+
// - 1 millisecond (or better) up to one second,
40+
// - 1 second (or better) up to it's maximum tracked value ( 30 seconds ).
41+
// nolint
42+
func ExampleHistogram_RecordValue() {
43+
lH := hdrhistogram.New(1, 30000000, 3)
44+
input := []int64{
45+
459876, 669187, 711612, 816326, 931423, 1033197, 1131895, 2477317,
46+
3964974, 12718782,
47+
}
48+
49+
for _, sample := range input {
50+
lH.RecordValue(sample)
51+
}
52+
53+
fmt.Printf("Percentile 50: %d\n", lH.ValueAtQuantile(50.0))
54+
55+
// Output:
56+
// Percentile 50: 931839
57+
}
58+
859
// The following example details the creation of an histogram used to track
960
// and analyze the counts of observed integer values between 0 us and 30000000 us ( 30 secs )
1061
// and the printing of the percentile output format
62+
// nolint
1163
func ExampleHistogram_PercentilesPrint() {
1264
lH := hdrhistogram.New(1, 30000000, 3)
1365
input := []int64{

example_log_writer_test.go

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package hdrhistogram_test
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
hdrhistogram "github.com/HdrHistogram/hdrhistogram-go"
7+
"io/ioutil"
8+
)
9+
10+
// The log format encodes into a single file, multiple histograms with optional shared meta data.
11+
// The following example showcases reading a log file into a slice of histograms
12+
// nolint
13+
func ExampleNewHistogramLogReader() {
14+
dat, _ := ioutil.ReadFile("./test/tagged-Log.logV2.hlog")
15+
r := bytes.NewReader(dat)
16+
17+
// Create a histogram log reader
18+
reader := hdrhistogram.NewHistogramLogReader(r)
19+
var histograms []*hdrhistogram.Histogram = make([]*hdrhistogram.Histogram, 0)
20+
21+
// Read all histograms in the file
22+
for hist, err := reader.NextIntervalHistogram(); hist != nil && err == nil; hist, err = reader.NextIntervalHistogram() {
23+
histograms = append(histograms, hist)
24+
}
25+
fmt.Printf("Read a total of %d histograms\n", len(histograms))
26+
27+
min := reader.RangeObservedMin()
28+
max := reader.RangeObservedMax()
29+
sigdigits := 3
30+
overallHistogram := hdrhistogram.New(min, max, sigdigits)
31+
32+
//// We can then merge all histograms into one and retrieve overall metrics
33+
for _, hist := range histograms {
34+
overallHistogram.Merge(hist)
35+
}
36+
fmt.Printf("Overall count: %d samples\n", overallHistogram.TotalCount())
37+
fmt.Printf("Overall Percentile 50: %d\n", overallHistogram.ValueAtQuantile(50.0))
38+
39+
// Output:
40+
// Read a total of 42 histograms
41+
// Overall count: 32290 samples
42+
// Overall Percentile 50: 344319
43+
44+
}
45+
46+
// The log format encodes into a single file, multiple histograms with optional shared meta data.
47+
// The following example showcases writing multiple histograms into a log file and then
48+
// processing them again to confirm a proper encode-decode flow
49+
// nolint
50+
func ExampleNewHistogramLogWriter() {
51+
var buff bytes.Buffer
52+
53+
// Create a histogram log writer to write to a bytes.Buffer
54+
writer := hdrhistogram.NewHistogramLogWriter(&buff)
55+
56+
writer.OutputLogFormatVersion()
57+
writer.OutputStartTime(0)
58+
writer.OutputLegend()
59+
60+
// Lets create 3 distinct histograms to exemply the logwriter features
61+
// each one with a time-frame of 60 secs ( 60000 ms )
62+
hist1 := hdrhistogram.New(1, 30000000, 3)
63+
hist1.SetStartTimeMs(0)
64+
hist1.SetEndTimeMs(60000)
65+
for _, sample := range []int64{10, 20, 30, 40} {
66+
hist1.RecordValue(sample)
67+
}
68+
hist2 := hdrhistogram.New(1, 3000, 3)
69+
hist1.SetStartTimeMs(60001)
70+
hist1.SetEndTimeMs(120000)
71+
for _, sample := range []int64{50, 70, 80, 60} {
72+
hist2.RecordValue(sample)
73+
}
74+
hist3 := hdrhistogram.New(1, 30000, 3)
75+
hist1.SetStartTimeMs(120001)
76+
hist1.SetEndTimeMs(180000)
77+
for _, sample := range []int64{90, 100} {
78+
hist3.RecordValue(sample)
79+
}
80+
writer.OutputIntervalHistogram(hist1)
81+
writer.OutputIntervalHistogram(hist2)
82+
writer.OutputIntervalHistogram(hist3)
83+
84+
ioutil.WriteFile("example.logV2.hlog", buff.Bytes(), 0644)
85+
86+
// read check
87+
// Lets read all again and confirm that the total sample count is 10
88+
dat, _ := ioutil.ReadFile("example.logV2.hlog")
89+
r := bytes.NewReader(dat)
90+
91+
// Create a histogram log reader
92+
reader := hdrhistogram.NewHistogramLogReader(r)
93+
var histograms []*hdrhistogram.Histogram = make([]*hdrhistogram.Histogram, 0)
94+
95+
// Read all histograms in the file
96+
for hist, err := reader.NextIntervalHistogram(); hist != nil && err == nil; hist, err = reader.NextIntervalHistogram() {
97+
histograms = append(histograms, hist)
98+
}
99+
fmt.Printf("Read a total of %d histograms\n", len(histograms))
100+
101+
min := reader.RangeObservedMin()
102+
max := reader.RangeObservedMax()
103+
sigdigits := 3
104+
overallHistogram := hdrhistogram.New(min, max, sigdigits)
105+
106+
//// We can then merge all histograms into one and retrieve overall metrics
107+
for _, hist := range histograms {
108+
overallHistogram.Merge(hist)
109+
}
110+
fmt.Printf("Overall count: %d samples\n", overallHistogram.TotalCount())
111+
// Output:
112+
// Read a total of 3 histograms
113+
// Overall count: 10 samples
114+
}

hdr.go

+30
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,33 @@ type Histogram struct {
4040
countsLen int32
4141
totalCount int64
4242
counts []int64
43+
startTimeMs int64
44+
endTimeMs int64
45+
tag string
46+
}
47+
48+
func (h *Histogram) Tag() string {
49+
return h.tag
50+
}
51+
52+
func (h *Histogram) SetTag(tag string) {
53+
h.tag = tag
54+
}
55+
56+
func (h *Histogram) EndTimeMs() int64 {
57+
return h.endTimeMs
58+
}
59+
60+
func (h *Histogram) SetEndTimeMs(endTimeMs int64) {
61+
h.endTimeMs = endTimeMs
62+
}
63+
64+
func (h *Histogram) StartTimeMs() int64 {
65+
return h.startTimeMs
66+
}
67+
68+
func (h *Histogram) SetStartTimeMs(startTimeMs int64) {
69+
h.startTimeMs = startTimeMs
4370
}
4471

4572
// New returns a new Histogram instance capable of tracking values in the given
@@ -93,6 +120,9 @@ func New(minValue, maxValue int64, sigfigs int) *Histogram {
93120
countsLen: countsLen,
94121
totalCount: 0,
95122
counts: make([]int64, countsLen),
123+
startTimeMs: 0,
124+
endTimeMs: 0,
125+
tag: "",
96126
}
97127
}
98128

0 commit comments

Comments
 (0)