客户端利用spring切面获取注解内容
发送至消息服务器(rabbitmq)
服务端监听消息服务器,并存储至数据库
日志存储流程如下:
1、业务端依赖引用log-client
2、业务端编写或修改切面内容,以获取日志注解内容(@ApiLogger(value = "操作内容"))
3、将日志内容格式化,并发送至消息中间件
4、日志服务端独立部署,实时监听消息中间件,消费消息后存入数据库。
5、由于整个架构是基于微服务,所以需要将日志服务端也接入注册中心,接受健康监测
部分代码如下:
服务端主要分为两个部分
rabbitmq(获取日志)
mysql(入库)
/**
* rabbit配置
* @author GaoYuan
* @date 2018/4/9 下午3:55
*/
@Configuration
public class RabbitServerConfig
{
/**
队列名称
*/
public
final static String queueName = "sc-log";
@Bean
Queue
queue()
{
return
new Queue(queueName,
false);
}
/**
指定消息按什么规则,路由到哪个Queue,Message消息先要到达Exchange,在Server中承担着从Produce接收Message的责任 */
@Bean
TopicExchange
exchange()
{
return
new TopicExchange("sc-log-exchange");
}
/**
绑定queue与exchange */
@Bean
Binding
binding(Queue
queue, TopicExchange exchange) {
return
BindingBuilder.bind(queue).to(exchange).with(queueName);
}
@Bean
SimpleMessageListenerContainer
container(ConnectionFactory
connectionFactory,
MessageListenerAdapter listenerAdapter) {
SimpleMessageListenerContainer
container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(queueName);
container.setMessageListener(listenerAdapter);
return container;
}
@Bean
MessageListenerAdapter
listenerAdapter(Receive
receiver) {
return
new MessageListenerAdapter(receiver,
"receiveMessage");
}
@Component
public class Receive {
private CountDownLatch latch = new CountDownLatch(1);
@Autowired
ApiLogServerService apiLogService;
/** 这里的方法在RabbitServerConfig里被调用 (见 listenerAdapter 方法) */
public void receiveMessage(String message) {
System.out.println( message );
ApiLog apiLog= JSON.parseObject(message,ApiLog.class);
apiLogService.saveLogger(apiLog);
latch.countDown();
}
}
[Mysql]
入库部分不详细讲解,底部提供源码链接
日志客户端主要提供
自定义注解(通过此注解获取日志内容)
RabbitMQ配置
日志提交API
package com.foruo.sc.log.client.annotation;
import java.lang.annotation.*;
/**
* 操作记录注解
* @author GaoYuan
* @date 2018/4/11 上午11:03
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLogger {
/** 操作说明 */
String value() default "";
/** 参数 */
String params() default "";
}
/**
* 日志服务层
* 保存日志或者存储至消息中间件
* @author GaoYuan
* @date 2018/4/9 下午3:48 */
* 日志服务层
* 保存日志或者存储至消息中间件
* @author GaoYuan
* @date 2018/4/9 下午3:48
*/
@Service
public class ApiLogClientService {
@Autowired
private AmqpTemplate rabbitTemplate;
public void log(ApiLog sysLog){
rabbitTemplate.convertAndSend(RabbitClientConfig.queueName, JSON.toJSONString(sysLog));
}
}
<!--日志客户端(已包含amqp) @author gaoyuan-->
<dependency>
<groupId>com.foruo.module</groupId>
<artifactId>sc-log-client</artifactId>
<version>1.0</version>
</dependency>
ApiLoggerAspect.java
/**
* api日志切面
* @author GaoYuan
* @date 2018/4/9 下午3:44
*/
@Aspect
@Component
public class ApiLoggerAspect {
@Autowired
private ApiLogClientService loggerService;
/** 定义切点 */
@Pointcut("@annotation(com.foruo.sc.log.client.annotation.ApiLogger)")
public void loggerPointCut() {
}
/** before - 顾名思义 */
@Before("loggerPointCut()")
public void saveSysLog(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
ApiLog sysLog = new ApiLog();
ApiLogger sysLogger = method.getAnnotation(ApiLogger.class);
if(sysLogger != null){
//注解上的描述
sysLog.setOperation(sysLogger.value());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLog.setMethod(className + "." + methodName + "()");
//请求的参数
Object[] args = joinPoint.getArgs();
String params="";
for(Object o:args){
params += JSON.toJSONString(o);
}
if(!StringUtils.isEmpty(params)) {
sysLog.setParams(params);
}
//设置IP地址
sysLog.setIp(HttpUtils.getIpAddress());
/** 在这里编写获取用户名 */
String username = UserUtils.getCurrentPrinciple();
if(!StringUtils.isEmpty(username)) {
sysLog.setUsername(username);
}
sysLog.setCreateDate(new Date());
//保存系统日志
loggerService.log(sysLog);
}
}
DemoController.java
/**
* 案例控制层
* @author GaoYuan
* @date 2018/4/9 下午3:43
*/
@RestController
@RequestMapping("/demo")
public class DemoController {
@ApiLogger("执行某某操作")
@PostMapping
@GetMapping
public void demo(){
System.out.println("执行某某操作");
}
}
先运行服务端,再运行业务模块端,访问/demo,发现日志成功入库。
期间发现使用 swagger 时也是要求写一些操作内容,其实也可以通过自定义切面获取 swagger 注解中填写的操作内容,这样就不需要单独写一个@ApiLogger了
码云地址 : https://gitee.com/gmarshal/foruo-sc-log
创建人 | 高元_G·Marshal |
文档编辑权限 | 创建者私有 |
文档阅读权限 | 来自分类 |
分类阅读权限 | 所有人 |
分类编辑权限 | 所有人 |
分类审核权限 | 无 |
修改日期 | 修改人 | 备注 |
2018-04-13 09:35:48[当前版本] | 高元_G·Marshal | CREAT |