欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文教會(huì)你使用Nginx訪問(wèn)日志統(tǒng)計(jì)PV與UV

 更新時(shí)間:2022年05月05日 11:42:42   作者:刷題刷到手抽筋  
做網(wǎng)站的都知道,平常經(jīng)常要查詢下網(wǎng)站PV、UV等網(wǎng)站的訪問(wèn)數(shù)據(jù),所以下面這篇文章主要給大家介紹了關(guān)于如何使用Nginx訪問(wèn)日志統(tǒng)計(jì)PV與UV的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

一個(gè)網(wǎng)站當(dāng)用戶量增大時(shí)候,不可避免有統(tǒng)計(jì)pv和uv的需求。

  • UV(Unique Visitor):獨(dú)立訪客,以cookie為依據(jù)區(qū)分不同訪客,UV計(jì)算一天之內(nèi)(00:00-24:00),訪問(wèn)網(wǎng)站的訪客數(shù)量。
  • PV(Page View):頁(yè)面訪問(wèn)量,同一個(gè)用戶對(duì)頁(yè)面多次訪問(wèn)累計(jì)。

本文介紹一種通過(guò)分析nginx日志統(tǒng)計(jì)pv、uv的方法。

一、方案設(shè)計(jì)

如何根據(jù)Nginx的訪問(wèn)日志統(tǒng)計(jì)pv和uv呢?

我們可以通過(guò)分析nginx的訪問(wèn)網(wǎng)站頁(yè)面的日志來(lái)統(tǒng)計(jì)參數(shù),比如一個(gè)單頁(yè)應(yīng)用的博客網(wǎng)站,用戶訪問(wèn)/、/article_list、/article_detail都應(yīng)該算作一次訪問(wèn)。

但是如果網(wǎng)站的路由不確定時(shí)候,就不好統(tǒng)計(jì)。當(dāng)路由變化時(shí)候,需要更新統(tǒng)計(jì)腳本。而且,用戶首次訪問(wèn)后才設(shè)置了cookie,所以首次頁(yè)面請(qǐng)求是不帶cookie的,這會(huì)導(dǎo)致漏報(bào)。另外,用cookie記錄數(shù)據(jù),由于是js寫(xiě)的cookie,所以需要保證同域訪問(wèn),這就很不靈活。如果不是js寫(xiě)的cookie,那就說(shuō)明依賴后端服務(wù),也不夠靈活。

所以我們采取的方法是前端上報(bào)頁(yè)面訪問(wèn)事件。

首先前端生成一個(gè)uuid,向Nginx發(fā)起一個(gè)請(qǐng)求并攜帶uuid,Nginx會(huì)精確匹配這個(gè)請(qǐng)求,然后返回204,以減小數(shù)據(jù)傳輸量。

由于上報(bào)地址和頁(yè)面是同域的,因此我們這里使用cookie保存uuid,如果不同域,還可以使用localStorage將uuid存在本地,然后在參數(shù)中將uuid帶上。

Nginx收到上報(bào)后,根據(jù)我們指定的固定格式生成日志。我們還要設(shè)置定時(shí)任務(wù),定期切割日志,以便分析日志時(shí)候以月和天為維度統(tǒng)計(jì)指標(biāo)。

整體流程示意圖如下:

二、上報(bào)訪問(wèn)事件

前端使用uuid這個(gè)庫(kù)生成uuid,使用js-cookie對(duì)cookie進(jìn)行讀寫(xiě),cookie有效期設(shè)置為30天,如果已經(jīng)存在則不設(shè)置。

這里上報(bào)地址是“/report.gif”。為了避免上報(bào)請(qǐng)求被緩存,請(qǐng)求參數(shù)加一個(gè)時(shí)間戳。

// index.js
import Cookies from 'js-cookie';
import {v4 as uuidv4} from 'uuid';

try {
  if (!Cookies.get('uuid')) {
    Cookies.set('uuid', uuidv4().replace(/-/g, ''), {expires: 30});
  }
  // 上報(bào)訪問(wèn)
  axios.get(`https://www.example.com/report.gif?t=${Date.now()}`);
}
catch (e) {}

Nginx需要配置響應(yīng)

location =/report.gif {
  return 204;
}

三、Nginx配置日志格式

我們可以指定Nginx訪問(wèn)日志的格式,分析日志時(shí)候更方便。

注意,log_format指令只能用在http模塊中,不能用在server模塊中。

這里在http模塊中通過(guò)log_format定義了一個(gè)格式,命名為main,然后在server模塊中使用access_log定義訪問(wèn)日志的存放目錄,并且引用main指定日志格式。server模塊中還匹配了請(qǐng)求里面的cookie,取出uuid賦值給$uuid變量以便寫(xiě)日志時(shí)候能夠正常讀取uuid。

http {
  log_format main '$remote_addr - [$time_local] "$request" '
    ' - $status "uuid:$uuid" ';
  server {
    access_log /path/to/log/access443.log main;
    if ( $http_cookie ~* "uuid=([A-Z0-9]*)"){
        set $uuid $1;
    }
  }
}

我們會(huì)得到這樣的日志

101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /assets/vendor.337922eb.js HTTP/1.1"  - 304 "uuid:a27050e998864af89de0fbc7605d1548"
101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /assets/style.81f77c22.css HTTP/1.1"  - 200 "uuid:a27050e998864af89de0fbc7605d1548"
101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /assets/index.9c0fae7c.js HTTP/1.1"  - 304 "uuid:a27050e998864af89de0fbc7605d1548"
101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /assets/quiz.5e3bb724.js HTTP/1.1"  - 304 "uuid:a27050e998864af89de0fbc7605d1548"
101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /report.gif?id=0&t=1651628194189 HTTP/1.1"  - 204 "uuid:a27050e998864af89de0fbc7605d1548"
101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /assets/logo.c5f2dde3.jpeg HTTP/1.1"  - 200 "uuid:a27050e998864af89de0fbc7605d1548"
101.241.91.99 - [04/May/2022:09:36:34 +0800] "GET /favicon.ico HTTP/1.1"  - 200 "uuid:a27050e998864af89de0fbc7605d1548"

四、日志切割

為了方便統(tǒng)計(jì)我們希望把日志文件按時(shí)間分割,分割成這樣的結(jié)構(gòu):

├── 2022
│   └── 05
│       └── 03.log

按照年、月、日分層,每天生成一個(gè)日志。

實(shí)現(xiàn)思路是,先建立一個(gè)日志存放目錄,每天的凌晨0點(diǎn)1分,將前一天的日志按照日期移動(dòng)到日志目錄中。然后再重新創(chuàng)建一個(gè)日志文件供Nginx寫(xiě)入。

先寫(xiě)一個(gè)腳本實(shí)現(xiàn)這個(gè)功能

log_split.sh

#!/bin/bash
# 定位到腳本所在目錄(注意我這里也是Nginx寫(xiě)訪問(wèn)日志的目錄,當(dāng)然這不是必須的)
log_base=$(cd `dirname $0`; pwd)
# 根據(jù)前一天的時(shí)間生成日志所在目錄名
log_path=${log_base}/$(date -d yesterday +%Y)/$(date -d yesterday +%m)
# 創(chuàng)建日志目錄
mkdir -p $log_path
# 將當(dāng)前Nginx的日志移動(dòng)到指定存放目錄
mv $log_base/access443.log $log_path/$(date -d yesterday +%d).log
# 重新創(chuàng)建日志文件,給Nginx寫(xiě)日志用
touch $log_base/access443.log
# 給Nginx發(fā)送信號(hào),注意你的Nginx目錄可能不同
kill -USR1 `cat /www/server/nginx/logs/nginx.pid`

值得注意的是,雖然移動(dòng)完日志,并且重新創(chuàng)建,但是Nginx的文件引用還是移走的那個(gè),所以最后要給Nginx發(fā)送信號(hào),讓它寫(xiě)到新的日志文件中。

腳本寫(xiě)完,我們還要定時(shí)(每天0點(diǎn)1分執(zhí)行切割任務(wù)),這用到了Linux的crontab工具。

首先在控制臺(tái)輸入crontab -e打開(kāi)編輯界面。然后輸入1 0 * * * sh /path/to/log/log_split.sh。這個(gè)定時(shí)任務(wù)的意思是每天0點(diǎn)1分執(zhí)行日志分割腳本,編輯完成后保存關(guān)閉,定時(shí)任務(wù)就生效了。

我們還可以通過(guò)crontab -l查看當(dāng)前的定時(shí)任務(wù);通過(guò)crontab -r移除當(dāng)前的定時(shí)任務(wù)。

五、Nodejs腳本分析日志,統(tǒng)計(jì)PV、UV

有了日志,就很容易分析PV、UV。我們可以使用Linux命令分析,但我這次選擇用Nodejs腳本來(lái)統(tǒng)計(jì),原因是對(duì)JS更熟悉,另外相對(duì)Linux也更靈活。

分析的大概思路是根據(jù)每天的訪問(wèn)日志,過(guò)濾出report.gif這個(gè)上報(bào)請(qǐng)求,上報(bào)次數(shù)就是PV,然后根據(jù)uuid去重,得到UV。

統(tǒng)計(jì)腳本如下:

// stats.js
const fs = require('fs');
const path = require('path');
const args = process.argv.slice(2);
const [year] = args;

// 打印統(tǒng)計(jì)結(jié)果
function echo() {
  yearDir = year || '2022';
  const stats = statsYearLog(yearDir);
  Object.entries(stats)
    .sort(([a], [b]) => a - b)
    .forEach(([month, dateStats]) => {
    console.log(`${month}月`);
    Object.entries(dateStats)
      .sort(([a], [b]) => a - b)
      .forEach(([date, {pv, uv}]) => {
      console.log('  ', `${date}日`, `pv: ${pv}`, `uv: ${uv}`);
    });
    console.log('\n');
  });
}

// 統(tǒng)計(jì)某一年的數(shù)據(jù)
function statsYearLog(year) {
  // 讀取目錄下的文件夾名字
  const dir = path.resolve(__dirname, year);
  const monthDirList = fs.readdirSync(dir);
  
  const logMap = monthDirList.reduce((result, monthDir) => {
    const monthStats = statsMonthLog(year, monthDir);
    result[monthDir] = monthStats;
    return result;
  }, {});
  
  return logMap;
}

// 統(tǒng)計(jì)每個(gè)月的數(shù)據(jù)
function statsMonthLog(year, month) {
  const dir = path.resolve(__dirname, year, month);
  const dateLogList = fs.readdirSync(dir);
  
  const monthLogMap = dateLogList.reduce((result, dateLogFileName) => {
    const dateStats = statsDateLog(year, month, dateLogFileName);
    result[dateLogFileName.replace('.log', '')] = dateStats;
    return result;
  }, {});
  
  return monthLogMap;
}

