木木困玉光

Hexo_网站统计分析


Tags: #软件 #Hexo
Created:
Updated:

前言

给网站拓展个统计分析功能,采用免费开源的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代码即可

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

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

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

image-20230708131344142

后话

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

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

-- 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部署过程报错了,报错信息如下(仅截取错误部分)

$ 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,意思是数据库已经有数据(初始化导致的错误)

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

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

:D 获取中...