This article is for the blogger to study notes, the content comes from the Internet, if there is infringement, please contact delete.

Personal Note: github.com/dbses/TechN…

01 | use physical components to realize the monitoring system

Spring Boot Actuator component is introduced

Introducing dependencies:

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

Service starts, visit http://localhost:8080/actuator you can see the following results:

{
  "_links": {"self": {"href":"http://localhost:8080/actuator"."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
    },
    
    // Above is the default exposure information, plus the following is all the information
    
    "beans": {"href":"http://localhost:8080/actuator/beans"."templated":false
    },
    "conditions": {"href":"http://localhost:8080/actuator/conditions"."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": {"href":"http://localhost:8080/actuator/loggers"."templated":false
    },
    "loggers-name": {"href":"http://localhost:8080/actuator/loggers/{name}"."templated":true
    },
    "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}}}Copy the code

If we want to see all endpoints, we can configure it in the configuration file:

management:
  endpoints:
    web:
      exposure:
        include: "*"
Copy the code

Common endpoints are combed as follows:

By accessing each of the endpoints in the table above, we can get the monitoring information we are interested in.

The health endpoint

Visit http://localhost:8082/actuator/health endpoints, you can get the basic state of service:

{
  "status":"UP".// More details below
  "components": {"diskSpace": {"status":"UP"."details": {"total":201649549312."free":3434250240."threshold":10485760}},"ping": {"status":"UP"}}}Copy the code

To obtain more detailed status information, you can configure the following parameters in the configuration file:

management: 
  endpoint:
    health:
      show-details: always
Copy the code

Expanding Actuator endpoints

Spring Boot by default exposes two of the most common endpoints in everyday development: Info and Health. Next, let’s discuss how to extend these two endpoints.

  • Extend Info endpoint

The Info endpoint is used to expose information about the Spring Boot application itself. The common InfoContributor in Spring Boot is as follows:

InfoContributor name describe
EnvironmentInfoContributor Expose all keys whose key is INFO in the Environment
GitInfoContributor Expose git information if a git.properties file exists
BuildInfoContributor Expose the build information if the meta-INF /build-info.properties file is present

All key under EnvironmentInfoContributor will collect the info, for example in application. In the yml:

Info: app: encoding: UTF-8 Java: source: 1.8.0_31 Target: 1.8.0_31Copy the code

We can also extend the info endpoint information:

@Component
public class CustomBuildInfoContributor implements InfoContributor {

    @Override
    public void contribute(Builder builder) {
        builder.withDetail("build", Collections.singletonMap("timestamp".newDate())); }}Copy the code

The final effect is as follows:

{
  "app": {"encoding":"UTF-8"."java": {"source":"1.8.0 comes with _31"."target":"1.8.0 comes with _31"}},"build": {"timestamp":1604307503710}}Copy the code
  • Extending the Health endpoint

The Health endpoint is used to check the Health status of the running application, which is retrieved from Spring’s ApplicationContext by the HealthIndicator object.

Common healthindicators are shown in the following table:

HealthIndicator name describe
DiskSpaceHealthIndicator Check whether the disk space is sufficient
DataSourceHealthIndicator Check whether the connection DataSource is available
ElasticsearchHealthIndicator Check whether the Elasticsearch cluster is started
JmsHealthIndicator Check whether the JMS agent is started
MailHealthIndicator Check whether the mail server is started
MongoHealthIndicator Check whether the Mongo database is started
RabbitHealthIndicator Check whether the RabbitMQ server is started
RedisHealthIndicator Check whether the Redis server is started
SolrHealthIndicator Check whether the Solr server has been started

To clarify the state of a service, we can define a custom endpoint to display the state of the service:

@Component
public class CustomerServiceHealthIndicator implements HealthIndicator {

    @Override
    public Health health(a) {
        try {
            URL url = new URL("http://localhost:8083/health/");
            HttpURLConnection conn = (HttpURLConnection) 
            url.openConnection();
            int statusCode = conn.getResponseCode();
            if (statusCode >= 200 && statusCode < 300) {
                return Health.up().build();
            } else {
                return Health.down().withDetail("HTTP Status Code", statusCode).build(); }}catch (IOException e) {
            returnHealth.down(e).build(); }}}Copy the code

The effect is as follows:

{
  "status": "UP"."details": {
    "customerservice": {
      "status": "UP"
    }
    …
  }
}
Copy the code
{
  "status": "DOWN"."details": {
    "customerservice": {
      "status": "DOWN"."details": {
        "HTTP Status Code": "404"}},... }}Copy the code
{
  "status": "DOWN"."details": {
    "customerservice": {
      "status": "DOWN"."details": {
        "error": "java.net.ConnectException: Connection refused: connect"}},... }}Copy the code

02 | custom metrics and physical endpoint

In Spring Boot, it provides us with a Metrics endpoint to implement production-level measurement tools. After visiting the Actuator /metrics endpoint, we get a series of metrics as shown below.

{
  "names": ["jvm.memory.max"."jvm.threads.states"."jdbc.connections.active"."jvm.gc.memory.promoted"."jvm.memory.used"."jvm.gc.max.data.size"."jdbc.connections.max"."jdbc.connections.min"."jvm.memory.committed"."system.cpu.count"."logback.events"."http.server.requests"."jvm.buffer.memory.used"."tomcat.sessions.created"."jvm.threads.daemon"."system.cpu.usage"."jvm.gc.memory.allocated"."hikaricp.connections.idle"."hikaricp.connections.pending"."jdbc.connections.idle"."tomcat.sessions.expired"."hikaricp.connections"."jvm.threads.live"."jvm.threads.peak"."hikaricp.connections.active"."hikaricp.connections.creation"."process.uptime"."tomcat.sessions.rejected"."process.cpu.usage"."jvm.classes.loaded"."hikaricp.connections.max"."hikaricp.connections.min"."jvm.gc.pause"."jvm.classes.unloaded"."tomcat.sessions.active.current"."tomcat.sessions.alive.max"."jvm.gc.live.data.size"."hikaricp.connections.usage"."hikaricp.connections.timeout"."jvm.buffer.count"."jvm.buffer.total.capacity"."tomcat.sessions.active.max"."hikaricp.connections.acquire"."process.start.time"]}Copy the code

We’d like to know the current memory usage, for example, you can through the physical/metrics/JVM memory. Informs the endpoints, as shown in the following code.

{
  "name":"jvm.memory.used"."description":"The amount of used memory"."baseUnit":"bytes"."measurements":[
    {
      "statistic":"VALUE"."value":115520544}]."availableTags":[
    {
      "tag":"area"."values": ["heap"."nonheap"] {},"tag":"id"."values": ["Compressed Class Space"."PS Survivor Space"."PS Old Gen"."Metaspace"."PS Eden Space"."Code Cache"]]}}Copy the code

Extend Metrics endpoints

The Metrics system includes Counter and Gauge Metrics. By injecting Counter or Gauge into our business code, we can record the metrics we want. Where Counter is used to expose the increment() method and Gauge is used to provide a value() method.

Let’s use Counter as an example to show how to embed custom Metrics in business code, as shown below:

@Component
public class CounterService {

    public CounterService(a) {
        Metrics.addRegistry(new SimpleMeterRegistry());
    }
 
    public void counter(String name, String... tags) { Counter counter = Metrics.counter(name, tags); counter.increment(); }}Copy the code

You can also use MeterRegistry for counting. For example, we want the system to count customer service work orders as they are created:

@Service
public class CustomerTicketService {
    
    @Autowired
    private MeterRegistry meterRegistry;

    public CustomerTicket generateCustomerTicket(Long accountId, String orderNumber) {

        CustomerTicket customerTicket = newCustomerTicket(); ... meterRegistry.summary("customertickets.generated.count").record(1);

        returncustomerTicket; }}Copy the code

Now access to physical/metrics/customertickets. Generated. Count endpoint, you will see the following information:

{
  "name":"customertickets.generated.count"."measurements":[
    {
      "statistic":"Count"."value":1
    },
    {
      "statistic":"Total"."value":19}}]Copy the code

You can use the same AbstractRepositoryEventListener achieve the effect of the above:

@Component
public class CustomerTicketMetrics extends AbstractRepositoryEventListener<CustomerTicket> {

    private MeterRegistry meterRegistry;

    public CustomerTicketMetrics(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
    }

    @Override
    protected void onAfterCreate(CustomerTicket customerTicket) {
        meterRegistry.counter("customerticket.created.count").increment(); }}Copy the code

Customize the Actuator endpoints

Suppose we need to provide a monitoring endpoint to get user information and machine name for the current system, we can do this through a separate MySystemEndPoint, as shown in the following code:

@Configuration
@Endpoint(id = "mysystem", enableByDefault=true)
public class MySystemEndpoint { 
 
    @ReadOperation
    public Map<String, Object> getMySystemInfo(a) {
        Map<String,Object> result= new HashMap<>();
        Map<String, String> map = System.getenv();
        result.put("username",map.get("USERNAME"));
        result.put("computername",map.get("COMPUTERNAME"));
        returnresult; }}Copy the code

The @readOperation annotation is used to identify read data operations. In the Actuator, @writeOperation and @deleteOperation annotations are also provided.

Now, by visiting http://localhost:8080/actuator/mysystem, we can get as shown in the following monitoring information.

{
  "computername":"LAPTOP-EQB59J5P"."username":"user"
}
Copy the code

Sometimes in order to obtain a specific metric information, parameters need to be passed to an endpoint, and the Actuator provides a special @selector annotation to identify the input parameters. Example code is as follows:

@Configuration
@Endpoint(id = "account", enableByDefault = true)
public class AccountEndpoint {
    
    @Autowired
    private AccountRepository accountRepository;    
 
    @ReadOperation
    public Map<String, Object> getMySystemInfo(@Selector String arg0) {
        Map<String, Object> result = new HashMap<>();
        result.put(accountName, accountRepository.findAccountByAccountName(arg0));
        returnresult; }}Copy the code

Then, using the port address http://localhost:8080/actuator/ account/account1 can trigger measurement operation.

03 | using the Admin Server management Spring applications

Spring Boot Admin is an application for monitoring Spring Boot. Its basic principle is to provide a concise visual WEB UI by counting and integrating various HTTP endpoints provided in Spring Boot Actuator.

There are two roles in the overall architecture of Spring Boot Admin: the Server component Admin Server and the Client component Admin Client. The Admin Client is actually a normal Spring Boot application, while the Admin Server is a standalone service that needs to be built specifically. As shown below:

There are two ways to build an Admin Server: one is simply based on a standalone Admin service; Another service registration and discovery mechanism that relies on a service registry.

Build Admin Server based on standalone services

Create a Spring Boot application and introduce dependencies:

<dependency>
  <groupId>de.codecentric</groupId>
  <artifactId>spring-boot-admin-server</artifactId>
</dependency>

<dependency>
  <groupId>de.codecentric</groupId>
  <artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
Copy the code

Add the @enableadMinServer annotation to the Bootstrap class:

@SpringBootApplication
@EnableAdminServer
public class AdminApplication {

    public static void main(String[] args) { SpringApplication.run(AdminApplication.class, args); }}Copy the code

Next we associate the application with the Admin Server.

Introducing dependencies:

<dependency>
  <groupId>de.codecentric</groupId>
  <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
Copy the code

We then add the Admin Server configuration information to the configuration file.

spring:
  boot:
    admin:
      client:
        url: http://localhost:9000
Copy the code

After starting the application and Admin Server, you can see the following:

Build the Admin Server based on the registry

Based on the registry, the interaction between the Admin Server and each Admin Client is shown as follows:

The purpose of introducing a registry is to decouple the Admin Client from the Admin Server.

Both Admin Client and Admin Server need to use the Eureka Client components shown below.

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Copy the code

Then configure the following in the Admin Server configuration file:

eureka:
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
Copy the code

Controlling access security

Some monitoring features should not be exposed to all developers. Therefore, we need to control the access security of the Admin Server.

Introducing dependencies:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
Copy the code

We then add the following configuration items to the configuration file:

spring:
  security:
    user:
      name: "springcss_admin"
      password: "springcss_password"
Copy the code

After restarting the Admin Server, we need to enter the user name and password when accessing the Web interface again, as shown in the following picture: