精华内容
下载资源
问答
  • 神策埋点的测试教程,自己的实际工作经验,有详细的图文介绍。
  • 需求: 公司是打车的业务,埋点这块后续加的是代驾的业务,运营想要在一些关键的节点上进行事件分析,比如乘客...乘客下单,下单完成——使用@Async异步调用神策数据埋点推送入参,异步调用避免神策埋点报错导致...

    需求:

             公司是打车的业务,埋点这块后续加的是代驾的业务,运营想要在一些关键的节点上进行事件分析,比如乘客、司机登录事件,代驾乘客下单,代驾乘客取消订单,代驾司机取消订单,司机接单、乘客确认支付、支付结果这些事件上添加数据分析,来分析事件发生的次数啥的。

    过程

    这个业务已经在顺风车引入了,后来其他同事就直接在相关事件后边加上了数据埋点,我是后来接手的,加了点公共属性做修改

    如:

    乘客下单,下单完成——使用@Async异步调用神策数据埋点推送入参,异步调用避免神策埋点报错导致主流程造成损害,神策入参拼接完成后,使用kafak生产者发送神策推送消息——》kafak消费者接收,使用神策的sdk提供的实体里的推送数据的方法发送数据——》根据配置累配置的接收神策数据推送的地址,查看数据推送结果,可以在这个web界面上进行事件分析,根据事件的属性进行分析

    具体引入

    1.直接引入神策数据埋点的sdk,即依赖

    <dependency>
    			<groupId>com.sensorsdata.analytics.javasdk</groupId>
    			<artifactId>SensorsAnalyticsSDK</artifactId>
    			<version>3.1.16</version>
    </dependency>

    2.添加配置类

    package com.wanshun.springboot;
    
    import com.sensorsdata.analytics.javasdk.SensorsAnalytics;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class SensorsApplication {
    
        private String saServerUrl;
    
        private Integer saBulkSize;
    
        private Boolean throwException;
    
        private Integer maxCacheSize;
    
        public String getSaServerUrl() {
            return saServerUrl;
        }
    
        @Value("${sensors.batch.saserverurl:")
        public void setSaServerUrl(String saServerUrl) {
            this.saServerUrl = saServerUrl;
        }
    
        public Integer getSaBulkSize() {
            return saBulkSize;
        }
    
        @Value("${sensors.batch.sabulksize:5}")
        public void setSaBulkSize(Integer saBulkSize) {
            this.saBulkSize = saBulkSize;
        }
    
        public Boolean getThrowException() {
            return throwException;
        }
    
        @Value("${sensors.batch.throwexception:false}")
        public void setThrowException(Boolean throwException) {
            this.throwException = throwException;
        }
    
        public Integer getMaxCacheSize() {
            return maxCacheSize;
        }
    
        @Value("${sensors.batch.maxcachesize:5000}")
        public void setMaxCacheSize(Integer maxCacheSize) {
            this.maxCacheSize = maxCacheSize;
        }
    
        @Bean
        public SensorsAnalytics sensorsAnalytics()  {
            // 从神策分析获取的数据接收的 URL,即运营或产品在web界面查看事件的数据分析平台
            final String SA_SERVER_URL = getSaServerUrl();
            // 当缓存的数据量达到50条时,批量发送数据
            final int SA_BULK_SIZE = getSaBulkSize();
            // 数据同步失败不抛出异常
            final boolean THROW_EXCEPTION = getThrowException();
            // 内存中数据最大缓存条数,如此值大于0,代表缓存的数据会有条数限制,最小 3000 条,最大 6000 条。否则无条数限制。
            final int MAX_CACHE_SIZE = getMaxCacheSize();
            // 使用 BatchConsumer 初始化 SensorsAnalytics
            // 建议不要在任何线上的服务中使用此DebugConsumer【神策数据的引入文档上也有注明】
            return new SensorsAnalytics(
    //                new SensorsAnalytics.DebugConsumer(SA_SERVER_URL, true));  //在正式环境不要用这个,因为这个debug模式,神策数据那边用的是神策那边的消费者,如果是debug模式,推送数据失败,程序就会报错,如果非debug模式,程序不会报错,但是可能对应的数据推送不过去,这个调试的时候用的话最好了
                    new SensorsAnalytics.BatchConsumer(SA_SERVER_URL, SA_BULK_SIZE, MAX_CACHE_SIZE, THROW_EXCEPTION));
        }
    
    }

    3.下单事件异步添加神策埋点事件

    controller

        /**
         * 车主端确认下单
         *
         * @param parmVO
         * @param rpcPacket
         * @return
         */
        @UrlMapping(url = "addDrivingOrder")
        public RpcPacket addDrivingOrder(RpcAddOrderDto parmVO, RpcPacket rpcPacket) {
            logger.info("车主端确认下单,入参,RpcAddOrderDto {}", JsonUtil.toJson(parmVO));
            RpcPacket packet = new RpcPacket();
            try {
                Long userId = rpcPacket.getId();
                Integer areaCode = parmVO.getCurAddr().getAreaCode();
                parmVO.setCarOwnerDevId(new Gson().fromJson(rpcPacket.getExtenData(), RpcPacketExtDto.class).getDeviceId());
                String orderId = drivingOrderService.addDrivingOrder(userId, areaCode, parmVO);
                Map<String, String> map = new HashMap<>();
                map.put("orderId", orderId);
                packet.setData(map);
                packet.setAnwserCode(new AnwserCode(1, "车主端确认下单成功"));
            } catch (ArgsException e) {
                logger.error("车主端确认下单失败 {}", e.toString());
                packet.setAnwserCode(e.getAnwserCode());
            } catch (Exception e) {
                logger.error("车主端确认下单失败 {}", e.toString());
                packet.setAnwserCode(OrderServiceAnwserCode.BUSS_ERROR_ADDORDERFAIL);
            }
            logger.info("车主端确认下单,出参,RpcAddOrderDto {},入参 rpcPacket:{} RpcAddOrderDto:{}", JsonUtil.toJson(packet), JsonUtil.toJson(rpcPacket), JsonUtil.toJson(parmVO));
            return packet;
        }

    service

        @Override
        public String addDrivingOrder(Long userId, Integer areaCode, RpcAddOrderDto parmVO) {
            String lockName = "";
            String orderId = "";
            String lockKey = OrderServiceModulConstant.LOCK_ADD_ORDER_CAROWN_LOKENAME + parmVO.getOrderType() + ":" + userId;
            try {
    //            logger.info("{} into -------------------init",Thread.currentThread().getId()+Thread.currentThread().getName());
                lockName = redisCache.getLockLua(lockKey, OrderServiceModulConstant.LLOCK_ADD_ORDER_CAROWN_LOKE_TIMEOUT);
                if (!StringUtil.isEmpty(lockName)) {
                    if (parmVO.getOrderType().equals(OrderAttributeConst.ORDERTYPE_SM)) {
                        orderId = addDrivingOrderForSMorder(userId, areaCode, parmVO);
                    } else {
                        orderId = addDrivingOrderForNoSMorder(userId, areaCode, parmVO);
                    }
    //                logger.info("{} lockeName&&&&&&&&&&&&&&& {}",Thread.currentThread().getId()+Thread.currentThread().getName(),lockName);
                } else {
                    throw new ArgsException(OrderServiceAnwserCode.BUSS_ERROR_CAROWNER_ADDORDER_REPEAT_COMMIT);
                }
                redisCache.deleteKey(OrderServiceModulConstant.KEY_CAROWNER_PUBLIC_ORDER_COUNT_TODAY + userId);
                return orderId;
            } catch (ArgsException e) {
                throw e;
            } catch (Exception e) {
                throw e;
            } finally {
    //            logger.info("{} release################# {}",Thread.currentThread().getId()+Thread.currentThread().getName(),lockName);
                redisCache.releaseLock(lockKey, lockName);
            }
        }
     /**
         * 新增预约单和实时单
         *
         * @param userId
         * @param areaCode
         * @param parmVO
         * @return
         */
        public String addDrivingOrderForNoSMorder(Long userId, Integer areaCode, RpcAddOrderDto parmVO) {
            logger.info("预约单和实时单下单,RpcAddOrderDto {},userId {}", JsonUtil.toJson(parmVO), JsonUtil.toJson(userId));
            if (!parmVO.getOrderType().equals(OrderAttributeConst.ORDERTYPE_YY)) {
                parmVO.setAppointTime(MyUtils.getNow());
            } else {// 加预约时间
                DrivingBaseAlgorithmResultDto dto = rpcService.getScheduleConfig(parmVO.getStartAddr().getAreaCode() / 100 * 100, parmVO.getOrderType());
                if (dto != null && dto.getSubscribeBaseRule() != null && dto.getSubscribeBaseRule().getReservationNumber() > 0) {
                    long current = System.currentTimeMillis() / (1000 * 3600 * 24) * (1000 * 3600 * 24) - TimeZone.getDefault().getRawOffset();
                    current = current / 1000;
                    long zero = current + dto.getSubscribeBaseRule().getReservationNumber() * 24 * 3600;
                    if (parmVO.getAppointTime().compareTo(zero) == 1) {
                        throw new ArgsException(new AnwserCode(19984, "新增预约单,预约时间不能超过" + dto.getSubscribeBaseRule().getReservationNumber() + "天"));
                    }
                } else {
                    throw new ArgsException(OrderServiceAnwserCode.INTERFACE_ERROR_RPC_GETSCHEDULECONFIG);
                }
            }
            //加费用--车主的费用 与包干司机、非包干司机费用比较  不合理就抛"后台系统数据异常"
            if (!checkEstmastExpenseCompare(parmVO.getChannelId(),parmVO.getOrderType(), parmVO.getStartAddr().getAreaCode() / 100 * 100, parmVO.getAppointTime(), parmVO.getEstDuration(), parmVO.getEstDistance())) {
                throw new ArgsException(OrderServiceAnwserCode.BUSS_ERROR_ADD_ORDER_COMPARE_EXPENSE_ERROR);
            }
    
            checkCrossCityAddOrder(parmVO.getStartAddr(), parmVO.getEndAddr(), parmVO.getOrderType());
            checkAddOrderMaxCountForCarOwner(userId, parmVO);
            checkAddOrderIsTimeConflict(userId, parmVO);
            //<editor-fold desc="赋值转换">
            String orderId = getOrderId(parmVO);
            DrivingOrderDo drivingOrderDo = new DrivingOrderDo();
            String riderNick = parmVO.getRiderNick();
            if(!StringUtil.isEmpty(riderNick)){
                riderNick = riderNick.trim();
            }
            drivingOrderDo.setRiderNick(riderNick);
            CarOwnerInfoInDto carOwnerInfoInDto = new CarOwnerInfoInDto();
            carOwnerInfoInDto.setId(userId);
            String carOwnerPhone = null;
            List<CarOwnerInfoOutDto> carOwnerInfoOutDtos = rpcCarOwnerInfoService.getCarOwnerInfo(carOwnerInfoInDto);
            if(CollectionUtils.isNotEmpty(carOwnerInfoOutDtos)){
                CarOwnerInfoOutDto carOwnerInfoOutDto = carOwnerInfoOutDtos.get(0);
                carOwnerPhone = carOwnerInfoOutDto.getPhone();
            }
            if(parmVO.getIsForOther() == null || parmVO.getIsForOther() == 0){
                drivingOrderDo.setRiderPhone(carOwnerPhone);
            }else{
                drivingOrderDo.setRiderPhone(parmVO.getRiderPhone());
            }
            if(drivingOrderDo.getRiderPhone().equals(carOwnerPhone)){
                drivingOrderDo.setIsForOther(0);
            }else{
                drivingOrderDo.setIsForOther(1);
            }
            drivingOrderDo.setCarOwnerName(rpcService.getCarOwnerInfo(userId).getName());
            drivingOrderDo.setOrderType(parmVO.getOrderType());
            drivingOrderDo.setCarOwnerId(userId);
            drivingOrderDo.setOrderId(orderId);
            drivingOrderDo.setStartAddr(JsonUtil.toJson(parmVO.getStartAddr()));
            drivingOrderDo.setEndAddr(JsonUtil.toJson(parmVO.getEndAddr()));
            drivingOrderDo.setResource(parmVO.getResource());
            drivingOrderDo.setStartCity(Integer.toString(parmVO.getStartAddr().getAreaCode() * 1 / 100 * 100));
            drivingOrderDo.setAreaCode(areaCode);
            drivingOrderDo.setCityCode(areaCode * 1 / 100 * 100);
            drivingOrderDo.setProvinceCode(areaCode * 1 / 10000 * 10000);
            drivingOrderDo.setCreateTime(MyUtils.getNow());
            drivingOrderDo.setUpdateTime(drivingOrderDo.getCreateTime());
            drivingOrderDo.setIsException(1);
            drivingOrderDo.setVersion(1);
            drivingOrderDo.setChannelId(parmVO.getChannelId());
    //        drivingOrderDo.setWaitingTime(0L);
            drivingOrderDo.setAppointTime(drivingOrderDo.getCreateTime());
            if (parmVO.getOrderType().equals(OrderAttributeConst.ORDERTYPE_YY)) {
                drivingOrderDo.setAppointTime(parmVO.getAppointTime());
            }
            OrderOtherProperty otherPro = new OrderOtherProperty();
            otherPro.setPulibAddr(parmVO.getCurAddr());
            otherPro.setCarOwnerDev(parmVO.getCarOwnerDevId());
            otherPro.setDriverDev(parmVO.getDriverDevId());
            drivingOrderDo.setOtherProperty(new Gson().toJson(otherPro));
            drivingOrderDo.setStatus(OrderAttributeConst.ORDER_STATUS_DISPATCHING);
            drivingOrderMapper.insert(drivingOrderDo);
            //保存乘车人标签记录
            try {
                if (drivingOrderDo.getIsForOther() != null && drivingOrderDo.getIsForOther() == 1) {
                    riderTagMapper.insert(RiderTagDo.builder().carOwnerId(userId).riderNick(parmVO.getRiderNick())
                            .riderPhone(parmVO.getRiderPhone()).createTime(new Date()).updateTime(new Date()).build());
                }
            }catch (Exception e){
                logger.error("save rider tags fail userId {} orderId {} exc {}" , userId , orderId , e.toString());
            }
            //</editor-fold>
            DrivingOrderEstimateDo estDo = new DrivingOrderEstimateDo();
            estDo.setOrderId(drivingOrderDo.getOrderId());
            estDo.setEstArrivTime(0L);
            estDo.setEstDistance(parmVO.getEstDistance());
            estDo.setEstDuration(parmVO.getEstDuration());
            estDo.setEstMoney(parmVO.getEstMoney());
            estDo.setCreateTime(drivingOrderDo.getCreateTime());
            estDo.setUpdateTime(drivingOrderDo.getCreateTime());
            drivingOrderEstimateMapper.insert(estDo);
            //调用调度接口将订单状态发送给腾讯
            this.modifySyncOrderStatus(drivingOrderDo);
            try{
                //神策埋点事件
                sensorsBurialSiteService.getAddPassengerOrderSensorcParams(drivingOrderDo , orderId , parmVO.getEstMoney());
            }catch (Exception ex){
                logger.error("神策埋点 创建订单失败 orderId {}" , orderId);
            }
            return drivingOrderDo.getOrderId();
        }
    
       
    

     sensorsBurialSiteServiceImpl

      /**
         * 乘客创建订单
         * @param drivingOrderDo   乘客下单入参
         * @param passengerOrderId    乘客订单号
         * @param prePayFee    预估费
         */
        @Async
        @Override
        public void getAddPassengerOrderSensorcParams(DrivingOrderDo drivingOrderDo, String passengerOrderId, Integer prePayFee){
            logger.info("乘客创建订单神策事件入参,drivingOrderDo:{},passengerOrderId:{},prePayFee:{}",JsonUtil.toJson(drivingOrderDo),passengerOrderId,prePayFee);
            SensorsAo sensorsAo = new SensorsAo();
    
            Map<String,Object> param = new HashMap<>();
            //添加公共属性
            addBasicParam(drivingOrderDo, param);
            // 事件名称
            sensorsAo.setEventName("BuildOrder");
            // 是否成功
            param.put("is_success",true);
            // 订单类型
            param.put("order_type",String.valueOf(drivingOrderDo.getOrderType()));
            // 失败原因
            param.put("fail_reason","暂无");
            // 业务类型
            param.put("service_type","800");
            // 订单ID
            param.put("order_id", passengerOrderId);
            // 订单起点
            if(StringUtils.isNotEmpty(drivingOrderDo.getStartAddr())) {
                RpcAddrPointDto startAddress = JsonUtil.fromJson(drivingOrderDo.getStartAddr(), RpcAddrPointDto.class);
                param.put("order_departure", startAddress.getPoiName());
            }
            // 订单终点
            if(StringUtils.isNotEmpty(drivingOrderDo.getEndAddr())) {
                RpcAddrPointDto endAddress = JsonUtil.fromJson(drivingOrderDo.getEndAddr(), RpcAddrPointDto.class);
                param.put("order_destination", endAddress.getPoiName());
            }
            // 订单预估价
            param.put("order_estimateprice", prePayFee);
            // 是否预付费订单
            param.put("is_payed",false);
            param.put("scan_order_type" , String.valueOf(drivingOrderDo.getOrderType()));
            param.put("valet_driver_type" , String.valueOf(drivingOrderDo.getIsForOther()));
            // 用户id
            sensorsAo.setUserId(drivingOrderDo.getCarOwnerId());
            // 订单id
            sensorsAo.setOrderId(passengerOrderId);
            // 推送参数
            sensorsAo.setParam(param);
            sensorsBurialSiteClusterEventProducer.sendSensorsEnlistEvent(sensorsAo);
        }
    
     /**
         * 添加神策事件的公共属性
         * @param drivingOrderDo
         * @param param
         * @return
         */
        public Map<String,Object> addBasicParam(DrivingOrderDo drivingOrderDo,Map<String,Object> param){
            RpcLocalCityVo nameByCode = rpcLocalCityService.getNameByCode(drivingOrderDo.getCityCode());
            logger.info("根据cityCode获取城市名称出参,nameByCode:{}",JsonUtil.toJson(nameByCode));
            if(nameByCode.getAnwserCode().getCode() == 1 && StringUtils.isNotEmpty(nameByCode.getName())) {
                //获取所在城市名称
                param.put("address", nameByCode.getCode() + nameByCode.getName());
            }
            //公共属性,平台类型,应用名称
            if(drivingOrderDo.getResource() != null && (drivingOrderDo.getResource() == 1 || drivingOrderDo.getResource() == 2)){
                param.put("platform_type", "app");
                param.put("app_name", "万顺叫车");
            }else if(drivingOrderDo.getResource() == 3){
                param.put("platform_type", "小程序");
                param.put("app_name", "万顺叫车代驾小程序");
            }
            //是否为登录状态
            param.put("is_login", "true");
            return param;
        }
    
    

    kafka生产者

    package com.wanshun.order.cluster.producer;
    
    import com.wanshun.common.utils.JsonUtil;
    import com.wanshun.constants.platform.daijiaservice.DaiJiaKafkaTopicConstants;
    import com.wanshun.net.cluster.ClusterEventBusProducer;
    import com.wanshun.net.cluster.metadata.ClusterEvent;
    import com.wanshun.net.kafka.KafkaConfig;
    import com.wanshun.rpcao.SensorsAo;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 神策埋点kafka消息
     * @author htc
     */
    public class SensorsBurialSiteClusterEventProducer {
    
    	public static Logger logger = LoggerFactory.getLogger(SensorsBurialSiteClusterEventProducer.class);
    
    	private ClusterEventBusProducer producer;
    
    	public SensorsBurialSiteClusterEventProducer(KafkaConfig kafkaConfig) {
    		producer = ClusterEventBusProducer.getClusterEventBusProducer();
    		producer.init(kafkaConfig);
    		producer.addTopic(DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC, false);
    	}
    
    
    	/**
    	 * 神策埋点推送消息
    	 * @param sensorsAo 事件类
    	 * @return 处理结果
    	 */
    	public boolean sendSensorsEnlistEvent(SensorsAo sensorsAo) {
    		ClusterEvent clusterEvent = new ClusterEvent();
    		String topic = DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC;
    		try {
    			clusterEvent.setBalanceId(sensorsAo.getOrderId());
    			clusterEvent.setData(JsonUtil.toJson(sensorsAo));
    			clusterEvent.setClusterEventType(DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC_EVENTTYPE_SENSORS);
    			boolean result = producer.publishImportantEvent(topic, clusterEvent);
    			if (!result) {
    				logger.info("神策埋点 推送消息, 但发送消息时,kafka发送异常 " +
    						"orderId:{}", sensorsAo.getOrderId());
    				throw new RuntimeException("发送事件异常");
    			}else{
    				logger.info("神策埋点 推送消息,发送成功 orderId {}" , sensorsAo.getOrderId());
    			}
    		}catch (Exception e){
    			logger.error(e.getMessage(), e);
    		}
    		return true;
    	}
    
    }
    

     kafk消费者S

    package com.wanshun.cluster;
    
    import com.alibaba.fastjson.JSON;
    import com.sensorsdata.analytics.javasdk.SensorsAnalytics;
    import com.wanshun.common.utils.JsonUtil;
    import com.wanshun.constants.platform.daijiaservice.DaiJiaKafkaTopicConstants;
    import com.wanshun.constants.platform.thirdplatform.ThirdplatformModuleConstant;
    import com.wanshun.net.cluster.ClusterEventBusConsumer;
    import com.wanshun.net.cluster.ClusterEventSubscribe;
    import com.wanshun.net.cluster.listener.ClusterEventBusListener;
    import com.wanshun.net.cluster.metadata.ClusterEvent;
    import com.wanshun.net.kafka.KafkaConfig;
    import com.wanshun.rpcao.SensorsAo;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.transaction.annotation.Transactional;
    
    import java.util.Set;
    
    public class SensorsConsumer extends ClusterEventBusListener implements ApplicationContextAware {
        public final static Logger logger = LoggerFactory.getLogger(SensorsConsumer.class);
    
        @Autowired
        private SensorsAnalytics sa;
    
        private final KafkaConfig kafkaConfig;
    
        private boolean isInit = false;
    
        public SensorsConsumer(KafkaConfig kafkaConfig) {
            this.kafkaConfig = kafkaConfig;
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (!isInit) {
                synchronized (this) {
                    if (!isInit) {
                        isInit = true;
    
                        ClusterEventSubscribe subscribe = new ClusterEventSubscribe();
                        subscribe.addTopic(false, false, DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC);
    
                        ClusterEventBusConsumer consumer = ClusterEventBusConsumer.getClusterEventBusConsumer(ThirdplatformModuleConstant.GROUP_NAME_SERVER, kafkaConfig);
                        consumer.init(this, subscribe);
                    }
                }
            }
            logger.info("三方服务kafka消费端启动");
        }
    
        @Override
        public boolean checkCanStartConsumer(String topicName) {
            if ( DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC.equals(topicName)) {
                return true;
            }
            return false;
        }
    
        @Transactional
        @Override
        public void eventNotify(String topicName, ClusterEvent clusterEvent) {
            logger.info("神策推送数据kafka消费事件: {}, topicName: {}", JSON.toJSONString(clusterEvent), topicName);
            if ( DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC.equals(topicName) &&
                    DaiJiaKafkaTopicConstants.THIRDPLAT_SERVICE_OUTER_TOPIC_EVENTTYPE_SENSORS == clusterEvent.getClusterEventType()) {
                String data = clusterEvent.getData();
                SensorsAo sensorsAo = JSON.parseObject(data, SensorsAo.class);
                try {
                    logger.info("神策推送数据入参,sensorsAo:{}", JsonUtil.toJson(sensorsAo));
                    sa.track(sensorsAo.getUserId().toString(), sensorsAo.isFlag(), sensorsAo.getEventName(), sensorsAo.getParam());
                    sa.flush();
                } catch (Exception e) {
                    logger.error("hotfix神策推送数据失败,data:{},sensorsAo:{}", data, JSON.toJSONString(sensorsAo), e);
                }
                logger.info("神策推送数据kafka消费事件: {}, topicName: 成功{}", JSON.toJSONString(clusterEvent), topicName);
            }
    
        }
    
        @Override
        public void notifyPartition(String topicName, Set<Integer> partitionSet) {
    
        }
    
        @Override
        public void destroyPartition(String topicName, Set<Integer> partitionSet) {
    
        }
    }
    
    展开全文
  • 神策埋点

    千次阅读 2019-07-01 17:31:00
    放入代码中可以调用神策的方法啦,如: sensors.track('event', {a: 1}); // 监听event并且传参a为1  检测是否埋点成功,点击左下方埋点: 输入id查看是否成功。     转载于:...

    首先进入后台管理点击生成导入代码:

    选好选项后点生成:

    以下是生成的代码:

    (function(para) {
        var p = para.sdk_url, n = para.name, w = window, d = document, s = 'script',x = null,y = null;
        if(typeof(w['sensorsDataAnalytic201505']) !== 'undefined') {
            return false;
        }
        w['sensorsDataAnalytic201505'] = n;
        w[n] = w[n] || function(a) {return function() {(w[n]._q = w[n]._q || []).push([a, arguments]);}};
        var ifs = ['track','quick','register','registerPage','registerOnce','trackSignup', 'trackAbtest', 'setProfile','setOnceProfile','appendProfile', 'incrementProfile', 'deleteProfile', 'unsetProfile', 'identify','login','logout','trackLink','clearAllRegister','getAppStatus'];
        for (var i = 0; i < ifs.length; i++) {
          w[n][ifs[i]] = w[n].call(null, ifs[i]);
        }
        if (!w[n]._t) {
          x = d.createElement(s), y = d.getElementsByTagName(s)[0];
          x.async = 1;
          x.src = p;
          x.setAttribute('charset','UTF-8');
          y.parentNode.insertBefore(x, y);
          w[n].para = para;
        }
      })({
        sdk_url: 'https://static.sensorsdata.cn/sdk/1.12.18/sensorsdata.min.js', // 这里可以把源码下载下来放在我们自己的域名下
        heatmap_url: 'https://static.sensorsdata.cn/sdk/1.12.18/heatmap.min.js', // 这里可以把源码下载下来放在我们自己的域名下
        name: 'sensors',
        server_url: '......', // 这里是直接生成的域名
        heatmap:{}
      });
      sensors.quick('autoTrack');  // name是sensors默认可以记录浏览量

    放入代码中可以调用神策的方法啦,如:

    sensors.track('event', {a: 1}); // 监听event并且传参a为1

     检测是否埋点成功,点击左下方埋点:

    输入id查看是否成功。

     

     

    转载于:https://www.cnblogs.com/xjy20170907/p/11115484.html

    展开全文
  • 神策埋点 一.什么是神策埋点? 埋点,大实话,就是理解为埋在地里的检测器,检测用户点击的按钮,做的某些操作。并且通过第三方去记录。这里的第三方我们特指神策的用户平台查看数据 二.神策埋点模块 全局埋点 操作...

    神策埋点

    一.什么是神策埋点?

    埋点,大实话,就是理解为埋在地里的检测器,检测用户点击的按钮,做的某些操作。并且通过第三方去记录。这里的第三方我们特指神策的用户平台查看数据

    二.神策埋点模块

    全局埋点

    操作步骤:首先会给你两个本地的js文件,我们姑且成为1.js和sensors.js
    1.js:大概就是神策那边的本地包,我们通过触发本地包然后达成记录功效
    sensors.js:是我们用来记录埋点的地方的文件一般sensors.js我们会在全局main.js中引入然后去使用
    这边神策还会给你两个文档关于对接的文档,上面有对接地址和你需要的测试地址,全局的话如何编写呢!
    在这里插入图片描述
    首先这里是我们的地址填写
    第二部分
    在这里插入图片描述
    在这里插入图片描述
    这里是引入和标签记录
    在这里插入图片描述
    这个图呢是你可以写到全局的sensors文件里面,也可以写到你其他文件夹去触发。
    是不是还挺简单
    到这一步的话大致就可以去品台上根据你的用户usermessage去测试

    按钮局部埋点

    局部的触发,在于记录某个按钮,某个窗口,单个的单独记录触发
    那么它是有触发方法的一般来说的话可以通过 to track去触发
    在这里插入图片描述
    在这里插入图片描述
    是不是一学就废

    展开全文
  • 神策埋点后端方案

    2020-10-22 16:23:28
    神策埋点后端方案 一、埋点方案 openresty+lua+logstash 二、openresty a. openresty安装 依赖包安装 yum install pcre-devel openssl-devel gcc curl openresty安装 wget ...

    神策埋点后端方案
    一、埋点方案
    openresty+lua+logstash
    在这里插入图片描述
    二、openresty
    a. openresty安装
    依赖包安装

    yum install pcre-devel openssl-devel gcc curl
    

    openresty安装

    wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
    tar xzvf openresty-1.17.8.2.tar.gz
    cd openresty-1.17.8.2
    ./configure
    make 
    make install
    

    b. zlib依赖安装

    yum install -y gcc gcc-c++ make automake
    yum install -y cmake
    wget https://github.com/brimworks/lua-zlib/archive/master.zip
    unzip master.zip
    cd lua-zlib-master/
    cmake -DLUA_INCLUDE_DIR=/usr/local/openresty/luajit/include/luajit-2.1 -DLUA_LIBRARIES=/usr/local/openresty/luajit/lib -DUSE_LUAJIT=ON -DUSE_LUA=OFF
    make
    cp zlib.so /usr/local/openresty/lualib/zlib.so
    

    c. lua脚本

    cd /usr/local/openresty/nginx/conf/
    vim lua_zlib_body.lua
    
    local zlib = require "zlib"
    local cjson = require("cjson")
    
    local function set_data(str)
          local s = string.sub(str,0,1)
          if s == "{" then
              str = "["..str.."]"
          end
          ngx.var.data=str
    end
    
    local method=ngx.req.get_method()
    if method == "POST" then
       ngx.req.read_body()
       local body = ngx.req.get_post_args()
       local gzip = body["gzip"]
       if gzip == "1" then
            local data_list = body["data_list"]
            if data_list then
                local stream = zlib.inflate()
                local dec= ngx.decode_base64(data_list)
                local str = stream(dec)
                set_data(str)
            end
       else
             local data = body["data"]
             if data then
                 local dec= ngx.decode_base64(data)
                 set_data(dec)
             end
       end
    elseif  method == "GET" then
         local args = ngx.req.get_uri_args()
         local data = args["data"]
         local dec= ngx.decode_base64(data)
         set_data(dec)
    end
    ngx.say("success")
    

    d. nginx配置

    vim nginx.conf
    
    #user  nobody;
    worker_processes  1;
    
    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;
    
    #pid        logs/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       mime.types;
        default_type  application/octet-stream;
    
        log_format user_log_format escape=json  $data;
    
    
        sendfile        on;
        keepalive_timeout  65;
    
        gzip  on;
    
        server {
            listen       8032;
            default_type 'application/json';
            charset utf-8;
    
    
            location /logate/data{
                add_header 'Access-Control-Allow-Origin' $http_origin;
                add_header 'Access-Control-Allow-Credentials' 'true';
                add_header 'Access-Control-Allow-Methods' 'GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS';
                if ($request_method = 'OPTIONS') {
                    add_header 'Access-Control-Max-Age' 1728000;
                    add_header 'Content-Type' 'text/plain; charset=utf-8';
                    add_header 'Content-Length' 0;
                    return 204;
                }
                set $data '';
                content_by_lua_file "/usr/local/openresty/nginx/conf/lua_zlib_body.lua";
                access_log /data/buried_point/data.log user_log_format;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }
    

    e. nginx启动

    mkdir /data/buried_point
    /usr/local/openresty/nginx/sbin/nginx
    ps -ef|grep nginx
    

    三、logstash
    a.下载:

    cd /data
    wget https://mirrors.huaweicloud.com/logstash/7.8.0/logstash-7.8.0.tar.gz
    

    b.解压:

    tar -zxvf logstash-7.8.0.tar.gz
    cd logstash-7.8.0/bin
    

    c.安装Webhdfs插件

    ./logstash-plugin install logstash-output-webhdfs
    

    d.编辑json文件:
    buried_point_logstash.conf

    input {
     file {
             path => "/data/buried_point/data.log"
             start_position => "beginning"
         }
    }
    
    output {
     webhdfs {
        host => "hadoop-master01"
        port => 50070
        path => "/tmp/buried-point-data-%{+YYYY-MM-dd}.log"
        user => "hdfs"
        retry_times => 100
      }
    }
    

    e.启动

    ../bin/logstash -f buried_point_logstash.conf &
    

    四、azkaban
    a. job
    buried-point-start.job

    #buried_point_data__analyze_workflow_start.job
    type=command
    user.to.proxy=spark
    command=echo "buried_point_data__analyze_workflow_start!"
    command.1=sh job/buried-point-hdfs2hive.sh "${dbName}"
    

    b. perproties
    buried-point.properties

    dbName=test
    

    c. sh
    buried-point-hdfs2hive.sh

    #!/bin/bash
    lastDay=$(date --date='1 day ago' "+%Y%m%d")
    lastDayFormat=$(date --date='1 day ago' "+%Y-%m-%d")
    dbName=$1
    #filepath=/tmp/buried-point-data-2020-09-10.log
    filepath=/tmp/buried-point-data-${lastDayFormat}.log
    /usr/hdp/current/hive-client/bin/hive -d lastDay="${lastDay}" -d file="${filepath}" -d dbName="${dbName}" -f "./sql/event_tracking.sql"
    

    d. job sql
    event_tracking.sql

    SET hive.exec.dynamic.partition=true;
    SET hive.exec.dynamic.partition.mode=nonstrict;
    
    drop table if exists ${dbName}.event_tracking;
    create table ${dbName}.event_tracking
    (
    creat_time string,
    node_id string,
    source_event_tracking STRING  COMMENT  '埋点原始数据'
    )COMMENT  '埋点原始数据表'
    ROW FORMAT DELIMITED FIELDS TERMINATED BY ' ' 
    STORED AS TEXTFILE;
    
    load data inpath "${file}" overwrite into table ${dbName}.event_tracking;
    
    select distinct_id,from_unixtime(cast(time/1000 as int)),event,properties
    from (
    SELECT explode(split(regexp_replace(regexp_replace(regexp_replace(regexp_replace(regexp_replace(source_event_tracking,'\\$',''),"\\\\",""),'\\[',''), '\\]',''),'\\}\\,\\{','\\}\\;\\{'),'\\;')) as json from  ${dbName}.event_tracking ) a
      lateral view json_tuple(a.json,'distinct_id','time','event','properties') b as distinct_id,time,event,properties;
    
    展开全文
  • vue 项目中神策埋点

    千次阅读 2020-10-09 22:15:05
    如何配置神策埋点信息? 1.安装依赖 npm install --save sa-sdk-javascript 2.项目配置 在 utils文件夹下新建sensors.js,配置单页应用的固定代码,(非单页应用不需要加上配置对象:is_track_single_page:true...
  • // 全埋点控制开关 autoTrack:{ appLaunch: true, // 默认为 true,false 则关闭 $MPLaunch 事件采集 appShow: true, // 默认为 true,false 则关闭 $MPShow 事件采集 appHide: true, // 默
  • const sensorData = { name: "sensors", server_url: "https://xxxxxxxx.i618.com.cn/sa?project=zhzqtg", // 全埋点控制开关 autoTrack: { appLaunch: true, // 默认为 true,false 则关闭 $MPLaunch 事件采集 ...
  • 【Android】神策埋点

    2019-05-22 19:44:24
    开篇感想:O(∩_∩)O~ 对于埋点,大概是我认识了一位从阿里...所以,作为一个正在进步的开发小白,我认为,只有一直学习,所以,就埋点技术,对神策的官方文档看了一下。 正文: 首先了解到 再有就是一堆的专业词...
  • 1、 埋点是什么? 埋点是数据采集领域(尤其是用户行为数据采集领域)的术语,指的是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。比如用户某个按钮点击次数、浏览某个一刻吗时长等等。 埋点...
  • 神策埋点 H5 交互

    千次阅读 2017-03-15 18:41:52
    最近公司引进第三方神策埋点,需要注意的是第三证书,查看日志,观察第三方证书是否成功 1》初始化Sensors Analytics SDK /** * 初始化 Sensors Analytics SDK */ private void initSensors(){ ...
  • 神策简介 (Sensors Data),隶属于神策网络科技(北京)有限公司,是一家专业的大...SensorsAnalytics SDK 是国内第一家开源商用版用户行为采集 SDK,目前支持代码埋点、全埋点、App 点击图、可视化全埋点等。目前已
  • 荐序:为了实现对数据的采集,可以使用三种方式:代码埋点、工具导入和全埋点。这三种方式都是手段,并且各有优缺点,选择需要完全基于实际的业务需求和现状来设计。埋点方式多种多样,按照埋点位置不同,可以分为...
  • sa-sdk-java 神策简介 神策数据 (Sensors Data),隶属于神策网络科技(北京)有限公司,是一家专业的大数据分析服务...SensorsAnalytics SDK 是国内第一家开源商用版用户行为采集 SDK,目前支持代码埋点、全埋点、Ap
  • 在使用神策分析 Web 可视化全埋点功能时,自动对即将埋点的页面进行截图,方便在神策分析的管理界面中查看。 在使用神策分析 Web 可视化埋点功能时,插件可以根据页面的埋点操作,自动对埋点页面进行截图,准确还原...
  • 数据驱动系列白皮书 Android 全埋点技术白皮书 ANDROID AUTOTRACK TECHNOLOGY WHITEPAPER 目录 02 01 全埋点概述 02 $AppViewScreen 全埋点 Application.ActivityLifecycleCallbacks 05 原理概述 06 实现步骤 06 ...
  • /** * 神策埋点kafka消息 * @author htc */ public class SensorsBurialSiteClusterEventProducer { public static Logger logger = LoggerFactory.getLogger(SensorsBurialSiteClusterEventProducer.class);...
  • 神策数据埋点埋点,也叫无埋点,无码埋点,自动埋点。全埋点是指预先收集用户的所有行为数据,然后再根据实际分析需求从中提取行为数据。。
  • 神策数据埋点

    千次阅读 2021-04-16 14:15:40
    一. 1.引入 SDK (1).下载神策官方的dome:...把神策官方dome中的sensorsdata.min.js复制到自己项目中,我这里放到里utils文件夹中 (3).在app.js文件中通过require()引入 SDK var sensors =...
  • 数据埋点神策埋点总结

    千次阅读 2019-09-11 14:28:57
    数据埋点神策埋点总结项目介绍埋点流程功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右...
  • (Sensors Data),隶属于神策网络科技(北京)有限公司,是一家专业的大数据分析服务公司,大数据分析行业开拓者,为客户提供深度用户行为分析平台、以及专业的咨询服务和行业解决方案,致力于帮助客户实现数据驱动...
  • 神策的第一篇为《从甲方角度,拆解神策》,后续要讲解实操经验,为提高阅读体验和连贯性,本篇文章将神策的实施,埋点流程,业务赋能实操,原本后3篇的内容,压缩到一篇来讲解,也能省去一些铺垫,如果有问题探讨,...
  • Vue前端神策数据埋点

    2021-05-07 18:10:24
    埋点 1、从 npm 获取 sdk npm install sa-sdk-javascript 2、utils新建sensors.js文件夹,Vue全局挂载 import sensors from 'sa-sdk-javascript'; sensors.init({ // 神策系统配置 server_url: '...
  • 1.初始化神策埋点 SAConfigOptions saConfigOptions = new SAConfigOptions(SA_SERVER_URL); //开启全埋点浏览事件 saConfigOptions.setAutoTrackEventType(SensorsAnalyticsAutoTrackEventType.APP_VIEW_SCRE

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 858
精华内容 343
关键字:

神策埋点