vue+node 前端埋點(一)統計PV、UV
目錄格式
main.js 文件
import track from './tools/track'
// track 執行
track.execute()
client/tool/track.js 文件
在 package.json
中添加 fingerprintjs2
"fingerprintjs2": "^1.8.6",
track.js
// PV、UV在beforeEach中統計
import Vue from 'vue'
import router from '../router/index.js'
import Fingerprint from 'fingerprintjs2'
import utils from '../store/utils'
// import uuid from 'uuid/v1'
// 判斷是否支持 performance
function getCurrentTime () {
try {
return performance.timing.navigationStart + performance.now()
} catch (e) {
return Date.now()
}
}
// 上傳數據格式
const trackInfo = {
eventId: '',
type: 'screen',
time: '',
properties: {
// 需要打點的數據
_appid: 'xxx', // app標識,事先約定
_user_agent: '', // 瀏覽器UA
_screen_type: '', // 所屬頁面
_screen_event: '', // 具體頁面事件類型
_screen_title: '', // 頁面標題
_screen_path: '', // 頁面路徑
_device_id : '' // web中使用瀏覽器指紋
}
}
// 是否首次進入
let firstEnter = true
const track = {
execute () {
router.beforeEach((to, from, next) => {
trackInfo.properties._screen_type = to.path
trackInfo.properties._screen_event = 'ScreenAppear'
trackInfo.properties._screen_title = to.name
trackInfo.properties._screen_path = from.path
trackInfo.time = getCurrentTime()
trackInfo.type = 'screen'
trackInfo.eventId = `template_${to.name}`
if (firstEnter) {
// 針對純web端項目,設備id取瀏覽器指紋
trackInfo.properties._user_agent = window.navigator.userAgent
// 判斷瀏覽器是否支持 requestIdleCallback
if (window.requestIdleCallback) {
requestIdleCallback(function () {
Fingerprint().get(function (result) {
trackInfo.properties._device_id = result
utils.callTrackServer(trackInfo)
})
})
} else {
setTimeout(function () {
Fingerprint().get(function (result) {
trackInfo.properties._device_id = result
utils.callTrackServer(trackInfo)
})
}, 500)
}
firstEnter = false
} else {
utils.callTrackServer(trackInfo)
}
next()
})
}
}
module.exports = track
client/store/utils.js
在 package.json
中添加 fingerprintjs2
"axios": "^0.17.1",
"uuid": "^3.3.2",
utils.js
import axios from 'axios'
import uuid from 'uuid/v1'
const utils = {
// 向node端發送埋點數據
callTrackServer (info) {
axios({
url: '/xxx/getTrackInfo',
method: 'post',
data: info
}).then(res => {
console.log('success')
}).catch(err => {
console.log(err)
})
}
}
module.exports = utils
server/routes/index.js
import Router from 'koa-router'
import Tools from '../tools'
var app = new Router()
// PV、UV
app.post('/payday/getTrackInfo', async (ctx, next) => {
await Tools.trackInfoServer(ctx, next)
})
module.exports = app
server/tools/index.js
import Axios from 'axios'
import {
loggerTrack
} from '../log'
import uuid from 'uuid'
const Tools = {
// PV、UV
trackInfoServer: function (ctx, next) {
console.log(ctx.request.body)
loggerTrack.info(`track:`, ctx.request.body)
ctx.body = {res: 'success'}
next()
},
}
module.exports = Tools
server/logs/index.js 日誌寫入
import { createLogger, format, transports } from 'winston'
import 'winston-daily-rotate-file'
import safeStringify from 'fast-safe-stringify'
// import the built-in formatting methods
const { combine, metadata, timestamp, printf, colorize, padLevels } = format
const loggerTrack = createLogger({
level: 'info',
format: combine(
timestamp({format: 'YYYY-MM-DD HH:mm:ss'}),
metadata({key: 'content', fillExcept: ['timestamp', 'level', 'message']}),
// printf(info => `${info.content.time} ${info.content}`)
printf(info => `${info.content.time}: ${safeStringify(info.content)}\n`)
),
transports: [
new transports.DailyRotateFile({
level: 'info',
filename: 'logs/track/track-%DATE%.log',
datePattern: 'YYYY-MM-DD',
// zippedArchive: true,
maxSize: '20m',
maxFiles: '30d'
})
]
})
module.exports =
{
loggerTrack
}