Skip to content

Commit cfa6558

Browse files
Merge pull request #22 from segmentio/v3
V3
2 parents 199939e + aac4f40 commit cfa6558

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2206
-2406
lines changed

README.md

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ import (
2929
)
3030

3131
func main() {
32-
// Creates a new datadog client reporting the state of the default stats
33-
// engine to localhost:8125.
34-
dd := datadog.NewDefaultClient()
32+
// Creates a new datadog client publishing metrics to localhost:8125
33+
dd := datadog.NewClient("localhost:8125")
3534

36-
// Close the client before the application terminates to ensure the latest
37-
// state of the stats engine was reported.
38-
defer dd.Close()
35+
// Register the client so it receives metrics from the default engine.
36+
stats.Register(dd)
37+
38+
// Flush the default stats engine on return to ensure all buffered
39+
// metrics are sent to the dogstatsd server.
40+
defer stats.Flush()
3941

4042
// That's it! Metrics produced by the application will now be reported!
4143
// ...
@@ -58,8 +60,8 @@ import (
5860
)
5961

6062
func main() {
61-
dd := datadog.NewDefaultClient()
62-
defer dd.Close()
63+
stats.Register(datadog.NewClient("localhost:8125"))
64+
defer stats.Flush()
6365

6466
// Increment counters.
6567
stats.Incr("user.login")
@@ -93,11 +95,11 @@ import (
9395

9496

9597
func main() {
96-
dd := datadog.NewDefaultClient()
97-
defer dd.Close()
98+
stats.Register(datadog.NewClient("localhost:8125"))
99+
defer stats.Flush()
98100

99101
// Start a new collector for the current process, reporting Go metrics.
100-
c := procstats.StartCollector(procstats.NewGoMetrics(nil))
102+
c := procstats.StartCollector(procstats.NewGoMetrics())
101103

102104
// Gracefully stops stats collection.
103105
defer c.Close()
@@ -125,13 +127,12 @@ import (
125127
)
126128

127129
func main() {
128-
dd := datadog.NewDefaultClient()
129-
defer dd.Close()
130+
stats.Register(datadog.NewClient("localhost:8125"))
131+
defer stats.Flush()
130132

131133
// ...
132134

133135
http.ListenAndServe(":8080", httpstats.NewHandler(
134-
nil, // use the default stats engine
135136
http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
136137
// This HTTP handler is automatically reporting metrics for all
137138
// requests it handles.
@@ -159,14 +160,13 @@ import (
159160
)
160161

161162
func main() {
162-
dd := datadog.NewDefaultClient()
163-
defer dd.Close()
163+
stats.Register(datadog.NewClient("localhost:8125"))
164+
defer stats.Flush()
164165

165166
// Make a new HTTP client with a transport that will report HTTP metrics,
166167
// set the engine to nil to use the default.
167168
httpc := &http.Client{
168169
Transport: httpstats.NewTransport(
169-
nil, // use the default stats engine
170170
&http.Transport{},
171171
),
172172
}
@@ -188,12 +188,11 @@ import (
188188
)
189189

190190
func main() {
191-
dd := datadog.NewDefaultClient()
192-
defer dd.Close()
191+
stats.Register(datadog.NewClient("localhost:8125"))
192+
defer stats.Flush()
193193

194-
// Wraps the default HTTP client's transport, set the engine to nil to use
195-
// the default.
196-
http.DefaultClient.Transport = httpstats.NewTransport(nil, http.DefaultClient.Transport)
194+
// Wraps the default HTTP client's transport.
195+
http.DefaultClient.Transport = httpstats.NewTransport(http.DefaultClient.Transport)
197196

198197
// ...
199198
}

clock.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,18 @@ func (c *Clock) Name() string {
1818

1919
// Tags returns the list of tags set on the clock.
2020
//
21-
// The returned slice is a copy of the internal slice maintained by the clock,
22-
// the program owns it and can safely modify it without affecting the clock.
21+
// The method returns a reference to the clock's internal tag slice, it does
22+
// not make a copy. It's expected that the program will treat this value as a
23+
// read-only list and won't modify its content.
2324
func (c *Clock) Tags() []Tag {
2425
return c.metric.Tags()
2526
}
2627

27-
// Clone returns a copy of the clock, potentially setting tags on the returned
28+
// WithTags returns a copy of the clock, potentially setting tags on the returned
2829
// object.
29-
func (c *Clock) Clone(tags ...Tag) *Clock {
30+
func (c *Clock) WithTags(tags ...Tag) *Clock {
3031
return &Clock{
31-
metric: c.metric.Clone(tags...),
32+
metric: *c.metric.WithTags(tags...),
3233
last: c.last,
3334
}
3435
}
@@ -69,9 +70,6 @@ func (c *Clock) StopAt(now time.Time) {
6970

7071
func (c *Clock) observe(stamp string, now time.Time) {
7172
h := c.metric
72-
h.key += "&stamp=" + stamp
73-
h.tags = make([]Tag, 0, len(c.metric.tags)+1)
74-
h.tags = append(h.tags, c.metric.tags...)
7573
h.tags = append(h.tags, Tag{"stamp", stamp})
7674
h.Observe(now.Sub(c.last).Seconds())
7775
c.last = now

clock_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package stats
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestClockStart(t *testing.T) {
9+
h := &handler{}
10+
e := NewEngine("E")
11+
e.Register(h)
12+
13+
m := e.Timer("A")
14+
c := m.Start()
15+
c.Stamp("1")
16+
c.Stamp("2")
17+
c.Stamp("3")
18+
c.Stop()
19+
20+
for i := range h.metrics {
21+
if h.metrics[i].Value == 0 {
22+
t.Error("clock time value should not be zero")
23+
}
24+
h.metrics[i].Value = 0 // unpredictable
25+
}
26+
27+
if !reflect.DeepEqual(h.metrics, []Metric{
28+
{
29+
Type: HistogramType,
30+
Namespace: "E",
31+
Name: "A",
32+
Tags: []Tag{{"stamp", "1"}},
33+
},
34+
{
35+
Type: HistogramType,
36+
Namespace: "E",
37+
Name: "A",
38+
Tags: []Tag{{"stamp", "2"}},
39+
},
40+
{
41+
Type: HistogramType,
42+
Namespace: "E",
43+
Name: "A",
44+
Tags: []Tag{{"stamp", "3"}},
45+
},
46+
{
47+
Type: HistogramType,
48+
Namespace: "E",
49+
Name: "A",
50+
Tags: []Tag{{"stamp", "total"}},
51+
},
52+
}) {
53+
t.Error("bad metrics:", h.metrics)
54+
}
55+
}
56+
57+
func TestClockWithTags(t *testing.T) {
58+
e := NewEngine("E")
59+
m := e.Timer("A", Tag{"base", "tag"})
60+
c1 := m.Start()
61+
c2 := c1.WithTags(Tag{"extra", "tag"})
62+
63+
if name := c2.Name(); name != "A" {
64+
t.Error("bad clock name:", name)
65+
}
66+
67+
if tags := c2.Tags(); !reflect.DeepEqual(tags, []Tag{{"base", "tag"}, {"extra", "tag"}}) {
68+
t.Error("bad clock tags:", tags)
69+
}
70+
}

cmd/dogstatsd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func client(cmd string, args ...string) {
8888
}
8989
}
9090

91-
dd := datadog.NewClient(datadog.ClientConfig{Address: addr})
91+
dd := datadog.NewClient(addr)
9292
defer dd.Close()
9393

9494
switch cmd {

counter.go

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,61 @@
11
package stats
22

3-
import "time"
3+
import "sync"
44

5-
// Counter is an immutable data strcture that can be used to represent metrics
6-
// that accumulate values.
5+
// A Counter represent a metric that is monotonically increasing.
76
type Counter struct {
8-
eng *Engine // the parent engine
9-
key string // cached metric key
10-
name string // the name of the counter
11-
tags []Tag // the tags set on the counter
12-
}
13-
14-
// C returns a new counter that produces metrics on the default engine.
15-
func C(name string, tags ...Tag) Counter {
16-
return MakeCounter(nil, name, tags...)
17-
}
18-
19-
// MakeCounter returns a new counter that produces metrics on the given engine.
20-
func MakeCounter(engine *Engine, name string, tags ...Tag) Counter {
21-
return makeCounter(engine, name, copyTags(tags))
7+
mutex sync.Mutex
8+
value float64 // current value of the counter
9+
eng *Engine // the engine to produce metrics on
10+
name string // the name of the counter
11+
tags []Tag // the tags set on the counter
2212
}
2313

2414
// Name returns the name of the counter.
25-
func (c Counter) Name() string {
15+
func (c *Counter) Name() string {
2616
return c.name
2717
}
2818

2919
// Tags returns the list of tags set on the counter.
3020
//
31-
// The returned slice is a copy of the internal slice maintained by the counter,
32-
// the program owns it and can safely modify it without affecting the counter.
33-
func (c Counter) Tags() []Tag {
34-
return copyTags(c.tags)
21+
// The method returns a reference to the counter's internal tag slice, it does
22+
// not make a copy. It's expected that the program will treat this value as a
23+
// read-only list and won't modify its content.
24+
func (c *Counter) Tags() []Tag {
25+
return c.tags
3526
}
3627

37-
// Clone returns a copy of the counter, potentially setting tags on the returned
28+
// Value returns the current value of the counter.
29+
func (c *Counter) Value() float64 {
30+
return c.value
31+
}
32+
33+
// WithTags returns a copy of the counter, potentially setting tags on the returned
3834
// object.
39-
func (c Counter) Clone(tags ...Tag) Counter {
40-
if len(tags) == 0 {
41-
return c
35+
//
36+
// The internal value of the returned counter is set to zero.
37+
func (c *Counter) WithTags(tags ...Tag) *Counter {
38+
return &Counter{
39+
eng: c.eng,
40+
name: c.name,
41+
tags: concatTags(c.tags, tags),
4242
}
43-
return makeCounter(c.eng, c.name, concatTags(c.tags, tags))
4443
}
4544

4645
// Incr increments the counter by a value of 1.
47-
func (c Counter) Incr() {
46+
func (c *Counter) Incr() {
4847
c.Add(1)
4948
}
5049

5150
// Add adds a value to the counter.
5251
//
5352
// Note that most data collection systems expect counters to be monotonically
5453
// increasing so the program should not call this method with negative values.
55-
func (c Counter) Add(value float64) {
56-
c.eng.Add(CounterType, c.key, c.name, c.tags, value, time.Now())
54+
func (c *Counter) Add(value float64) {
55+
c.mutex.Lock()
56+
c.value += value
57+
c.mutex.Unlock()
58+
c.eng.Add(c.name, value, c.tags...)
5759
}
5860

5961
// Set sets the value of the counter.
@@ -64,16 +66,13 @@ func (c Counter) Add(value float64) {
6466
//
6567
// This method is useful for reporting values of counters that aren't managed
6668
// by the application itself, like CPU ticks for example.
67-
func (c Counter) Set(value float64) {
68-
c.eng.Add(CounterType, c.key, c.name, c.tags, value, time.Now())
69-
}
70-
71-
func makeCounter(eng *Engine, name string, tags []Tag) Counter {
72-
sortTags(tags)
73-
return Counter{
74-
eng: eng,
75-
key: MetricKey(name, tags),
76-
name: name,
77-
tags: tags,
69+
func (c *Counter) Set(value float64) {
70+
c.mutex.Lock()
71+
if value < c.value {
72+
c.value = value
73+
} else {
74+
c.value, value = value, value-c.value
7875
}
76+
c.mutex.Unlock()
77+
c.eng.Add(c.name, value, c.tags...)
7978
}

0 commit comments

Comments
 (0)