Introducing the Spring Boot Actuator, a function that makes the operation of Spring Boot applications easier.

Summary for those in a hurry

--Various information can be easily obtained by using SpringBoot Actuator. --Only add and configure dependent libraries to use the minimum functionality --Be careful about security as you will be able to refer to and change system operation information.

What are the functions required for system operation?

It is not the end of creating a system, but it is also important to operate it stably and how much it is used. Even with DevOps and recent agile, it's important to get feedback after the release and take the next strategy. Feedback is not only "I want you to do this" and "I want this function, I don't need it" from the user, but also "I don't use this function" or "This function suddenly started to be used" from the system operator. It is also important to notice from the provider side.

Spring Boot has a function called Spring Boot Actuator, which is a function to obtain necessary information in the latter current system, so we would like to introduce it.

What is SpringBoot Actuator?

With the extension function of SpringBoot, you can easily get various information. Typical ones

-Is the app running? (Health check) --JVM settings --Application settings

It is information such as. Details can be found at the link below.

https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html

How to Get Started It's easy, so I'll use Spring Initializr. The version of Spring Boot uses 2.3.0 M1 this time. Select Spring Web and Spring Boot Actuator for Dependencies. image.png

After completing the settings, press Genarate to download the source code template. When you're done, unzip it and open it in your preferred IDE.

If you look at pom.xml, you can see that the dependent libraries for SpringBoot Actuator are listed.

pom.xml


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

The information that can be learned with this function can be useful information for attackers who exploit vulnerabilities, so the function is turned off by default. Change the application settings to enable it.

application.properties


management.endpoints.enabled-by-default=true
management.endpoints.web.exposure.include=*

management.endpoints.enabled-by-default sets information acquisition availability by default, management.endpoints.web.exposure.include is a setting that enables REST endpoints. The former is set to true and can be obtained by default, and the latter is set to * in the sense that it is enabled for all endpoints.

After setting, build & start. You can follow the normal Spring Boot app.

Build with mvn package and start with java -jar target / demo-0.0.1-SNAPSHOT.jar.

Once started, try accessing http: // localhost: 8080 / actuator /. Then, you can get the endpoint list in JSON.

curl  http://localhost:8080/actuator | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1659    0  1659    0     0   162k      0 --:--:-- --:--:-- --:--:--  162k
{
  "_links": {
    "self": {
      "href": "http://localhost:8080/actuator",
      "templated": false
    },
    "beans": {
      "href": "http://localhost:8080/actuator/beans",
      "templated": false
    },
    "caches-cache": {
      "href": "http://localhost:8080/actuator/caches/{cache}",
      "templated": true
    },
    "caches": {
      "href": "http://localhost:8080/actuator/caches",
      "templated": false
    },
    "health-path": {
      "href": "http://localhost:8080/actuator/health/{*path}",
      "templated": true
    },
    "health": {
      "href": "http://localhost:8080/actuator/health",
      "templated": false
    },
    "info": {
      "href": "http://localhost:8080/actuator/info",
      "templated": false
    },
    "conditions": {
      "href": "http://localhost:8080/actuator/conditions",
      "templated": false
    },
    "shutdown": {
      "href": "http://localhost:8080/actuator/shutdown",
      "templated": false
    },
    "configprops": {
      "href": "http://localhost:8080/actuator/configprops",
      "templated": false
    },
    "env": {
      "href": "http://localhost:8080/actuator/env",
      "templated": false
    },
    "env-toMatch": {
      "href": "http://localhost:8080/actuator/env/{toMatch}",
      "templated": true
    },
    "loggers-name": {
      "href": "http://localhost:8080/actuator/loggers/{name}",
      "templated": true
    },
    "loggers": {
      "href": "http://localhost:8080/actuator/loggers",
      "templated": false
    },
    "heapdump": {
      "href": "http://localhost:8080/actuator/heapdump",
      "templated": false
    },
    "threaddump": {
      "href": "http://localhost:8080/actuator/threaddump",
      "templated": false
    },
    "metrics-requiredMetricName": {
      "href": "http://localhost:8080/actuator/metrics/{requiredMetricName}",
      "templated": true
    },
    "metrics": {
      "href": "http://localhost:8080/actuator/metrics",
      "templated": false
    },
    "scheduledtasks": {
      "href": "http://localhost:8080/actuator/scheduledtasks",
      "templated": false
    },
    "mappings": {
      "href": "http://localhost:8080/actuator/mappings",
      "templated": false
    }
  }
}

Since the amount is large, I will not explain everything, but for example, if it is health, it shows that the life and death state of the application can be acquired with this endpoint as a health check function.

curl  http://localhost:8080/actuator/health | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    15    0    15    0     0     35      0 --:--:-- --:--:-- --:--:--    35
{
  "status": "UP"
}

Another way to get environmental information is to publish it on an endpoint called env.

