The business scenario

In a recent development project, there was a need for users to view operation logs. Since our backend is a multi-springBoot microservice interface, we planned to develop a logging Starter based on AOP+ custom annotations to record user operation logs.

* I will introduce each business through code comments, which are easier to understandCopy the code

Building a Starter project

  • rest-log-spring-boot-start
  • Custom annotation RestLog
Inherited @Retention(retentionPolicy.runtime) @target ({elementType.method}) public @interface RestLog {/** * module name */  String module(); /** * action */ String action(); /** * describe */ String describe() default ""; }Copy the code
In our business scenario, we need to record the module that users operate and what operations they do. The description information is an extended field, and more information can be added according to actual requirements.Copy the code
  • Defining the log object
@Data / / Lombok annotation
public class LogBean {
    private Long id;
    / / userId
    private String userId;
    / / module
    private String module;
    / / operation
    private String action;
    // Description
    private String describe;
    // Interface address
    private String api;
    // GET POST DELETE PUT...
    private String method;
    // Interface parameter information
    private String paramJson;
    // Operation time
    private Date restTime;
}
Copy the code
  • Define the plane
@Aspect @Component public class RestLogAspect { private static final Logger LOG = LoggerFactory.getLogger(RestOperationLogAspect.class); @Autowired private KafkaTemplate<String, String> kafkaTemplate; / / @value ("${rest-log.topic:}") private String topic; /** * @value ("${rest-log.topic:}") private String topic; /** * Aspect */ @pointCut ("@annotation(com.demo.restLog)") private void restLogCut() {// Operation log aspect} /** * Post execution log store operation ** @param joinPoint */ @After("restLogCut()") public void after(JoinPoint joinPoint) { try { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); OperationLog annotation = method.getanNotation (restlog.class); / / get request object it RequestAttributes RequestAttributes = RequestContextHolder. GetRequestAttributes (); HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); String userId = request.getheader (" auth-userid "); String userId = request.getheader (" auth-userid "); If (userId == null) {if(userId == null) {if(userId == null) {return; } / / get the parameter name String [] names = signature. GetParameterNames (); Object[] args = joinPoint.getargs (); JSONObject paramJson = new JSONObject(); JSONObject paramJson = new JSONObject(); for(int i = 0; i <names.lenth; i++) { paramJson.put(names[i], args[i]); } // Create a log object to transmit log information LogBean LogBean = new LogBean(); logBean.setUserId(userId); logBean.setModule(annotation.module()); logBean.setAction(annotation.action()); logBean.setDescribe(annotation.describe()); logBean.setApi(request.getRequestURI()); logBean.setMethod(request.getMethod()); logBean.setParamJson(); logBean.setRestTime(new Date()); If (stringutils.isNotBlank (topic)) {// Send the log to kafka kafkatemplate.send (topic, JSONObject.toJSONString(logBean)); } } catch (Exception e) { LOG.error(e.getMessage(), e); }}}Copy the code

Summary: 1. In the business aspect, the request header is judged (whether it is a request between microservices or a client request, so as to avoid the REST request between microservices being recorded in the log); 2. 2. Encapsulate request parameters, module information and so on into an entity and send it to Kafka to reduce the impact of log business on interface performance; 3, the use of Kafka send can be more flexible application in the micro-service system, log management service listening topic, micro-service integrated with Stater after the configuration of this topic, the final micro-service operation log system can be quickly integrated, unified management.

Application of the starter

The SpringBoot service introduces the starter dependency

<dependency>
   <groupId>com.demo</groupId>
   <artifactId>rest-log-spring-boot-start</artifactId>
   <version>0.0.1 - the SNAPSHOT</version>
</dependency>
Copy the code

Add configuration to application.yaml

rest-log:
  topic: rest_log
Copy the code

Add annotations to the interface

@RestController
@RequestMapping("/demo")
public class DemoController {
    @PostMapping
    @restlog (module = "test module", action = "new", describe = "this is a description ")
    public void add(@RequestBody Demo demo) {
        // Omit the implementation}}Copy the code

Add a kafka listener (only add a listener to a service that provides log storage and query)

@Service
public class LogListener {
    @KafkaListener(topics = "iot-original-history-message", containerFactory = "batchConsumerFactory")
    public void listener(List<ConsumerRecord<String, String>> records) {
        // Traversal records to achieve storage services can be omitted}}Copy the code

Kafka batch consumption configuration can refer to the previous article has been introduced