{"id":13832,"date":"2019-10-21T17:09:45","date_gmt":"2019-10-21T15:09:45","guid":{"rendered":"https:\/\/touk.pl\/blog\/?p=13832"},"modified":"2023-03-20T16:08:50","modified_gmt":"2023-03-20T15:08:50","slug":"deep-dive-into-spring-boot-actuator-http-metrics","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2019\/10\/21\/deep-dive-into-spring-boot-actuator-http-metrics\/","title":{"rendered":"Deep dive into Spring Boot Actuator HTTP metrics"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/touk.pl\/blog\/wp-content\/uploads\/2019\/10\/grafana.png\" alt=\"\" width=\"\" height=\"\" class=\"alignnone size-medium wp-image-13793\" \/><\/p>\n<h3 id=\"actuator-metrics\">Actuator Metrics<\/h3>\n<p>As reported in Micha\u0142 Bobowski <a href=\"https:\/\/touk.pl\/blog\/2018\/03\/05\/spring-boot-2-0-http-request-metrics-with-micrometer\/\">post<\/a>, we heavily use Spring Boot Actuator metrics system based on Micrometer. It provides a set of practical metrics regarding JVM stats like CPU or memory utilization. Our applications have to meet the most sophisticated needs of our clients thus we try to take advantage of <code>http.server.request<\/code> endpoint.<\/p>\n<h3 id=\"introduction\">Introduction<\/h3>\n<p>By default, Spring Boot Actuator gathers endpoint statistics for all classes annotated with <code>@RestController<\/code>. It registers a <a href=\"https:\/\/github.com\/spring-projects\/spring-boot\/blob\/master\/spring-boot-project\/spring-boot-actuator\/src\/main\/java\/org\/springframework\/boot\/actuate\/metrics\/web\/servlet\/WebMvcMetricsFilter.java\">WebMvcMetricsFilter<\/a> bean, which is responsible for timing a request. A special <code>TimingContext<\/code> attribute is attached to the request so that Spring Boot knows when the request started.<\/p>\n<h3 id=\"actuator-metrics-model\">Actuator metrics model<\/h3>\n<p>When you call <code>http:\/\/localhost:8080\/actuator\/metrics\/http.server.request<\/code> endpoint you will get something similar to this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">\r\n{\r\n  \"name\": \"http.server.requests\",\r\n  \"description\": null,\r\n  \"baseUnit\": \"milliseconds\",\r\n  \"measurements\": [\r\n    {\r\n      \"statistic\": \"COUNT\",\r\n      \"value\": 12\r\n    },\r\n    {\r\n      \"statistic\": \"TOTAL_TIME\",\r\n      \"value\": 21487.256644\r\n    },\r\n    {\r\n      \"statistic\": \"MAX\",\r\n      \"value\": 2731.787888\r\n    }\r\n  ],\r\n  \"availableTags\": [\r\n    {\r\n      \"tag\": \"exception\",\r\n      \"values\": [\r\n        \"None\",\r\n        \"RuntimeException\"\r\n      ]\r\n    },\r\n    {\r\n      \"tag\": \"method\",\r\n      \"values\": [\r\n        \"GET\"\r\n      ]\r\n    },\r\n    {\r\n      \"tag\": \"uri\",\r\n      \"values\": [\r\n        \"\/example\/success\"\r\n      ]\r\n    },\r\n    {\r\n      \"tag\": \"outcome\",\r\n      \"values\": [\r\n        \"SERVER_ERROR\",\r\n        \"SUCCESS\"\r\n      ]\r\n    },\r\n    {\r\n      \"tag\": \"status\",\r\n      \"values\": [\r\n        \"500\",\r\n        \"200\"\r\n      ]\r\n    }\r\n  ]\r\n}\r\n<\/pre>\n<p>You will surely see the <code>measurements<\/code> section. It provides types and values of statistics recorded at a certain point in time. Types of statistics are ones described in <a href=\"https:\/\/github.com\/micrometer-metrics\/micrometer\/blob\/master\/micrometer-core\/src\/main\/java\/io\/micrometer\/core\/instrument\/Statistic.java\">Statistics<\/a> enum.<br \/>\nAnother one is the <code>availableTags<\/code> section, which contains a set of default tags distinguishing each metric by URI, status, or method. You can easily put your tags there like a host or container. If you want to check metric for a particular tag, Actuator lets you do this by using tag query <code>http:\/\/localhost:8080\/actuator\/metrics\/http.server.request?tag=status:200<\/code><\/p>\n<h3 id=\"metric-system-model\">Metric system model<\/h3>\n<p>However, each monitoring system has its own metrics model and therefore uses different names for the same things. In our case, we use <a href=\"https:\/\/micrometer.io\/docs\/registry\/influx\">Influx Registry<\/a>.<br \/>\nLet&#8217;s look into <a href=\"https:\/\/github.com\/micrometer-metrics\/micrometer\/blob\/master\/implementations\/micrometer-registry-influx\/src\/main\/java\/io\/micrometer\/influx\/InfluxMeterRegistry.java#L203\">InfluxMeterRegistry<\/a> class implementation.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">private Stream writeTimer(Timer timer) {\r\n    final Stream fields = Stream.of(\r\n        new Field(\"sum\", timer.totalTime(getBaseTimeUnit())),\r\n        new Field(\"count\", timer.count()),\r\n        new Field(\"mean\", timer.mean(getBaseTimeUnit())),\r\n        new Field(\"upper\", timer.max(getBaseTimeUnit()))\r\n    );\r\n\r\n    return Stream.of(influxLineProtocol(timer.getId(), \"histogram\", fields));\r\n}\r\n<\/pre>\n<p>We see which field in influx corresponds to actuators measurement. Moreover, our registry equips us with an additional <code>mean<\/code> field, which is basically <code>TOTAL_TIME<\/code> divided by <code>COUNT<\/code>. Therefore we don&#8217;t need to calculate it manually inside our monitoring system.<\/p>\n<h3 id=\"summary\">Summary<\/h3>\n<p>(1) Be aware that the Actuator metric model directly corresponds to Micrometer model<br \/>\n(2) When it comes to timing requests carefully choose the step in which metrics are exported<br \/>\n(3) Do not mix composing metric values with aggregations, selectors, and transformations, e.g. mean(mean)<\/p>\n","protected":false},"excerpt":{"rendered":"Actuator Metrics As reported in Micha\u0142 Bobowski post, we heavily use Spring Boot Actuator metrics system based on&hellip;\n","protected":false},"author":79,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[],"class_list":{"0":"post-13832","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/13832","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/79"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=13832"}],"version-history":[{"count":13,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/13832\/revisions"}],"predecessor-version":[{"id":15447,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/13832\/revisions\/15447"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=13832"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=13832"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=13832"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}