本文会列出session的属性值、统计指标,重点讲解session几个字段值,虽然从代码中看出的考虑策略,session和view、app均有关联,但本文仅从代码层面对session的创建、更新、过期的逻辑进行讲解,其中会把关键的变量值也会列出来。
定义:
用户会话信息记录,当前会话中,将会基于会话维度用户页面、资源、操作、错误、长任务相关访问数据。 下面简单列出session有哪些属性,仅供参考。
属性
字段 | 类型 | 描述 |
session_id |
string | 会话 id(用户会话 15 分钟内未产生交互行为则视为过期 ) |
session_type |
string | 会话类型。参考值:user synthetics - user 表示是RUM功能产生的数据;- synthetics 表示是 headless拨测产生的数据。 |
session_referrer |
string | 会话来源。一般是记录来源的页面地址。 |
session_first_view_id |
string | 当前会话的第一个页面的 view_id |
session_first_view_url |
string | 当前会话的第一个页面的 URL |
session_first_view_host |
string | 当前会话的第一个页面的域名 |
session_first_view_path |
string | 当前会话的第一个页面的地址 |
session_first_view_path_group |
string | 当前会话的第一个页面的地址分组 |
session_first_view_url_query |
string | 当前会话的第一个页面的 query 信息 |
session_last_view_id |
string | 当前会话的最后一个访问页面的 view_id |
session_last_view_url |
string | 当前会话的最后一个页面的 URL |
session_last_view_host |
string | 当前会话的最后一个页面的域名 |
session_last_view_path |
string | 当前会话的最后一个页面的地址 |
session_last_view_path_group |
string | 当前会话的最后一个页面的地址分组 |
session_last_view_url_query |
object | 当前会话的最后一个页面的 query 信息 |
统计指标
字段 | 类型 | 描述 |
time_spent |
number(ns) | 当前会话持续时长 |
session_view_count |
number | 当前会话关联view_id 个数 |
session_error_count |
number | 当前会话产生错误个数 |
session_resource_count |
number | 当前会话加载资源个数 |
session_action_count |
number | 当前会话用户操作次数 |
session_long_task_count |
number | 当前会话产生长任务次数 |
session部分逻辑
并不是所有字段都有值得讲解,比如session_has_replay这个字段代表是否有会话是否有录制。今天只针对session的生命周期进行讲解。
id的生成
这个简单,首先这个要从startSessionStore,其中session要从cookie中获取,如果没有就需要创建,创建或更新的这部分逻辑如下:
function expandOrRenewCookie(cookieSession) { var sessionState = computeSessionState(cookieSession[productKey]) var trackingType = sessionState.trackingType var isTracked = sessionState.isTracked cookieSession[productKey] = trackingType if (isTracked && !cookieSession.id) { cookieSession.id = UUID() cookieSession.created = String(dateNow()) } return isTracked } 复制代码
上面需要注意一点,这里的cookie值是_dataflulx_usr_id
,如何查看当前的cookie值呢,一般可以通过document.cookie进行获取,简单的查看方式便是f12打开控制台,在application中查看,如下图所示。
在上图中,我们除了能看到当前的cookie的value,还有比较重要的内容:
- domain
- 过期时间
- 大小
获取cookie
有关如何获取cookie,这里实现的逻辑是调用
#bytemd-mermaid-1679971038295-0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#bytemd-mermaid-1679971038295-0 .error-icon{fill:#552222;}#bytemd-mermaid-1679971038295-0 .error-text{fill:#552222;stroke:#552222;}#bytemd-mermaid-1679971038295-0 .edge-thickness-normal{stroke-width:2px;}#bytemd-mermaid-1679971038295-0 .edge-thickness-thick{stroke-width:3.5px;}#bytemd-mermaid-1679971038295-0 .edge-pattern-solid{stroke-dasharray:0;}#bytemd-mermaid-1679971038295-0 .edge-pattern-dashed{stroke-dasharray:3;}#bytemd-mermaid-1679971038295-0 .edge-pattern-dotted{stroke-dasharray:2;}#bytemd-mermaid-1679971038295-0 .marker{fill:#333333;stroke:#333333;}#bytemd-mermaid-1679971038295-0 .marker.cross{stroke:#333333;}#bytemd-mermaid-1679971038295-0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#bytemd-mermaid-1679971038295-0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#bytemd-mermaid-1679971038295-0 .cluster-label text{fill:#333;}#bytemd-mermaid-1679971038295-0 .cluster-label span{color:#333;}#bytemd-mermaid-1679971038295-0 .label text,#bytemd-mermaid-1679971038295-0 span{fill:#333;color:#333;}#bytemd-mermaid-1679971038295-0 .node rect,#bytemd-mermaid-1679971038295-0 .node circle,#bytemd-mermaid-1679971038295-0 .node ellipse,#bytemd-mermaid-1679971038295-0 .node polygon,#bytemd-mermaid-1679971038295-0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#bytemd-mermaid-1679971038295-0 .node .label{text-align:center;}#bytemd-mermaid-1679971038295-0 .node.clickable{cursor:pointer;}#bytemd-mermaid-1679971038295-0 .arrowheadPath{fill:#333333;}#bytemd-mermaid-1679971038295-0 .edgePath .path{stroke:#333333;stroke-width:1.5px;}#bytemd-mermaid-1679971038295-0 .flowchart-link{stroke:#333333;fill:none;}#bytemd-mermaid-1679971038295-0 .edgeLabel{background-color:#e8e8e8;text-align:center;}#bytemd-mermaid-1679971038295-0 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#bytemd-mermaid-1679971038295-0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#bytemd-mermaid-1679971038295-0 .cluster text{fill:#333;}#bytemd-mermaid-1679971038295-0 .cluster span{color:#333;}#bytemd-mermaid-1679971038295-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80,100%,96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#bytemd-mermaid-1679971038295-0:root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#bytemd-mermaid-1679971038295-0 flowchart{fill:apa;}
name
document.cookie,name
findCommanSeparatedValue是利用正则进行获取,代码如下:
export function findCommaSeparatedValue(rawString, name) { var matches = rawString.match('(?:^|;)\\s*' + name + '\\s*=\\s*([^;]+)') return matches ? matches[1] : undefined } 复制代码
创建cookie的值
接着上面的逻辑,如果是首次进入,需要创建和设置cookie,我们先看创建的代码:
cookieSession.id = UUID() 复制代码
UUID这个方法实现也比较简单,是通过Math.random后最后转换成16进制,可以看下面代码:
export function UUID(placeholder) { return placeholder ? // eslint-disable-next-line no-bitwise ( parseInt(placeholder, 10) ^ ((Math.random() * 16) >> (parseInt(placeholder, 10) / 4)) ).toString(16) : `${1e7}-${1e3}-${4e3}-${8e3}-${1e11}`.replace(/[018]/g, UUID) } 复制代码
但是我们需要注意,还有几个其他相关属性很重要
export var SESSION_TIME_OUT_DELAY = 4 * ONE_HOUR export var SESSION_EXPIRATION_DELAY = 15 * ONE_MINUTE 复制代码
这里SESSION_TIME_OUT_DELAY用于设定最大时长,也就是说4个小时;SESSION_EXPIRATION_DELAY用于判断是否过期,这里是15分钟。
说到时间,就需要知道cookieSession创建时,还有一个比较重要的参数,上面两个变量便是依据这个参数进行的对比,这个参数是:cookieSession.created:
cookieSession.created = String(dateNow()) 复制代码
目测是本地时间,但是得看一下源码import { dateNow, UUID, throttle } from '../helper/tools'
dataNow也来自helper/tools中,其中代码是这样写的:
export function dateNow() { return new Date().getTime() } 复制代码
看代码采用的是new Date(),也就是客户端的时间,在上面两个相对的时间后,就会执行相关session的更新或者创建。所以对于session的判断也有必要讲一讲,这里使用的函数是根据hasSessionInCache的返回值真假来判断 return sessionCache[productKey] !== undefined
,如果存在,还需要判断是否过期(isSessionInCacheOutdated),这里判断条件除了id外还有另外一个值
function isSessionInCacheOutdated(cookieSession) { return ( sessionCache.id !== cookieSession.id || sessionCache[productKey] !== cookieSession[productKey] ) } 复制代码
假设返回为假,则需要session过期(expireSession):
function expireSession() { sessionCache = {} expireObservable.notify() } 复制代码
检查session
因为session的特殊性,所以不能频繁更新和检查session,所以应该有性能上的节流。 expandOrRenewSession: throttle(expandOrRenewSession, COOKIE_ACCESS_DELAY) .throttled,
目前软件的节流时间是export var COOKIE_ACCESS_DELAY = ONE_SECOND 节流函数比较简单,就不做介绍了。 其中还有最后一项,就是session是否在有效期内(isActiveSession):
function isActiveSession(session) { return ( (session.created === undefined || dateNow() - Number(session.created) < SESSION_TIME_OUT_DELAY) && (session.expire === undefined || dateNow() < Number(session.expire)) ) } 复制代码
session的过期
SESSION_TIME_OUT_DELAY就是上面提到的比较重要的属性值,目前是export var SESSION_TIME_OUT_DELAY = 4 * ONE_HOUR
有关session是否还要持久化的方法(persistSession)
export function persistSession(session, options) { if (isExpiredState(session)) { clearSession(options) return } session.expire = String(dateNow() + SESSION_EXPIRATION_DELAY) setSession(session, options) } 复制代码
SESSION_EXPIRATION_DELAY就是上面提到的比较重要的属性值,目前是15分钟。
有关用户是否活动,是通过事件监听dom是否出现VISIBILITY_CHANGE来判断。
var _addEventListener= addEventListener(document, DOM_EVENT.VISIBILITY_CHANGE, expandSessionWhenVisible) 复制代码
总结
本文介绍了session的属性和常见统计指标,单独把session的id的创建、更新、获取逻辑以及过期时间的逻辑都做了讲解,希望能对读者有所启发。
作者:Yestodorrow
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。