java 注解方式写入日志记录

文章介绍了在Java项目中使用接口注解`ApiLogRecord`来记录接口调用的日志,以及通过SpringAOP实现自动捕获并保存日志的方法,包括请求路径、数据关联ID等信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package com.nuzar.fcms.framwork.route.annotations;

import com.nuzar.fcms.framwork.route.enums.InvokeType;

import java.lang.annotation.*;

/**
 * description: 接口日志记录
 *
 * @author shizhiyuan
 * @date 2022-12-08 16:29:38
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiLogRecord {

    //请求路径
    String path() default "";

    //数据Id
    String dataId() default "";

    InvokeType invokeType() default InvokeType.INNER;

    String apiName() default "";

}
package com.nuzar.fcms.accept.aop;

import cn.hutool.json.JSONUtil;
import com.nuzar.fcms.common.core.business.utils.SpelExpressionUtils;
import com.nuzar.cloud.common.utils.DateUtils;
import com.nuzar.cloud.common.utils.StringUtils;
import com.nuzar.fcms.framwork.route.annotations.ApiLogRecord;
import com.nuzar.fcms.framwork.route.enums.InvokeStatus;
import com.nuzar.fcms.framwork.route.log.model.ApiLog;
import com.nuzar.fcms.framwork.route.log.service.ApiLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * description:
 *
 * @author shizhiyuan
 * @date 2022-12-08 16:37:37
 */
@Slf4j
public class ApiLogRecordAspect {

    private ApiLogService apiLogService;

    @Pointcut("@annotation(com.nuzar.fcms.framwork.route.annotations.ApiLogRecord)")
    public void logPointCut() {

    }

    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //执行方法
        Object result = null;
        ApiLog apiLog = null;
        try {
            result = point.proceed();
        } catch (Throwable e) {
            apiLog = new ApiLog();
            apiLog.setStatus(InvokeStatus.FAIL.code);
            try {
                apiLog.setErrorInfo(StringUtils.left(ExceptionUtils.getStackTrace(e), 1000));
            } catch (Exception ex) {
                log.error("build api_log error:", ex);
            }
            throw e;
        } finally {
            //保存日志
            try {
                saveApiLog(point, apiLog, result);
            } catch (Exception e) {
                log.error("save api_log error:", e);
            }
        }

        return result;
    }

    private void saveApiLog(ProceedingJoinPoint joinPoint, ApiLog apiLog, Object result) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (Objects.isNull(method)) {
            return;
        }

        ApiLogRecord apiLogRecord = method.getAnnotation(ApiLogRecord.class);
        if (Objects.isNull(apiLogRecord)) {
            return;
        }

        if (Objects.isNull(apiLog)) {
            apiLog = new ApiLog();
            apiLog.setStatus(InvokeStatus.SUCCESS.code);
        }

        apiLog.setDataId(SpelExpressionUtils.generateKeyBySpEL(apiLogRecord.dataId(), joinPoint));
        apiLog.setPath(apiLogRecord.path());
        apiLog.setType(apiLogRecord.invokeType().code);
        apiLog.setRequest(JSONUtil.toJsonStr(joinPoint.getArgs()));
        apiLog.setResponse(JSONUtil.toJsonStr(result));
        apiLog.setInvokeTime(DateUtils.getNow());
        apiLog.setApiName(apiLogRecord.apiName());
        apiLogService.save(apiLog);

    }

    @Autowired
    public void setApiLogService(ApiLogService apiLogService) {
        this.apiLogService = apiLogService;
    }
}
package com.nuzar.fcms.framwork.route.log.model;

import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.Date;

/**
 * api调用日志数据库实体
 *
 * @author tangang
 */
@Data
@TableName("API_LOG")
@Schema(name = "api日志", description = "api日志")
public class ApiLog {

    @Schema(description = "主键ID")
    @TableId(value = "id")
    private String id;

    @Schema(description = "调用类型(0-调出;1-调入)")
    @TableField("TYPE")
    private Integer type;

    @Schema(description = "调用类型")
    @TableField(exist = false)
    private String typeDesc;

    @Schema(description = "请求来源ip")
    @TableField("SOURCE_IP")
    private String sourceIp;

    @Schema(description = "请求目标ip")
    @TableField("TARGET_IP")
    private String targetIp;

    @Schema(description = "调用服务Id")
    @TableField("SERVICE_ID")
    private String serviceId;

    @Schema(description = "api名称")
    @TableField("API_NAME")
    private String apiName;

    @Schema(description = "请求路径")
    @TableField("PATH")
    private String path;

    @Schema(description = "调用状态(0-失败;1-成功)")
    @TableField("STATUS")
    private Integer status;

    @Schema(description = "调用状态")
    @TableField(exist = false)
    private String statusDesc;

    @Schema(description = "请求耗时(单位ms)")
    @TableField("DURATION")
    private Long duration;

    @Schema(description = "请求参数")
    @TableField("REQUEST")
    private String request;

    @Schema(description = "请求数据关联ID")
    @TableField("DATA_ID")
    private String dataId;

    @Schema(description = "响应结果")
    @TableField("RESPONSE")
    private String response;

    @Schema(description = "错误信息")
    @TableField("ERROR_INFO")
    private String errorInfo;

    @Schema(description = "调用时间")
    @TableField("INVOKE_TIME")
    private Date invokeTime;

    @Schema(description = "创建时间")
    @TableField(
            value = "CREATE_TIME",
            fill = FieldFill.INSERT,
            updateStrategy = FieldStrategy.NEVER
    )
    private Date createTime;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值