Hexo_网站统计分析

前言

给网站拓展个统计分析功能,采用免费开源的umaimi

参考一些博文写的不是很详尽(参考资料3博主遇到同样问题),官方文档写的非常简单,不了解程序(摸熟)完全看不懂,就如之前提到过的,好的程序也不一定有好的文档,全凭开发者用心程度

总体搭建过程花费1小时多
不想重复造轮子,但踩了些小坑,写篇总结文,方便以后查阅,有笔记的话,搭建估计15分钟左右就能完成
应该算是这个架构(Hexo+Supabase+Vercel)最详尽的教程了吧….

另外,虽然说是用于Hexo,但其实博客程序(HugoTypechoWordPress )也是通用的
毕竟本质只是引入了一个 js 用于追踪,外加提供给用户一个网页用于查看

追踪的说明

追踪符合 GDPR 规定,不会收集任何个人身份信息,并对收集的所有数据进行匿名处理。

用户无法被识别,也不会跨网站被跟踪。

另外不会在跟踪代码中使用任何 cookie。

详细见:umami-faq

流程与架构

简单介绍下实现的流程架构

实现流程包括

umami流程

  1. 创建数据库:用于存储网站访问的数据(什么位置、什么平台、什么系统),数据全部存储于数据库
  2. 创建站点:创建个网页程序,用于查询数据,将数据图示化呈现给用户(游客、自己)观看
  3. Hexo配置:给博客注入追踪脚本,用于统计访客数据

架构

umami架构

  • 博客:Hexo
  • 托管程序(创建站点):Vercel
  • 托管数据库(创建数据库):Supabase

以下为托管的其他可选项,选择对应可用的即可

个人采用以上架构,如用其他需自行尝试摸索
另外数据库不要采用Heroku,好像没有免费计划了,详见参考资料3

托管详细完整介绍也可参考官方文档

参考资料

  1. 部署独立统计分析服务Umami:写的比较详尽,但初始化数据库会踩坑,本篇在此基础上,结合参考其他文档完善
  2. 使用 Umami 统计个人网站访问数据:与博主采用不同架构(PlanetScale + vercel),仅作为了解使用
  3. 如何不花一分钱搭建 Umami 统计工具:介绍了一些坑
  4. 在 Vercel 部署 umami 网站统计及报错解决:介绍了2个数据库报错解决方案
  5. 使用 vercel+supabase 免费部署 umami_:不错的教程, 但还不够详尽
  6. 给Hexo静态博客添加Umami数据分析 :与博主采用不同架构(Heroku + vercle),仅作为了解使用

创建数据库

打开Supabase官网,使用Github登录,没有也可以注册一个帐号后登录

推荐使用Github,下面建立站点的时候也要使用到

Snipaste_2023-07-08_11-56-52

登陆成功后,创建一个新的项目New project->personal

我这里为事后总结,所以已经有1个项目,总之就是找到New project按钮后,点击新建一个项目

image-20230708120133172

进入创建页面后,填写相应信息

  • Name:项目的名称
  • Database Password:数据库密码(可以点击Generate a password自动生成,输入后记住后面要用到)
  • Region:采用默认West US(North California)
  • Pricing Plan:采用默认Free

image-20230708120519616

创建数据库后,点击设置图标,找到Database,再找到Connection string,点击URL

将这个URL复制下来,将其中[YOUR-PASSWORD]改为上面输入的数据库密码,不要中括号[]

例如我的密码是123456

默认:postgresql://postgres:[YOUR-PASSWORD]@db.jxlqbxdxbujxopupqsnd.supabase.co:5432/postgres

修改后:postgresql://postgres:123456@db.jxlqbxdxbujxopupqsnd.supabase.co:5432/postgres

至此数据库建立完毕

站点

创建站点

先登录Github,点击这里,Fork Umami项目(拷贝一份到自己仓库)

或者也可以进入Umami仓库,点击右上角的Fork,拉取一份到自己的仓库

image-20230708121443670

登录Vercel,点击这里,找到上面Github Fork Umami的项目

例如个人是umami-repository,点击Import

image-20230708121836355

之后开始输环境变量

Snipaste_2023-07-08_09-45-16

  • DATABASE_URL:粘贴创建数据库步骤中获得的数据库URL
  • HASH_SALT:任意字符串,可以点击这里生成一串UUID
  • TRACKER_SCRIPT_NAME:任意字符串,可以点击这里生成一串UUID

Snipaste_2023-07-08_09-45-50

环境变量填写后点击Deploy开始部署

部署需要两分钟多,正常部署成功后会有一个彩纸的喜庆页面。

部署成功

由于这里个人踩坑部署失败,所以没有对应的截图,懒的新建一个部署,这里采用参考资料1博主的喜庆页面图,用于演示

这里说明部署失败后怎么重新部署,如果部署成功可忽略这里

如果部署失败,解决问题后(一般是数据库问题),就进入这个项目(程序),重新部署即可

