Skip to content

Commit 7a49cb1

Browse files
committed
Merge pull request #95 from brharrington/bucket-counter
helper for managing bucketed counters/timers
2 parents 01886c2 + d652315 commit 7a49cb1

File tree

19 files changed

+712
-40
lines changed

19 files changed

+712
-40
lines changed

Diff for: spectator-api/src/main/java/com/netflix/spectator/api/DefaultDistributionSummary.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,12 @@ final class DefaultDistributionSummary implements DistributionSummary {
2727
private final AtomicLong count;
2828
private final AtomicLong totalAmount;
2929

30-
private final Id countId;
31-
private final Id totalAmountId;
32-
3330
/** Create a new instance. */
3431
DefaultDistributionSummary(Clock clock, Id id) {
3532
this.clock = clock;
3633
this.id = id;
3734
count = new AtomicLong(0L);
3835
totalAmount = new AtomicLong(0L);
39-
countId = id.withTag("statistic", "count");
40-
totalAmountId = id.withTag("statistic", "totalAmount");
4136
}
4237

4338
@Override public Id id() {
@@ -58,8 +53,8 @@ final class DefaultDistributionSummary implements DistributionSummary {
5853
@Override public Iterable<Measurement> measure() {
5954
final long now = clock.wallTime();
6055
final List<Measurement> ms = new ArrayList<>(2);
61-
ms.add(new Measurement(countId, now, count.get()));
62-
ms.add(new Measurement(totalAmountId, now, totalAmount.get()));
56+
ms.add(new Measurement(id.withTag(Statistic.count), now, count.get()));
57+
ms.add(new Measurement(id.withTag(Statistic.totalAmount), now, totalAmount.get()));
6358
return ms;
6459
}
6560

Diff for: spectator-api/src/main/java/com/netflix/spectator/api/DefaultLongTaskTimer.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,11 @@ final class DefaultLongTaskTimer implements LongTaskTimer {
3131
private final Id id;
3232
private final ConcurrentMap<Long, Long> tasks = new ConcurrentHashMap<>();
3333
private final AtomicLong nextTask = new AtomicLong(0L);
34-
private final Id activeTasksId;
35-
private final Id durationId;
3634

3735
/** Create a new instance. */
3836
DefaultLongTaskTimer(Clock clock, Id id) {
3937
this.clock = clock;
4038
this.id = id;
41-
42-
this.activeTasksId = id.withTag("statistic", "activeTasks");
43-
this.durationId = id.withTag("statistic", "duration");
4439
}
4540

4641
@Override public Id id() {
@@ -89,8 +84,8 @@ final class DefaultLongTaskTimer implements LongTaskTimer {
8984
final List<Measurement> ms = new ArrayList<>(2);
9085
final long now = clock.wallTime();
9186
final double durationSeconds = duration() / NANOS_PER_SECOND;
92-
ms.add(new Measurement(durationId, now, durationSeconds));
93-
ms.add(new Measurement(activeTasksId, now, activeTasks()));
87+
ms.add(new Measurement(id.withTag(Statistic.duration), now, durationSeconds));
88+
ms.add(new Measurement(id.withTag(Statistic.activeTasks), now, activeTasks()));
9489
return ms;
9590
}
9691
}

Diff for: spectator-api/src/main/java/com/netflix/spectator/api/DefaultTimer.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,12 @@ final class DefaultTimer implements Timer {
2929
private final AtomicLong count;
3030
private final AtomicLong totalTime;
3131

32-
private final Id countId;
33-
private final Id totalTimeId;
34-
3532
/** Create a new instance. */
3633
DefaultTimer(Clock clock, Id id) {
3734
this.clock = clock;
3835
this.id = id;
3936
count = new AtomicLong(0L);
4037
totalTime = new AtomicLong(0L);
41-
countId = id.withTag("statistic", "count");
42-
totalTimeId = id.withTag("statistic", "totalTime");
4338
}
4439

4540
@Override public Id id() {
@@ -61,8 +56,8 @@ final class DefaultTimer implements Timer {
6156
@Override public Iterable<Measurement> measure() {
6257
final long now = clock.wallTime();
6358
final List<Measurement> ms = new ArrayList<>(2);
64-
ms.add(new Measurement(countId, now, count.get()));
65-
ms.add(new Measurement(totalTimeId, now, totalTime.get()));
59+
ms.add(new Measurement(id.withTag(Statistic.count), now, count.get()));
60+
ms.add(new Measurement(id.withTag(Statistic.totalTime), now, totalTime.get()));
6661
return ms;
6762
}
6863

Diff for: spectator-reg-servo/src/main/java/com/netflix/spectator/servo/Statistic.java renamed to spectator-api/src/main/java/com/netflix/spectator/api/Statistic.java

+9-5
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,12 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.netflix.spectator.servo;
17-
18-
import com.netflix.spectator.api.Tag;
16+
package com.netflix.spectator.api;
1917

2018
/**
2119
* The valid set of statistics that can be reported by timers and distribution summaries.
2220
*/
23-
enum Statistic implements Tag {
21+
public enum Statistic implements Tag {
2422
/** Rate per second for calls to record. */
2523
count,
2624

@@ -34,7 +32,13 @@ enum Statistic implements Tag {
3432
totalOfSquares,
3533

3634
/** The sum of the times recorded. */
37-
totalTime;
35+
totalTime,
36+
37+
/** Number of currently active tasks for a long task timer. */
38+
activeTasks,
39+
40+
/** Duration of a running task. */
41+
duration;
3842

3943
@Override public String key() {
4044
return "statistic";

Diff for: spectator-api/src/test/java/com/netflix/spectator/api/CompositeDistributionSummaryTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,9 @@ public void testMeasure() {
8080
clock.setWallTime(3712345L);
8181
for (Measurement m : t.measure()) {
8282
Assert.assertEquals(m.timestamp(), 3712345L);
83-
if (m.id().equals(t.id().withTag("statistic", "count"))) {
83+
if (m.id().equals(t.id().withTag(Statistic.count))) {
8484
Assert.assertEquals(m.value(), 1.0, 0.1e-12);
85-
} else if (m.id().equals(t.id().withTag("statistic", "totalAmount"))) {
85+
} else if (m.id().equals(t.id().withTag(Statistic.totalAmount))) {
8686
Assert.assertEquals(m.value(), 42, 0.1e-12);
8787
} else {
8888
Assert.fail("unexpected id: " + m.id());

Diff for: spectator-api/src/test/java/com/netflix/spectator/api/CompositeTimerTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ public void testMeasure() {
150150
clock.setWallTime(3712345L);
151151
for (Measurement m : t.measure()) {
152152
Assert.assertEquals(m.timestamp(), 3712345L);
153-
if (m.id().equals(t.id().withTag("statistic", "count"))) {
153+
if (m.id().equals(t.id().withTag(Statistic.count))) {
154154
Assert.assertEquals(m.value(), 1.0, 0.1e-12);
155-
} else if (m.id().equals(t.id().withTag("statistic", "totalTime"))) {
155+
} else if (m.id().equals(t.id().withTag(Statistic.totalTime))) {
156156
Assert.assertEquals(m.value(), 42e6, 0.1e-12);
157157
} else {
158158
Assert.fail("unexpected id: " + m.id());

Diff for: spectator-api/src/test/java/com/netflix/spectator/api/DefaultDistributionSummaryTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ public void testMeasure() {
6363
clock.setWallTime(3712345L);
6464
for (Measurement m : t.measure()) {
6565
Assert.assertEquals(m.timestamp(), 3712345L);
66-
if (m.id().equals(t.id().withTag("statistic", "count"))) {
66+
if (m.id().equals(t.id().withTag(Statistic.count))) {
6767
Assert.assertEquals(m.value(), 1.0, 0.1e-12);
68-
} else if (m.id().equals(t.id().withTag("statistic", "totalAmount"))) {
68+
} else if (m.id().equals(t.id().withTag(Statistic.totalAmount))) {
6969
Assert.assertEquals(m.value(), 42.0, 0.1e-12);
7070
} else {
7171
Assert.fail("unexpected id: " + m.id());

Diff for: spectator-api/src/test/java/com/netflix/spectator/api/DefaultLongTaskTimerTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,9 @@ public void testStop() {
6565
static void assertLongTaskTimer(Meter t, long timestamp, int activeTasks, double duration) {
6666
for (Measurement m : t.measure()) {
6767
Assert.assertEquals(m.timestamp(), timestamp);
68-
if (m.id().equals(t.id().withTag("statistic", "activeTasks"))) {
68+
if (m.id().equals(t.id().withTag(Statistic.activeTasks))) {
6969
Assert.assertEquals(m.value(), activeTasks, 1.0e-12);
70-
} else if (m.id().equals(t.id().withTag("statistic", "duration"))) {
70+
} else if (m.id().equals(t.id().withTag(Statistic.duration))) {
7171
Assert.assertEquals(m.value(), duration, 1.0e-12);
7272
} else {
7373
Assert.fail("unexpected id: " + m.id());

Diff for: spectator-api/src/test/java/com/netflix/spectator/api/DefaultTimerTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ public void testMeasure() {
134134
clock.setWallTime(3712345L);
135135
for (Measurement m : t.measure()) {
136136
Assert.assertEquals(m.timestamp(), 3712345L);
137-
if (m.id().equals(t.id().withTag("statistic", "count"))) {
137+
if (m.id().equals(t.id().withTag(Statistic.count))) {
138138
Assert.assertEquals(m.value(), 1.0, 0.1e-12);
139-
} else if (m.id().equals(t.id().withTag("statistic", "totalTime"))) {
139+
} else if (m.id().equals(t.id().withTag(Statistic.totalTime))) {
140140
Assert.assertEquals(m.value(), 42e6, 0.1e-12);
141141
} else {
142142
Assert.fail("unexpected id: " + m.id());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* Copyright 2015 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.netflix.spectator.sandbox;
17+
18+
import com.netflix.spectator.api.Counter;
19+
import com.netflix.spectator.api.DistributionSummary;
20+
import com.netflix.spectator.api.Id;
21+
import com.netflix.spectator.api.Measurement;
22+
import com.netflix.spectator.api.Registry;
23+
import com.netflix.spectator.api.Spectator;
24+
25+
import java.util.Collections;
26+
27+
/** Counters that get incremented based on the bucket for recorded values. */
28+
public final class BucketCounter implements DistributionSummary {
29+
30+
/**
31+
* Creates a distribution summary object that manages a set of counters based on the bucket
32+
* function supplied. Calling record will increment the appropriate counter.
33+
*
34+
* @param id
35+
* Identifier for the metric being registered.
36+
* @param f
37+
* Function to map values to buckets.
38+
* @return
39+
* Distribution summary that manages sub-counters based on the bucket function.
40+
*/
41+
public static BucketCounter get(Id id, BucketFunction f) {
42+
return get(Spectator.registry(), id, f);
43+
}
44+
45+
/**
46+
* Creates a distribution summary object that manages a set of counters based on the bucket
47+
* function supplied. Calling record will increment the appropriate counter.
48+
*
49+
* @param registry
50+
* Registry to use.
51+
* @param id
52+
* Identifier for the metric being registered.
53+
* @param f
54+
* Function to map values to buckets.
55+
* @return
56+
* Distribution summary that manages sub-counters based on the bucket function.
57+
*/
58+
public static BucketCounter get(Registry registry, Id id, BucketFunction f) {
59+
return new BucketCounter(registry, id, f);
60+
}
61+
62+
private final Registry registry;
63+
private final Id id;
64+
private final BucketFunction f;
65+
66+
/** Create a new instance. */
67+
BucketCounter(Registry registry, Id id, BucketFunction f) {
68+
this.registry = registry;
69+
this.id = id;
70+
this.f = f;
71+
}
72+
73+
@Override public Id id() {
74+
return id;
75+
}
76+
77+
@Override public Iterable<Measurement> measure() {
78+
return Collections.emptyList();
79+
}
80+
81+
@Override public boolean hasExpired() {
82+
return false;
83+
}
84+
85+
@Override public void record(long amount) {
86+
counter(f.apply(amount)).increment();
87+
}
88+
89+
/**
90+
* Return the count for a given bucket.
91+
*/
92+
public Counter counter(String bucket) {
93+
return registry.counter(id.withTag("bucket", bucket));
94+
}
95+
96+
@Override public long count() {
97+
return 0L;
98+
}
99+
100+
@Override public long totalAmount() {
101+
return 0L;
102+
}
103+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Copyright 2015 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.netflix.spectator.sandbox;
17+
18+
import com.netflix.spectator.api.DistributionSummary;
19+
import com.netflix.spectator.api.Id;
20+
import com.netflix.spectator.api.Measurement;
21+
import com.netflix.spectator.api.Registry;
22+
import com.netflix.spectator.api.Spectator;
23+
24+
import java.util.Collections;
25+
26+
/** Distribution summaries that get updated based on the bucket for recorded values. */
27+
public final class BucketDistributionSummary implements DistributionSummary {
28+
29+
/**
30+
* Creates a distribution summary object that manages a set of distribution summaries based on
31+
* the bucket function supplied. Calling record will be mapped to the record on the appropriate
32+
* distribution summary.
33+
*
34+
* @param id
35+
* Identifier for the metric being registered.
36+
* @param f
37+
* Function to map values to buckets.
38+
* @return
39+
* Distribution summary that manages sub-counters based on the bucket function.
40+
*/
41+
public static BucketDistributionSummary get(Id id, BucketFunction f) {
42+
return get(Spectator.registry(), id, f);
43+
}
44+
45+
/**
46+
* Creates a distribution summary object that manages a set of distribution summaries based on
47+
* the bucket function supplied. Calling record will be mapped to the record on the appropriate
48+
* distribution summary.
49+
*
50+
* @param registry
51+
* Registry to use.
52+
* @param id
53+
* Identifier for the metric being registered.
54+
* @param f
55+
* Function to map values to buckets.
56+
* @return
57+
* Distribution summary that manages sub-counters based on the bucket function.
58+
*/
59+
public static BucketDistributionSummary get(Registry registry, Id id, BucketFunction f) {
60+
return new BucketDistributionSummary(registry, id, f);
61+
}
62+
63+
private final Registry registry;
64+
private final Id id;
65+
private final BucketFunction f;
66+
67+
/** Create a new instance. */
68+
BucketDistributionSummary(Registry registry, Id id, BucketFunction f) {
69+
this.registry = registry;
70+
this.id = id;
71+
this.f = f;
72+
}
73+
74+
@Override public Id id() {
75+
return id;
76+
}
77+
78+
@Override public Iterable<Measurement> measure() {
79+
return Collections.emptyList();
80+
}
81+
82+
@Override public boolean hasExpired() {
83+
return false;
84+
}
85+
86+
@Override public void record(long amount) {
87+
distributionSummary(f.apply(amount)).record(amount);
88+
}
89+
90+
/**
91+
* Return the count for a given bucket.
92+
*/
93+
public DistributionSummary distributionSummary(String bucket) {
94+
return registry.distributionSummary(id.withTag("bucket", bucket));
95+
}
96+
97+
@Override public long count() {
98+
return 0L;
99+
}
100+
101+
@Override public long totalAmount() {
102+
return 0L;
103+
}
104+
}

0 commit comments

Comments
 (0)