// 統(tǒng)計(jì)某天的數(shù)據(jù)
function statsDateLog(year, month, dateFile) {
  const logPath = path.resolve(__dirname, year, month, dateFile);
  const logText = fs.readFileSync(logPath, 'utf-8');
  const logList = logText.split('\n');
  const pvLogList = logList.filter((line) => {
    return /report.gif/.test(line)
  });
  const uvLogMap = pvLogList.reduce((result, line) => {
    const match = line.match(/uuid:(\S+)"/);
    if (match && match[1]) {
      result[match[1]] = 1;
    }
    return result;
  }, {});
  
  return {pv: pvLogList.length, uv: Object.keys(uvLogMap).length};
}

// 執(zhí)行打印統(tǒng)計(jì)結(jié)果
echo();

執(zhí)行統(tǒng)計(jì)腳本node stats.js 2022

打印結(jié)果

05月
   03日 pv: 1 uv: 1

六、展望

后續(xù)可以考慮擴(kuò)展現(xiàn)有能力,讓Node實(shí)現(xiàn)日志切割的功能,并提供api和界面,可以可視化統(tǒng)計(jì)PV、UV。

到此這篇關(guān)于Nginx訪問(wèn)日志統(tǒng)計(jì)PV與UV的文章就介紹到這了,更多相關(guān)Nginx統(tǒng)計(jì)PV與UV內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Nginx主機(jī)域名配置實(shí)現(xiàn)

    Nginx主機(jī)域名配置實(shí)現(xiàn)

    本文主要介紹了Nginx主機(jī)域名配置實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • 詳解Ngigx+Tomcat配置動(dòng)靜分離,負(fù)載均衡

    詳解Ngigx+Tomcat配置動(dòng)靜分離,負(fù)載均衡

    本篇文章主要介紹了Ngigx+Tomcat配置動(dòng)靜分離,負(fù)載均衡,具有一定的參考價(jià)值,有需要的可以了解一下。
    2016-11-11
  • linux下Nginx 0.8.40的安裝方法

    linux下Nginx 0.8.40的安裝方法

    這篇文章主要介紹了linux下Nginx 0.8.40的安裝方法,需要的朋友可以參考下
    2014-11-11
  • Nginx服務(wù)器屏蔽與禁止屏蔽網(wǎng)絡(luò)爬蟲(chóng)的方法

    Nginx服務(wù)器屏蔽與禁止屏蔽網(wǎng)絡(luò)爬蟲(chóng)的方法

    今天小編就為大家分享一篇關(guān)于Nginx服務(wù)器屏蔽與禁止屏蔽網(wǎng)絡(luò)爬蟲(chóng)的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • windows下nginx服務(wù)關(guān)不掉問(wèn)題解決

    windows下nginx服務(wù)關(guān)不掉問(wèn)題解決

    這篇文章主要給大家介紹了關(guān)于windows下nginx服務(wù)關(guān)不掉問(wèn)題解決的相關(guān)資料,nginx是一種網(wǎng)絡(luò)服務(wù)器,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-08-08
  • Keepalived實(shí)現(xiàn)Nginx負(fù)載均衡高可用的示例代碼

    Keepalived實(shí)現(xiàn)Nginx負(fù)載均衡高可用的示例代碼

    這篇文章主要介紹了Keepalived實(shí)現(xiàn)Nginx負(fù)載均衡高可用的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • nginx 如何實(shí)現(xiàn)if嵌套的方法示例

    nginx 如何實(shí)現(xiàn)if嵌套的方法示例

    這篇文章主要介紹了nginx 如何實(shí)現(xiàn)if嵌套的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • Nginx配置HTTP強(qiáng)制跳轉(zhuǎn)到HTTPS的解決辦法

    Nginx配置HTTP強(qiáng)制跳轉(zhuǎn)到HTTPS的解決辦法

    這篇文章主要給大家介紹了關(guān)于Nginx配置HTTP強(qiáng)制跳轉(zhuǎn)到HTTPS的解決辦法,當(dāng)Nginx配置https后通常需要將用戶http請(qǐng)求強(qiáng)制跳轉(zhuǎn)到https,需要的朋友可以參考下
    2023-08-08
  • 啟用Nginx目錄瀏覽功能的方法

    啟用Nginx目錄瀏覽功能的方法

    這篇文章主要介紹了啟用Nginx目錄瀏覽功能的方法,需要的朋友可以參考下
    2014-03-03
  • 使用Nginx實(shí)現(xiàn)端口轉(zhuǎn)發(fā)TCP代理的實(shí)現(xiàn)示例

    使用Nginx實(shí)現(xiàn)端口轉(zhuǎn)發(fā)TCP代理的實(shí)現(xiàn)示例

    本文主要介紹了使用Nginx實(shí)現(xiàn)端口轉(zhuǎn)發(fā)TCP代理的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12

最新評(píng)論