先进入指示板,可以点击这里进入,点击部署失败的程序image-20230708124041287

找到部署选项,重新部署即可

image-20230708124259515

配置站点

上面部署成功后,需要登录vercel分配的网站,进行配置

不知道怎么看的话,点击这里,找到你创建的项目(程序),点击进去

image-20230708124513428

点击图示位置的超链接进去

image-20230708124548666

再点击Visit访问即可

image-20230708124651124

进入登录界面,默认用户名admin和密码umami

image-20230708124816490

为确保安全,先修改密码
点击Setting-Profile,再点击Change password进行修改密码

image-20230708125108096

之后,添加要统计分析的网站
点击Settings-Websites,再点击Add website进行添加

image-20230708125348157

输入站点名称和域名(不用加协议)

Snipaste_2023-07-08_09-58-21

完成后,目前虽然可以访问,但是博客没有追踪代码,所以是不会数据的,所以要拿到js代码用于博客中去统计数据

点击Edit进行编辑image-20230708125727353

点击Tracking code,将其中的js代码复制记录下来,待会Hexo配置用到

image-20230708130929461

至此站点配置完毕(修改密码、添加统计分析站点)

Hexo配置与测试

获取的js可以插入到主题代码中去,也可以用注入器
个人主推后者,就如同插件一样,不想用了,直接删除文件即可
所以这里采用的是注入器的方式

注入器是Hexo 5 版本自身加入的一项新功能

所以使用的Hexo版本需要>=5

使用文档可参考:官方文档

在博客根目录下新建一个scripts文件夹

image-20230708130637505

scripts文件夹下面添加一个新js文件,例如个人新建一个umami-statistical.js

image-20230708130722015

将下面的代码复制粘贴进去,将xxx替换为配置站点步骤获得的js代码即可

1
hexo.extend.injector.register('head_end', xxx);

配置完毕后,Hexo重新生成部署后,可以自己访问下自己的博客

之后在Vercel搭建的站点点击查看,检查是否开始统计

image-20230708131344142

后话

说下踩的坑,个人最开始是参考资料1进行搭建,其中数据库有个初始化(个人也认为很正常,数据库要建立对应表和列)

但其中提供的初始化代码链接已经失效
没办法,个人翻阅 umami 仓库,搜索以 .sql 结尾的文件,找到可能是初始化数据库的代码进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
-- CreateExtension
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- CreateTable
CREATE TABLE "user" (
"user_id" UUID NOT NULL,
"username" VARCHAR(255) NOT NULL,
"password" VARCHAR(60) NOT NULL,
"role" VARCHAR(50) NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(6),
"deleted_at" TIMESTAMPTZ(6),

CONSTRAINT "user_pkey" PRIMARY KEY ("user_id")
);

-- CreateTable
CREATE TABLE "session" (
"session_id" UUID NOT NULL,
"website_id" UUID NOT NULL,
"hostname" VARCHAR(100),
"browser" VARCHAR(20),
"os" VARCHAR(20),
"device" VARCHAR(20),
"screen" VARCHAR(11),
"language" VARCHAR(35),
"country" CHAR(2),
"subdivision1" VARCHAR(20),
"subdivision2" VARCHAR(50),
"city" VARCHAR(50),
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "session_pkey" PRIMARY KEY ("session_id")
);

-- CreateTable
CREATE TABLE "website" (
"website_id" UUID NOT NULL,
"name" VARCHAR(100) NOT NULL,
"domain" VARCHAR(500),
"share_id" VARCHAR(50),
"reset_at" TIMESTAMPTZ(6),
"user_id" UUID,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(6),
"deleted_at" TIMESTAMPTZ(6),

CONSTRAINT "website_pkey" PRIMARY KEY ("website_id")
);

-- CreateTable
CREATE TABLE "website_event" (
"event_id" UUID NOT NULL,
"website_id" UUID NOT NULL,
"session_id" UUID NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
"url_path" VARCHAR(500) NOT NULL,
"url_query" VARCHAR(500),
"referrer_path" VARCHAR(500),
"referrer_query" VARCHAR(500),
"referrer_domain" VARCHAR(500),
"page_title" VARCHAR(500),
"event_type" INTEGER NOT NULL DEFAULT 1,
"event_name" VARCHAR(50),

CONSTRAINT "website_event_pkey" PRIMARY KEY ("event_id")
);

-- CreateTable
CREATE TABLE "event_data" (
"event_id" UUID NOT NULL,
"website_id" UUID NOT NULL,
"website_event_id" UUID NOT NULL,
"event_key" VARCHAR(500) NOT NULL,
"event_string_value" VARCHAR(500),
"event_numeric_value" DECIMAL(19,4),
"event_date_value" TIMESTAMPTZ(6),
"event_data_type" INTEGER NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "event_data_pkey" PRIMARY KEY ("event_id")
);

