So verwenden Sie Nginx Lua zum Sammeln von Daten in Website-Statistiken

WBOY
Freigeben: 2023-05-28 17:32:48
nach vorne
857 Leute haben es durchsucht

Webmaster und Betreiber verwenden häufig Google Analytics, Baidu Statistics, Tencent Analytics usw. Wenn Sie Statistiken sammeln möchten, müssen Sie zunächst die Prinzipien der Datenerfassung analysieren Datenerfassungssystem.

Analyse des Datenerfassungsprinzips

Einfach ausgedrückt muss das Website-Statistikanalysetool das Verhalten von Benutzern beim Surfen auf der Zielwebsite erfassen (z. B. Öffnen einer Webseite, Klicken auf eine Schaltfläche, Hinzufügen von Produkten zum Warenkorb usw.). .) und zusätzliche Verhaltensdaten (z. B. die durch eine Bestellung generierte Bestellmenge usw.). Frühe Website-Statistiken erfassten oft nur ein Nutzerverhalten: das Öffnen einer Seite. Dann kann das Verhalten des Nutzers auf der Seite nicht erfasst werden. Diese Erfassungsstrategie kann gängige Analyseperspektiven wie grundlegende Verkehrsanalysen, Quellenanalysen, Inhaltsanalysen und Besucherattribute erfüllen. Mit der weit verbreiteten Verwendung von Ajax-Technologie und E-Commerce-Websites steigt jedoch die Nachfrage nach statistischen Analysen von E-Commerce-Zielen Diese traditionelle Sammelstrategie wird immer stärker und übersteigt ihre Möglichkeiten.
Später führte Google in seinem Produkt Google Analytics innovativ anpassbare Datenerfassungsskripte ein. Benutzer können benutzerdefinierte Ereignisse und benutzerdefinierte Indikatoren über die von Google Analytics definierte erweiterbare Schnittstelle implementieren, indem sie eine kleine Menge Javascript-Tracking und -Analyse schreiben. Derzeit haben Produkte wie Baidu Statistics und Sogou Analytics das Google Analytics-Modell kopiert.
Tatsächlich sind die Grundprinzipien und Prozesse der beiden Datenerfassungsmodi gleich, letzterer erfasst jedoch mehr Informationen über JavaScript. Werfen wir heute einen Blick auf die Grundprinzipien der Datenerfassung für verschiedene Website-Statistiktools.

Prozessübersicht

Zunächst löst das Verhalten des Benutzers eine HTTP-Anfrage vom Browser an die zu zählende Seite aus. Nehmen wir an, dass das Verhalten darin besteht, die Webseite zu öffnen. Wenn die Webseite geöffnet wird, wird das in die Seite eingebettete Javascript-Snippet ausgeführt. Freunde, die verwandte Tools verwendet haben, sollten wissen, dass Benutzer bei allgemeinen Website-Statistik-Tools ein kleines Stück Javascript-Code zur Webseite hinzufügen müssen erstellt normalerweise dynamisch ein Skript und verweist src auf eine separate JS-Datei. Zu diesem Zeitpunkt wird diese separate JS-Datei (grüner Knoten in Abbildung 1) vom Browser angefordert und ausgeführt Skript. Nachdem die Datenerfassung abgeschlossen ist, fordert js ein Back-End-Datenerfassungsskript an (Backend in Abbildung 1). Dieses Skript ist normalerweise ein dynamisches Skriptprogramm, das als Bild getarnt ist und von PHP, Python oder einer anderen Serverseite geschrieben werden kann Sprachen. Die gesammelten Daten werden über http-Parameter an das Back-End-Skript übergeben und in einem festen Format im Zugriffsprotokoll aufgezeichnet in die HTTP-Antwort an den Client eingefügt.
Das Obige ist ein allgemeiner Prozess der Datenerfassung. Im Folgenden wird Google Analytics als Beispiel verwendet, um eine relativ detaillierte Analyse jeder Phase durchzuführen.

Ausführungsphase des vergrabenen Skripts

Um Google Analytics (im Folgenden als GA bezeichnet) zu verwenden, müssen Sie ein von Google Analytics bereitgestelltes Javascript-Fragment in die Seite einfügen. Dieses Fragment wird oft als vergrabener Code bezeichnet.

