在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干的一件事,同时系统正常运行过程中必要的日志打印也是必须的。
在笔者刚接触java程序的时候,打印日志经常使用到到下面的代码,
System.out.println("hello log");
我相信在不了解日志系统的前提下使用上述的方式是最多的,同时也是新手小白最常用的方式,笔者曾经也是使用最多的。那么除了上述的方式还有其他的方式吗?答案是肯定的
在java的API中提供了一套日志打印的方法,java程序人员在设计之初已经想到了这方面的功能,所以从JDK1.4起提供了日志打印的API,只不过被大多数人忽略了。这套API在java.util.logging包下,使用该种方式不需要引任何的jar,只要在java环境下即可使用。
如上图,是java提供的日志的一些类。使用方法类似下面的代码,
public static Logger logger=Logger.getLogger(Test.class.toString());
logger.info("hello log");
注意Logger的路径是java.util.logging.Logger。
log4j是apache的一个项目,其中又分为log4j1和log4j2,所谓log4j1指的就是其大版本号为1,不过log41在很早之前就已经停止更新了,源码官网:https://github.com/apache/logging-log4j1
可以看的在2012年已经停止更新了,也就是说现在通常来说使用的log4j都是log4j2,更确切的说是log4j,为了准确期间,这里还是和之前的版本进行区分,使用log4j2的名字,log4j2是在log4j1基础上的升级,并吸收了logback这个框架的优秀之处且修复了其很多问题,可以说log4j2是一个优秀的日志框架,其源码官网:https://github.com/apache/logging-log4j2
官网:https://logging.apache.org/log4j/2.x/index.html
log4j2的maven依赖如下,引入log4j-api和log4j-core即可,
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.17.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.17.1</version>
</dependency>
这里有个问题要注意,log4j1和log4j2的groupId是不一样的,log4j1的是org.apache.log4j,log4j2的是org.apache.logging.log4j,带来的变化就是在使用的过程中要注意引用的类的路径,从路径上可以确定是使用的log4j1.x还是log4j2.x,如果是org.apache.log4j开头的包路径那么是版本1的,是org.apache.logging.log4j开头的是版本2的。
使用方式类似如下,
private static final Logger logger=LogManager.getLogger();
logger.info();
logback是一个开源的日志框架,是log4j的作者为了代替log4j而开发的。logback包含三部分,logback-core、logback-classic、logback-access,logback-core是其他两个模块的核心,常用到的是logback-core+logback-classic。logback-access常和jetty和tomcat结合。
logback的groupId为ch.qos.logback,其maven依赖如下
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.10</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
</dependency>
<!--平时用不到,可不引入-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.2.10</version>
</dependency>
使用方法可参考:https://www.jianshu.com/p/3e3b550920b3
其官网:https://logback.qos.ch/index.html
slf4j不能称之为一个日志框架,因为它仅仅提供了一系列的标准,提供一系列接口,但没有实现,采用的是门面模式。
其依赖为:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>
上面便是slf4j的核心包。
注意:如果使用slf4j出现下面的日志
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
说明没有日志实现框架,slf4j自己实现了一个日志框架,可以加上下面的依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
slf4j可以和其他具体的日志实现框架进行结合使用,如下
上图是一个slf4j和其他日志框架结合的图形展示,
slf4j+logback
需要slf4j-api、logback-api、logback-classic三个包
slf4j+JDK日志
需要slf4j-api、slf4j-jdk14,其中slf4j-jdk14是slf4j和JDK日志结合的jar。
slf4j+log4j
需要slf4j+slf4j-log4j12
slf4j+JCL
需要slf4j、common-logging
其官网:https://www.slf4j.org/
JCL是Jakarta Commons Logging的简写,又叫Apache Commons Logging,提供的是一个 Java 的日志接口,同时兼顾轻量级和不依赖于具体的日志实现工具。它提供给中间件/日志工具开发者一个简单的日志操作抽象,允许程序开发人员使用不同的具体日志实现工具。用户被假定已熟悉某种日志实现工具的更高级别的细节。JCL提供的接口,对其它一些日志工具,包括Log4J, Avalon LogKit, and JDK 1.4等,进行了简单的包装,此接口更接近于Log4J和LogKit的实现。
其包为common-logging.jar包含了所有的功能,还有其他另外两个包common-logging-api、common-logging-adapters
官网:https://commons.apache.org/proper/commons-logging/guide.html
本文简单总结了java中常用的日志,其中slf4j和JCL是日志的接口,又都进行了简单实现,既可以自己单独使用,又可以和其他实现日志框架结合使用,如,log4j、logback、JDK logging等。
来源:https://www.cnblogs.com/teach/p/15887258.html
ogstash 是一个开源的数据收集引擎,它具有备实时数据传输能力。它可以统一过滤来自不同源的数据,并按照开发者的制定的规范输出到目的地。顾名思义,Logstash 收集数据对象就是日志文件。由于日志文件来源多(如:系统日志、服务器日志、网络设备日志等),且内容杂乱,不便于人类进行观察。因此,我们可以使用 Logstash 对日志文件进行收集和统一过滤,变成可读性高的内容,方便开发者或运维人员观察,从而有效的分析系统/项目运行的性能,做好监控和预警的准备工作等。
Logstash 通过管道进行运作,管道有两个必需的元素,输入和输出,还有一个可选的元素,过滤器。输入插件从数据源获取数据,过滤器插件根据用户指定的数据格式修改数据,输出插件则将数据写入到目的地。在实际工作中Logstash数据收集的一个流程大概是:数据源→通过input插件(如file、redis、stdin)→output插件→写到Elasticsearch。
下面我通过ELK平台收集下图所示的日志,举例说明Logstash是怎么收集一些常用各类日志的。这些日志对zabbix服务器的正常运行至关重要,这也是大部分应用系统正常运行会包含的一些日志。关于ELK的搭建可以参考快速搭建ELK日志分析平台,对zabbix监控技术有兴趣的同学可以参考搭建Zabbix监控系统部署详细步骤。
1.file插件收集日志文件
在zabbix服务器172.18.20.28上编辑logstash配置文件,并将收集到的zabbix_server.log文件数据提交到elasticsearch中:
#cat logstash-zabbixserver.conf input { file{ path=> " /var/log/zabbix/zabbix_server.log" #文件路径 type=> "zabbix-server" #类似打个标记,自定义 start_position=> "beginning" #文件头部读取,相反还有end } } output { elasticsearch { hosts=> ["172.28.29.211:9200"] #输出到elasticsearch index=> "zabbix-%{+YYYY.MM.dd}" #按年月日格式生成索引 } }
运行logstash:
/usr/local/logstash-6.2.4/bin/logstash -f logstash-zabbixserver.conf
在elasticsearch上查看数据:
2. if判断收集多个日志
现在需要在收集另外一个日志文件mariadb.log,我们修改logstash配置文件使用if判断进行收集:
#cat logstash-zabbixserver.conf input { file{ path=> " /var/log/zabbix/zabbix_server.log" type=> "zabbix-server" start_position=> "beginning" } file{ path=> " /var/log/mariadb/mariadb.log" type=> "mysql" start_position=> "beginning" } } output { if [type]==" zabbix-server " { #根据type来匹配 elasticsearch { hosts=> ["172.28.29.211:9200"] index=> " zabbix -%{+YYYY.MM.dd}" } } if [type]==" mysql " { elasticsearch { hosts=> ["172.28.29.211:9200"] index=> " zabbix-mysql -%{+YYYY.MM}" #按年月 } } }
再次运行logstash:
/usr/local/logstash-6.2.4/bin/logstash -f logstash-zabbixserver.conf
在elasticsearch上查看另一个收集的日志数据:
3.syslog插件收集系统网络日志
syslog默认是通过514端口去发送日志,可以使用logstash安装对应的syslog插件,监听514端口来收集日志。如果只是监听系统日志可以不用安装logstash的agent,只需要监听对应的514端口,收集系统数据即可。logstash在INPUT插件中提供了syslog的模块,可以用于不安装本地日志收集agent的设备(如硬件防火墙等),当然支持此类协议的普通服务器也适用。
注意:此INPUT插件会同时监听TCP和UDP端口。
服务器rsyslog收集
创建编辑logstash-syslog配置文件,使用syslog插件:
#cat logstash-syslog.conf input { syslog { type=> "system-syslog" port=> 514 #默认为514端口,可自行修改 } } output { elasticsearch { hosts=> ["172.28.29.211:9200"] #输出到elasticsearch index=> "zabbix-syslog-%{+YYYY.MM}" #名称按年月保存收集 } }
运行logstash:
/usr/local/logstash-6.2.4/bin/logstash -f logstash-syslog.conf
重新开启一个窗口,查看服务是否启动:
# netstat –ntlp | grep 514 tcp6 0 0 :::514 :::* LISTEN 21544/java
修改rsyslog配置文件:
# vi /etc/rsyslog.conf … #*.* @@remote-host:514 *.* @@172.18.20.28:514 #添加远程syslog服务器IP,这里是本机
重启rsyslog:
systemctl restart rsyslog
在elasticsearch上查看收集到的服务器rsyslog日志:
网络设备syslog收集
收集交换机网和防火墙syslog日志,配置如下:
#cat wl-syslog.conf input{ syslog { type=> "wl-syslog" port=> 514 } } output { if [host]=="172.18.20.254"{ #根据host来匹配生成相应的索引 elasticsearch { hosts=> ["172.28.29.211:9200"] index=> "jhj-%{+YYYY.MM}" } } if [host]=="172.18.16.254"{ elasticsearch { hosts=> ["172.28.29.211:9200"] index=> "fhq-%{+YYYY.MM}" } } }
相应的网络设备上开启并指定syslog服务器,以Cisco设备为例:
logging on logging host 172.28.29.211
在elasticsearch上查看收集这两台网络设备的日志:
4.grok插件收集Apache访问日志
一般系统或服务生成的日志都是一大长串。每个字段之间用空格隔开。logstash在获取日志是整个一串获取,如果把日志中每个字段代表的意思分割开来在传给elasticsearch。这样呈现出来的数据更加清晰,而且也能让kibana更方便的绘制图形。Grok是Logstash最重要的插件。它的主要作用就是将文本格式的字符串,转换成为具体的结构化的数据,配合正则表达式使用。
grok事先已经预定义好了许多正则表达式规则,该规则文件存放路径:
/usr/local/logstash-6.2.4/vendor/bundle/jruby/2.3.0/gems/logstash-patterns- core-4.1.2/patterns
grok插件语法说明, 以一个简单的访问日志为例:
55.3.244.1 GET /index.html 15824 0.043
这条日志可切分为5个部分,IP(55.3.244.1)、方法(GET)、请求文件路径(/index.html)、字节数(15824)、访问时长(0.043) ,如果不做拆分的话Kibana里会将所有内容都写在messages字段里。如果我们想把不同字段做分类的话,就可以用grok来进行定义,在默认配置文件里其实很多配置都已经写好了,只需要引用下:
%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}
大写的单词是预定义的正则表达式,可以在grok-patterns文件看到其具体匹配的内容。如果匹配的话,就将该字段名称重新定义为冒号后面的小写的单词。用上面那条访问日志的客户端IP来说明,它将在Kibana里被定义为client字段并单独显示出来,而不是全部塞在了message里。
写到filter中:
filter { grok { match=> { "message"=> "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}"} } }
解析后:
client: 55.3.244.1 method: GET request: /index.html bytes: 15824 duration: 0.043
下面是一条zabbix服务器Apache日志:
192.168.33.203 - - [11/Jul/2018:09:37:07 +0800] "POST /zabbix/jsrpc.php?output=json-rpc HTTP/1.1" 200 65 "http://192.168.33.29/zabbix/zabbix.php?action=dashboard.view" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:61.0) Gecko/20100101 Firefox/61.0"
创建编辑logstash-apache配置文件,使用filter中的grok插件:
# cat logstash-apache.conf input{ file{ path=> "/etc/httpd/logs/access_log" type=> "apache" start_position=> "beginning" } } filter{ if[type]=="apache"{ grok{ match=> {"message"=> "%{COMBINEDAPACHELOG}"} } } } output{ if[type]=="apache"{ elasticsearch{ hosts=> ["172.28.29.211:9200"] index=> "zabbix_apache-%{+YYYY.MM}" } } } #fileter中的message代表一条一条的日志,%{COMBINEDAPACHELOG}代表解析日志的正则表达式
运行logstash:
/usr/local/logstash-6.2.4/bin/logstash -f logstash-apache.conf
在elasticsearch上查看收集到的Apache日志:
整合到一个logstash配置文件运行
我们已成功收集到各项日志,现在我们需要将这些单独的logstash配置文件整合到一个配置文件中,配置如下:
#cat logstash-all.conf input { syslog{ type=> "system-syslog" port=> 514 } file{ path=> "/var/log/zabbix/zabbix_server.log" type=> "zabbix-server" start_position=> "beginning" } file{ path=> "/var/log/mariadb/mariadb.log" type=> "mysql" start_position=> "beginning" } file{ path=> "/etc/httpd/logs/access_log" type=> "apache" start_position=> "beginning" } } filter{ if[type]=="apache"{ grok{ match=> {"message"=> "%{COMBINEDAPACHELOG}"} } } } output { if [type]=="system-syslog" { elasticsearch { hosts=> ["172.28.29.211:9200"] index=> "zabbix-syslog-%{+YYYY.MM}" } } if [type]=="zabbix-server" { elasticsearch { hosts=> ["172.28.29.211:9200"] index=> "zabbix _server-%{+YYYY.MM}" } } if [type]=="mysql" { elasticsearch { hosts=> ["172.28.29.211:9200"] index=> "zabbix-mysql -%{+YYYY.MM}" } } if[type]=="apache"{ elasticsearch{ hosts=> ["172.28.29.211:9200"] index=> "zabbix_apache-%{+YYYY.MM}" } } }
至此我们配置完成收集到所有zabbix服务器上日志的logstash文件,最后在后台运行logstash:
# nohup /usr/local/logstash-6.2.4/bin/logstash -f logstash-all.conf -w 4 &
Kibana上日志展示
Kibana是为Elasticsearch提供的可视化平台,负责数据的美观展示。Kibana服务默认监控在5601端口,浏览器访问http://IP:5601可以打开Kibana的界面。左侧导航栏有很多选项,Discover用于和Elasticsearch交互和展示搜索结果,Visualize用于报表生成。
我们新建一个收集zabbix-sever的运行日志。点击工具栏中的Management --> 选择index patterns --> 点击Create Index Pattern按钮。
然后选择一个包含了时间戳的索引字段,可以用来做基于时间的处理。Kibana会读取索引的映射,然后列出所有包含了时间戳的字段。
点击create之后,创建完成。
在DISCOVER就可以选择查看并搜索相应的日志了。
同理我们创建其他的日志,可以在discover左边栏选择fields更加美观的展示日志。
埋点是数据采集的专用术语,在数据驱动型业务中,如营销策略、产品迭代、业务分析、用户画像等,都依赖于数据提供决策支持,希望通过数据来捕捉特定的用户行为,如按钮点击量、阅读时长等统计信息。因此,数据埋点可以简单理解为:针对特定业务场景进行数据采集和上报的技术方案。
数据埋点非常看重两件事,一个是数据记录的准确性,另一个则是数据记录的完备性。
先讲数据的准确性。数据埋点非常强调规范和流程,因为参数的规范与合法,将直接影响到数据分析的准确性,如果准确性得不到保障,那么所有基于埋点得出的结论,都是不可信的。辛辛苦苦做了很久的方案,一旦因为一个疏忽的小问题,导致下游集中投诉,其实非常划不来。
道理每个人都懂,但现实情况中,数据埋点所面对的客观环境,其实非常复杂,例如:
因此本文有非常长的篇幅来写流程问题,其实是非常有必要的。
再讲数据的完备性。因为埋点主要是面向分析使用,对用户而言是个额外的功能,因此埋点的业务侵入性很强,很容易对用户体验造成影响。别的不说,仅仅是流量的消耗,就很容被用户喷。因此,要提前想清楚,我们要采集哪些东西,因为修改方案的成本,是伤不起的。
通常情况下,我们需要记录用户在使用产品过程中的操作行为,通过4W1H模型可以比较好的保障信息是完备的。4W1H包括:
规定好记录信息的基本方法之后,按照固定的频率,如每小时、每天,或者是固定的数量,比如多少条日志,或者是网络环境,比如在Wifi下上传,我们就可以开心的把埋点数据用起来了。
当然,数据记录的时效性也比较重要,但因为埋点数据通常量级会比较大,且各个端数据回传的时间不同,因此想做到实时统计,还是需要分场景来展开。在Flink技术日渐成熟的今天,全链路的实时采集与统计,已经不是什么难题。
在埋点的技术方案中,首先要重视的,是用户唯一标识的建设。如果做不到对用户的唯一识别,那么基础的UV统计,都将是错误的。
因此,在数据埋点方案中,有两个信息是一定要记录的,即设备ID+用户ID。设备ID代表用户使用哪个设备,如安卓的ANDROID_ID/IMEI,IOS中的IDFA/UDID,浏览器的Cookie,小程序的OpenID等。用户ID,代表用户在产品中所注册的账号,通常是手机号,也可以是邮箱等其他格式。
当这两个信息能够获得时,不论是用户更换设备,或者是同一台设备不同账号登录,我们都能够根据这两个ID,来识别出谁在对设备做操作。
其次,我们来看一下Web的数据采集技术。Web端数据采集主要通过三种方式实现:服务器日志、URL解析及JS回传。
浏览器的日志采集种类又可以分为两大类:页面浏览日志和页面交互日志。
除此之外,还有一些针对特定场合统计的日志,例如页面曝光时长日志、用户在线操作监控等,但原理都基于上述两类日志,只是在统计上有所区分。
再次,我们来看下客户端的数据采集。与网页日志对应的,是手机应用为基础的客户端日志,由于早期手机网络通讯能力较差,因而SDK往往采用延迟发送日志的方式,也就是先将日志统计在本地,然后选择在Wifi环境下上传,因而往往会出现统计数据延迟的情况。现如今网络环境好了很多,4G、5G流量充足,尤其是视频类APP基本上都是一直联网,因而很多统计能够做到实时统计。
客户端的日志统计主要通过SDK来完成,根据不同的用户行为分成不同的事件,“事件”是客户端日志行为的最小单位,根据类型的不同,可以分为页面事件(类比页面浏览)和控件点击事件(类比页面交互)。对于页面事件,不同的SDK有不同的方式,主要区别为是在页面创建时发送日志,还是在页面浏览结束后发送日志,区别在于业务统计是否需要采集用户的页面停留时长。
页面事件的统计主要统计如下三类信息:
最后,我们还需要考虑小程序等场景的埋点方案,小程序通常情况下,开发者会声明好相应的方法,按照需求调用即可,例如微信提供了API上报和填写配置两种方案。
埋点其实还需要考虑数据上传的方案,批量的数据可以通过Flume直接上报,流式的可以写到Kafka,或者直接使用Flink来处理。这些框架相关的内容不是本文考虑的重点,有兴趣的可以自行查阅资料。
有了指导思路和技术方案后,我们就可以着手制定相应的数据埋点流程规范了。
笼统上,流程规范会分成五个步骤,即需求评审、埋点申请、技术开发、埋点验证、发布上线。
第一步,需求评审。
前文提到过,数据埋点的方案一旦确定,返工和排查问题的成本都很高,但数据埋点之后的分析工作,又涉及到了PD、BI、算法、数据等多个角色。因此非常有必要,将需求内容和数据口径统一收口,所有人在一套口径下,将需求定义出来,随后业务侧再介入,进行埋点方案的设计和开发。
以前文提到的4W1H模型为例,常见的记录内容如下:
最后我们统计时,按照上述约定,统计用户在某个时间和地点中,看到了哪些信息,并完成了怎样的动作。上下游的相关人员,在使用这份数据时,产生的歧义或者是分歧,会小很多。
第二步,埋点申请。
当下的热门应用,大多是以超级APP的形式出现,比如微信、淘宝、支付宝、抖音,超级APP会承载非常多的业务,因此技术方案上会十分统一。
因此,当我们的技术方案确定后,通常要在相应的埋点平台上,进行埋点申请。申请的内容包括分配的SPM、SCM码是什么,涉及到的平台是哪些,等等。SPM、SCM是什么,有什么用,同样可以自行查阅。
第三步,技术开发。
当需求确定、申请通过后,我们就可以开始开发动作了,这里基本上是对研发同学进行约束。埋点的开发,简单讲,是分成行为埋点和事件埋点两个大类,每一类根据端的不同进行相应的开发。具体的技术方案详见前文01章节。
详细的设计规范,是需要留文档的,因为代码不能反应业务的真实意图,而不论是事后复盘与业务交接,都需要完整的文档来阐述设计思路。
第四步,埋点验证。
埋点的验证很关键,如果上线后才发现问题,那么历史数据是无法追溯的。
验证有两种方式,一种是实时的功能验证,一种是离线的日志验证。
实时功能验证,指功能开发好后,在灰度环境上测试相应的埋点功能是否正常,比如点击相应的业务模块,日志是否会正确的打印出来。通常而言,我们需要验证如下三个类型的问题:
除去实时验证,我们也需要把日志写到测试环境中,查看数据上报的过程是否正确,以及对上报后的数据进行统计,侧面验证记录的准确性,如统计基本的PV、UV,行为、事件的发生数量。
很多时候,数据是需要多方验证的,存在一定的上下游信息不同步问题,比如对某个默认值的定义有歧义,日志统计会有效的发现这类问题。
第五步,发布上线。
应用的发布上线通常会有不同的周期,例如移动端会有统一的发版时间,而网页版只需要根据自己的节奏走,因此数据开始统计的时间是不同的。最后,应用应当对所有已发布的埋点数据,有统一的管理方法。
大多数时候,数据埋点的技术方案,只需要设计一次,但数据准确性的验证,却需要随着产品的生命周期持续下去,因此仅仅依靠人肉来准确性验证是不够的,我们需要平台来支持自动化的工作。埋点的准确性,大体有两种方法保障:一种是灰度环境下验证真实用户数据的准确性;另一种则是在线上环境中,验证全量数据的准确性。因此,发布上线之后,后续的管理动作,应该是对现有流程的自动化管理,因为团队大了,需要埋点的东西多种多样,让平台自己测试、自动化测试,就是很多测试团队必须走的路。
目前行业中,已经有很多比较成熟的数据统计平台,大家对于数据埋点也都有自己的方案。常见的有:GrowingIO、神策数据、百度统计、谷歌分析、友盟等。官网都有比较详细的介绍,这里不再赘述。
数据埋点只是技能的一种,通过埋点的数据,如何去做分析,其实也很重要。做过互联网的同学,基本都会有自己的宝藏库,来看看业界的同行都是如何分析问题的,著名的如艾瑞咨询的数据报告。其实再高大上的报告,归根结底,也是通过数据+模型来分析得到的结论。
最后说说自己做数据埋点方案的利弊。一些流量型的业务模型,使用第三方是没有问题的,因为第三方通常提供了很强大、很完备的功能,稳定性也有保障,但缺点是,无法做平台规则之外的数据埋点。但如果业务数据是非常敏感的,比如金融相关,那么还是建议自己做技术方案,且现有的数据埋点方法,都是基于流量分析平台来做的,对于一些偏传统的业务场景,其实并不是非常适用。
最后,数据埋点,只是一种技术或者是工具,想要得出有价值的分析成果,需要有有科学的分析模型做指导,也需要有正确的学习路线来坚持。
*请认真填写需求信息,我们会在24小时内与您取得联系。