Skip to content

Commit

Permalink
allow to configure Reservoir implementations
Browse files Browse the repository at this point in the history
introduction of a setting in the MetricsConfiguration class
to be able to configure the Reservoir implementation to use for
produced Timer & Histogram instances.

see #12
  • Loading branch information
McFoggy authored and astefanutti committed Feb 19, 2018
1 parent 3b64cfa commit 9da35a7
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Copyright © 2013 Antonin Stefanutti (antonin.stefanutti@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.astefanutti.metrics.cdi.se;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;

import com.codahale.metrics.Reservoir;
import com.codahale.metrics.SlidingTimeWindowArrayReservoir;

import io.astefanutti.metrics.cdi.MetricsConfiguration;
import io.astefanutti.metrics.cdi.ReservoirBuidler;
import io.astefanutti.metrics.cdi.ReservoirUsage;

@ApplicationScoped
public class ReservoirBuilderNullContributor {
AtomicInteger counter = new AtomicInteger();

public int calls() {
return counter.get();
}

void configuration(@Observes MetricsConfiguration configuration) {
configuration.useReservoirBuilder(new ReservoirBuidler() {
@Override
public Reservoir build(String metricName, ReservoirUsage type) {
counter.incrementAndGet();
return null;
}
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Copyright © 2013 Antonin Stefanutti (antonin.stefanutti@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.astefanutti.metrics.cdi.se;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import javax.inject.Inject;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.EmptyAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.Test;
import org.junit.runner.RunWith;

import io.astefanutti.metrics.cdi.MetricsExtension;

@RunWith(Arquillian.class)
public class ReservoirBuilderTest {
@Inject
ReservoirBuilderNullContributor reservoirBuilder;

@Inject
TimerFieldBean timerBean;

@Inject
HistogramFieldBean histogramBean;


@Deployment
public static Archive<?> createTestArchive() {
return ShrinkWrap.create(JavaArchive.class)
// Test bean class with Timer injection
.addClass(TimerFieldBean.class)
// Test bean class with Histogram injection
.addClass(HistogramFieldBean.class)
// The ReservoirBuilder counting calls
.addClass(ReservoirBuilderNullContributor.class)
// Metrics CDI extension
.addPackage(MetricsExtension.class.getPackage())
// Bean archive deployment descriptor
.addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
}

@Test
public void checkReservoirBuilderCalls() {
int NB_TIMER_FIELDS_IN_BEAN = 6;
int NB_HISTOGRAM_FIELDS_IN_BEAN = 1;

int expectedCalls = NB_TIMER_FIELDS_IN_BEAN + NB_HISTOGRAM_FIELDS_IN_BEAN;
assertThat("Number of ReservoirBuilder calls differ from expected # of Timer fields", reservoirBuilder.calls(), is(expectedCalls));
}
}
43 changes: 39 additions & 4 deletions impl/src/main/java/io/astefanutti/metrics/cdi/MetricProducer.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Reservoir;
import com.codahale.metrics.Timer;

import javax.annotation.Priority;
Expand Down Expand Up @@ -53,8 +54,25 @@ public T getValue() {
}

@Produces
private static Histogram histogram(InjectionPoint ip, MetricRegistry registry, MetricName metricName) {
return registry.histogram(metricName.of(ip));
private static Histogram histogram(InjectionPoint ip, MetricRegistry registry, MetricName metricName, MetricsExtension extension) {
String histogramName = metricName.of(ip);
Reservoir reservoir = null;
ReservoirBuidler reservoirBuidler = extension.getReservoirBuidler();
if (reservoirBuidler != null) {
reservoir = reservoirBuidler.build(histogramName, ReservoirUsage.HISTOGRAM);
}

if (reservoir == null) {
return registry.histogram(histogramName);
} else {
final Reservoir r = reservoir;
return registry.histogram(histogramName, new MetricRegistry.MetricSupplier<Histogram>() {
@Override
public Histogram newMetric() {
return new Histogram(r);
}
});
}
}

@Produces
Expand All @@ -63,7 +81,24 @@ private static Meter meter(InjectionPoint ip, MetricRegistry registry, MetricNam
}

@Produces
private static Timer timer(InjectionPoint ip, MetricRegistry registry, MetricName metricName) {
return registry.timer(metricName.of(ip));
private static Timer timer(InjectionPoint ip, MetricRegistry registry, MetricName metricName, MetricsExtension extension) {
String timerName = metricName.of(ip);
Reservoir reservoir = null;
ReservoirBuidler reservoirBuidler = extension.getReservoirBuidler();
if (reservoirBuidler != null) {
reservoir = reservoirBuidler.build(timerName, ReservoirUsage.TIMER);
}

if (reservoir == null) {
return registry.timer(timerName);
} else {
final Reservoir r = reservoir;
return registry.timer(timerName, new MetricRegistry.MetricSupplier<Timer>() {
@Override
public Timer newMetric() {
return new Timer(r);
}
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ public interface MetricsConfiguration {
* @throws IllegalStateException if called outside of the observer method invocation
*/
MetricsConfiguration useAbsoluteName(boolean useAbsoluteName);

/**
* Registers a builder to produce different {@link com.codahale.metrics.Reservoir} implementations depending on the metric.
* @param builder the builder to use to produce {@link com.codahale.metrics.Reservoir} instances
* @return this Metrics CDI configuration
* @throws IllegalStateException if called outside of the observer method invocation
*/
MetricsConfiguration useReservoirBuilder(ReservoirBuidler builder);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
import java.util.EnumSet;
import java.util.Set;

import com.codahale.metrics.Reservoir;

/* package-private */ final class MetricsConfigurationEvent implements MetricsConfiguration {

private final EnumSet<MetricsParameter> configuration = EnumSet.noneOf(MetricsParameter.class);

private ReservoirBuidler reservoirBuilder;
private volatile boolean unmodifiable;

@Override
Expand All @@ -36,10 +39,21 @@ public MetricsConfiguration useAbsoluteName(boolean useAbsoluteName) {
return this;
}

@Override
public MetricsConfiguration useReservoirBuilder(ReservoirBuidler builder) {
throwsIfUnmodifiable();
this.reservoirBuilder = builder;
return this;
}

Set<MetricsParameter> getParameters() {
return Collections.unmodifiableSet(configuration);
}

ReservoirBuidler getReservoirBuilder() {
return reservoirBuilder;
}

void unmodifiable() {
unmodifiable = true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ public class MetricsExtension implements Extension {
Set<MetricsParameter> getParameters() {
return configuration.getParameters();
}

ReservoirBuidler getReservoirBuidler() {
return configuration.getReservoirBuilder();
}

private void addInterceptorBindings(@Observes BeforeBeanDiscovery bbd, BeanManager manager) {
declareAsInterceptorBinding(Counted.class, manager, bbd);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright © 2013 Antonin Stefanutti (antonin.stefanutti@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.astefanutti.metrics.cdi;

import com.codahale.metrics.Reservoir;

/**
* Builder class allowing the production of different {@link Reservoir} implementations based on the metric kind & names.
*/
public interface ReservoirBuidler {
/**
* Builds a {@link Reservoir} for the given metric
* @param metricName the name of the metric for which a Reservoir needs to be used
* @param type the kind of metric for which a reservoir is required
* @return the reservoir to use, or null if default reservoir implementation has to be used
*/
Reservoir build(String metricName, ReservoirUsage type);
}
20 changes: 20 additions & 0 deletions impl/src/main/java/io/astefanutti/metrics/cdi/ReservoirUsage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Copyright © 2013 Antonin Stefanutti (antonin.stefanutti@gmail.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.astefanutti.metrics.cdi;

public enum ReservoirUsage {
HISTOGRAM, TIMER;
}

0 comments on commit 9da35a7

Please sign in to comment.