wobei _gaq das globale Array von GA ist, das zum Platzieren verschiedener Konfigurationen verwendet wird. Das Format jeder Konfiguration ist:

_gaq.push([‘Action’, ‘param1’, ‘param2’, &hellip ;]);

Action gibt die Konfigurationsaktion an, gefolgt von einer Liste der zugehörigen Parameter. Der von GA bereitgestellte Standard-Einbettungscode gibt zwei voreingestellte Konfigurationen an. _setAccount wird zum Festlegen der Website-Identifikations-ID verwendet. Diese Identifikations-ID wird bei der Registrierung von GA zugewiesen. _trackPageview weist GA an, einen Seitenbesuch zu verfolgen. Weitere Konfigurationsmöglichkeiten finden Sie unter: https://developers.google.com/analytics/devguides/collection/gajs/. Tatsächlich wird dieser _gaq als FIFO-Warteschlange verwendet und der Konfigurationscode muss nicht vor dem vergrabenen Code erscheinen. Weitere Informationen finden Sie in den Anweisungen im obigen Link.
In diesem Artikel steht der Mechanismus von _gaq nicht im Mittelpunkt. Der Fokus liegt auf dem Code der dahinter liegenden anonymen Funktion. Der Hauptzweck dieses Codes besteht darin, eine externe js-Datei (ga.js) einzuführen, indem über die Methode document.createElement ein Skript erstellt und der src entsprechend dem Protokoll (http oder https) auf die entsprechende ga.js verwiesen wird, und schließlich Hinzufügen dieses Elements Einfügen in den DOM-Baum der Seite.
Beachten Sie, dass ga.async = true bedeutet, dass die externe JS-Datei asynchron aufgerufen wird, dh die Analyse des Browsers nicht blockiert wird, und sie asynchron ausgeführt wird, nachdem der externe JS-Download abgeschlossen ist. Dieses Attribut wurde in HTML5 neu eingeführt.

Ausführungsphase des Datenerfassungsskripts

