1. Introduction
1.介绍
When we work with microservices or web services in general, it’s quite useful to know how our users interact with our services. This can be achieved by tracing all the requests that hit our services and collect this information to analyze it later.
当我们使用微服务或一般的Web服务时,了解我们的用户如何与我们的服务互动是相当有用的。这可以通过追踪所有撞击我们服务的请求来实现,并收集这些信息以便日后进行分析。
There some systems available out there that can help us with this and can be easily integrated with Spring like Zipkin. However, Spring Boot Actuator has this functionality built-in and can be used through its httpTrace endpoint which traces all HTTP requests. In this tutorial, we’ll show how to use it and how to customize it to fit better our requirements.
有一些可用的系统可以帮助我们实现这一点,并且可以轻松地与Spring集成,例如Zipkin。然而,Spring Boot Actuator内置了这种功能,可以通过其httpTrace端点来使用,该端点可以跟踪所有HTTP请求。在本教程中,我们将展示如何使用它以及如何定制它以更好地满足我们的要求。
2. HttpTrace Endpoint Setup
2.HttpTrace端点设置
For the sake of this tutorial, we’ll use a Maven Spring Boot project.
在本教程中,我们将使用一个Maven Spring Boot项目。
The first thing we need to do is to add the Spring Boot Actuator dependency to our project:
我们需要做的第一件事是将Spring Boot Actuator依赖项添加到我们的项目中。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
After that, we’ll have to enable the httpTrace endpoint in our application.
之后,我们必须在我们的应用程序中启用httpTrace端点。
To do so, we just need to modify our application.properties file to include the httpTrace endpoint:
要做到这一点,我们只需要修改我们的application.properties文件以包括httpTrace端点。
management.endpoints.web.exposure.include=httptrace
In case we need more endpoints, we can just concatenate them separated by commas or we can include all of them by using the wildcard *.
如果我们需要更多的端点,我们可以用逗号把它们连接起来,或者使用通配符*把所有的端点都包括进去。
Now, our httpTrace endpoint should appear in the actuator endpoints list of our application:
现在,我们的httpTrace端点应该出现在我们应用程序的执行器端点列表中。
{
"_links": {
"self": {
"href": "http://localhost:8080/actuator",
"templated": false
},
"httptrace": {
"href": "http://localhost:8080/actuator/httptrace",
"templated": false
}
}
}
Notice that we can list all the enabled actuator endpoints by going to the /actuator endpoint of our web service.
注意,我们可以通过进入我们的网络服务的/actuator端点来列出所有启用的执行器端点。
3. Analyzing the Traces
3.分析踪迹
Let’s analyze now the traces that the httpTrace actuator endpoint returns.
现在让我们分析一下httpTrace执行器端点返回的痕迹。
Let’s make some requests to our service, call the /actuator/httptrace endpoint and take one of the traces returned:
让我们向我们的服务发出一些请求,调用/actuator/httptrace 端点,并获取其中一个返回的跟踪信息。
{
"traces": [
{
"timestamp": "2019-08-05T19:28:36.353Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/echo?msg=test",
"headers": {
"accept-language": [
"en-GB,en-US;q=0.9,en;q=0.8"
],
"upgrade-insecure-requests": [
"1"
],
"host": [
"localhost:8080"
],
"connection": [
"keep-alive"
],
"accept-encoding": [
"gzip, deflate, br"
],
"accept": [
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
],
"user-agent": [
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 OPR/62.0.3331.66"
]
},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"12"
],
"Date": [
"Mon, 05 Aug 2019 19:28:36 GMT"
],
"Content-Type": [
"text/html;charset=UTF-8"
]
}
},
"timeTaken": 82
}
]
}
As we can see, the response is divided into several nodes:
正如我们所看到的,反应被分为几个节点。
- timestamp: the time when the request was received
- principal: the authenticated user who did the request, if applicable
- session: any session associated with the request
- request: information about the request such as the method, full URI or headers
- response: information about the response such as the status or the headers
- timeTaken: the time taken to handle the request
We can adapt this response to our needs if we feel it’s too verbose. We can tell Spring what fields we want to be returned by specifying them in the management.trace.http.include property of our application.properties:
如果我们觉得这个响应过于冗长,我们可以根据自己的需要进行调整。我们可以通过application.properties中的management.trace.http.include属性来告诉Spring我们想要返回哪些字段。
management.trace.http.include=RESPONSE_HEADERS
In this case, we specified that we only want the response headers. Hence, we can see that fields that were included before like the request headers or the time taken are not present in the response now:
在这种情况下,我们指定我们只想要响应头信息。因此,我们可以看到,以前包括的字段,如请求头或所花的时间,现在没有出现在响应中。
{
"traces": [
{
"timestamp": "2019-08-05T20:23:01.397Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/echo?msg=test",
"headers": {},
"remoteAddress": null
},
"response": {
"status": 200,
"headers": {
"Content-Length": [
"12"
],
"Date": [
"Mon, 05 Aug 2019 20:23:01 GMT"
],
"Content-Type": [
"text/html;charset=UTF-8"
]
}
},
"timeTaken": null
}
]
}
All the possible values that can be included can be found in the source code, as well as the default ones.
可以在源代码中找到所有可能包含的值,以及默认值。
4. Customizing the HttpTraceRepository
4.自定义HttpTraceRepository
By default, the httpTrace endpoint only returns the last 100 requests and it stores them in memory. The good news is that we can also customize this by creating our own HttpTraceRepository.
默认情况下,httpTrace端点只返回最后的100个请求,并且它将这些请求存储在内存中。好消息是,我们也可以通过创建我们自己的HttpTraceRepository来定制这个。
Let’s now create our repository. The HttpTraceRepository interface is very simple and we only need to implement two methods: findAll() to retrieve all the traces; and add() to add a trace to the repository.
现在让我们来创建我们的资源库。HttpTraceRepository接口非常简单,我们只需要实现两个方法。findAll() 检索所有的跟踪;和add() 将一个跟踪添加到资源库中。
For simplicity, our repository will also store the traces in memory and we’ll store only the last GET request that hits our service:
为了简单起见,我们的存储库也将在内存中存储痕迹,我们将只存储最后一次击中我们服务的GET请求。
@Repository
public class CustomTraceRepository implements HttpTraceRepository {
AtomicReference<HttpTrace> lastTrace = new AtomicReference<>();
@Override
public List<HttpTrace> findAll() {
return Collections.singletonList(lastTrace.get());
}
@Override
public void add(HttpTrace trace) {
if ("GET".equals(trace.getRequest().getMethod())) {
lastTrace.set(trace);
}
}
}
Even though this simple example may not look very useful, we can see how powerful this can get and how we could store our logs anywhere.
尽管这个简单的例子可能看起来不是很有用,但我们可以看到这可以变得多么强大,我们可以在任何地方存储我们的日志。
5. Filtering the Paths to Trace
5.筛选要追踪的路径
The last thing we’re going to cover is how to filter the paths that we want to trace, so we can ignore some requests that we’re not interested in.
我们要讲的最后一件事是如何过滤我们要追踪的路径,所以我们可以忽略一些我们不感兴趣的请求。
If we play with the httpTrace endpoint a little after making some requests to our service, we can see that we also get traces for the actuator requests:
如果我们在向我们的服务发出一些请求后,稍微玩一下httpTrace端点,我们可以看到,我们也得到了执行器请求的跟踪信息。
{
"traces": [
{
"timestamp": "2019-07-28T13:56:36.998Z",
"principal": null,
"session": null,
"request": {
"method": "GET",
"uri": "http://localhost:8080/actuator/",
// ...
}
We may not find these traces useful for us and we’d prefer to exclude them. In that case, we just need to create our own HttpTraceFilter and specify what paths we want to ignore in the shouldNotFilter method:
我们可能觉得这些痕迹对我们没有用处,我们更愿意排除它们。在这种情况下,我们只需要创建我们自己的HttpTraceFilter并在shouldNotFilter方法中指定我们想要忽略的路径:。
@Component
public class TraceRequestFilter extends HttpTraceFilter {
public TraceRequestFilter(HttpTraceRepository repository, HttpExchangeTracer tracer) {
super(repository, tracer);
}
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return request.getServletPath().contains("actuator");
}
}
Notice that the HttpTraceFilter is just a regular Spring filter but with some tracing-specific functionality.
请注意,HttpTraceFilter只是一个普通的Spring过滤器,但具有一些特定的跟踪功能。
6. Conclusion
6.结论
In this tutorial, we’ve introduced the httpTrace Spring Boot Actuator endpoint and shown its main features. We’ve also dug a bit deeper and explained how to change some default behaviors to fit better our specific needs.
在本教程中,我们介绍了httpTrace Spring Boot Actuator端点,并展示了其主要功能。我们还深入探讨了如何改变一些默认行为以更好地满足我们的特定需求。
As always, the full source code for the examples is available over on GitHub.
一如既往,这些示例的完整源代码可在GitHub上获取。