spring maven项目 实时接口请求次数及时间发送到grafana监控_亲测成功
说明: spring项目使用aop方式拿到请求接口uri,算出从请求到响应的耗时, 然后使用statsd包发送udp数据给grafana去展示.
完全不影响代码性能和稳定性,因为使用udp协议发送,就算grafana那边挂了,也不影响项目正常运行
UDP简单介绍
UDP提供不可靠服务
UDP是一个非连接的协议,传输数据之前源端和终端不建立连接, 当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。 在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、 计算机的能力和传输带宽的限制; 在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
maven项目pom.xml引入依赖包
<dependency>
<groupId>com.timgroup</groupId>
<artifactId>java-statsd-client</artifactId>
<version>3.1.0</version>
</dependency>
配置监控udp地址
statsd:
prefix: dev
host: 192.168.1.53
port: 8125
初始化配置
package com.beyond.app.config;
import com.timgroup.statsd.NonBlockingStatsDClient;
import com.timgroup.statsd.StatsDClient;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class StatsdConfig {
private static final Logger logger = LogManager.getLogger(StatsdConfig.class);
@Value("${spring.statsd.prefix}")
private String prefix;
@Value("${spring.statsd.host}")
private String host;
@Value("${spring.statsd.port}")
private int port;
@Bean(name = "statsDClient")
public StatsDClient statsDClient() {
logger.info("StatsdConfig Configuring Statsd {}-{}:{}", prefix, host, port);
return new NonBlockingStatsDClient(prefix, host, port);
}
}
定义service
package com.beyond.app.service;
import com.timgroup.statsd.StatsDClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* Created by liang.
*/
@Service
public class StatsdService {
@Autowired
private StatsDClient statsDClient;
@Async
public void statsd (String uri, long time) {
statsDClient.time("manage." + uri, time);
//dev.manage.uri:10|ms
//dev开发环境, manage功能, uri接口, 10ms接口耗时
}
}
spring aop环绕通知发送接口数据
package com.beyond.app.aop;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.beyond.app.service.StatsdService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
/**
* Created by liang.
*/
@Component
@Aspect
public class LogAspect {
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
@Autowired
private StatsdService statsdService;
/**
* 定义一个切入点.
* 解释下:
*
* ~ 第一个 * 代表任意修饰符及任意返回值.
* ~ 第二个 * 定义在web包或者子包
* ~ 第三个 * 任意方法
* ~ .. 匹配任意数量的参数.
*/
@Pointcut("execution(* com.beyond.app.api..*.*(..))")
public void logPointCut(){
}
@Around("logPointCut()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
long start = System.currentTimeMillis();
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
long end = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
end = System.currentTimeMillis();
logger.info("+++++around " + joinPoint + "\tUse time : " + (end - start) + " ms!");
return result;
} catch (Throwable e) {
end = System.currentTimeMillis();
logger.error("+++++around " + joinPoint + "\tUse time : " + (end - start) + " ms with exception : " + e.getMessage());
throw e;
} finally {
statsdService.statsd(request.getRequestURI(), end - start);
}
}
}