精华内容
下载资源
问答
  • JAVA 日志埋点

    千次阅读 2017-02-15 10:46:56
     JAVA 日志埋点使用总结: 环境:jdk1.7、tomcat7、win10、maven 3.2.5   一、 删除应用中所有的log jar包 二、 导入unslog jar包   <dependency> <groupId>com.uns.inf&...

     

     JAVA 日志埋点使用总结:

    环境:jdk1.7、tomcat7、win10、maven 3.2.5

     

    一、  删除应用中所有的log jar包

    二、  导入unslog jar包

      

    <dependency>
         <groupId>com.uns.inf</groupId>
         <artifactId>unslog</artifactId>
         <version>1.0.0</version>
    </dependency>

     

    三、  在resource目录下追加unslog.properties(可选)

    内容如下:

    #项目名称(工程化项目自动获取,无需修改)
    app_name=${projectName}
    #日志级别
    #log_level=info
    #日志存放天数
    #maxHistory=30
    #业务埋点是否输出( true输出 false关闭 默认是关闭)
    #bizlog=true
    #控制台日志关闭 (true 打印 false关闭 默认是关闭)
    #console=false

     

    日志文件存放路径(在unslog.jar包中写死的路径):

    windos在d://logs/应用名称/日期/日志文件

    linux在 在/opt/ci/logs/应用名称/日期/日志文件

     

    四、  日志打印实例

    // 一般日志打印

        logger.info("test start");

     

    // 日志规则ID(可统一编排)
         longbzId = 10000;
         // 创建日志对象
         UnsLogInfo uli = new UnsLogInfo(bzId);
         // 设置日志信息
         uli.put("userid", 12434);
         uli.put("userName", "name001");
         uli.put("startDt", new Date());
         // 打印业务日志
         logger.info(uli.toString());

     // 一般日志打印

     

         logger.info("test end");

    五、  说明

    日志规则ID:是业务埋点的唯一标示,不同的业务埋点不同,可以根据需要统一编制。

    后台进行业务统计分析时重要的标示(日志规则ID对应后台的报警规则ID一个或多个,监控平台并进行统计分析)

     

    注:如果日志采用slf4j的都可以灰度替换,其他的需要自己修改下LoggerFactory的获取方式(也是很简单的)

     

     

    六、实践

    1.导入unslog.jar包,在pom.xml文件中加入如下代码:

     

    <dependency>
         <groupId>com.uns.inf</groupId>
         <artifactId>unslog</artifactId>
         <version>1.0.0</version>
    </dependency>

    2. 使用slf4j的Logger,因为它可以在log4j和logback之间随意切换,根据你使用的logjar包,代码如下:

     

     

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    public final Logger log = LoggerFactory.getLogger(getClass());

     3.编写一个日志埋点的公用方法,代码如下:

     

     

    /**
    	 * 日志埋点
    	 * @param curtran
    	 * @param flag 1:成功,0:失败;bzId 日志规则ID
    	 * @return
    	 */
    	public static String monitoring(Long bzId, Curtran curtran,String flag) {
    	    // 创建日志对象
    	    UnsLogInfo uli = new UnsLogInfo(bzId);
    	    // 设置日志信息
    	    if (Constant.TRUE.equals(flag)) {
    	    	uli.setSuccess(1);
    		} else {
    			uli.setFailure(1);
    		}
    	    if (curtran != null) {
    	    	uli.put("merchantId", curtran.getMerchantid());
    	    	uli.put("terminalid", curtran.getTerminalid());
    	    	uli.put("orderId", curtran.getTrannumber());
    	    	uli.put("cardNo", curtran.getCard());
    	    	uli.put("amount", curtran.getAmount());
    		}
    	    return uli.toString();
    	}

     4.项目中应用,代码如下:

     

     

    // 日志埋点
    log.info("Monitoring unspay start");
    // 打印业务日志
    log.info(Common.monitoring(20005L, curtran, Constant.TRUE));
    log.info("Monitoring unspay end");

     

     

     5.如果是WEB项目,想将控制台的日志输出在catalina.out文件中,则需要新建一个配置文件unslog.properties

    在文件中添加如下内容:

    #项目名称(工程化项目自动获取,无需修改)  
    app_name=${projectName}
    #日志级别  
    #log_level=info  
    #日志存放天数  
    #maxHistory=30  
    #业务埋点是否输出( true输出 false关闭 默认是关闭)  
    bizlog=true
    #控制台日志关闭 (true 打印 false关闭 默认是关闭)  
    console=true

    6.如果部署到Linux服务器,需要确认服务器上,是否有预先建立目录/opt/ci/logs 目录

     

    7.注意要点:本次日志埋点使用的是logback,作为日志输出

     

    8.JAR包下载(见附件) 

     

     

     

     

     

     

     

     

    展开全文
  • 实战:第四章:java后端日志埋点实现

    千次阅读 多人点赞 2019-10-31 14:17:30
    前段时间架构让我弄日志埋点,因为其他工作不断延期,而且到现在也没给明确的需求,这里自己手写一套简单的日志埋点: 第一步:引入依赖 <!--aop--> <dependency> <groupId>org.spring...

    前段时间架构让我弄日志埋点,因为其他工作不断延期,而且到现在也没给明确的需求,这里自己手写一套简单的日志埋点:

    第一步:引入依赖

    <!--aop-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
    <!--log4j-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.3</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.25</version>
    </dependency>

    第二步:因为公司有自己的日志配置,这里我简单配置一条凑合用就行,在application.properties配置:

    #日志文件路径 默认生成文件名:spring.log 为了简单便于学习这里我使用默认的
    logging.path=F:/Log4j

    第三步:自定义注解:

    package com.javaliao.portal.annotations;
    
    import org.springframework.web.bind.annotation.ResponseBody;
    import java.lang.annotation.*;
    
    /**
     *  app controller 统一包装注解类
     */
    @Target({ElementType.PARAMETER, ElementType.METHOD})//作用在参数和方法上
    @Retention(RetentionPolicy.RUNTIME)//运行时注解
    @Documented//表明这个注解应该被 javadoc工具记录
    @ResponseBody//响应时转JSON格式
    public @interface AppController {
    
    	/**
    	 * 业务描述
    	 * @return
    	 */
    	String description() default "";
    	
    	/**
    	 * 是否打日志 默认打
    	 */
    	boolean isLog() default true;
    }
    

    第四步:拦截用户请求

    package com.javaliao.portal.aspect;
    
    import com.alibaba.fastjson.JSON;
    import com.javaliao.portal.annotations.AppController;
    import com.javaliao.portal.common.CommonResult;
    import com.javaliao.portal.model.TbLogVisit;
    import com.javaliao.portal.service.ActionService;
    import com.javaliao.portal.util.CollectionHelp;
    import com.javaliao.portal.util.TimeUtils;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.lang.reflect.Method;
    import java.net.InetAddress;
    import java.util.*;
    import java.util.concurrent.atomic.AtomicLong;
    
    @Component
    @Aspect
    @SuppressWarnings("all") //@SuppressWarnings("all")抑制所有警告.@SuppressWarnings注解主要用在取消一些编译器产生的警告对代码左侧行列的遮挡,有时候这会挡住我们断点调试时打的断点
    public class AppControllerAspect {
    
        //注入Service用于把日志保存数据库,实际项目入库采用队列做异步
        @Resource
        private ActionService actionService;
        //日志工厂获取日志对象
        static Logger logger = LoggerFactory.getLogger(AppControllerAspect.class);
    
        /**
         * ThreadLocal多线程环境下,创建多个副本,各自执行,互不干扰
         */
    
        //startTime存放开始时间
        ThreadLocal<Map<String, Long >> startTime = new ThreadLocal<>();
        //count存放方法被调用的次数O 使用volatile利用它的三大特性:保证可见性(遵守JMM的可见性),不保证原子性,禁止指令重排
        volatile ThreadLocal<Map<String, Long>> count = new ThreadLocal<>();
        //timeConsuming存放方法总耗时
        ThreadLocal<Map<String, Long >> timeConsuming = new ThreadLocal<>();
        //fromType存放渠道
        ThreadLocal<Map<String, String >> fromType = new ThreadLocal<>();
        //tbLogVisit日志访问对象
        ThreadLocal<TbLogVisit> tbLogVisit = new ThreadLocal<>();
    
        //Controller层切点
        @Pointcut("@annotation(com.javaliao.portal.annotations.AppController)")
        public void controllerAspectse() {
        }
    
        //前置通知  用于拦截Controller层记录用户的操作
        @Before("controllerAspectse()")
        public void before(JoinPoint pjp) {
            //初始化
            TbLogVisit tbLogVisit = this.tbLogVisit.get();
            tbLogVisit = new TbLogVisit();
            Map<String, Long> countMap = this.count.get();
            countMap = new HashMap<>();
            this.count.set(countMap);
            Map<String, Long> timeConsumingMap = this.timeConsuming.get();
            timeConsumingMap = new HashMap<>();
            this.timeConsuming.set(timeConsumingMap);
            Map<String, String> fromTypeMap = this.fromType.get();
            fromTypeMap = new HashMap<>();
            this.fromType.set(fromTypeMap);
            Map<String, Long> map = new HashMap<>();
            map.put("startTime",System.currentTimeMillis());
            this.startTime.set(map);
            logger.info("==============前置通知开始:记录用户的操作==============");
            String currentTime = TimeUtils.getCurrentTime("YYYY-MM-dd HH:mm:ss");
            logger.info("请求开始时间:" + currentTime);
            tbLogVisit.setVisitStartTime(new Date());
            String resultString = "";
            // 是否打日志 默认打
            boolean isLog = true;
            try {
                MethodSignature signature = (MethodSignature) pjp.getSignature();
                AppController appController = signature.getMethod().getAnnotation(AppController.class);
                //是否开启日志打印
                isLog = appController.isLog();
                if(isLog){
                    //开始打印日志
                    HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                    HttpSession session = request.getSession();
                    String api = pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName();
                    logger.info("请求API:" + api);
                    tbLogVisit.setVisitApi(api);
    
                    String methodDescription = getControllerMethodDescription(pjp);
                    logger.info("方法描述:" + methodDescription);
                    tbLogVisit.setVisitDescription(methodDescription);
    
                    String ipAddress = InetAddress.getLocalHost().toString().substring(InetAddress.getLocalHost().toString().lastIndexOf("/") + 1);
                    logger.info("请求ip:"+ ipAddress);
                    tbLogVisit.setVisitIpAddress(ipAddress);
    
                    String hostName = InetAddress.getLocalHost().getHostName();
                    logger.info("机器名:" + hostName);
                    tbLogVisit.setVisitHostName(hostName);
    
                    Enumeration<?> enu = request.getParameterNames();
                    String params = "{";
                    while (enu.hasMoreElements()) {
                        String paraName = (String) enu.nextElement();
                        params += "\"" + paraName + "\":\"" + request.getParameter(paraName) + "\",";
                    }
                    String methodParams = params + "}";
                    String substring = methodParams.substring(0, methodParams.length() - 2);
                    substring = substring + "}";
                    logger.info("方法参数:" + substring);
                    tbLogVisit.setVisitParams(substring);
    
                    StringBuffer url = request.getRequestURL();
                    logger.info("URL:" + url);
                    tbLogVisit.setVisitUrl(String.valueOf(url));
                }
            } catch (Exception e) {
                StackTraceElement stackTraceElement2 = e.getStackTrace()[2];
                String reason = "异常:【"+
                        "类名:"+stackTraceElement2.getClassName()+";"+
                        "文件:"+stackTraceElement2.getFileName()+";"+"行:"+
                        stackTraceElement2.getLineNumber()+";"+"方法:"
                        +stackTraceElement2.getMethodName() + "】";
                //记录本地异常日志
                logger.error("==============前置通知异常:记录访问异常信息==============");
                String message = e.getMessage() + "|" + reason;
                logger.error("异常信息:",message);
                tbLogVisit.setVisitThrowingErro(message);
                tbLogVisit.setVisitResult("请求发生异常,异常信息:" + message);
            }finally {
                this.tbLogVisit.set(tbLogVisit);
            }
        }
    
        @Around("controllerAspectse()")
        public Object around(ProceedingJoinPoint pjp)throws Throwable {
            String result = JSON.toJSONString(pjp.proceed());
            logger.info("请求结果:" + result);
            TbLogVisit tbLogVisit = this.tbLogVisit.get();
            tbLogVisit.setVisitResult(result);
            this.tbLogVisit.set(tbLogVisit);
            return CommonResult.success("");
        }
    
    
        /**
         * 对Controller下面的方法执行后进行切入,统计方法执行的次数和耗时情况
         *  注意,这里的执行方法统计的数据不止包含Controller下面的方法,也包括环绕切入的所有方法的统计信息
         * @param jp
         */
    
        @AfterReturning("controllerAspectse()")
        public void afterMehhod(JoinPoint jp) {
            logger.info("==============方法执行完成==============");
            TbLogVisit tbLogVisit = this.tbLogVisit.get();
            try {
                //获取方法名
                String methodName = jp.getSignature().getName();
                //开始统计数量与耗时
                if(count.get().get(methodName) == null){
                    //第一次赋值为0
                    count.get().put(methodName,0L);
                }
                //使用原子整型进行增值
                AtomicLong atomicInteger = new AtomicLong(count.get().get(methodName));
                //加一 这里暂时不解决ABA问题,仅保证原子性 解决了volatile不保证原子性的问题 getAndIncrement()先返回再加1,incrementAndGet()先加1再返回
                long increment = atomicInteger.incrementAndGet();
                //然后增加新值
                count.get().replace(methodName,increment);
                Long end = System.currentTimeMillis();
                Long total =  end - startTime.get().get("startTime");
                logger.info("执行总耗时为:" +total);
                if(timeConsuming.get().containsKey(methodName)){
                    timeConsuming.get().replace(methodName, total);
                }else {
                    timeConsuming.get().put(methodName, (total));
                }
                tbLogVisit = this.tbLogVisit.get();
                tbLogVisit.setVisitTimeConsuming(String.valueOf(total));
                String endTime = TimeUtils.getCurrentTime("YYYY-MM-dd HH:mm:ss");
                logger.info("请求结束时间:" + endTime);
                tbLogVisit.setVisitEndTime(new Date());
                /**
                 * 从原来的map中将最后的连接点方法给移除了,替换成最终的,避免连接点方法多次进行叠加计算,
                 * 由于原来的map受ThreadLocal的保护,这里不支持remove,因此,需要单开一个map进行数据交接
                 */
                //重新new一个map
                Map<String, Long> map = new HashMap<>();
                for(Map.Entry<String, Long> entry:timeConsuming.get().entrySet()){
                    if(entry.getKey().equals(methodName)){
                        map.put(methodName, total);
                    }else{
                        map.put(entry.getKey(), entry.getValue());
                    }
                }
                for (Map.Entry<String, Long> entry :count.get().entrySet()) {
                    for(Map.Entry<String, Long> entry2 :map.entrySet()){
                        if(entry.getKey().equals(entry2.getKey())){
                            Long num = entry.getValue();
                            logger.info("调用次数:" + num);
                            tbLogVisit.setVisitNum(num);
                        }
                    }
                }
                //这里的渠道暂时写死
                Map<String, String> stringMap = fromType.get();
                Map<String, String> fromMap ;
                if(CollectionHelp.isMapNotEmpty(stringMap)){
                    fromMap = stringMap;
                }else {
                    fromMap = new HashMap<>();
                    fromMap.put(methodName,"个人开发电商平台");
                }
                String channel = fromMap.get(methodName);
                logger.info("渠道:" + channel);
                tbLogVisit.setVisitChannel(channel);
            } catch (Exception e) {
                StackTraceElement stackTraceElement2 = e.getStackTrace()[2];
                String reason = "异常:【"+
                        "类名:"+stackTraceElement2.getClassName()+";"+
                        "文件:"+stackTraceElement2.getFileName()+";"+"行:"+
                        stackTraceElement2.getLineNumber()+";"+"方法:"
                        +stackTraceElement2.getMethodName() + "】";
                //记录本地异常日志
                logger.error("==============通知异常:记录访问异常信息==============");
                String message = e.getMessage() + "|" + reason;
                logger.error("异常信息:",message);
                tbLogVisit.setVisitThrowingErro(message);
                tbLogVisit.setVisitResult("请求发生异常!!!");
            } finally {
                this.tbLogVisit.set(tbLogVisit);
                //添加日志信息入库
                actionService.insertLogVisit(this.tbLogVisit.get());
            }
        }
    
    
    
        /**
         * 获取注解中对方法的描述信息 用于Controller层注解
         */
        public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
            String targetName = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();//目标方法名
            Object[] arguments = joinPoint.getArgs();
            Class targetClass = Class.forName(targetName);
            Method[] methods = targetClass.getMethods();
            String description = "";
            for (Method method:methods) {
                if (method.getName().equals(methodName)){
                    Class[] clazzs = method.getParameterTypes();
                    if (clazzs.length==arguments.length){
                        description = method.getAnnotation(AppController.class).description();
                        break;
                    }
                }
            }
            return description;
        }
    
    }
    

    第五步:业务层发消息:

    package com.javaliao.portal.service.impl;
    
    import com.javaliao.portal.mapper.TbLogVisitMapper;
    import com.javaliao.portal.model.TbLogVisit;
    import com.javaliao.portal.service.ActionService;
    import com.javaliao.portal.util.ActiveMQUtil;
    import net.sf.json.JSONObject;
    import org.apache.activemq.command.ActiveMQMapMessage;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import javax.jms.*;
    
    @Service
    public class ActionServiceImpl implements ActionService {
    
        @Autowired
        TbLogVisitMapper tbLogVisitMapper;
    
        @Autowired
        ActiveMQUtil activeMQUtil;
    
        @Override
        public void insertLogVisit(TbLogVisit tbLogVisit) {
            try {
                // 连接消息服务器
                Connection connection = activeMQUtil.getConnection();
                connection.start();
                //第一个值表示是否使用事务,如果选择true,第二个值相当于选择0
                Session session = connection.createSession(true, Session.SESSION_TRANSACTED);
                // 发送消息
                Queue testqueue = session.createQueue("LOG_VISIT_QUEUE");
                MessageProducer producer = session.createProducer(testqueue);
                MapMessage mapMessage=new ActiveMQMapMessage();
                String toString = JSONObject.fromObject(tbLogVisit).toString();
                mapMessage.setString("tbLogVisit",toString);
                producer.setDeliveryMode(DeliveryMode.PERSISTENT);
                producer.send(mapMessage);
                session.commit();// 事务型消息,必须提交后才生效
                connection.close();
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    第六步:接收消息执行添加业务:

    package com.javaliao.portal.listener;
    
    import com.javaliao.portal.log4j.BaseLogger;
    import com.javaliao.portal.model.TbLogVisit;
    import com.javaliao.portal.service.ActionService;
    import net.sf.json.JSONObject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jms.annotation.JmsListener;
    import org.springframework.stereotype.Component;
    import javax.jms.JMSException;
    import javax.jms.MapMessage;
    
    @Component
    public class LogVisitListener {
    
        @Autowired
        ActionService actionService;
    
        @JmsListener(containerFactory = "jmsQueueListener" ,destination = "LOG_VISIT_QUEUE")
        public void consumeLogResult(MapMessage mapMessage){
            try {
                String object = mapMessage.getString("tbLogVisit");
                JSONObject jsonObject = new JSONObject().fromObject(object);
                TbLogVisit logVisit = (TbLogVisit) JSONObject.toBean(jsonObject, TbLogVisit.class);
                int count = actionService.insertLog(logVisit);
                if(count < 1){
                    BaseLogger.info("日志更新失败");
                }
            } catch (JMSException e) {
                e.printStackTrace();
            }
        }
    
    }
    

    执行业务:

    package com.javaliao.portal.service.impl;
    
    import com.javaliao.portal.mapper.TbLogVisitMapper;
    import com.javaliao.portal.model.TbLogVisit;
    import com.javaliao.portal.model.TbLogVisitExample;
    import com.javaliao.portal.service.ActionService;
    import com.javaliao.portal.util.ActiveMQUtil;
    import com.javaliao.portal.util.CollectionHelp;
    import com.javaliao.portal.util.NumberUtils;
    import net.sf.json.JSONObject;
    import org.apache.activemq.command.ActiveMQMapMessage;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import javax.jms.*;
    import java.util.Date;
    import java.util.List;
    
    @Service
    public class ActionServiceImpl implements ActionService {
    
        @Autowired
        TbLogVisitMapper tbLogVisitMapper;
    
        //这里去掉了之前发消息的代码
        /**
         * 添加日志信息入库
         * @param tbLogVisit
         * @return
         */
        @Override
        public int insertLog(TbLogVisit tbLogVisit) {
            tbLogVisit.setUpdateTime(new Date());
            int count = 0;
            //如果有异常直接添加
            if(StringUtils.isNoneEmpty(tbLogVisit.getVisitThrowingErro())){
                tbLogVisit.setCreateTime(new Date());
                count = tbLogVisitMapper.insert(tbLogVisit);
            }else {
                String visitIpAddress = tbLogVisit.getVisitIpAddress();
                String visitApi = tbLogVisit.getVisitApi();
                TbLogVisitExample tbLogVisitExample = new TbLogVisitExample();
                TbLogVisitExample.Criteria criteria = tbLogVisitExample.createCriteria();
                criteria.andVisitIpAddressEqualTo(visitIpAddress);
                criteria.andVisitApiEqualTo(visitApi);
                List<TbLogVisit> tbLogVisits = tbLogVisitMapper.selectByExample(tbLogVisitExample);
                if(CollectionHelp.isNotEmpty(tbLogVisits)){
                    Long nums = 0L;
                    Double sums = 0D;
                    for (TbLogVisit logVisit : tbLogVisits) {
                        //统计调用次数
                        Long visitNum = logVisit.getVisitNum();
                        nums = tbLogVisit.getVisitNum() + visitNum;
                        //统计耗时
                        Double visitTimeConsumingData = NumberUtils.Double(logVisit.getVisitTimeConsuming());
                        Double visitTimeConsumingParam = NumberUtils.Double(tbLogVisit.getVisitTimeConsuming());
                        Double sum = visitTimeConsumingData + visitTimeConsumingParam;
                        sums = sums + sum;
                    }
                    Double numDouble = NumberUtils.Double(String.valueOf(nums));
                    //统计平均耗时
                    Double avg = sums / numDouble;
                    tbLogVisit.setVisitTimeConsuming(avg.toString());
                    tbLogVisit.setVisitNum(nums);
                    count = tbLogVisitMapper.updateByExample(tbLogVisit,tbLogVisitExample);
                }else {
                    tbLogVisit.setCreateTime(new Date());
                    count = tbLogVisitMapper.insert(tbLogVisit);
                }
            }
    
            return count;
        }
    }
    

     

    这里提供我写的项目地址:https://github.com/javaliao/personalmall

    一开始没有设计好,后面强迫改动,导致访客的开始时间和结束时间都是最近一次的,不过我把每次请求的耗时改为平均耗时,勉强达到效果(不过有些请求异常的耗时时间长的就比较影响耗时统计了,唉不说了,最开始没有设计好,也算勉强了),效率也不算太差,不会太影响性能,

     

     

     

     

    展开全文
  • 用于记录应用程序埋点数据的API https://github.com/kevinten10/vrml 埋点API的问题 主流程隔离 例如旁支逻辑的NPE或者GSON解析异常等 支持Debug级别支持Debug级别 简洁易用的API 实现思路和方案 单个异常的...

    用于记录应用程序埋点数据的API

    https://github.com/kevinten10/vrml

    埋点API的问题

    1. 主流程隔离
      例如旁支逻辑的NPE或者GSON解析异常等
    2. 支持Debug级别支持Debug级别
    3. 简洁易用的API

    实现思路和方案

    1. 单个异常的隔离
      通过闭包进行trycatch,进行异常的隔离
    2. 支持不同级别的配置
      通过闭包传入配置,实现动态的配置
    3. 简洁易用的API

    Metrics API

    • 单个异常的隔离 √
    • 支持不同级别的配置 √
    • 简洁易用的API √
    • 支持局部分片 √
    • 支持表达式 √

    Metric API

    Metric API提供了一系列方法来记录应用程序的埋点数据。

    /**
     * API demo show
     */
    private static void metrics(BiConsumer<Map<String, String>, Map<String, String>> howToShow) {
        //  Option 1: add metric manually
        Metrics.metric(() -> {
            // index
            index(MetricIndexs.metric_type, "index");
            // store
            store(MetricStores.context, "store");
            // exception
            exception(new RuntimeException());
            // object
            object(new Object());
        });
        howToShow.accept(Metrics.showIndexs(), Metrics.showStores());
        Metrics.build();
        // Option 2: add metric by automatic placeholder "$"
        Metrics.Log().of(
                // index
                $(MetricIndexs.metric_type, "index"),
                // store
                $(MetricStores.context, "store"),
                // exception
                $(new RuntimeException()),
                // object
                $(new Object())
        );
        howToShow.accept(Metrics.showIndexs(), Metrics.showStores());
        Metrics.build();
        // Also you can use {@code local()} to start a local scope
        String local = Metrics.local();
        Metrics.Log(local).of(
                // Also you can use supplier
                () -> $(MetricIndexs.metric_type, "index"),
                () -> $(MetricStores.context, "store"),
                () -> $(new RuntimeException()),
                () -> $(new Object())
        );
        howToShow.accept(Metrics.showIndexs(), Metrics.showStores());
        Metrics.build(local);
    }

    Maven

    <dependency>
      <groupId>com.kevinten</groupId>
      <artifactId>vrml-metric</artifactId>
      <version>1.0.0</version>
    </dependency>
    展开全文
  • 日志工具类-java实现

    2019-12-16 09:52:41
    开发项目经常需要日志模块打印输出,因此封装一个日志内,供自己平时使用,有些模块重复书写浪费时间,所以直接拉下来能快速一点。
  • 待续。

    待续。

    待续。代码将整理后上传。

    展开全文
  • 【用户行为分析】-Java埋点

    万次阅读 热门讨论 2018-11-23 17:25:24
    Java后端登录处埋点,获取的事件属性包括:是否成功,登录方式以及神策预置属性。并进行用户ID的打通,使用神策接口把用户匿名ID和登录ID进行打通。 什么是用户ID打通? 用户有时会再注册或登录之前,会在页面...
  • (二)日志埋点

    2020-08-30 23:33:51
    1.日志埋点介绍 所谓埋点,就是在业务系统的程序中,植入一些收集事件数据的SDK(工具代码),进行各种事件的收集; 埋点分为两种 埋点代码可以植入到业务系统的后端程序中(比如java、php等) 也可以植入到业务...
  • 安卓日志埋点

    2020-11-09 14:41:23
    import android.app.Activity; import android.content.Context; import android.view....import java.util.ArrayList; import java.util.List; /** * 异常监控 * 使用: * 1.BaseActivity里重写该方法 * * @..
  • 埋点的方式有很多种,本文主要介绍 日志埋点 这种方式以及实现思路和案例。 日志埋点 就是通过程序打印 log 日志的方式进行业务/行为数据的记录   二、总体架构 通过 日志埋点 来实现业务监控和行为分析...
  • web日志埋点

    2014-06-23 17:46:59
    java"] [/code] 2、applicationContext-servlet.xml [code="java"] [/code] 3、com.youku.ddshow.cont...
  • java用户行为埋点-注解方式

    千次阅读 2020-03-06 15:22:14
    1)定义注解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Log { String value() default ""; } 2)定义entity 这里我用的jpa ... * @description 行为日志类 * @date 20...
  • 文章目录 前言 一、日志有什么作用? 二、使用步骤 1.导入 AOP 依赖 2.设计组件注解 3.编写日志切面 效果 前言 SpringAop 想必大家都熟悉不能再熟悉了,AOP在项目中的使用场景有很多很多,今天主要是以日志收集为例...
  • 主要的内容就是根据模型的字段要求,在相应的游戏逻辑执行时将埋点的json串发送到Kafka 代码实现 由于游戏服务端采用Java编写,所以现在以Java为例进行说明 public abstract class LogEvent implements Serializable...
  • 通过自定义注解实现java埋点提出问题分析问题解决问题总结 提出问题 近期在实习中负责了一个日志系统,主要功能为每个项目收集到用户的操作日志,将这些日志发送到一个专门收集统计日志的项目对这些日志进行管理与...
  • java日志数据的采集显示
  • 日志埋点 --- log4j的配置及使用

    千次阅读 2019-03-11 10:37:14
    本文的运行环境为:IDEA + Maven,有关Maven框架的使用可自行百度。 1. 导入log4j包 在项目的pom.xml的标签下添加如下代码,然后等待Maven将...总而言之,日志埋点在我们的开发过程中,是非常有用且有必要的!
  • 史上最全Java各类日志组件分析汇总

    千次阅读 2017-12-08 12:03:51
    Java日志工具基本介绍在java的世界里有许多实现日志功能的工具,最早得到广泛使用的是 log4j,现在比较流行的是slf4j+logback。作为开发人员,我们有时候需要封装一些组件(二方包)提供给其他人员使用,但是那么多...
  •  日志埋点分为客户端和服务器端。参考并转自:https://www.cnblogs.com/hzhuxin/p/11152805.html,如有侵权,请联系删除。)  ①客户端埋点:支持 iOS、安卓、Web/H5、微信小程序,主要用于分析 UV、PV、点击量...
  • 在前端页面编写js代码用于发送日志数据 这种操作称为埋点 埋点分三种: 代码埋点 数据可视化埋点埋点 埋点主要关注两点: 地点和数据 埋点事件 也就是自定义指令,在需要的地方给标签属性即可。减少代码量 vue ...
  • 公司的埋点方式是引入sdk注册到全局后,在需要埋点的地方使用js调用进行埋点埋点代码完全混合在业务代码里,有时甚至得专门加个事件和方法来埋点。经过一番研究后发现,使用自定义指令可以很好地实现埋点代码和...
  • 在开发过程中,可能会遇到需要记录用户操作记录的情况,这时候可以使用Spring的AOP实现日志埋点,记录用户的操作行为 实现步骤: 1.日志记录注解(使用时直接添加到需要记录的方法上) package ...
  • 堆 ( Java代码可及的 Java堆 和 JVM自身使用的方法区)、 栈 ( 服务Java方法的虚拟机栈 和 服务Native方法的本地方法栈 ) 保证程序在多线程环境下能够连续执行的程序计数器 特别地,我们当时就提到Java堆是进行...
  • 文章目录埋点实现以及全流程日志记录(基于SSM的AOP)1. 需求2. 实现思路3. 代码实现3.1 需求13.1.1 自定义注解 MyLog3.1.2 切面类 AopLog3.1.3 IAopLogService/AopLogServiceImpl3.1.4 IAopLogDao3.1.5 SysLogInfo...
  • 通过埋点搜集日志数据的简单架构

    千次阅读 2019-11-28 15:03:44
    后台数据库和日志文件一般只能够满足常规的统计分析,对于具体的产品和项目来说,一般还要根据项目的目标和分析需求进行针对性地“数据埋点”工作。 所谓埋点,就是在额外的正常功能逻辑上添加针对性的统计逻辑,即...
  • SpringBoot AOP 实现埋点日志记录(完整源码)一、Spring Boot AOP二、AOP的常用术语三、源码实现埋点日志记录3.1 项目结构图3.2 代码实现 随着互联网技术的深入发展,各个系统的日活用户、访问量、点击量成指数上升...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,048
精华内容 2,419
关键字:

java日志埋点

java 订阅