-- CreateTable
CREATE TABLE "team" (
"team_id" UUID NOT NULL,
"name" VARCHAR(50) NOT NULL,
"access_code" VARCHAR(50),
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(6),

CONSTRAINT "team_pkey" PRIMARY KEY ("team_id")
);

-- CreateTable
CREATE TABLE "team_user" (
"team_user_id" UUID NOT NULL,
"team_id" UUID NOT NULL,
"user_id" UUID NOT NULL,
"role" VARCHAR(50) NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(6),

CONSTRAINT "team_user_pkey" PRIMARY KEY ("team_user_id")
);

-- CreateTable
CREATE TABLE "team_website" (
"team_website_id" UUID NOT NULL,
"team_id" UUID NOT NULL,
"website_id" UUID NOT NULL,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "team_website_pkey" PRIMARY KEY ("team_website_id")
);

-- CreateIndex
CREATE UNIQUE INDEX "user_user_id_key" ON "user"("user_id");

-- CreateIndex
CREATE UNIQUE INDEX "user_username_key" ON "user"("username");

-- CreateIndex
CREATE UNIQUE INDEX "session_session_id_key" ON "session"("session_id");

-- CreateIndex
CREATE INDEX "session_created_at_idx" ON "session"("created_at");

-- CreateIndex
CREATE INDEX "session_website_id_idx" ON "session"("website_id");

-- CreateIndex
CREATE UNIQUE INDEX "website_website_id_key" ON "website"("website_id");

-- CreateIndex
CREATE UNIQUE INDEX "website_share_id_key" ON "website"("share_id");

-- CreateIndex
CREATE INDEX "website_user_id_idx" ON "website"("user_id");

-- CreateIndex
CREATE INDEX "website_created_at_idx" ON "website"("created_at");

-- CreateIndex
CREATE INDEX "website_share_id_idx" ON "website"("share_id");

-- CreateIndex
CREATE INDEX "website_event_created_at_idx" ON "website_event"("created_at");

-- CreateIndex
CREATE INDEX "website_event_session_id_idx" ON "website_event"("session_id");

-- CreateIndex
CREATE INDEX "website_event_website_id_idx" ON "website_event"("website_id");

-- CreateIndex
CREATE INDEX "website_event_website_id_created_at_idx" ON "website_event"("website_id", "created_at");

-- CreateIndex
CREATE INDEX "website_event_website_id_session_id_created_at_idx" ON "website_event"("website_id", "session_id", "created_at");

-- CreateIndex
CREATE INDEX "event_data_created_at_idx" ON "event_data"("created_at");

-- CreateIndex
CREATE INDEX "event_data_website_id_idx" ON "event_data"("website_id");

-- CreateIndex
CREATE INDEX "event_data_website_event_id_idx" ON "event_data"("website_event_id");

-- CreateIndex
CREATE UNIQUE INDEX "team_team_id_key" ON "team"("team_id");

-- CreateIndex
CREATE UNIQUE INDEX "team_access_code_key" ON "team"("access_code");

-- CreateIndex
CREATE INDEX "team_access_code_idx" ON "team"("access_code");

-- CreateIndex
CREATE UNIQUE INDEX "team_user_team_user_id_key" ON "team_user"("team_user_id");

-- CreateIndex
CREATE INDEX "team_user_team_id_idx" ON "team_user"("team_id");

-- CreateIndex
CREATE INDEX "team_user_user_id_idx" ON "team_user"("user_id");

-- CreateIndex
CREATE UNIQUE INDEX "team_website_team_website_id_key" ON "team_website"("team_website_id");

-- CreateIndex
CREATE INDEX "team_website_team_id_idx" ON "team_website"("team_id");

-- CreateIndex
CREATE INDEX "team_website_website_id_idx" ON "team_website"("website_id");

-- AddSystemUser
INSERT INTO "user" (user_id, username, role, password) VALUES ('41e2b680-648e-4b09-bcd7-3e2b10c06264' , 'admin', 'admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa');

之后确实初始化成功,如图所示(前后对比),建立了对应的表

Snipaste_2023-07-08_09-27-46

Snipaste_2023-07-08_09-28-10

Vercel部署过程报错了,报错信息如下(仅截取错误部分)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ node scripts/check-db.js
DATABASE_URL is defined.
Database connection successful.
Database version check successful.
Error: P3005
The database schema is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline
Command failed: prisma migrate deploy
Error: P3005
The database schema is not empty. Read more about how to baseline an existing production database: https://pris.ly/d/migrate-baseline
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
ERROR: "check-db" exited with 1.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Error: Command "yarn run build" exited with 1

数据库链接是成功的,但数据库架构不为空,

报错P3005,意思是数据库已经有数据(初始化导致的错误)

报错后,将上述数据库的表全部清空,再重新部署即可

所以,数据库初始化这一步骤非必须的,推测可能是版本差异问题吧


Hexo_网站统计分析
https://linguoguang.com/2023/07/08/Hexo_网站统计分析/
作者
linguoguang
发布于
2023年7月8日
许可协议