日志采集系统

日志采集系统开发记录

接到开发任务,需要一个开发一个日志记录系统,主要分析哪个人再什么时间做了什么操作,业务是否执行成功,请求参数和返回参数是什么,用的什么方法,方便后台直接定位到问题。
要求写一个log-starter ,进行日志的采集工作,在写一个log-center日志进行添加和查询的功能。
一、自定义一个注解@LogAnnotation

@Target({ElementType.METHOD}) //注解做用在哪里 
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAnnotation {
//需要注解获取的内容
    String serverName() default "";
    String module() default "";
    String description() default "";
    boolean recordParam() default true;
}

二、配置log-starter:

@EnableAsync
@Configuration
@ComponentScan(basePackages = {"com.gw.log.autoconfigure","com.gw.log.feign"})
@ConditionalOnClass(value = {LogAspect.class,RemoteLogService.class})
@ConditionalOnWebApplication
@ConditionalOnProperty(name = "enable",prefix = "com.log",havingValue = "true",matchIfMissing = true)
//EnableFeignClients指向定义FeignClient类
@EnableFeignClients(clients = com.gw.log.feign.RemoteLogService.class)
public class LogAutoConfiguration {
    @Bean
    public LogAspect logAspect() {
        LogAspect logAspect = new LogAspect();
        return new LogAspect();
    }
}

三、写一个切面(提前准备日志实体类Syslog)

@Aspect
@Component
public class LogAspect {

    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
    @Value("${spring.application.name}")
    private String serverName;

    @Resource
    RemoteLogService remoteLogService;

    @Around(value = "@annotation(com.gw.log.constants.LogAnnotation)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取当前毫秒
        long beginTime = System.currentTimeMillis();
        SysLog sysLog = new SysLog();
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String authorization = request.getHeader("authorization");
        if(authorization!=null){
            TokenEntity tokenInfo = AuthUtil.getTokenInfo();
            if (tokenInfo != null) {
                sysLog.setUserName(tokenInfo.getUserName());
                sysLog.setUserCode(tokenInfo.getUserCode());
                sysLog.setPlatformCode(tokenInfo.getPlatformId().toString());
            }
        }

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class);
        //方法名称
        String name = methodSignature.getName();
        sysLog.setOperationModule(logAnnotation.module());
        //描述信息
        sysLog.setRemark(logAnnotation.description());
        //方法路径
        String method_path = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
        sysLog.setRequestAddress(method_path);
        //请求方式
        String   requestMethod =    request.getMethod();
        sysLog.setRequestMethod(requestMethod);
        //系统名称
        sysLog.setSystemName(StringUtils.isNotBlank(sysLog.getSystemName()) ? sysLog.getSystemName() : serverName);
        if (logAnnotation.recordParam() || true) {
            // 获取参数名称
            String[] paramNames = methodSignature.getParameterNames();
            // 获取参数值
            Object[] params = joinPoint.getArgs();
            // 把参数名称和参数值组装成json格式
            JSONObject paramsJson = new JSONObject(paramNames.length);
            for (int i = 0; i < paramNames.length; i++) {
                paramsJson.put(paramNames[i], params[i]);
            }
            try {
                // 以json的形式记录参数
                sysLog.setRequestParameters(JSONObject.toJSONString(paramsJson));
            } catch (Exception e) {
                log.error("记录参数失败:{}", e.getMessage());
            }
        }
        try {
            // 执行时长(毫秒)
            Long time = System.currentTimeMillis() - beginTime;
            // 执行原方法
            Object obj = joinPoint.proceed();
            //返回值
            String s = JSON.toJSONString(obj);
            sysLog.setReturnParameter(s);
            sysLog.setStatus(Boolean.TRUE);
            // 执行时长(毫秒)
            sysLog.setOperationTime(time.toString());
            //获取用户ip地址
            sysLog.setIpAddress(getIpAddr(((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()));
            getMethod(joinPoint, sysLog);
            return obj;
        } catch (Exception e) {
            // 方法执行失败
            sysLog.setStatus(Boolean.FALSE);
            // 备注记录失败原因
            sysLog.setRemark(e.getMessage());
            throw e;
        } finally {
            // 异步将Log对象发送到队
                try {
                    String token = request.getHeader("authorization")!=null?request.getHeader("authorization").split(" ")[1]:null;
                    remoteLogService.saveLog(sysLog,token);
                    log.info("通过feign发送到log-center服务:{}", log);
                } catch (Exception e2) {
                    e2.getMessage();
                }

        }


    }
    private void getMethod(ProceedingJoinPoint joinPoint, SysLog sysLog) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        sysLog.setOperationMethod(className + "." + methodName + "()");
        log.info("---------------- " + log);
    }

    /**
     * 获取target字符第x次出现的位置
     * @param string
     * @param target
     * @param x
     * @return
     */
    public static int getCharacterPosition(String string, String target, int x) {
        // 这里是获取target符号的位置
        Matcher matcher = Pattern.compile(target).matcher(string);
        int mIdx = 0;
        while (matcher.find()) {
            mIdx++;
            // 当target符号第x次出现的位置
            if (mIdx == x) {
                break;
            }
        }
        int start = matcher.start();
        return start;
    }

    /**
     * 获取当前网络ip
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request){
        String ipAddress = request.getHeader("x-forwarded-for");
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                //根据网卡取本机配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    log.error(e.getMessage());
                }
                if (null != inet){
                    ipAddress= inet.getHostAddress();
                }
            }
        }
        //对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割
        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
            if(ipAddress.indexOf(",")>0){
                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }
}

这是一个环绕通知,value为切点,切点为@LogAnnotation注解所在的位置
@Around(value = “@annotation(com.gw.log.constants.LogAnnotation)”)

四、配置@FeignClient

@FeignClient(value = "log" , url = "http://127.0.0.1:8888" , fallback = RemoteLogServiceFallback.class)
public interface RemoteLogService {
    /**
     * 保存日志
     * @param sysLog log
     * @return boolean
     */
    @PostMapping("/syslog/createLog")
    String saveLog(@RequestBody SysLog sysLog, @RequestHeader("Authorization") String Authorization);

}

@FeignClient(value = “log” , url = “http://127.0.0.1:8888” , fallback = RemoteLogServiceFallback.class)
value随便写 ,url为需要连接的主机地址,fallback相当于熔断器,当调用主机方法出错时调用RemoteLogServiceFallback里面的方法。
RemoteLogServiceFallback实现RemoteLogService 的方法,并加上@Commont注解

@Component
public class RemoteLogServiceFallback implements RemoteLogService {
    private static final Logger LOG = LoggerFactory.getLogger(RemoteLogServiceFallback.class);
    private Throwable cause;
    public Throwable getCause() {
        return cause;
    }
    public void setCause(Throwable cause) {
        this.cause = cause;
    }
    @Override
    public String saveLog(SysLog sysLog, String Authorization) {
        LOG.error("feign 插入日志失败", cause);
        return null;
    }

}

log-stater完成
下面配置log-center

新建一个项目
导入log-starter sdk
在controller里面编写RemoteLogService 里面的方法。启动。

五、如何调用

在需要采集的项目中导入 log-starter sdk , 导入spring-cloud-starter-openfeign依赖 。启动类中加入@EnableFeignClients注解。
在需要采集日志的接口上加上注解@LogAnnotation(description = “logClient测试”,module = “测试模块”)
启动,测试。

完成!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值