GIF埋点方案

1. 方案介绍

所谓“埋点”,是数据采集领域(尤其是用户行为数据采集领域)的术语。指的是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。 埋点的技术实质,是先监听软件应用运行过程中的事件,当需要关注的事件发生时进行判断和捕获。本文主要介绍nginx,logstash-output-datahub,odps来实现埋点。

上图的流程是这样的,应用推送规定的参数到埋点服务器,nginx接收埋点信息,将其转换成json文件保存到服务器上,然后logstash读取json文件,经过过滤将其推送到datahub,最后odps定时去datahub中拉取埋点数据。

注:这里为什么选择gif文件返回,最小的BMP文件需要74个字节,PNG需要67个字节,而合法的GIF,只需要43个字节。同样的响应,GIF可以比BMP节约41%的流量,比PNG节约35%的流量。

2. 方案优势

传统的埋点方案:开发人员编写java埋点应用,通过post的方式获取埋点信息,再推送到datahub。

与传统的埋点方案相比,这个方案有以下几点优势

2.1. 响应速度快

2.2. 防止跨域

一般而言,埋点域名都不是当前域名,所以所有的接口请求都会构成跨域。而跨域请求很容易出现由于配置不当被浏览器拦截并报错,这是不能接受的。但图片的src属性并不会跨域,并且同样可以发起请求。(排除接口上报)

2.3. 防止阻塞页面加载,影响用户体验

通常,创建资源节点后只有将对象注入到浏览器DOM树后,浏览器才会实际发送资源请求。反复操作DOM不仅会引发性能问题,而且载入js/css资源还会阻塞页面渲染,影响用户体验。

但是图片请求例外。构造图片打点不仅不用插入DOM,只要在js中new出Image对象就能发起请求,而且还没有阻塞问题,在没有js的浏览器环境中也能通过img标签正常打点,这是其他类型的资源请求所做不到的。(排除文件方式)

3. 安装教程

3.1. 第一步:配置nginx

由于公司ecs镜像都有nginx,因此安装nginx的教程省略....此处主要讲解一下nginx配置文件的设置。

#auto_report日志输出格式
log_format  auto_report '{"trackTime": "$time_iso8601", '
                        '"trackid": "$arg_trackid", '
                        '"uuid": "$arg_uuid", '
                        '"accessKeyId": "$arg_accessKeyId", '
                        '"libVersion": "$arg_libVersion", '
                        ' }';
#login_report日志输出格式
log_format  login_report  '{"trackTime": "$time_iso8601", '
                        '"trackid": "$arg_trackid", '
                        '"uuid": "$arg_uuid", '
                        '"accessKeyId": "$arg_accessKeyId", '
                        '"userType": "$arg_userType", '
                        '"userId": "$arg_userId", '
                        '"userName": "$arg_userName", '
                        '"idCard": "$arg_idCard", '
                        '"belong": "$arg_belong", '
                        '"UA": "$arg_UA", '
                        '"referer": "$arg_referer", '
                        '"url": "$arg_url", '
                        '"pageName": "$arg_pageName", '
                        '"pageLevel": "$arg_pageLevel", '
                        '"libVersion": "$arg_libVersion", '
                        ' }';
#获取埋点时间yyyyMMdd
map $time_iso8601 $logdate {
		'~^(?<ymd>\d{4}-\d{2}-\d{2})' $ymd;
		default    'date-not-found';
}
server {
      listen       8123;
      server_name  127.0.0.1;
      charset utf-8;
      client_max_body_size 200m;
      #charset koi8-r;
      # 静态页面目录
		  root   /home/md;
     	index  index.html;
      location /md/auto.gif {
          log_subrequest on;
          #json的输出路径
          access_log /home/md/log/auto_report_$logdate.json auto_report;
          #返回一个空的文件
          add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";
          add_header Pragma "no-cache";
          add_header Cache-Control "no-cache, max-age=0, must-revalidate";
          #返回一个1×1的空gif图片
          empty_gif;
			}
		  location /md/login.gif {
          log_subrequest on;
          #json的输出路径
          access_log /home/md/log/login_report_$logdate.json login_report;
          #返回一个空的文件
          add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";
          add_header Pragma "no-cache";
          add_header Cache-Control "no-cache, max-age=0, must-revalidate";
          #返回一个1×1的空gif图片
          empty_gif;
      }
}

将这个文件放到指定的路径下, 重启nginx即可。

做完这一步你可以尝试触发一下,然后再json的输出路径下看一下是否有json文件生成。

注意:配置文件37行,root /home/md; 这个路径配置错误的话,则不会生成json文件,但是./nginx -t时通过的,作者的血泪史

3.2. 第二步:安装logstash-output-datahub

3.2.1. 一键安装

阿里云提供了免安装下载:点此下载

然后解压即可使用

3.2.2. 单独安装

安装Logstash: 参看Logstash官网提供的[安装教程]进行安装工作。特别注意的是,最新的Logstash需要Java 7及以上版本。安装DataHub插件: 下载所需要的插件。

