SpringBoot切面发送日志JSON给Kafka给Logstash给Elasticsearch

3 篇文章 0 订阅
3 篇文章 0 订阅

Kafka、Elasticsearch、Logstash、Kibana环境搭建见这里
Logstash如何消费Kafka中的JSON输出给Elasticsearch见这里

Maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

application.properties

spring.kafka.bootstrap-servers=192.168.184.134:9092
spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer
spring.kafka.template.default-topic=kafka-test  #默认topic名称可以与logstash的input的名称一致

LogBean.java (日志记录对象)

public class LogBean {
    // 这些字段与Elasticsearch模板创建的字段一致
    private String ip; //请求ip
    private int code; //响应码
    private String url; //请求url
    private String args; //请求参数
    private String msg; //响应信息
    private Date startTime; //响应开始时间
    private long runTime; //响应耗时(毫秒)
    
    // Getter ... Setter ...
}

ApiResult.java (Controller返回对象)

public class ApiResult {
    private static final int SUCCESS = 200;
    private static final int FAIL = 504;
    private final int code;
    private final String msg;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private final Object data;

    public ApiResult(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public static ApiResult success(){
        return new ApiResult(SUCCESS,"操作成功",null);
    }
    public static ApiResult fail(){
        return new ApiResult(FAIL,"操作失败",null);
    }
    public static ApiResult success(Object o){
        return new ApiResult(SUCCESS,"操作成功",o);
    }
    public static ApiResult fail(String msg){
        return new ApiResult(FAIL,msg,null);
    }
    // Getter ...
}

KafkaProducer.java (发送消息给Kafka)

@Component
public class KafkaProducer {
    private KafkaTemplate<String, String> kafkaTemplate;
    @Autowired
    public void setKafkaTemplate(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }
    
    @Async  //异步发送消息
    public void send(String msg) {
        kafkaTemplate.sendDefault(msg);  // 发送给默认topic
    }
}

LogAspect.java (日志功能切面)

@Aspect
@Component
public class LogAspect {
    private Gson gson;
    private KafkaProducer kafkaProducer;
    
    @Autowired
    public void setProducer(KafkaProducer kafkaProducer) {
        this.kafkaProducer = kafkaProducer;
    }
    
    public LogAspect() {
        elasticsearch();  // 初始化适合Elasticsearch的Gson转换模板
    }
    
    /**
     * Elasticsearch的时间格式需要存入"yyyy-MM-dd'T'HH:mm:ss+08:00",否则使用Kibana查询得到的时间会快8小时
     */
    public void elasticsearch() {
        int offset = TimeZone.getDefault().getRawOffset();
        int a = offset / 3600000; //计算所在时区的HH
        int b = (int) (((float) offset / 3600000 - a) * 60); //计算所在时区的mm
        DecimalFormat df = new DecimalFormat("00");
        gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss+" + df.format(a) + ":" + df.format(b))
                .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
                .create();
    }
    
    @Pointcut("execution(public * com.example.kafkademo.controller.*.*(..))")
    public void log() {

    }

    @Around("log()")
    public Object around(ProceedingJoinPoint pjp) {
        Instant startTime = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        LogBean logBean = new LogBean();
        logBean.setStartTime(Date.from(startTime));
        logBean.setUrl(request.getRequestURL().toString());
        logBean.setIp(request.getRemoteAddr());
        Object[] args = pjp.getArgs();
        logBean.setArgs(gson.toJson(args[0]));
        try {
            ApiResult apiResult = (ApiResult) pjp.proceed();
            logBean.setCode(apiResult.getCode());
            logBean.setMsg(apiResult.getMsg());
            logBean.setRunTime(Duration.between(startTime,LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant()).toMillis());
            kafkaProducer.send(gson.toJson(logBean));
            return apiResult;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return ApiResult.fail("日志切面出错!");
        }
    }

}

TestForm.java (请求参数对象)

public class TestForm {

    private String fileName;
    private String filePath;

    // getter ... setter ...
}

TestApi.java

@RestController
@RequestMapping("/test")
public class TestApi {

    @RequestMapping("/test")
    public ApiResult test(@RequestBody TestForm testForm){

        return ApiResult.success(testForm);
    }

}

KafkademoApplication.java (启动类)

@SpringBootApplication
@EnableAsync
public class KafkademoApplication {

    public static void main(String[] args) {
        SpringApplication.run(KafkademoApplication.class, args);
    }

}

运行结果

请求参数↓↓↓↓
在这里插入图片描述
控制台打印发送给Kafka的JSON↓↓↓↓

{"ip":"172.16.10.10","code":200,"url":"http://172.16.10.10:8080/test/test","args":"{\"file_name\":\"testFile\",\"file_path\":\"/usr/bin\"}","msg":"操作成功","start_time":"2021-01-23T20:01:37+08:00","run_time":0}

Kibana查询结果↓↓↓↓
在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值