Das Datenerfassungsskript (ga.js) wird nach der Anforderung ausgeführt. Dieses Skript führt im Allgemeinen Folgendes aus:
1 Sammeln Sie Informationen über die integrierten Javascript-Objekte, z. B. den Seitentitel (. über document.title), Referrer (vorherige URL, über document.referrer), Auflösung des Benutzermonitors (über windows.screen), Cookie-Informationen (über document.cookie) und andere Informationen.
2. _gaq analysieren, um Konfigurationsinformationen zu sammeln. Dazu können benutzerdefinierte Ereignisverfolgung und Geschäftsdaten (z. B. Produktnummern auf E-Commerce-Websites usw.) gehören.
3. Analysieren und verbinden Sie die in den beiden oben genannten Schritten gesammelten Daten gemäß dem vordefinierten Format.
4. Fordern Sie ein Back-End-Skript an, geben Sie die Informationen in den http-Anfrageparameter ein und übertragen Sie sie an das Back-End-Skript.
Das einzige Problem hier ist Schritt 4. Die gängige Methode für JavaScript zum Anfordern von Back-End-Skripten ist Ajax, aber Ajax kann keine domänenübergreifenden Anfragen stellen. Hier wird ga.js in der Domäne der gezählten Website ausgeführt und das Back-End-Skript befindet sich in einer anderen Domäne (das Back-End-Statistikskript von GA ist http://www.google-analytics.com/__utm.gif). und Ajax funktioniert nicht. Eine übliche Methode besteht darin, ein Image-Objekt in einem JS-Skript zu erstellen, das src-Attribut des Image-Objekts auf das Backend-Skript zu verweisen und Parameter zu übertragen. Zu diesem Zeitpunkt wird eine domänenübergreifende Anforderung an das Backend implementiert. Aus diesem Grund werden Backend-Skripte oft als GIF-Dateien getarnt. Durch die HTTP-Paketerfassung können Sie die Anforderung von ga.js an __utm.gif sehen.

Sie können sehen, dass ga.js viele Informationen liefert, wenn Sie __utm.gif anfordern. Beispielsweise ist utmsr=1280×1024 die Bildschirmauflösung, utmac=UA-35712773-1 wird von _gaq analysiert Meine GA-ID und so weiter.
Es ist zu beachten, dass __utm.gif möglicherweise nicht nur angefordert wird, wenn der eingebettete Code ausgeführt wird. Wenn die Ereignisverfolgung mit _trackEvent konfiguriert ist, wird dieses Skript auch angefordert, wenn das Ereignis auftritt.
Da ga.js komprimiert und verschleiert wurde und die Lesbarkeit sehr schlecht ist, werden wir es in der späteren Implementierungsphase nicht analysieren.

Backend-Skriptausführungsphase

GAs __utm.gif ist ein als GIF getarntes Skript. Diese Art von Back-End-Skript muss im Allgemeinen die folgenden Dinge ausführen:
1. Analysieren Sie die Informationen der http-Anforderungsparameter.
2. Erhalten Sie einige Informationen vom Server (WebServer), die der Client nicht erhalten kann, z. B. Besucher-IP usw.
3. Schreiben Sie die Informationen entsprechend dem Format in das Protokoll.
4. Generieren Sie ein 1×1 leeres GIF-Bild als Antwortinhalt und legen Sie den Inhaltstyp des Antwortheaders auf image/gif fest.
5. Legen Sie über Set-cookie einige erforderliche Cookie-Informationen im Antwortheader fest.
Der Grund, warum Cookies gesetzt werden, liegt darin, dass, wenn Sie eindeutige Besucher verfolgen möchten, der übliche Ansatz darin besteht, dass, wenn bei der Anfrage festgestellt wird, dass der Client nicht über ein bestimmtes Tracking-Cookie verfügt, entsprechend ein global eindeutiges Cookie generiert wird Die Regeln werden dem Benutzer zugewiesen, andernfalls wird das erhaltene Tracking-Cookie in das Cookie eingefügt, um das Cookie des gleichen Benutzers unverändert zu lassen (siehe Abbildung 4).

Obwohl dieser Ansatz nicht perfekt ist (Benutzer, die beispielsweise Cookies löschen oder den Browser wechseln, werden als zwei Benutzer betrachtet), handelt es sich derzeit um eine weit verbreitete Methode. Beachten Sie, dass Sie js verwenden können, um Cookies unter der Domain der zu zählenden Website zu platzieren, wenn es nicht erforderlich ist, denselben Benutzer auf verschiedenen Websites zu verfolgen (GA erledigt dies). Wenn Sie das gesamte Netzwerk einheitlich positionieren möchten, können Sie Cookies platzieren in der Serverdomäne über Back-End-Skripte (unsere Implementierung wird dies später tun).

Systemdesign und -implementierung

Basierend auf den oben genannten Prinzipien habe ich selbst ein System zur Erfassung von Zugriffsprotokollen erstellt.
Ich nenne dieses System MyAnalytics.

Bestimmen Sie die gesammelten Informationen

Der Einfachheit halber werde ich nicht das vollständige Datenerfassungsmodell von GA implementieren, sondern sammeln die Informationen.

Code für vergrabene Punkte

Code für vergrabene Punkte Ich werde aus dem GA-Modell lernen, aber derzeit ist das Konfigurationsobjekt nicht verfügbar Wird als FIFO-Warteschlange verwendet.

Ich verwende derzeit ein Statistikskript namens ma.js und habe den sekundären Domainnamen Analytics.codinglabs.org aktiviert. Natürlich gibt es hier ein kleines Problem, da ich keinen https-Server habe. Wenn der Code also auf einer https-Site bereitgestellt wird, wird es Probleme geben, aber ignorieren wir es hier.

Front-End-Statistikskript

Ich habe ein Statistikskript ma.js geschrieben, das nicht sehr vollständig ist, aber die grundlegende Arbeit abschließen kann: # 🎜🎜#

    (function () {
    var params = {};
    //Document对象数据
    if(document) {
    params.domain = document.domain || '';
    params.url = document.URL || '';
    params.title = document.title || '';
    params.referrer = document.referrer || '';
    }
    //Window对象数据
    if(window && window.screen) {
    params.sh = window.screen.height || 0;
    params.sw = window.screen.width || 0;
    params.cd = window.screen.colorDepth || 0;
    }
    //navigator对象数据
    if(navigator) {
    params.lang = navigator.language || '';
    }
    //解析_maq配置
    if(_maq) {
    for(var i in _maq) {
    switch(_maq[i][0]) {
    case '_setAccount':
    params.account = _maq[i][1];
    break;
    default:
    break;
    }
    }
    }
    //拼接参数串
    var args = '';
    for(var i in params) {
    if(args != '') {
    args += '&';
    }
    args += i + '=' + encodeURIComponent(params[i]);
    }
    //通过Image对象请求后端脚本
    var img = new Image(1, 1);
    img.src = 'http://analytics.codinglabs.org/1.gif?' + args;
    })();
Nach dem Login kopieren
Das gesamte Skript wird in einer anonymen Funktion platziert, um sicherzustellen, dass es die globale Umgebung nicht verschmutzt. Die Funktion wurde im Prinzipteil erläutert und wird nicht noch einmal beschrieben. Darunter ist 1.gif das Back-End-Skript.

Protokollformat

Das Protokoll verwendet einen Datensatz pro Zeile unter Verwendung des unsichtbaren Zeichens ^A (ASCII-Code 0x01, verfügbar unter Linux) Strg + v Strg + eine Eingabe, „^A“ wird unten verwendet, um unsichtbare Zeichen 0x01 darzustellen), das spezifische Format ist wie folgt:

