learn.lianglianglee.com/专栏/重学操作系统-完/11 高级技巧之日志分析:利用 Linux 指令分析 Web 日志.md.html
2022-05-11 18:57:05 +08:00

1083 lines
29 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>11 高级技巧之日志分析:利用 Linux 指令分析 Web 日志.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/重学操作系统-完/00 开篇词 为什么大厂面试必考操作系统?.md.html">00 开篇词 为什么大厂面试必考操作系统?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/00 课前必读 构建知识体系,可以这样做!.md.html">00 课前必读 构建知识体系,可以这样做!.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/01 计算机是什么:“如何把程序写好”这个问题是可计算的吗?.md.html">01 计算机是什么:“如何把程序写好”这个问题是可计算的吗?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/02 程序的执行:相比 32 位64 位的优势是什么?(上).md.html">02 程序的执行:相比 32 位64 位的优势是什么?(上).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/03 程序的执行:相比 32 位64 位的优势是什么?(下).md.html">03 程序的执行:相比 32 位64 位的优势是什么?(下).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/04 构造复杂的程序:将一个递归函数转成非递归函数的通用方法.md.html">04 构造复杂的程序:将一个递归函数转成非递归函数的通用方法.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/05 存储器分级L1 Cache 比内存和 SSD 快多少倍?.md.html">05 存储器分级L1 Cache 比内存和 SSD 快多少倍?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/05 (1) 加餐 练习题详解(一).md.html">05 (1) 加餐 练习题详解(一).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/06 目录结构和文件管理指令rm -rf 指令的作用是?.md.html">06 目录结构和文件管理指令rm -rf 指令的作用是?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/07 进程、重定向和管道指令xargs 指令的作用是?.md.html">07 进程、重定向和管道指令xargs 指令的作用是?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/08 用户和权限管理指令: 请简述 Linux 权限划分的原则?.md.html">08 用户和权限管理指令: 请简述 Linux 权限划分的原则?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/09 Linux 中的网络指令:如何查看一个域名有哪些 NS 记录?.md.html">09 Linux 中的网络指令:如何查看一个域名有哪些 NS 记录?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/10 软件的安装: 编译安装和包管理器安装有什么优势和劣势?.md.html">10 软件的安装: 编译安装和包管理器安装有什么优势和劣势?.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/重学操作系统-完/11 高级技巧之日志分析:利用 Linux 指令分析 Web 日志.md.html">11 高级技巧之日志分析:利用 Linux 指令分析 Web 日志.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/12 高级技巧之集群部署:利用 Linux 指令同时在多台机器部署程序.md.html">12 高级技巧之集群部署:利用 Linux 指令同时在多台机器部署程序.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/12 (1)加餐 练习题详解(二).md.html">12 (1)加餐 练习题详解(二).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/13 操作系统内核Linux 内核和 Windows 内核有什么区别?.md.html">13 操作系统内核Linux 内核和 Windows 内核有什么区别?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/14 用户态和内核态:用户态线程和内核态线程有什么区别?.md.html">14 用户态和内核态:用户态线程和内核态线程有什么区别?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/15 中断和中断向量Javajs 等语言为什么可以捕获到键盘输入?.md.html">15 中断和中断向量Javajs 等语言为什么可以捕获到键盘输入?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/16 WinMacUnixLinux 的区别和联系:为什么 Debian 漏洞排名第一还这么多人用?.md.html">16 WinMacUnixLinux 的区别和联系:为什么 Debian 漏洞排名第一还这么多人用?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/16 (1)加餐 练习题详解(三).md.html">16 (1)加餐 练习题详解(三).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/17 进程和线程:进程的开销比线程大在了哪里?.md.html">17 进程和线程:进程的开销比线程大在了哪里?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/18 锁、信号量和分布式锁:如何控制同一时间只有 2 个线程运行?.md.html">18 锁、信号量和分布式锁:如何控制同一时间只有 2 个线程运行?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/19 乐观锁、区块链:除了上锁还有哪些并发控制方法?.md.html">19 乐观锁、区块链:除了上锁还有哪些并发控制方法?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/20 线程的调度:线程调度都有哪些方法?.md.html">20 线程的调度:线程调度都有哪些方法?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/21 哲学家就餐问题:什么情况下会触发饥饿和死锁?.md.html">21 哲学家就餐问题:什么情况下会触发饥饿和死锁?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/22 进程间通信: 进程间通信都有哪些方法?.md.html">22 进程间通信: 进程间通信都有哪些方法?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/23 分析服务的特性:我的服务应该开多少个进程、多少个线程?.md.html">23 分析服务的特性:我的服务应该开多少个进程、多少个线程?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/23 (1)加餐 练习题详解(四).md.html">23 (1)加餐 练习题详解(四).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/24 虚拟内存 :一个程序最多能使用多少内存?.md.html">24 虚拟内存 :一个程序最多能使用多少内存?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/25 内存管理单元: 什么情况下使用大内存分页?.md.html">25 内存管理单元: 什么情况下使用大内存分页?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/26 缓存置换算法: LRU 用什么数据结构实现更合理?.md.html">26 缓存置换算法: LRU 用什么数据结构实现更合理?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/27 内存回收上篇:如何解决内存的循环引用问题?.md.html">27 内存回收上篇:如何解决内存的循环引用问题?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/28 内存回收下篇:三色标记-清除算法是怎么回事?.md.html">28 内存回收下篇:三色标记-清除算法是怎么回事?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/28 (1)加餐 练习题详解(五).md.html">28 (1)加餐 练习题详解(五).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/29 Linux 下的各个目录有什么作用?.md.html">29 Linux 下的各个目录有什么作用?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/30 文件系统的底层实现FAT、NTFS 和 Ext3 有什么区别?.md.html">30 文件系统的底层实现FAT、NTFS 和 Ext3 有什么区别?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/31 数据库文件系统实例MySQL 中 B 树和 B+ 树有什么区别?.md.html">31 数据库文件系统实例MySQL 中 B 树和 B+ 树有什么区别?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/32 HDFS 介绍:分布式文件系统是怎么回事?.md.html">32 HDFS 介绍:分布式文件系统是怎么回事?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/32 (1)加餐 练习题详解(六).md.html">32 (1)加餐 练习题详解(六).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/33 互联网协议群TCPIP多路复用是怎么回事.md.html">33 互联网协议群TCPIP多路复用是怎么回事.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/34 UDP 协议UDP 和 TCP 相比快在哪里?.md.html">34 UDP 协议UDP 和 TCP 相比快在哪里?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/35 Linux 的 IO 模式selectpollepoll 有什么区别?.md.html">35 Linux 的 IO 模式selectpollepoll 有什么区别?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/36 公私钥体系和网络安全:什么是中间人攻击?.md.html">36 公私钥体系和网络安全:什么是中间人攻击?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/36 (1)加餐 练习题详解(七).md.html">36 (1)加餐 练习题详解(七).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/37 虚拟化技术介绍VMware 和 Docker 的区别?.md.html">37 虚拟化技术介绍VMware 和 Docker 的区别?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/38 容器编排技术:如何利用 K8s 和 Docker Swarm 管理微服务?.md.html">38 容器编排技术:如何利用 K8s 和 Docker Swarm 管理微服务?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/39 Linux 架构优秀在哪里.md.html">39 Linux 架构优秀在哪里.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/40 商业操作系统:电商操作系统是不是一个噱头?.md.html">40 商业操作系统:电商操作系统是不是一个噱头?.md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/40 (1)加餐 练习题详解(八).md.html">40 (1)加餐 练习题详解(八).md.html</a>
</li>
<li>
<a href="/专栏/重学操作系统-完/41 结束语 论程序员的发展——信仰、选择和博弈.md.html">41 结束语 论程序员的发展——信仰、选择和博弈.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>11 高级技巧之日志分析:利用 Linux 指令分析 Web 日志</h1>
<p>著名的黑客、自由软件运动的先驱理查德.斯托曼说过,“编程不是科学,编程是手艺”。可见,要想真正搞好编程,除了学习理论知识,还需要在实际的工作场景中进行反复的锤炼。</p>
<p>所以今天我们将结合实际的工作场景,带你利用 Linux 指令分析 Web 日志,这其中包含很多小技巧,掌握了本课时的内容,将对你将来分析线上日志、了解用户行为和查找问题有非常大地帮助。</p>
<p>本课时将用到一个大概有 5W 多条记录的<code>nginx</code>日志文件,你可以在<a href="https://github.com/ramroll/lagou-os/blob/main/access.log"> GitHub</a>上下载。 下面就请你和我一起,通过分析这个<code>nginx</code>日志文件,去锤炼我们的手艺。</p>
<h3>第一步:能不能这样做?</h3>
<p>当我们想要分析一个线上文件的时候,首先要思考,能不能这样做? 这里你可以先用<code>htop</code>指令看一下当前的负载。如果你的机器上没有<code>htop</code>,可以考虑用<code>yum</code>或者<code>apt</code>去安装。</p>
<p><img src="assets/CgqCHl-BkJ6AcP32AAduMy8fcSw412.png" alt="Drawing 0.png" /></p>
<p>如上图所示,我的机器上 8 个 CPU 都是 0 负载,<code>2G</code>的内存用了一半多,还有富余。 我们用<code>wget</code>将目标文件下载到本地(如果你没有 wget可以用<code>yum</code>或者<code>apt</code>安装)。</p>
<pre><code>wget 某网址(自己替代)
</code></pre>
<p>然后我们用<code>ls</code>查看文件大小。发现这只是一个 7M 的文件,因此对线上的影响可以忽略不计。如果文件太大,建议你用<code>scp</code>指令将文件拷贝到闲置服务器再分析。下图中我使用了<code>--block-size</code><code>ls</code><code>M</code>为单位显示文件大小。</p>
<p><img src="assets/Ciqc1F-BkKeAQDs9AACqJbZ2jCM025.png" alt="Drawing 1.png" /></p>
<p>确定了当前机器的<code>CPU</code>和内存允许我进行分析后,我们就可以开始第二步操作了。</p>
<h3>第二步LESS 日志文件</h3>
<p>在分析日志前,给你提个醒,记得要<code>less</code>一下,看看日志里面的内容。之前我们说过,尽量使用<code>less</code>这种不需要读取全部文件的指令,因为在线上执行<code>cat</code>是一件非常危险的事情,这可能导致线上服务器资源不足。</p>
<p><img src="assets/CgqCHl-BkK6AcDGvAAjaPXe-Nbc605.png" alt="Drawing 2.png" /></p>
<p>如上图所示,我们看到<code>nginx</code><code>access_log</code>每一行都是一次用户的访问,从左到右依次是:</p>
<ul>
<li>IP 地址;</li>
<li>时间;</li>
<li>HTTP 请求的方法、路径和协议版本、返回的状态码;</li>
<li>User Agent。</li>
</ul>
<h3>第三步PV 分析</h3>
<p>PVPage View用户每访问一个页面就是一次<code>Page View</code>。对于<code>nginx</code><code>acess_log</code>来说,分析 PV 非常简单,我们直接使用<code>wc -l</code>就可以看到整体的<code>PV</code></p>
<p><img src="assets/Ciqc1F-BkL6AGiY-AABQPMnGu40979.png" alt="Drawing 3.png" /></p>
<p>如上图所示:我们看到了一共有 51462 条 PV。</p>
<h3>第四步PV 分组</h3>
<p>通常一个日志中可能有几天的 PV为了得到更加直观的数据有时候需要按天进行分组。为了简化这个问题我们先来看看日志中都有哪些天的日志。</p>
<p>使用<code>awk '{print $4}' access.log | less</code>可以看到如下结果。<code>awk</code>是一个处理文本的领域专有语言。这里就牵扯到领域专有语言这个概念英文是Domain Specific Language。领域专有语言就是为了处理某个领域专门设计的语言。比如awk是用来分析处理文本的DSLhtml是专门用来描述网页的DSLSQL是专门用来查询数据的DSL……大家还可以根据自己的业务设计某种针对业务的DSL。</p>
<p>你可以看到我们用<code>$4</code>代表文本的第 4 列,也就是时间所在的这一列,如下图所示:</p>
<p><img src="assets/CgqCHl-BkMaAb421AAGUr-N08hM187.png" alt="Drawing 4.png" /></p>
<p>我们想要按天统计,可以利用 <code>awk</code>提供的字符串截取的能力。</p>
<p><img src="assets/CgqCHl-BkMuAKo9UAAIcPR902XQ858.png" alt="Drawing 5.png" /></p>
<p>上图中,我们使用<code>awk</code><code>substr</code>函数,数字<code>2</code>代表从第 2 个字符开始,数字<code>11</code>代表截取 11 个字符。</p>
<p>接下来我们就可以分组统计每天的日志条数了。</p>
<p><img src="assets/CgqCHl-BkNGAB-VgAASNmct9nQA628.png" alt="Drawing 6.png" /></p>
<p>上图中,使用<code>sort</code>进行排序,然后使用<code>uniq -c</code>进行统计。你可以看到从 2015 年 5 月 17 号一直到 6 月 4 号的日志,还可以看到每天的 PV 量大概是在 2000~3000 之间。</p>
<h3>第五步:分析 UV</h3>
<p>接下来我们分析 UV。UVUniq Visitor也就是统计访问人数。通常确定用户的身份是一个复杂的事情但是我们可以用 IP 访问来近似统计 UV。</p>
<p><img src="assets/Ciqc1F-BkNeAam2YAACxCjlKsvc488.png" alt="Drawing 7.png" /></p>
<p>上图中,我们使用 awk 去打印<code>$1</code>也就是第一列,接着<code>sort</code>排序,然后用<code>uniq</code>去重,最后用<code>wc -l</code>查看条数。 这样我们就知道日志文件中一共有<code>2660</code>个 IP也就是<code>2660</code>个 UV。</p>
<h3>第六步:分组分析 UV</h3>
<p>接下来我们尝试按天分组分析每天的 UV 情况。这个情况比较复杂,需要较多的指令,我们先创建一个叫作<code>sum.sh</code><code>bash</code>脚本文件,写入如下内容:</p>
<pre><code>#!/usr/bin/bash
awk '{print substr($4, 2, 11) &quot; &quot; $1}' access.log |\
sort | uniq |\
awk '{uv[$1]++;next}END{for (ip in uv) print ip, uv[ip]}'
</code></pre>
<p>具体分析如下。</p>
<ul>
<li>文件首部我们使用<code>#!</code>,表示我们将使用后面的<code>/usr/bin/bash</code>执行这个文件。</li>
<li>第一次<code>awk</code>我们将第 4 列的日期和第 1 列的<code>ip</code>地址拼接在一起。</li>
<li>下面的<code>sort</code>是把整个文件进行一次字典序排序,相当于先根据日期排序,再根据 IP 排序。</li>
<li>接下来我们用<code>uniq</code>去重,日期 +IP 相同的行就只保留一个。</li>
<li>最后的<code>awk</code>我们再根据第 1 列的时间和第 2 列的 IP 进行统计。</li>
</ul>
<p>为了理解最后这一行描述,我们先来简单了解下<code>awk</code>的原理。</p>
<p><code>awk</code>本身是逐行进行处理的。因此我们的<code>next</code>关键字是提醒<code>awk</code>跳转到下一行输入。 对每一行输入,<code>awk</code>会根据第 1 列的字符串(也就是日期)进行累加。之后的<code>END</code>关键字代表一个触发器,就是 END 后面用 {} 括起来的语句会在所有输入都处理完之后执行——当所有输入都执行完,结果被累加到<code>uv</code>中后,通过<code>foreach</code>遍历<code>uv</code>中所有的<code>key</code>,去打印<code>ip</code><code>ip</code>对应的数量。</p>
<p>编写完上面的脚本之后,我们保存退出编辑器。接着执行<code>chmod +x ./sum.sh</code>,给<code>sum.sh</code>增加执行权限。然后我们可以像下图这样执行,获得结果:</p>
<p><img src="assets/CgqCHl-BkOKAfpNwAAOFk0EhDjU183.png" alt="Drawing 8.png" /></p>
<p>如上图,<code>IP</code>地址已经按天进行统计好了。</p>
<h3>总结</h3>
<p>今天我们结合一个简单的实战场景——Web 日志分析与统计练习了之前学过的指令,提高熟练程度。此外,我们还一起学习了新知识——功能强大的<code>awk</code>文本处理语言。在实战中,我们对一个<code>nginx</code><code>access_log</code>进行了简单的数据分析,直观地获得了这个网站的访问情况。</p>
<p>我们在日常的工作中会遇到各种各样的日志,除了 nginx 的日志,还有应用日志、前端日志、监控日志等等。你都可以利用今天学习的方法,去做数据分析,然后从中得出结论。</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/重学操作系统-完/10 软件的安装: 编译安装和包管理器安装有什么优势和劣势?.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/重学操作系统-完/12 高级技巧之集群部署:利用 Linux 指令同时在多台机器部署程序.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"70997d5ffdcc3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>