接口服务中的日志

先来看下日志对于一个接口服务的作用:

  • 监控服务的状态,一般程序中会增加一些跟踪或者提示性的日志,用来判断服务执行的详细情况,特别是执行一些复合功能的接口或者叫聚合接口非常有利于我们判断接口的执行情况
  • 安全,用来分析调用者的身份信息,防止接口被非法恶意调用等
  • 性能,可以统计每个接口的访问执行时间来分析系统的瓶颈
  • 异常分析,对于线上的异常,在没有debug的环境下,要想分析问题原因最有价值的就要算异常的堆栈信息

上面的这几点需求,如果接口服务使用的是一些高级产品比如dubbo,其实它已经实现了大部分功能,不需要人为的去全部处理功能。

  • 安全,可利用访问日志的功能来实现,访问日志中详细的记录了客户端调用的时间,身份,调用时的详细参数。
[DUBBO] [2016-08-27 14:47:06] 10.10.50.20:64948 -> 10.10.50.20:20960
 - ProductFacadeService getDataDictionaryByType(DataDictionaryParamInfo)
 [{"code":0,"type":1}], dubbo version: 2.8.1, current host: 10.10.50.20

上面的日志我们可以看到如下有用的信息:

1:调用方IP以及端口信息:10.10.50.20:64948

2:服务端的IP以及端口信息:10.10.50.20:20960

3:调用时间:2016-08-27 14:47:06

4:调用的接口方法:ProductFacadeService getDataDictionaryByType(DataDictionaryParamInfo)
5:调用的接口方法参数:[{"code":0,"type":1}]

  • 异常分析,会自动将产生的未捕获异常信息记录到日志中,不需要手工的去处理异常的记录。上面访问日志中的参数记录信息也对分析线上问题提供了非常有力的帮助。


其实dubbo自己提供的日志功能已经非常强了,大多数情况下已经够用,但如果想有一些更加强的功能就需要自己想想办法了:

  • 监控服务的状态,这类跟踪信息只能依靠程序逻辑来实现,没有其它捷径
  • 性能,dubbo的访问日志只记录了接口调用的开始时间,没有结束时间,要想统计某个方法或者某个请求的整体执行时间是无能为力的

如果你的服务接口不是dubbo,比如是基于spring mvc 实现的rest api接口,那么就没有上面dubbo帮你做的那些好用的日志功能了。但是spring mvc实现上面的日志需求方法也是很多的,典型的例子可以借助HandlerInterceptor这类拦截器,只需要实现这个接口,然后在实现类中增加日志功能即可:我们可以通过handler这个参数来获取你想要的所有数据,另外还有request以及response两个信息丰富的对象供你使用。

public interface HandlerInterceptor {

    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception;

    void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;

    void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;

}

还有一种是自己实现一个AOP功能去解决我们的需求问题。AOP不是这篇的重点,我贴一张图用来简单展示AOP的作用(上面提到的HandlerInterceptor 也属于AOP的具体应用)。

将某些非业务的功能通过拦截的形式注入到流程中,而非紧密耦合在业务逻辑中,比如下面的记录方法参数的代码就是紧耦合,不推荐:

public ValueResult<ApplyIsvRoleInfo> queryUserApplyIsvInfo(String appKey, String accessToken) {
        log.info("receive queryUserApplyIsvInfo! and the params appKey: [" + appKey + "], accessToken:[" + accessToken + "]");
     ...... do something
}

AOP我这里使用aspectj,当然也可以使用spring自带的。

  • 创建一个用于日志的注解,用来控制记录的具体功能。比如有些方法是不推荐记录返回记录的,像列表查询,也有利于精确的配置日志生效的范围

 @Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLog {

    /**
     * 是否启动日志功能
     * @return
     */
    boolean enable() default true;

    /**
     * 是否记录返回值
     * 列表数据不推荐记录
     * @return
     */
    boolean isLogResult() default false;

    /**
     * 是否记录方法的参数名称以及值
     * @return
     */
    boolean isLogParameter() default true;

    /**
     * 是否记录执行时间
     * @return
     */
    boolean isLogElapsed() default true;
}

  • 创建一个服务端的日志拦截器,由于我们需要记录方法的执行时间,那么最适合的就是写一个around的方法,在方法执行前后记录时间从而计算出时间差。对于参数,我们也很容易实现,根据反射我们可以轻松得到调用方法的所有参数名称以及参数的具体值,下面是实现这个拦截器用的工具类介绍:

a:计算时间,这里采用google提供的Stopwatch,这个东西对于从.NET转JAVA的来讲太亲切了

       Stopwatch sw=Stopwatch.createStarted();
        Object result = joinPoint.proceed();
        sw.stop();
        long elapsed=sw.elapsed(TimeUnit.NANOSECONDS);

b:记录参数内容,对于object对象,我们将其序列化成json,可以利用jackson完成,其它的复杂点的就是通过反射来完成参数以及值。记录日志根据注解的配置来判断应该记录哪些日志项。

@Aspect
public class ServicesLoggerInterceptor {

    @Pointcut("execution(* com.chanjet.csp.product.service.service.impl.*ServiceImpl*.*(..))")
    public void pointCut() {
    }

    @Around(value = "pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Stopwatch sw=Stopwatch.createStarted();
        Object result = joinPoint.proceed();
        sw.stop();

        long elapsed=sw.elapsed(TimeUnit.NANOSECONDS);

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method targetMethod = methodSignature.getMethod();

        MethodLog methodLog= targetMethod.getAnnotation(MethodLog.class);
        if(null!=methodLog&&methodLog.enable()){
            StringBuilder logLine = new StringBuilder(joinPoint.getSignature().getName());
            if(methodLog.isLogParameter()) {
                Object[] paramValues = joinPoint.getArgs();
                CodeSignature codeSignature= ((CodeSignature) joinPoint.getSignature());
                String[] paramNames = codeSignature.getParameterNames();
                logLine.append("(");
                if (paramNames.length != 0) {
                    AspectLogUtils.logParamValues(logLine, paramNames, paramValues);
                }
                logLine.append(") - started");
            }
            if(methodLog.isLogResult()) {
                logLine.append("  Return Value : ");
                logLine.append(AspectLogUtils.toString(result));
            }
            if(methodLog.isLogElapsed()) {
                logLine.append("  elapsed nanoseconds:" + elapsed);
            }
            AspectLogUtils.getLogger().info(logLine.toString());

        }

        return result;
    }
}

c:创建一个日志的工具类,用来实现具体的日志记录。

public final  class AspectLogUtils {

    private static Logger logger = LoggerFactory.getLogger(AspectLogUtils.class);

    private AspectLogUtils() {

    }

    public static Logger getLogger() {
        return logger;
    }

    public static void logParamValues(StringBuilder logLine, String[] paramNames, Object[] paramValues) {
        for (int i = 0; i < paramValues.length; i++) {
            logLine.append(paramNames[i]).append("=").append(toString(paramValues[i]));
            if (i < paramValues.length - 1) {
                logLine.append(", ");
            }
        }
    }

    public static String toString(Object object) {
        return JsonUtils.toJsonString(object);
    }
}

  • 在Spring中加载这个拦截器
<bean class="ServicesLoggerInterceptor"></bean>
    <aop:aspectj-autoproxy proxy-target-class="true"/>

INFO  getDataDictionaryByType(dataDictionaryParamInfo={"type":1,"code":0}) - started  elapsed nanoseconds:11491670

http://www.cnblogs.com/ASPNET2008/p/5813518.html

时间: 2024-10-16 14:06:52

接口服务中的日志的相关文章

REST服务中的日志可视化(关键技术实现)

