SpringBoot:定制-Actuator

metrics:
enabled: true

正如以上片段所示,`endpoints.enabled`设置为false就能禁用Actuator的全部端点,然后将`endpoints.metrics.enabled`设置为true重新启用`/metrics`端点。

# 三、添加自定义度量信息
你可能还想定义自己的度量,用来捕获应用程序中的特定信息。

比方说,我们想要知道用户往阅读列表里保存了多少次图书,最简单的方法就是在每次调用`ReadingListController`的`addToReadingList()`方法时增加计数器值。计数器很容易实现,但这个不断变化的总计值如何同`/metrics`端点发布的度量信息一起发布出来呢?

再假设我们想要获得最后保存图书的时间戳。时间戳可以通过调用`System.currentTime-Millis()`来获取,但如何在`/metrics`端点里报告该时间戳呢?

实际上,自动配置允许Actuator创建`CounterService`的实例,并将其注册为Spring的应用程序上下文中的Bean。`CounterService`这个接口里定义了三个方法,分别用来增加、减少或重置 特定名称的度量值,代码如下:
```java
package org.springframework.boot.actuate.metrics; 
public interface CounterService { 
 void increment(String metricName); 
 void decrement(String metricName); 
 void reset(String metricName); 
}

Actuator的自动配置还会配置一个GaugeService类型的Bean。该接口与CounterService类似,能将某个值记录到特定名称的度量值里。GaugeService看起来是这样的:

package org.springframework.boot.actuate.metrics; 
public interface GaugeService { 
 void submit(String metricName, double value); 
}

你无需实现这些接口。Spring Boot已经提供了两者的实现。我们所要做的就是把它们的实例注入所需的Bean,在适当的时候调用其中的方法,更新想要的度量值。

针对上文提到的需求,我们需要把CounterServiceGaugeService Bean注入Reading-ListController,然后在addToReadingList()方法里调用其中的方法。

使用注入的CounterServiceGaugeService

@Controller 
@RequestMapping("/") 
@ConfigurationProperties("amazon") 
public class ReadingListController { 
 ... 
 private CounterService counterService; 
 @Autowired 
 public ReadingListController( 
 ReadingListRepository readingListRepository, 
 AmazonProperties amazonProperties, 
 CounterService counterService, 
 GaugeService gaugeService) { 
 this.readingListRepository = readingListRepository; 
 this.amazonProperties = amazonProperties; 
 this.counterService = counterService; 
 this.gaugeService = gaugeService; 
 } 
 ... 
 @RequestMapping(method=RequestMethod.POST) 
 public String addToReadingList(Reader reader, Book book) { 
 book.setReader(reader); 
 readingListRepository.save(book); 
 counterService.increment("books.saved");
 gaugeService.submit( 
 "books.last.saved", System.currentTimeMillis()); 
 return "redirect:/"; 
 } 
}

修改后的ReadingListController使用了自动织入机制,通过控制器的构造方法注入CounterServiceGaugeService,随后把它们保存在实例变量里。此后,addToReading-List()方法每次处理请求时都会调用counterService.increment ("books.saved")gaugeService.submit("books. last.saved")来调整度量值。

尽管CounterServiceGaugeService用起来很简单,但还是有一些度量值很难通过增加计数器或记录指标值来捕获。对于那些情况,我们可以实现PublicMetrics接口,提供自己需要的度量信息。该接口定义了一个metrics()方法,返回一个Metric对象的集合:

package org.springframework.boot.actuate.endpoint; 
public interface PublicMetrics { 
 Collection<Metric<?>> metrics(); 
}

为了解PublicMetrics的使用方法,这里假设我们想报告一些源自Spring应用程序上下文的度量值——应用程序上下文启动的时间、Bean及Bean定义的数量,这些都包含进来会很有意思。 顺便再报告一下添加了 @Controller注解的 Bean 的数量。

发布自定义度量信息

package readinglist; 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.actuate.endpoint.PublicMetrics; 
import org.springframework.boot.actuate.metrics.Metric; 
import org.springframework.context.ApplicationContext; 
import org.springframework.stereotype.Component; 
import org.springframework.stereotype.Controller; 
@Component 
public class ApplicationContextMetrics implements PublicMetrics { 
 private ApplicationContext context;
 @Autowired 
 public ApplicationContextMetrics(ApplicationContext context) { 
 this.context = context; 
 } 
 @Override 
 public Collection<Metric<?>> metrics() { 
 List<Metric<?>> metrics = new ArrayList<Metric<?>>(); 
 metrics.add(new Metric<Long>("spring.context.startup-date",
 context.getStartupDate())); 
 metrics.add(new Metric<Integer>("spring.beans.definitions",
 context.getBeanDefinitionCount())); 
 metrics.add(new Metric<Integer>("spring.beans", 
 context.getBeanNamesForType(Object.class).length));
 metrics.add(new Metric<Integer>("spring.controllers", 
 context.getBeanNamesForAnnotation(Controller.class).length));
 return metrics; 
 } 
}

Actuator会调用metrics()方法,收集ApplicationContextMetrics提供的度量信息。该方法调用了所注入的ApplicationContext上的方法,获取我们想要报告为度量的数量。每个度量值都会创建一个Metrics实例,指定度量的名称和值,将其加入要返回的列表。

创建ApplicationContextMetrics,并在ReadingListController里使用Counter-ServiceGaugeService之后,我们可以在/metrics端点的响应中找到如下条目:

{ 
 ... 
 spring.context.startup-date: 1429398980443, 
 spring.beans.definitions: 261, 
 spring.beans: 272, 
 spring.controllers: 2, 
 books.count: 1, 
 gauge.books.save.time: 1429399793260, 
 ... 
}

当然,这些度量的实际值会根据添加了多少书、何时启动应用程序及何时保存最后一本书而发生变化。在这个例子里,你一定会好奇为什么spring.controllers是2。因为这里算上了ReadingListController以及Spring Boot提供的BasicErrorController

四、创建自定义跟踪仓库

默认情况下,/trace端点报告的跟踪信息都存储在内存仓库里,100个条目封顶。一旦仓库满了,就开始移除老的条目,给新的条目腾出空间。在开发阶段这没什么问题,但在生产环境中,大流量会造成跟踪信息还没来得及看就被丢弃。

为了避免这个问题,你可以声明自己的InMemoryTraceRepository Bean,将它的容量调整至100以上。如下配置类可以将容量调整至1000个条目:

package readinglist; 
import org.springframework.boot.actuate.trace.InMemoryTraceRepository; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
@Configuration 
public class ActuatorConfig { 
 @Bean 
 public InMemoryTraceRepository traceRepository() { 
 InMemoryTraceRepository traceRepo = new InMemoryTraceRepository(); 
 traceRepo.setCapacity(1000); 
 return traceRepo; 
 } 
}

仓库容量翻了10倍,跟踪信息的保存时间应该会更久。不过,繁忙到一定程度,应用程序还是可能在你查看这些信息前将其丢弃。这是一个内存存储的仓库,还要避免容量增长太多,影响应用程序的内存使用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值