Skip to content

Commit 1ff87a1

Browse files
committed
Merge pull request #194 from brharrington/composite
allow adding and removing from the composite
2 parents a6081fd + f8daccf commit 1ff87a1

File tree

11 files changed

+302
-171
lines changed

11 files changed

+302
-171
lines changed

spectator-api/src/main/java/com/netflix/spectator/api/CompositeCounter.java

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,31 @@
1515
*/
1616
package com.netflix.spectator.api;
1717

18+
import java.util.Collection;
19+
import java.util.Iterator;
20+
1821
/** Counter implementation for the composite registry. */
1922
final class CompositeCounter extends CompositeMeter implements Counter {
2023

21-
private final Counter[] counters;
22-
2324
/** Create a new instance. */
24-
CompositeCounter(Id id, Counter[] counters) {
25-
super(id);
26-
this.counters = counters;
27-
}
28-
29-
@Override protected Meter[] meters() {
30-
return counters;
25+
CompositeCounter(Id id, Collection<Registry> registries) {
26+
super(id, registries);
3127
}
3228

3329
@Override public void increment() {
34-
for (Counter c : counters) {
35-
c.increment();
30+
for (Registry r : registries) {
31+
r.counter(id).increment();
3632
}
3733
}
3834

3935
@Override public void increment(long amount) {
40-
for (Counter c : counters) {
41-
c.increment(amount);
36+
for (Registry r : registries) {
37+
r.counter(id).increment(amount);
4238
}
4339
}
4440

4541
@Override public long count() {
46-
return (counters.length == 0) ? 0L : counters[0].count();
42+
Iterator<Registry> it = registries.iterator();
43+
return it.hasNext() ? it.next().counter(id).count() : 0L;
4744
}
4845
}

spectator-api/src/main/java/com/netflix/spectator/api/CompositeDistributionSummary.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,30 @@
1515
*/
1616
package com.netflix.spectator.api;
1717

18+
import java.util.Collection;
19+
import java.util.Iterator;
20+
1821
/** Distribution summary implementation for the composite registry. */
1922
final class CompositeDistributionSummary extends CompositeMeter implements DistributionSummary {
2023

21-
private final DistributionSummary[] summaries;
22-
2324
/** Create a new instance. */
24-
CompositeDistributionSummary(Id id, DistributionSummary[] summaries) {
25-
super(id);
26-
this.summaries = summaries;
27-
}
28-
29-
@Override protected Meter[] meters() {
30-
return summaries;
25+
CompositeDistributionSummary(Id id, Collection<Registry> registries) {
26+
super(id, registries);
3127
}
3228

3329
@Override public void record(long amount) {
34-
for (DistributionSummary t : summaries) {
35-
t.record(amount);
30+
for (Registry r : registries) {
31+
r.distributionSummary(id).record(amount);
3632
}
3733
}
3834

3935
@Override public long count() {
40-
return (summaries.length == 0) ? 0L : summaries[0].count();
36+
Iterator<Registry> it = registries.iterator();
37+
return it.hasNext() ? it.next().distributionSummary(id).count() : 0L;
4138
}
4239

4340
@Override public long totalAmount() {
44-
return (summaries.length == 0) ? 0L : summaries[0].totalAmount();
41+
Iterator<Registry> it = registries.iterator();
42+
return it.hasNext() ? it.next().distributionSummary(id).totalAmount() : 0L;
4543
}
4644
}

spectator-api/src/main/java/com/netflix/spectator/api/CompositeMeter.java

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,52 @@
1616
package com.netflix.spectator.api;
1717

1818
import java.util.ArrayList;
19+
import java.util.Collection;
1920
import java.util.List;
2021

2122

2223
/**
2324
* Base class for composite implementations of core meter types.
2425
*/
25-
abstract class CompositeMeter implements Meter {
26+
class CompositeMeter implements Meter {
2627

2728
/** Identifier for the meter. */
2829
protected final Id id;
2930

31+
/** Underlying registries that are keeping the data. */
32+
protected final Collection<Registry> registries;
33+
3034
/**
3135
* Create a new instance.
3236
*
3337
* @param id
3438
* Identifier for the meter.
3539
*/
36-
public CompositeMeter(Id id) {
40+
public CompositeMeter(Id id, Collection<Registry> registries) {
3741
this.id = id;
42+
this.registries = registries;
3843
}
3944

40-
/** Subclasses should define this method to specify the list of meters for the composite. */
41-
protected abstract Meter[] meters();
42-
4345
@Override public Id id() {
4446
return this.id;
4547
}
4648

4749
@Override public boolean hasExpired() {
48-
for (Meter m : meters()) {
50+
for (Registry r : registries) {
51+
Meter m = r.get(id);
4952
if (!m.hasExpired()) return false;
5053
}
5154
return true;
5255
}
5356

5457
@Override public Iterable<Measurement> measure() {
5558
final List<Measurement> ms = new ArrayList<>();
56-
for (Meter meter : meters()) {
57-
for (Measurement measurement : meter.measure()) {
58-
ms.add(measurement);
59+
for (Registry r : registries) {
60+
Meter m = r.get(id);
61+
if (m != null) {
62+
for (Measurement measurement : m.measure()) {
63+
ms.add(measurement);
64+
}
5965
}
6066
}
6167
return ms;

spectator-api/src/main/java/com/netflix/spectator/api/CompositeRegistry.java

Lines changed: 31 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,31 @@
1919
import java.util.HashSet;
2020
import java.util.Iterator;
2121
import java.util.Set;
22+
import java.util.concurrent.CopyOnWriteArraySet;
2223

2324
/**
2425
* Maps calls to zero or more sub-registries. If zero then it will act similar to the noop
2526
* registry. Otherwise activity will be sent to all registries that are part of the composite.
2627
*/
2728
final class CompositeRegistry implements Registry {
2829

30+
/**
31+
* Id used for a meter storing all gauges registered with the composite. Since there is no
32+
* activity on a gauge, all gauges will get registered with a sub-registry when it is added
33+
* by including the meter with this id.
34+
*/
35+
static final Id GAUGES_ID = new DefaultId("spectator.composite.gauges");
36+
2937
private final Clock clock;
30-
private final Registry[] registries;
38+
private final CopyOnWriteArraySet<Registry> registries;
39+
40+
private final RegistryMeter gauges;
3141

3242
/** Creates a new instance. */
33-
CompositeRegistry(Clock clock, Registry[] registries) {
43+
CompositeRegistry(Clock clock) {
3444
this.clock = clock;
35-
this.registries = registries;
45+
this.registries = new CopyOnWriteArraySet<>();
46+
this.gauges = new RegistryMeter(GAUGES_ID);
3647
}
3748

3849
/**
@@ -49,6 +60,17 @@ <T extends Registry> T find(Class<T> c) {
4960
return null;
5061
}
5162

63+
/** Add a registry to the composite. */
64+
public void add(Registry registry) {
65+
registries.add(registry);
66+
registry.register(gauges);
67+
}
68+
69+
/** Remove a registry from the composite. */
70+
public void remove(Registry registry) {
71+
registries.remove(registry);
72+
}
73+
5274
@Override public Clock clock() {
5375
return clock;
5476
}
@@ -62,69 +84,27 @@ <T extends Registry> T find(Class<T> c) {
6284
}
6385

6486
@Override public void register(Meter meter) {
65-
for (Registry r : registries) {
66-
r.register(meter);
67-
}
87+
gauges.register(meter);
6888
}
6989

7090
@Override public Counter counter(Id id) {
71-
final int n = registries.length;
72-
if (n == 0) {
73-
return NoopCounter.INSTANCE;
74-
} else {
75-
final Counter[] meters = new Counter[n];
76-
for (int i = 0; i < n; ++i) {
77-
meters[i] = registries[i].counter(registries[i].createId(id.name(), id.tags()));
78-
}
79-
return new CompositeCounter(id, meters);
80-
}
91+
return new CompositeCounter(id, registries);
8192
}
8293

8394
@Override public DistributionSummary distributionSummary(Id id) {
84-
final int n = registries.length;
85-
if (n == 0) {
86-
return NoopDistributionSummary.INSTANCE;
87-
} else {
88-
final DistributionSummary[] meters = new DistributionSummary[n];
89-
for (int i = 0; i < n; ++i) {
90-
meters[i] = registries[i].distributionSummary(registries[i].createId(id.name(), id.tags()));
91-
}
92-
return new CompositeDistributionSummary(id, meters);
93-
}
95+
return new CompositeDistributionSummary(id, registries);
9496
}
9597

9698
@Override public Timer timer(Id id) {
97-
final int n = registries.length;
98-
if (n == 0) {
99-
return NoopTimer.INSTANCE;
100-
} else {
101-
final Timer[] meters = new Timer[n];
102-
for (int i = 0; i < n; ++i) {
103-
meters[i] = registries[i].timer(registries[i].createId(id.name(), id.tags()));
104-
}
105-
return new CompositeTimer(id, clock, meters);
106-
}
99+
return new CompositeTimer(id, clock, registries);
107100
}
108101

109102
@Override public Meter get(Id id) {
110-
final int n = registries.length;
111-
if (n == 0) {
112-
return null;
113-
} else {
114-
final Meter[] meters = new Meter[n];
115-
for (int i = 0; i < n; ++i) {
116-
meters[i] = registries[i].get(registries[i].createId(id.name(), id.tags()));
117-
}
118-
return new CompositeMeter(id) {
119-
@Override protected Meter[] meters() {
120-
return meters;
121-
}
122-
};
123-
}
103+
return new CompositeMeter(id, registries);
124104
}
125105

126106
@Override public Iterator<Meter> iterator() {
127-
if (registries.length == 0) {
107+
if (registries.isEmpty()) {
128108
return Collections.<Meter>emptyList().iterator();
129109
} else {
130110
final Set<Id> ids = new HashSet<>();

spectator-api/src/main/java/com/netflix/spectator/api/CompositeTimer.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,25 @@
1515
*/
1616
package com.netflix.spectator.api;
1717

18+
import java.util.Collection;
19+
import java.util.Iterator;
1820
import java.util.concurrent.Callable;
1921
import java.util.concurrent.TimeUnit;
2022

2123
/** Timer implementation for the composite registry. */
2224
final class CompositeTimer extends CompositeMeter implements Timer {
2325

2426
private final Clock clock;
25-
private final Timer[] timers;
2627

2728
/** Create a new instance. */
28-
CompositeTimer(Id id, Clock clock, Timer[] timers) {
29-
super(id);
29+
CompositeTimer(Id id, Clock clock, Collection<Registry> registries) {
30+
super(id, registries);
3031
this.clock = clock;
31-
this.timers = timers;
32-
}
33-
34-
@Override protected Meter[] meters() {
35-
return timers;
3632
}
3733

3834
@Override public void record(long amount, TimeUnit unit) {
39-
for (Timer t : timers) {
40-
t.record(amount, unit);
35+
for (Registry r : registries) {
36+
r.timer(id).record(amount, unit);
4137
}
4238
}
4339

@@ -62,10 +58,12 @@ final class CompositeTimer extends CompositeMeter implements Timer {
6258
}
6359

6460
@Override public long count() {
65-
return (timers.length == 0) ? 0L : timers[0].count();
61+
Iterator<Registry> it = registries.iterator();
62+
return it.hasNext() ? it.next().timer(id).count() : 0L;
6663
}
6764

6865
@Override public long totalTime() {
69-
return (timers.length == 0) ? 0L : timers[0].totalTime();
66+
Iterator<Registry> it = registries.iterator();
67+
return it.hasNext() ? it.next().timer(id).totalTime() : 0L;
7068
}
7169
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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.api;
17+
18+
import java.util.ArrayList;
19+
import java.util.List;
20+
21+
22+
/**
23+
* Wraps a registry as a meter that can be added to another registry. This is currently used to
24+
* manage the gauges for the composite registry. Since there is no activity gauges should get
25+
* polled and must get tracked as a group and added to each sub-registry.
26+
*/
27+
class RegistryMeter implements Meter {
28+
29+
private final Id id;
30+
private final Registry registry;
31+
32+
/** Create a new instance. */
33+
RegistryMeter(Id id) {
34+
this(id, new DefaultRegistry());
35+
}
36+
37+
/** Create a new instance. */
38+
RegistryMeter(Id id, Registry registry) {
39+
this.id = id;
40+
this.registry = registry;
41+
}
42+
43+
/** Register a meter with the wrapped registry. */
44+
void register(Meter meter) {
45+
registry.register(meter);
46+
}
47+
48+
@Override public Id id() {
49+
return id;
50+
}
51+
52+
@Override public Iterable<Measurement> measure() {
53+
List<Measurement> ms = new ArrayList<>();
54+
for (Meter m : registry) {
55+
for (Measurement measurement : m.measure()) {
56+
ms.add(measurement);
57+
}
58+
}
59+
return ms;
60+
}
61+
62+
@Override public boolean hasExpired() {
63+
return false;
64+
}
65+
}

0 commit comments

Comments
 (0)