{"id":96,"date":"2024-08-27T04:00:00","date_gmt":"2024-08-27T04:00:00","guid":{"rendered":"https:\/\/imcodinggenius.com\/?p=96"},"modified":"2024-08-27T04:00:00","modified_gmt":"2024-08-27T04:00:00","slug":"sending-spring-boot-metrics-to-datadog","status":"publish","type":"post","link":"https:\/\/imcodinggenius.com\/?p=96","title":{"rendered":"Sending Spring Boot Metrics to Datadog"},"content":{"rendered":"<p>Hello and welcome to the next article in which we will briefly discuss Datadog and Micrometer, but what\u2019s more important- we will learn how to send <strong>Spring Boot metrics<\/strong> to <strong>Datadog in practice<\/strong>.<\/p>\n<p>Moreover, we will take a quick look into the Spring Boot Actuator and how it can help us, so, to let\u2019s not waste our time and let\u2019s get to work!  <\/p>\n<h2 class=\"wp-block-heading\">Video Tutorial<\/h2>\n<p>If you prefer <strong>video content<\/strong>, then check out my video:<\/p>\n<div>\n<p><span class=\"w1il8vGOyhKsqecrgTLn\"><\/span><\/p>\n<div class=\"responsive-video\"><\/div>\n<p><\/p>\n<\/div>\n<p>If you find this content useful,<strong> please leave a subscription<\/strong> <\/p>\n<h2 class=\"wp-block-heading\">Datadog<\/h2>\n<p>If you came here directly, then I bet you already know what <a href=\"https:\/\/www.datadoghq.com\/\" target=\"_blank\" rel=\"noopener\">Datadog<\/a> is and what purpose it will serve in your project.<\/p>\n<p>However, for those who hear about it for the first time, let me give you a really short intro.<\/p>\n<p>Long story short- Datadog is an <strong>integrated platform for monitoring &amp; security<\/strong>. It provides tools for monitoring applications, databases, distributed tracing, logs management, and many many more. In other words, makes all the things that are not so cool, but necessary in production-ready environments, a bit less painful <\/p>\n<p>However, what is the most important for us today- it provides tools to <strong>collect metrics<\/strong> from our applications so that later we can make use of them.<\/p>\n<p>But, what are they? <\/p>\n<h2 class=\"wp-block-heading\">What Are Metrics? <\/h2>\n<p>According to the Datadog documentation:<\/p>\n<p>Metrics are numerical values that can track anything about your environment over time.<\/p>\n<p>And I must admit- I love this definition for its completeness in its simplicity.<\/p>\n<p>Because basically, <strong>metric<\/strong> is everything in our system that we can assign a number to and track. From Garbage Collector stats, JVM memory, CPU, and request latency, to the average cart size. Literally everything.<\/p>\n<p>And in this tutorial, we will see how to send metrics <strong>collected automatically<\/strong> by our Spring Boot app to DataDog.<\/p>\n<h2 class=\"wp-block-heading\">Create New Project<\/h2>\n<p>As the first step, let\u2019s navigate to the <a href=\"https:\/\/start.spring.io\/\" target=\"_blank\" rel=\"noopener\">Spring Initializr page<\/a>, select the following and import the project to our IDE:<\/p>\n<div class=\"wp-block-image\">\n<\/div>\n<p>Apart from versions and metadata, we can see that we added two dependencies: <strong>Spring Web<\/strong> and <strong>Spring Boot Actuator.<\/strong> <\/p>\n<p>The first one is quite obvious, but in terms of metrics Spring Boot Actuator provides dependency management and auto-configuration for <strong>Micrometer<\/strong> \u2013 a vendor-neutral application observability facade. <\/p>\n<p>With that, Spring Boot takes care of configuring MeterRegistry and the only thing we need to do is to add the micrometer-registry-{system} dependency to the build.gradle.kts :<\/p>\n<p>implementation(&#171;io.micrometer:micrometer-registry-datadog&#187;)<\/p>\n<p><strong>Note:<\/strong> we could achieve exactly the same using the Spring Initializr page and searching for the Datadog dependency, but I wanted to emphasize the fact, that other vendors, like Elastic, or OpenTelemetry can be added in the same manner.  <\/p>\n<h2 class=\"wp-block-heading\">Verify and Expose Metrics Endpoint<\/h2>\n<p>After we import our project, let\u2019s run it, and let\u2019s take a look at the endpoints exposed by default by Spring Boot Actuator: <\/p>\n<p>curl &#8212;location &#8212;request GET &#8216;http:\/\/localhost:8080\/actuator&#8217; <\/p>\n<p>As a result, we should see the following: <\/p>\n<p>{<br \/>\n    &#171;_links&#187;: {<br \/>\n        &#171;self&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator&#187;,<br \/>\n            &#171;templated&#187;: false<br \/>\n        },<br \/>\n        &#171;health&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator\/health&#187;,<br \/>\n            &#171;templated&#187;: false<br \/>\n        },<br \/>\n        &#171;health-path&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator\/health\/{*path}&#187;,<br \/>\n            &#171;templated&#187;: true<br \/>\n        }<br \/>\n    }<br \/>\n}<\/p>\n<p>And the first lesson is that <strong>the metrics endpoint is not exposed by default.<\/strong><\/p>\n<p>So to change that, let\u2019s navigate to the application.yaml and add the following:<\/p>\n<p>management:<br \/>\n  endpoints:<br \/>\n    web:<br \/>\n      exposure:<br \/>\n        include: metrics, health<\/p>\n<p>After that, let\u2019s rerun the application. <\/p>\n<p>As a result, this time, we should see that two new endpoints are present: <\/p>\n<p>{<br \/>\n    &#171;_links&#187;: {<br \/>\n        &#171;self&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator&#187;,<br \/>\n            &#171;templated&#187;: false<br \/>\n        },<br \/>\n        &#171;health&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator\/health&#187;,<br \/>\n            &#171;templated&#187;: false<br \/>\n        },<br \/>\n        &#171;health-path&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator\/health\/{*path}&#187;,<br \/>\n            &#171;templated&#187;: true<br \/>\n        },<br \/>\n        &#171;metrics-requiredMetricName&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator\/metrics\/{requiredMetricName}&#187;,<br \/>\n            &#171;templated&#187;: true<br \/>\n        },<br \/>\n        &#171;metrics&#187;: {<br \/>\n            &#171;href&#187;: &#171;http:\/\/localhost:8080\/actuator\/metrics&#187;,<br \/>\n            &#171;templated&#187;: false<br \/>\n        }<br \/>\n    }<br \/>\n}<\/p>\n<p>The last one- \/actuator\/metrics\u2013 simply <strong>displays a list of available meter names<\/strong>, and when we invoke it, we should see the following JSON response: <\/p>\n<p>{<br \/>\n    &#171;names&#187;: [<br \/>\n        &#171;application.ready.time&#187;,<br \/>\n        &#171;application.started.time&#187;,<br \/>\n        &#171;disk.free&#187;,<br \/>\n        &#171;disk.total&#187;,<br \/>\n        &#171;executor.active&#187;,<br \/>\n        &#171;executor.completed&#187;,<br \/>\n        &#171;executor.pool.core&#187;,<br \/>\n        &#171;executor.pool.max&#187;,<br \/>\n        &#171;executor.pool.size&#187;,<br \/>\n        &#171;executor.queue.remaining&#187;,<br \/>\n        &#171;executor.queued&#187;,<br \/>\n        &#171;http.server.requests&#187;,<br \/>\n        &#171;http.server.requests.active&#187;,<br \/>\n        &#171;jvm.buffer.count&#187;,<br \/>\n        &#171;jvm.buffer.memory.used&#187;,<br \/>\n        &#171;jvm.buffer.total.capacity&#187;,<br \/>\n        &#171;jvm.classes.loaded&#187;,<br \/>\n        &#171;jvm.classes.unloaded&#187;,<br \/>\n        &#171;jvm.compilation.time&#187;,<br \/>\n        &#171;jvm.gc.concurrent.phase.time&#187;,<br \/>\n        &#171;jvm.gc.live.data.size&#187;,<br \/>\n        &#171;jvm.gc.max.data.size&#187;,<br \/>\n        &#171;jvm.gc.memory.allocated&#187;,<br \/>\n        &#171;jvm.gc.memory.promoted&#187;,<br \/>\n        &#171;jvm.gc.overhead&#187;,<br \/>\n        &#171;jvm.gc.pause&#187;,<br \/>\n        &#171;jvm.info&#187;,<br \/>\n        &#171;jvm.memory.committed&#187;,<br \/>\n        &#171;jvm.memory.max&#187;,<br \/>\n        &#171;jvm.memory.usage.after.gc&#187;,<br \/>\n        &#171;jvm.memory.used&#187;,<br \/>\n        &#171;jvm.threads.daemon&#187;,<br \/>\n        &#171;jvm.threads.live&#187;,<br \/>\n        &#171;jvm.threads.peak&#187;,<br \/>\n        &#171;jvm.threads.started&#187;,<br \/>\n        &#171;jvm.threads.states&#187;,<br \/>\n        &#171;logback.events&#187;,<br \/>\n        &#171;process.cpu.time&#187;,<br \/>\n        &#171;process.cpu.usage&#187;,<br \/>\n        &#171;process.start.time&#187;,<br \/>\n        &#171;process.uptime&#187;,<br \/>\n        &#171;system.cpu.count&#187;,<br \/>\n        &#171;system.cpu.usage&#187;,<br \/>\n        &#171;tomcat.sessions.active.current&#187;,<br \/>\n        &#171;tomcat.sessions.active.max&#187;,<br \/>\n        &#171;tomcat.sessions.alive.max&#187;,<br \/>\n        &#171;tomcat.sessions.created&#187;,<br \/>\n        &#171;tomcat.sessions.expired&#187;,<br \/>\n        &#171;tomcat.sessions.rejected&#187;<br \/>\n    ]<br \/>\n}<\/p>\n<p>In simple words, this is the list of all metrics collected at this point by our Spring Boot application. And yes- we will be able to export them to Datadog. <\/p>\n<p>Nevertheless, let\u2019s verify what the second endpoint- \/actuator\/metrics\/{requiredMetricName}\u2013 does.<\/p>\n<p>To do that, let\u2019s make a GET request and specify any metric name:<\/p>\n<p>curl &#8212;location &#8212;request GET &#8216;http:\/\/localhost:8080\/actuator\/metrics\/process.cpu.usage&#8217;<\/p>\n<p>This time, the endpoint will return metric details along with the <strong>current value<\/strong>:<\/p>\n<p>{<br \/>\n    &#171;name&#187;: &#171;process.cpu.usage&#187;,<br \/>\n    &#171;description&#187;: &#171;The &#171;recent cpu usage&#187; for the Java Virtual Machine process&#187;,<br \/>\n    &#171;measurements&#187;: [<br \/>\n        {<br \/>\n            &#171;statistic&#187;: &#171;VALUE&#187;,<br \/>\n            &#171;value&#187;: 0.038209510879134205<br \/>\n        }<br \/>\n    ],<br \/>\n    &#171;availableTags&#187;: []<br \/>\n}<\/p>\n<h2 class=\"wp-block-heading\">Create Datadog Account<\/h2>\n<p>Excellent! At this point, we are sure that our Spring Boot app collects metrics, so it\u2019s time to proceed with the Datadog part. <\/p>\n<p>If you haven\u2019t done it yet, then let\u2019s create a trial account together. <\/p>\n<p>Let\u2019s navigate to the <a href=\"https:\/\/www.datadoghq.com\/\">https:\/\/www.datadoghq.com\/<\/a> and click the \u201cFree trial\u201d button:<\/p>\n<div class=\"wp-block-image\">\n<\/div>\n<p>Following, let\u2019s fill out the signup form: <\/p>\n<div class=\"wp-block-image\">\n<\/div>\n<p>And with that done, when we confirm our e-mail address, we will land on this page: <\/p>\n<p>As we can see, the above page contains a bunch of guides on how to set up the agent. <\/p>\n<p>And although we are not interested in any of those, this page has one, valuable information for us- the <strong>API key<\/strong>. <\/p>\n<p><strong>Note:<\/strong> I think that readers of this blog are well aware of that, but for my own peace of mind- API keys are vulnerable data, so you <strong>must be cautious<\/strong> with them!  <\/p>\n<p>At this point, please copy this value and we will use it in the proceeding steps. <\/p>\n<h2 class=\"wp-block-heading\">Configure App To Send Metrics<\/h2>\n<p>When we have our Datadog account ready, we can finally configure our app. <\/p>\n<h3 class=\"wp-block-heading\">API Key<\/h3>\n<p>Firstly, let\u2019s get back to our Spring Boot project and update the application.yaml :<\/p>\n<p>management:<br \/>\n  endpoints:<br \/>\n    web:<br \/>\n      exposure:<br \/>\n        include: metrics, health<br \/>\n  datadog:<br \/>\n    metrics:<br \/>\n      export:<br \/>\n        api-key: YOUR_KEY_VALUE<\/p>\n<p>Of course, we must replace the YOUR_KEY_VALUE with the actual API key. <\/p>\n<h3 class=\"wp-block-heading\">Update Datadog URI <\/h3>\n<p>If you are using Datadog US (the option you could select when signing up), then that\u2019s pretty much it and you can restart the application.<\/p>\n<p>By default, metrics are sent to the Datadog US site (api.datadoghq.com). If your Datadog project is hosted on one of the other sites, or you need to send metrics through a proxy, configure the URI accordingly.<\/p>\n<p>So given the above, if we use another region, then we need to add one more line: <\/p>\n<p>management:<br \/>\n  endpoints:<br \/>\n    web:<br \/>\n      exposure:<br \/>\n        include: metrics, health<br \/>\n  datadog:<br \/>\n    metrics:<br \/>\n      export:<br \/>\n        api-key: YOUR_KEY_VALUE<br \/>\n        uri: https:\/\/api.datadoghq.eu<\/p>\n<h3 class=\"wp-block-heading\">Update Metrics Upload Interval<\/h3>\n<p>Following, let\u2019s see how easily we can update the interval, in which data are sent to Datadog: <\/p>\n<p>management:<br \/>\n  endpoints:<br \/>\n    web:<br \/>\n      exposure:<br \/>\n        include: metrics, health<br \/>\n  datadog:<br \/>\n    metrics:<br \/>\n      export:<br \/>\n        api-key: YOUR_KEY_VALUE<br \/>\n        uri: https:\/\/api.datadoghq.eu<br \/>\n        step: 10s<\/p>\n<p>The default value is <strong>30 seconds<\/strong>. And to change that, the only thing we need to do is to add the step value. <\/p>\n<h3 class=\"wp-block-heading\">Set Spring Logging Level to DEBUG<\/h3>\n<p>As the last thing, which technically is not directly related to sending metrics, I would like to add the following to the root of our application.yaml file: <\/p>\n<p>logging:<br \/>\n  level:<br \/>\n    root: DEBUG<\/p>\n<p>This way we set the logging level in our Spring Boot application to DEBUG. <\/p>\n<p>Why? It will be useful in a moment when we will be testing our implementation. <\/p>\n<h2 class=\"wp-block-heading\">Testing <\/h2>\n<p>With all of that done, we can finally verify that everything is working properly. <\/p>\n<h3 class=\"wp-block-heading\">Verify Spring Boot Sends Data to Datadog<\/h3>\n<p>Firstly, let\u2019s rerun our application and take a look at the logs.<\/p>\n<p>If we see the following: <\/p>\n<p>i.m.datadog.DatadogMeterRegistry         : successfully sent 78 metrics to datadog<\/p>\n<p>Then data are successfully sent to the Datadog API. <\/p>\n<p>Let\u2019s leave it running for some time (like 2 minutes, or something), so that we have actual data later to work with  <\/p>\n<h2 class=\"wp-block-heading\">Review Metrics in Datadog <\/h2>\n<p>After that time, the only thing left is to take a look at metrics in Datadog. <\/p>\n<p>If we haven\u2019t closed the Datadog \u201cAgent Setup\u201d page, then it should automatically close and redirect us to the dashboard. <\/p>\n<p>However, if that didn\u2019t happen, then no worries, we can simply navigate to the <a href=\"https:\/\/app.datadoghq.eu\/metric\/summary\" target=\"_blank\" rel=\"noopener\">metrics summary page<\/a>: <\/p>\n<div class=\"wp-block-image\">\n<\/div>\n<p>On this page, we can see all the metrics that have been gathered so far. Long story short, this page contains meta-information about metrics themselves, like tags, etc. <\/p>\n<p>I strongly recommend you spend here some time and figure out different options. <\/p>\n<p>And if we would like to take a look at the actual values, then let\u2019s navigate to the <a href=\"https:\/\/app.datadoghq.eu\/metric\/explorer\" target=\"_blank\" rel=\"noopener\">metrics explorer<\/a>: <\/p>\n<div class=\"wp-block-image\">\n<\/div>\n<p>I know, the image is quite small (the \u201cOpen Image in New Tab\u201d option will help here  ). However, the only thing we need to do here is to specify the metric name in the left upper part and the period we would like to view in the right upper part. <\/p>\n<p>After that, we will see the above chart. <\/p>\n<p>And basically, that\u2019s how metrics work with Spring Boot and Datadog, but please don\u2019t close this article yet, I wanted to show you two, interesting things that may be useful to you in real life. <\/p>\n<h2 class=\"wp-block-heading\">Sending Custom Tags <\/h2>\n<p><strong>Tags<\/strong> are nothing else, than additional metadata you can send with metrics.  <\/p>\n<p>Why are they useful? Well, thanks to them we can later differentiate different metrics. For example, we can send a tag with the application name, so that later we will group metrics by microservices, or environment value, like dev, staging, or prod. <\/p>\n<p>In Spring Boot, we have several ways to achieve that. And probably the easiest way is to (again) update the application.yaml:<\/p>\n<p>management:<br \/>\n  endpoints:<br \/>\n    web:<br \/>\n      exposure:<br \/>\n        include: metrics, health<br \/>\n  datadog:<br \/>\n    metrics:<br \/>\n      export:<br \/>\n        api-key: YOUR_KEY_VALUE<br \/>\n        uri: https:\/\/api.datadoghq.eu<br \/>\n        step: 10s<br \/>\n  metrics:<br \/>\n    tags:<br \/>\n      application: &#171;my-app-one&#187;<\/p>\n<p>As we can see, we can add a custom tag by using  metrics.tags and specifying that as a key-value pair. In our case- the application tag has the my-app-one value. <\/p>\n<p>This approach is not only straightforward but also quite flexible. We could always put a placeholder for the environment variable instead of the hardcoded value. <\/p>\n<p>Anyway, when we rerun our application and let Spring send some metrics to the Datadog, we will see that from now on we can <strong>filter values using the \u201cfrom\u201d field:<\/strong><\/p>\n<p>Again, the \u201cOpen Image in New Tab\u201d may be helpful here  <\/p>\n<h2 class=\"wp-block-heading\">Turn Off Metrics Export<\/h2>\n<p>As the last thing, let\u2019s take a look at how we can instruct our Spring app to <strong>stop sending metrics to Datadog<\/strong>.<\/p>\n<p>Again, let\u2019s navigate to the application.yaml file and set the enabled flag to false: <\/p>\n<p>management:<br \/>\n  endpoints:<br \/>\n    web:<br \/>\n      exposure:<br \/>\n        include: metrics, health<br \/>\n  datadog:<br \/>\n    metrics:<br \/>\n      export:<br \/>\n        enabled: false<br \/>\n        api-key: YOURE_KEY_VALUE<br \/>\n        uri: https:\/\/api.datadoghq.eu<br \/>\n        step: 10s<\/p>\n<p>Of course, we can use an environment variable placeholder (like ${DATADOG_ENABLED}) and turn on\/off export in different environments. <\/p>\n<h2 class=\"wp-block-heading\">Summary <\/h2>\n<p>That\u2019s all for this tutorial on <strong>how to send Spring Boot metrics to Datadog<\/strong>. <\/p>\n<p>As always, you can find the source code in <a href=\"https:\/\/github.com\/codersee-blog\/spring-boot-3-kotlin-datadog\" target=\"_blank\" rel=\"noopener\">this GitHub repository<\/a>.<\/p>\n<p>Have a great day and don\u2019t forget to <strong>leave a comment<\/strong>! <\/p>\n<p>The post <a href=\"https:\/\/codersee.com\/sending-spring-boot-metrics-datadog\/\">Sending Spring Boot Metrics to Datadog<\/a> appeared first on <a href=\"https:\/\/codersee.com\/\">Codersee | Kotlin, Ktor, Spring<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Hello and welcome to the next article in which we will briefly discuss Datadog and Micrometer, but what\u2019s more important- we will learn how to send Spring Boot metrics to Datadog in practice. Moreover, we will take a quick look into the Spring Boot Actuator and how it can help &#8230; <\/p>\n<div><a class=\"more-link bs-book_btn\" href=\"https:\/\/imcodinggenius.com\/?p=96\">Read More<\/a><\/div>\n","protected":false},"author":1,"featured_media":97,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-96","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-news"],"_links":{"self":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/posts\/96"}],"collection":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=96"}],"version-history":[{"count":0,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/posts\/96\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=\/wp\/v2\/media\/97"}],"wp:attachment":[{"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/imcodinggenius.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}