Creating custom metrics

Every program manager loves metrics. In fact, a popular company (Netflix) is so well known in this arena that people describe it as a metrics-gathering company that happens to stream video.

When it comes to Spring Boot, metrics are a prime piece of Spring Boot Actuator functionality. If we visit /application/metrics, we can see a list of metrics:

    {
"names": [
"jvm.buffer.memory.used",
"jvm.memory.used",
"jvm.buffer.count",
"logback.events",
"process.uptime",
"jvm.memory.committed",
"http.server.requests",
"jvm.buffer.total.capacity",
"jvm.memory.max",
"process.starttime"
]
}

This lists all sorts of stuff--memory, garbage collection, heap versus nonheap, threads, and more. That's nice, but what's usually needed is the ability to create our own metrics.

Spring Boot provides an interface to register our own metrics and have them appear on the same page. Supplied immediately is the ability to grab a MeterRegistry.

To make use of this three meter registry, we need to inject it into  ImageService we built in Chapter 3, Reactive Data Access with Spring Boot:

    @Service 
    public class ImageService { 
 
      ... 
 
      private final MeterRegistry meterRegistry; 
 
      public ImageService(ResourceLoader resourceLoader, 
        ImageRepository imageRepository, 
        MeterRegistry meterRegistry) { 
 
          this.resourceLoader = resourceLoader; 
          this.imageRepository = imageRepository; 
          this.meterRegistry = meterRegistry; 
        } 
        ... 

This code shows the following:

  • Three metric services, CounterService, GaugeService, and InMemoryMetricRepository declared as final attributes
  • These three fields are populated by constructor injection, ensuring they are supplied when the service is created

With that in place, further down inside createImage, we can define custom metrics:

    public Mono<Void> createImage(Flux<FilePart> files) { 
      return files 
       .log("createImage-files") 
       .flatMap(file -> { 
         Mono<Image> saveDatabaseImage = imageRepository.save( 
           new Image( 
             UUID.randomUUID().toString(), 
             file.filename())) 
             .log("createImage-save"); 
 
             Mono<Void> copyFile = Mono.just(Paths.get(UPLOAD_ROOT,
file.filename()).toFile()) .log("createImage-picktarget") .map(destFile -> { try { destFile.createNewFile(); return destFile; } catch (IOException e) { throw new RuntimeException(e); } }) .log("createImage-newfile") .flatMap(file::transferTo) .log("createImage-copy"); Mono<Void> countFile = Mono.fromRunnable(() -> { meterRegistry
.summary("files.uploaded.bytes")
.record(Paths.get(UPLOAD_ROOT,
file.filename()).toFile().length()) });
return Mono.when(saveDatabaseImage, copyFile, countFile) .log("createImage-when"); }) .log("createImage-flatMap") .then() .log("createImage-done"); }

The first part of the code where a new image is created is the same, but following that is meterRegistry.summary("files.uploaded.bytes").record(… ), which creates a new distribution summary named files.uploaded.bytes. A distribution summary includes both a name, optional tags, and a value. What is registered is both a value and an occurrence. Each time a meter is added, it counts it, and the running total is tabulated.

With these adjustments, we can refresh the application, wait for it to reload, and then upload a few images, as shown here:

After uploading these images, if we revisit /application/metrics, we can see our new metric at the bottom of the list:

    {
      "names": [
        "jvm.buffer.memory.used",
        "jvm.memory.used",
        "jvm.buffer.count",
        "logback.events",
        "process.uptime",
        "jvm.memory.committed",
        "http.server.requests",
        "jvm.buffer.total.capacity",
        "jvm.memory.max",
        "process.starttime",
        "files.uploaded.bytes"
      ]
    }

If we navigate to http://localhost:8080/application/metrics/files.uploaded.bytes, we can view it:

    {
      "name": "files.uploaded.bytes",
      "measurements": [
        {
          "statistic": "Count",
          "value": 3.0
        },
        {
          "statistic": "Total",
          "value": 208020.0
        }
      ],
      "availableTags": [

      ]
    }

This JSON shows that three measurements have been registered with files.uploaded.bytes, totaling 208020 bytes. What's not immediately shown is also the time when these metrics were posted. It's possible to calculate upload trends using the new Micrometer module (http://micrometer.io).

Micrometer is a new project at Pivotal. It's a facade for metrics gathering. Think SLF4J, but for metrics instead. It is designed to integrate with lots of metric-gathering systems, including Atlas, Prometheus, Datadog, Influx, Graphite, and more. In this case, it's using a memory-based solution. Since it's currently under development and could warrant its own book, we will not delve too deep.

This is but a sampling of the possible metrics that can be defined. Feel free to dig in and experiment with the data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.225.234.28