上传至DataHub请使用: DataHub Logstash Output插件

使用如下命令进行安装:

$ {LOG_STASH_HOME}/bin/logstash-plugin install --local logstash-output-datahub-1.0.10.gem
$ {LOG_STASH_HOME}/bin/logstash-plugin install --local logstash-input-datahub-1.0.10.gem

LOG_STASH_HOME:指安装logstash的路径

如果安装时遇到类似如下错误:

WARNING: can not set Session#timeout=(0) no session context

先确认机器是否能够访问外网。网络能通的情况下,可以尝试修改为国内的镜像源。 https://gems.ruby-china.com/

注意:此处强烈推荐一键安装,有些项目的服务器不允许访问外网

3.3. 第三步:配置logstash的配置文件

#读取json文件
input {
    file {
        path => ["/home/md/log/auto_report_*.json"]
        type => "auto"
        start_position => "beginning"
        #点位存储位置
        sincedb_path => "/home/md/sincedb/filedatahub"
        codec => json {
            charset => "UTF-8"
        }
    }
    file {
        path => ["/home/md/log/login_report_*.json"]
        type => "login"
        start_position => "beginning"
        #点位存储位置
        sincedb_path => "/home/md/sincedb/filedatahub"
        codec => json {
            charset => "UTF-8"
        }
    }
}
#过滤器
filter {
  if [type] == "auto"{
    mutate {
      #json到datahub字段映射
      rename => {
        "trackTime"        =>    "tracktime"
        "trackid"        =>    "trackid"
        "uuid"        =>    "uuid"
        "accessKeyId"        =>    "accesskeyid"
        "libVersion"        =>    "libversion"
      }
    }
  }
  if [type] == "login"{
    mutate {
      rename => {
        "trackTime"        =>    "tracktime"
        "trackid"        =>    "trackid"
        "uuid"        =>    "uuid"
        "accessKeyId"        =>    "accesskeyid"
        "userType"        =>    "usertype"
        "userId"        =>    "userid"
        "userName"        =>    "username"
        "idCard"        =>    "idcard"
        "belong"        =>    "belong"
        "UA"        =>    "ua"
        "referer"        =>    "referer"
        "url"        =>    "url"
        "pageName"        =>    "pagename"
        "pageLevel"        =>    "pagelevel"
        "libVersion"        =>    "libversion"
      }
    }
  }
}
output {
	if [type] == "auto"{
		datahub {
			access_id => "xxxx"
			access_key => "xxxxx"
			endpoint => "http://xxxxxxxx"
			project_name => "xxxxx"
			topic_name => "xxxxx"
			dirty_data_continue => true
			dirty_data_file => "/usr/local/logstash-2/data/auto_dirty.log"
			dirty_data_file_max_size => 1000
		}
	}
  if [type] == "login"{
		datahub {
			access_id => "xxxxx"
			access_key => "xxxxx"
			endpoint => "http://xxxxxxxx"
			project_name => "xxxxx"
			topic_name => "xxxxx"
			dirty_data_continue => true
			dirty_data_file => "/usr/local/logstash-2/data/login_dirty.log"
			dirty_data_file_max_size => 1000
		}
	}
}

注意:第8,18行,sincedb_path => "/home/md/sincedb/filedatahub"必须要配,并且filedatahub是文件,不是文件夹

4. 优化点

4.1. nginx时间点优化

nginx的$time_iso8601默认时间格式是2022-07-21T12:46:11+08:00,如果你想要把它转换成yyyy-MM-dd HH:mm:ss这种格式的话,需要进行以下操作。

首先修改ngx_http_log_module.c文件(src/http/modules/ngx_http_log_module.c):b

{ ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1,
更改后
{ ngx_string("time_iso8601"), sizeof("1970-09-28 12:00:00") - 1, 

然后修改ngx_times.c文件(src/core/ngx_times.c):st

[sizeof("1970-09-28T12:00:00+06:00")];
更改后
[sizeof("1970-09-28 12:00:00")]; 



ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1;
更改成
ngx_cached_http_log_iso8601.len = sizeof("1970-09-28 12:00:00") - 1;



(void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",  
                    tm.ngx_tm_year, tm.ngx_tm_mon,  
                    tm.ngx_tm_mday, tm.ngx_tm_hour,  
                    tm.ngx_tm_min, tm.ngx_tm_sec,  
                    tp->gmtoff < 0 ? '-' : '+',  
                    ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); 
更改成
(void) ngx_sprintf(p3, "%4d-%02d-%02d %02d:%02d:%02d",  
                    tm.ngx_tm_year, tm.ngx_tm_mon,  
                    tm.ngx_tm_mday, tm.ngx_tm_hour,  
                    tm.ngx_tm_min, tm.ngx_tm_sec); 

最后执行make && make install指令即可

注意:要先执行./nginx -s stop,然后再启动nginx

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值