Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Register MetricRegistry inside Dropwizard Bundle

I am creating a Dropwizard Bundle to be reused across all my microservices. One of the things I would like to standardize on is the MetricRegistry each service uses.

It would be great if I could I could configure each service to use the same MetricRegistry by simply adding my bundle on init, so something like:

class Microservice1 extends Application<Microservice1Config> {
    @Override
    void initialize(Bootstrap<Microservice1Config> cfg) {
        // Boom! Standardized metrics/reporters configured and initialized!
        bootstrap.addBundle(new MyBundle())
    }
}

The problem is that the Bundle API doesn't seem to be conducive to this type of behavior:

class MyBundle implements Bundle {
    MetricRegistry metricRegistry

    @Override
    void initialize(Bootstrap bootstrap) {

    }

    @Override
    void run(Environment environment) {
        environment.jersey().register(???)
    }
}

Since the register(...) method doesn't register metricRegistry as a JAX-RS resource, I'm at a loss as to how to wire things up so that this metricRegistry is used for all metrics throughout the entire microservice. Ideas?


Update

What I'm looking for is where to put the following:

MetricRegistry metricRegistry = new MetricRegistry()
Slf4jReporter slf4jReporter = Slf4jReporter.forRegistry(metricRegistry)
    .convertRatesTo(TimeUnit.SECONDS)
    .convertDurationsTo(TimeUnit.SECONDS)
    .build()

slf4jReporter.start(5, TimeUnit.SECONDS)
like image 491
smeeb Avatar asked Sep 10 '15 20:09

smeeb


1 Answers

Well, there is a metric registry accessible from environment.metrics(). There are lots of ways to get that injected where you need it. I use the dropwizard-guice bundle to add Guice support.

private GuiceBundle<MyConfiguration> guiceBundle;

@Override
public void initialize(Bootstrap<MyConfiguration> bootstrap) {

  guiceBundle = GuiceBundle.<MyConfiguration>newBuilder()
    .addModule(new MyModule())
    .setConfigClass(MyConfiguration.class)
    .build(Stage.DEVELOPMENT);

  bootstrap.addBundle(guiceBundle);
}

Then I create a provider rule in the application's module for the metric registry.

public class MyModule extends AbstractModule {

  ...

  @Provides
  @Singleton
  public MetricRegistry provideRegistry( Environment environment ) {
    return environment.metrics();
  }
}

And in my resource, I mark the registry as injected.

@Path("/resource")
public class MyResource {
  @Inject
  MetricRegistry registry;
}

Finally, I am requesting my static resources from Guice's injector and then passing an instance to Jersey, instead of a class name.

@Override
public void run(Environment environment) {
  Injector injector = guiceBundle.getInjector();
  environment.jersey().register(injector.getInstance(MyResource.class));
}

You could probably just register the class name and rely on the Guice/HK2 bridge to provide the injection, but historically Guice/HK2 integration has been problematic.

Once you have the metric registry wired up, you will need to configure metrics to send data somewhere. You can do this with the metrics configuration block.

For example, if you would like to send metrics to graphite, you can set up the graphite metrics reporter. You will need to add a dependency on the graphite reporter.

<dependency>
  <artifactId>dropwizard-metrics-graphite</artifactId>
  <groupId>io.dropwizard</groupId>
  <version>${dropwizard.version}</version>
</dependency>

and add configuration for the reporter.

metrics:
  reporters:
    - type: graphite
      prefix: <PREFIX_FOR_METRICS>
      host: <GRAPHITE_HOST>
      port: <GRAPHITE_PORT>
      frequency: 10s
like image 156
Christian Trimble Avatar answered Oct 26 '22 15:10

Christian Trimble