Zeit^AIP^ADomänenname^AURL^ASeitentitel^AReferrer^AHohe Auflösung^ AResolution Breite^AFarbtiefe^ASprache^AClient-Informationen^ABenutzer-ID^AWebsite-ID

Backend-Skript

为了简单和效率考虑,我打算直接使用nginx的access_log做日志收集,不过有个问题就是nginx配置本身的逻辑表达能力有限,所以我选用了OpenResty做这个事情。OpenResty是一个基于Nginx扩展出的高性能应用开发平台,内部集成了诸多有用的模块,其中的核心是通过ngx_lua模块集成了Lua,从而在nginx配置文件中可以通过Lua来表述业务。关于这个平台我这里不做过多介绍,感兴趣的同学可以参考其官方网站http://openresty.org/,或者这里有其作者章亦春(agentzh)做的一个非常有爱的介绍OpenResty的slide:http://agentzh.org/misc/slides/ngx-openresty-ecosystem/,关于ngx_lua可以参考:https://github.com/chaoslawful/lua-nginx-module。
首先,需要在nginx的配置文件中定义日志格式:
log_format tick “$msec^A$remote_addr^A$u_domain^A$u_url^A$u_title^A$u_referrer^A$u_sh^A$u_sw^A$u_cd^A$u_lang^A$http_user_agent^A$u_utrace^A$u_account”;
注意这里以u_开头的是我们待会会自己定义的变量,其它的是nginx内置变量。
然后是核心的两个location:

    location /1.gif {
    #伪装成gif文件
    default_type image/gif;
    #本身关闭access_log,通过subrequest记录log
    access_log off;
    access_by_lua "
    -- 用户跟踪cookie名为__utrace
    local uid = ngx.var.cookie___utrace
    if not uid then
    -- 如果没有则生成一个跟踪cookie,算法为md5(时间戳+IP+客户端信息)
    uid = ngx.md5(ngx.now() .. ngx.var.remote_addr .. ngx.var.http_user_agent)
    end
    ngx.header['Set-Cookie'] = {'__utrace=' .. uid .. '; path=/'}
    if ngx.var.arg_domain then
    -- 通过subrequest到/i-log记录日志,将参数和用户跟踪cookie带过去
    ngx.location.capture('/i-log?' .. ngx.var.args .. '&utrace=' .. uid)
    end
    ";
    #此请求不缓存
    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 /i-log {
    #内部location,不允许外部直接访问
    internal;
    #设置变量,注意需要unescape
    set_unescape_uri $u_domain $arg_domain;
    set_unescape_uri $u_url $arg_url;
    set_unescape_uri $u_title $arg_title;
    set_unescape_uri $u_referrer $arg_referrer;
    set_unescape_uri $u_sh $arg_sh;
    set_unescape_uri $u_sw $arg_sw;
    set_unescape_uri $u_cd $arg_cd;
    set_unescape_uri $u_lang $arg_lang;
    set_unescape_uri $u_utrace $arg_utrace;
    set_unescape_uri $u_account $arg_account;
    #打开日志
    log_subrequest on;
    #记录日志到ma.log,实际应用中最好加buffer,格式为tick
    access_log /path/to/logs/directory/ma.log tick;
    #输出空字符串
    echo '';
    }
Nach dem Login kopieren

要完全解释这段脚本的每一个细节有点超出本文的范围,而且用到了诸多第三方ngxin模块(全都包含在OpenResty中了),重点的地方我都用注释标出来了,可以不用完全理解每一行的意义,只要大约知道这个配置完成了我们在原理一节提到的后端逻辑就可以了。

日志轮转

日志收集系统需要处理大量的访问日志,在时间的累积下文件规模急剧膨胀,放在同一文件中管理不便。所以通常要按时间段将日志切分,例如每天或每小时切分一个日志。我这里为了效果明显,每一小时切分一个日志。通过 crontab 定时调用一个 shell 脚本,以下是该脚本的内容:

    _prefix="/path/to/nginx"
    time=`date +%Y%m%d%H`
    mv ${_prefix}/logs/ma.log ${_prefix}/logs/ma/ma-${time}.log
    kill -USR1 `cat ${_prefix}/logs/nginx.pid`
Nach dem Login kopieren

这个脚本将ma.log移动到指定文件夹并重命名为ma-{yyyymmddhh}.log,然后向nginx发送USR1信号令其重新打开日志文件。
然后再/etc/crontab里加入一行:

59 * * * * root /path/to/directory/rotatelog.sh
Nach dem Login kopieren

在每个小时的59分启动这个脚本进行日志轮转操作。

测试

下面可以测试这个系统是否能正常运行了。我昨天就在我的博客中埋了相关的点,通过http抓包可以看到ma.js和1.gif已经被正确请求。
同时可以看一下1.gif的请求参数。
相关信息确实也放在了请求参数中。
然后我tail打开日志文件,然后刷新一下页面,因为没有设access log buffer, 我立即得到了一条新日志:
1351060731.360^A0.0.0.0^Awww.codinglabs.org^Ahttp://www.codinglabs.org/^ACodingLabs^A^A1024^A1280^A24^Azh-CN^AMozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4^A4d612be64366768d32e623d594e82678^AU-1-1
注意实际上原日志中的^A是不可见的,这里我用可见的^A替换为方便阅读,另外IP由于涉及隐私我替换为了0.0.0.0。

关于分析

通过上面的分析和开发可以大致理解一个网站统计的日志收集系统是如何工作的。有了这些日志,就可以进行后续的分析了。本文只注重日志收集,所以不会写太多关于分析的东西。
注意,原始日志最好尽量多的保留信息而不要做过多过滤和处理。例如上面的MyAnalytics保留了毫秒级时间戳而不是格式化后的时间,时间的格式化是后面的系统做的事而不是日志收集系统的责任。后面的系统根据原始日志可以分析出很多东西,例如通过IP库可以定位访问者的地域、user agent中可以得到访问者的操作系统、浏览器等信息,再结合复杂的分析模型,就可以做流量、来源、访客、地域、路径等分析了。当然,一般不会直接对原始日志分析,而是会将其清洗格式化后转存到其它地方,如MySQL或HBase中再做分析。
分析部分的工作有很多开源的基础设施可以使用,例如实时分析可以使用Storm,而离线分析可以使用Hadoop。当然,在日志比较小的情况下,也可以通过shell命令做一些简单的分析,例如,下面三条命令可以分别得出我的博客在今天上午8点到9点的访问量(PV),访客数(UV)和独立IP数(IP):

    awk -F^A '{print $1}' ma-2012102409.log | wc -l
    awk -F^A '{print $12}' ma-2012102409.log | uniq | wc -l
    awk -F^A '{print $2}' ma-2012102409.log | uniq | wc -l
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonSo verwenden Sie Nginx Lua zum Sammeln von Daten in Website-Statistiken. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:yisu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!