引言 在系统构建完成之后,我们通常会使用REST API对外提供服务,在REST API的处理过程中经常会出现一些异想不到的问题(用户权限不足.参数不全.数据库访问异常等),导致请求失败,很多时候用户并不能理解这些失败是如何造成的,他们更多的是直接找到相应的开发者询问:“我的这个接口失败了,没有拿到数据,帮忙看一下吧”,更为复杂的是当我们询问其他用户的时候,他们却说:“你这个接口是正常的啊”,开发者这时就很郁闷:“我又没对你做特殊处理,怎么别人是好的,偏偏就你的失败”(本人在工作初期,经常遇到此

使用日志服务进行Kubernetes日志采集

阿里云容器服务Kubernetes集群集成了日志服务(SLS),您可在创建集群时启用日志服务,快速采集Kubernetes 集群的容器日志,包括容器的标准输出以及容器内的文本文件. 新建 Kubernetes 集群 如果您尚未创建任何的 Kubernetes 集群,可以按照本节的步骤来进行操作: 登录 容器服务管理控制台. 单击左侧导航栏中集群,单击右上角创建Kubernetes集群. 进入创建页面后,参见创建Kubernetes集群进行配置. 拖动到页面底部,勾选日志服务配置项,表示在新建的

网站数据统计分析中的日志收集原理及其实现

> 网站数据统计分析工具是网站站长和运营人员经常使用的一种工具,比较常用的有谷歌分析.百度统计 和 腾讯分析等等.所有这些统计分析工具的第一步都是网站访问数据的收集.目前主流的数据收集方式基本都是基于javascript的.本文将简要分析这种数据收集的原理,并一步一步实际搭建一个实际的数据收集系统. 1.数据收集原理分析 简单来说,网站统计分析工具需要收集到用户浏览目标网站的行为(如打开某网页.点击某按钮.将商品加入购物车等)及行为附加数据(如某下单行为产生的订单金额等).早期的网站统计往往只收

谈谈微服务中的 API 网关(API Gateway)

转载至:http://www.cnblogs.com/savorboard/p/api-gateway.html 背景 我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest Api 风格的接口来被 H5, Android, IOS 以及第三方应用程序调用. 但是在UI上进行展示的时候,我们通常需要在一个界面上展示很多数据,这些数据可能来自于不同的微服务中,举

玩转ASP.NET Core中的日志组件

玩转ASP.NET Core中的日志组件简介日志组件,作为程序员使用频率最高的组件,给程序员开发调试程序提供了必要的信息.ASP.NET Core中内置了一个通用日志接口ILogger,并实现了多种内置的日志提供器,例如 ConsoleDebugEventSourceEventLogTraceSourceAzure App Service除了内置的日志提供器,ASP.NET Core还支持了多种第三方日志工具,例如 elmah.ioGelfJSNLogKissLog.netLoggrNLogSe

Springboot中的日志管理

本案例中可以了解,怎么配置日志的输出路径,输出格式(比如说zip格式),按日期进行划分(今天的日志输出为一个文件,明天的日志输出到另一个文件),在按日期划分的同时又按文件大小划分(比如说每天的日志记录很多,希望一个日志文件为5GB...),上面的功能,看完这篇都能实现.(参考链接超有用,建议直接下拉打开链接) Slf4j 日志管理的抽象接口 Log4j,log4j2,logback,日志管理框架,日志管理实现 Springboot中pom.xml,若引入了web的起步依赖,不需要再引入日志管理相

为服务中网关的作用

什么是网关 随着互联网的快速发展,当前以步入移动互联.物联网时代.用户访问系统入口也变得多种方式,由原来单一的PC客户端,变化到PC客户端.各种浏览器.手机移动端及智能终端等.同时系统之间大部分都不是单独运行,经常会涉及与其他系统对接.共享数据的需求.所以系统需要升级框架满足日新月异需求变化,支持业务发展,并将框架升级为微服务架构.“API网关”核心组件是架构用于满足此些需求. 很多互联网平台已基于网关的设计思路,构建自身平台的API网关,国内主要有京东.携程.唯品会等,国外主要有Netflix

微服务中使用MQ——RabbitMQ

概念 什么是消息 消息是指在两个独立的系统间传递的数据.这两个系统可以是两台计算机,也可以是两个进程. 消息是平台无关和语言无关的! 什么是队列 队列是一种数据结构,内部是用数组或链表实现的, 队列的特点是只能队尾放入,队头取出,即先入先出[FIFO] 队列的操作有入队和出队 也就是你有一个程序在产生内容然后入队(生产者) 另一个程序读取内容,内容出队(消费者) 什么是消息队列 简单的理解就是:在消息的传输过程中使用队列作为保存消息的容器. 队列是在消息的传输过程中的通道,是保存消息的容器, 根

ROS中的日志(log)消息

学会使用日志(log)系统,做ROS大型项目的主治医生 通过显示进程的运行状态是好的习惯,但需要确定这样做不会影响到软件的运行效率和输出的清晰度.ROS 日志 (log) 系统的功能就是让进程生成一些日志消息,显示在屏幕上.发送到特定 topic 或者储存在特定 log 文档中,以方便调试.记录.报警等.下面简单介绍如何生成和查看日志消息. 日志消息 在ROS中,有一个特殊的话题叫作/rosout,它承载着所有节点的所有日志消息./rosout消息的类型是rosgraph_msgs/Log: r