curl  http://localhost:8080/actuator/env | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 12493    0 12493    0     0   154k      0 --:--:-- --:--:-- --:--:--  154k
{
  "activeProfiles": [],
  "propertySources": [
    {
      "name": "server.ports",
      "properties": {
        "local.server.port": {
          "value": 8080
        }
      }
    },
    {
      "name": "servletContextInitParams",
      "properties": {}
    },
    {
      "name": "systemProperties",
      "properties": {
        "java.runtime.name": {
          "value": "OpenJDK Runtime Environment"
        },
        "java.protocol.handler.pkgs": {
          "value": "org.springframework.boot.loader"
        },
        "sun.boot.library.path": {
          "value": "/Users/user/.sdkman/candidates/java/8.0.212-amzn/jre/lib"
        },
        "java.vm.version": {
          "value": "25.212-b04"
        },
        "gopherProxySet": {
          "value": "false"
        },
        "java.vm.vendor": {
          "value": "Amazon.com Inc."
        },
        "java.vendor.url": {
          "value": "https://aws.amazon.com/corretto/"
        },
        "path.separator": {
          "value": ":"
        },
        "java.vm.name": {
          "value": "OpenJDK 64-Bit Server VM"
        },
        "file.encoding.pkg": {
          "value": "sun.io"
        },
        "user.country": {
          "value": "JP"
        },
        "sun.java.launcher": {
          "value": "SUN_STANDARD"
        },
        "sun.os.patch.level": {
          "value": "unknown"
        },
        "PID": {
          "value": "59317"
        },
        "java.vm.specification.name": {
          "value": "Java Virtual Machine Specification"
        },
        "user.dir": {
          "value": "/Users/user/oper/spring/spring-docker"
        },
        "java.runtime.version": {
          "value": "1.8.0_212-b04"
        },
        "java.awt.graphicsenv": {
          "value": "sun.awt.CGraphicsEnvironment"
        },
        "java.endorsed.dirs": {
          "value": "/Users/user/.sdkman/candidates/java/8.0.212-amzn/jre/lib/endorsed"
        },
        "os.arch": {
          "value": "x86_64"
        },
        "java.io.tmpdir": {
          "value": "/var/folders/1m/v_pnk3kd3hj0558d1z3nsnzh0000gn/T/"
        },
        "line.separator": {
          "value": "\n"
        },
        "java.vm.specification.vendor": {
          "value": "Oracle Corporation"
        },
        "os.name": {
          "value": "Mac OS X"
        },
        "sun.jnu.encoding": {
          "value": "UTF-8"
        },
Omitted below.

If you look here, what is the OS, what is the Java implementation, version, and character encoding? You can get information such as.

In addition, Beans that can get a list of registered beans and configprops that can get the set contents are convenient for checking the environment at the time of usual troubleshooting.

Advanced version

So far, we have only introduced Endpoint, which is provided by default, but you can customize it. If there is something you want to return specially in the application, you can create an endpoint and easily return it in JSON. I will omit the example here, so if you want to do it, please see the official guide.

https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-endpoints-custom

Summary

What did you think? This time, I couldn't find out how to get the operation statistics information on how much functions such as necessary are used in DevOps, but I hope you can think that it seems easy to get the environmental information. If you haven't installed the (?) Spring Boot app, Spring Boot Actuator, please try it.

Recommended Posts

Introducing the Spring Boot Actuator, a function that makes the operation of Spring Boot applications easier.
A story packed with the basics of Spring Boot (solved)
A memo that touched Spring Boot
Get a proxy instance of the component itself in Spring Boot
A story that made me regret when a "NotReadablePropertyException" occurred during the development of the Spring Boot application.
Think of RxJava as a library that makes asynchronous processing easier to write
Get the path defined in Controller class of Spring boot as a list
Resource handler settings when delivering SPA with the static resource function of Spring Boot
The story of raising Spring Boot 1.5 series to 2.1 series
Let's check the feel of Spring Boot + Swagger 2.0
Let's make a circuit breaker for back-end service using Actuator of Spring Boot (Part 1)
[Spring Boot] The story that the bean of the class with ConfigurationProperties annotation was not found
A memorandum of addiction to Spring Boot2 x Doma2
Access the built-in h2db of spring boot with jdbcTemplate
05. I tried to stub the source of Spring Boot
I tried to reduce the capacity of Spring Boot
A review note of the Spring Framework Resource interface
A record of studying the Spring Framework from scratch
I made a reply function for the Rails Tutorial extension (Part 4): A function that makes the user unique
The story of raising Spring Boot from 1.5 series to 2.1 series part2
Deploy Spring Boot applications to Heroku without using the Heroku CLI
Determine that the value is a multiple of 〇 in Ruby
Accelerate testing of Validators that require DI in Spring Boot
Check the operation of two roles with a chat application
Let's grasp the operation image (atmosphere) of the DI container of Spring
A note about the seed function of Ruby on Rails
A program that counts the number of words in a List
Introducing Spring Boot2, a Java framework for web development (for beginners)
Introduction of library ff4j that realizes FeatureToggle with Spring Boot
I made a GitHub Action that makes it easy to understand the execution result of RSpec