分析服务器参考

自托管分析

Supabase Analytics 服务器是 Logflare 的一个可自托管实例,用于管理摄取和查询管道,以搜索和聚合结构化分析事件。

自托管 Analytics 服务器时,Studio 实例中提供了与 Supabase 平台相同的完整日志记录体验,从而实现了集成和增强的开发体验。但是,需要注意的是,由于平台的基础设施,可能会出现某些差异

支持的后端#

Analytics 服务器支持 PostgresBigQuery 作为后端。supabase-cli 体验默认使用 Postgres 后端。然而,Supabase 平台使用 BigQuery 后端存储所有平台日志。

使用 BigQuery 后端时,会在提供的 Google Cloud 项目中创建一个 BigQuery 数据集,并为每个源创建表。日志事件会流式传输到每个表中,并且 Studio 或日志浏览器生成的所有查询都会针对 BigQuery API 执行。此后端需要互联网访问才能工作,并且无法完全在本地运行。

使用 Postgres 后端时,会在提供的模式中为每个源创建表(对于 supabase-cli,这将是 _analytics)。Logflare 接收到的日志事件会直接插入到相应的表中。Studio 中所有 BigQuery 方言的 SQL 查询都将由 Analytics 服务器中的翻译层处理。此翻译层将查询翻译为 PostgreSQL 方言,然后针对 Postgres 数据库执行。

Postgres 后端尚未针对高容量插入或繁重查询使用进行优化。目前,翻译层仅处理 BigQuery 方言的有限子集。因此,当使用 Postgres 后端时,日志浏览器可能会对更高级的查询产生错误。

入门#

在熟悉和尝试自托管 Supabase 时,建议使用 Postgres 后端。对于生产环境,我们建议使用 BigQuery 后端。有关更多信息,请参阅生产建议

要设置自托管 Supabase 中的日志记录,请参阅 docker-compose 示例。需要两个 compose 服务:Logflare 和 Vector。Logflare 是 HTTP 分析服务器,而 Vector 是日志记录管道,用于将所有 compose 服务的 syslog 路由到 Logflare 服务器。

无论选择哪个后端,都必须supabase/logflare docker 镜像设置以下环境变量

  • LOGFLARE_SINGLE_TENANT=true:用于启用 Logflare 单租户模式的功能标志。必须设置为 true
  • LOGFLARE_SUPABASE_MODE=true:用于初始化 Supabase 相关数据的功能标志。必须设置为 true

有关所有其他配置环境变量,请参阅 Logflare 自托管文档

Postgres 后端设置#

示例 docker-compose 默认使用 Postgres 后端。

1
# clone the supabase/supabase repo, and run the following
2
cd docker
3
docker compose -f docker-compose.yml up

配置和要求#

  • supabase/logflare:1.4.0 或更高版本
  • 相关环境变量
    • POSTGRES_BACKEND_URL:必需。Postgres 数据库的连接字符串。
    • POSTGRES_BACKEND_SCHEMA:可选。允许自定义用于在数据库中限定所有后端操作的模式。

BigQuery 后端设置#

BigQuery 后端是一个更健壮、可扩展的后端选项,经过实战检验,已可用于生产环境。如果您打算进行大量日志记录使用并需要高级查询功能(例如日志浏览器),请使用此后端。

配置和要求#

创建项目后的要求如下

  • 已启用账单的 Google Cloud 项目
  • 项目 ID
  • 项目编号
  • 服务帐号密钥。

设置 BigQuery 服务帐号#

所使用的服务帐号必须具有足够的权限才能插入您的 Google Cloud BigQuery。确保服务帐号具有以下任一权限:

  • BigQuery Admin 角色;或
  • 以下权限
    • bigquery.datasets.create
    • bigquery.datasets.get
    • bigquery.datasets.getIamPolicy
    • bigquery.datasets.update
    • bigquery.jobs.create
    • bigquery.routines.create
    • bigquery.routines.update
    • bigquery.tables.create
    • bigquery.tables.delete
    • bigquery.tables.get
    • bigquery.tables.getData
    • bigquery.tables.update
    • bigquery.tables.updateData

您可以根据 Google Cloud 文档,通过网络控制台或 gcloud CLI 创建服务帐号。在网络控制台中,您可以通过导航到 IAM > 服务帐号 > 操作(下拉菜单)> 管理密钥来创建密钥

我们建议设置 BigQuery Admin 角色,因为它简化了权限设置。

下载服务帐号密钥#

创建服务帐号后,您需要为该服务帐号创建一个密钥。此密钥将签署 Analytics 服务器向 BigQuery 发出的 API 请求的 JWT。这可以通过 Google Cloud 控制台中的 IAM 部分完成。

Docker 镜像配置#

使用基于 docker-compose 的示例自托管堆栈,您可以使用以下命令包含日志记录相关服务

  1. 使用必要的环境变量更新 .env.example 文件。
  • GOOGLE_PROJECT_ID
  • GOOGLE_PROJECT_NUMBER
  1. 将您的服务帐号密钥放置在当前工作目录中,文件名为 gcloud.json
  2. docker-compose.yml 中,取消注释注释 # Uncomment to use Big Query backend for analytics 下方的块部分
  3. docker-compose.yml 中,注释掉注释 # Comment variables to use Big Query backend for analytics 下方的块部分

此后,您可以使用以下命令启动示例堆栈

1
# assuming you clone the supabase/supabase repo.
2
cd docker
3
docker compose -f docker-compose.yml

BigQuery 数据集存储位置#

目前,由 Analytics 存储和管理的所有 BigQuery 数据集,无论是通过 CLI 还是自托管,都将默认使用美国区域。

Vector 使用#

在 Docker Compose 示例中,Vector 用于日志记录管道,其中日志事件转发到 Analytics API 进行摄取。

定制自己的设置时,请参阅 Vector 配置文件

必须确保有效载荷与预期的事件模式结构匹配。如果没有正确的结构,将导致 Studio Logs UI 功能中断。

与平台的差异#

API 日志依赖于 Kong 而非 Supabase Cloud API Gateway。来自 Kong 的日志未包含平台专属数据。

在自托管设置中,所有日志都通过 Vector 路由到 Logflare。由于 Kong 将 API 请求路由到 PostgREST,因此自托管或本地部署将导致 Kong 请求日志。这将导致自托管 API 请求和 Supabase 平台请求之间的日志事件元数据存在差异。

生产建议#

为了在生产环境中自托管,我们建议执行以下操作以获得更好的体验。

确保 Logflare 位于防火墙后方,并限制除安全请求之外的所有网络访问。#

自托管的 Logflare 已禁用 UI 身份验证,并旨在向互联网开放。我们建议限制对仪表板的访问,该仪表板可通过 /dashboard 路径访问。如果需要仪表板访问来管理源,我们建议使用身份验证层,例如 VPN。

使用不同的 Postgres 数据库来存储 Logflare 数据。#

Logflare 需要 Postgres 数据库才能运行。但是,如果您的自托管 Postgres 服务出现问题,您将无法调试它,因为它也会同时使 Logflare 崩溃。

自托管示例仅用作运行整个堆栈的最小示例,但不建议将相同的数据库服务器用于生产和可观测性。

使用 BigQuery 作为 Logflare 后端#

当前的 Postgres 摄取后端尚未针对生产使用进行优化。对于更繁重的使用场景,我们建议使用 BigQuery。

我们建议在生产环境中使用 BigQuery 后端,因为它提供了更好的扩展性和查询/调试体验。

定期轮换加密密钥#

Logflare 服务器使用在 LOGFLARE_DB_ENCRYPTION_KEY 环境变量上设置的 Base64 加密密钥,对敏感数据库列执行静态加密。

要执行加密密钥轮换,请将已弃用的密钥移动到 LOGFLARE_DB_ENCRYPTION_KEY_RETIRED 环境变量中,并将 LOGFLARE_DB_ENCRYPTION_KEY 环境变量替换为新密钥。执行服务器重启并检查 info 日志以检测和执行迁移。

迁移完成后,您可以安全地删除已弃用的密钥。


列出端点

get/api/endpoints

响应代码

  • 200

响应 (200)

1
[
2
{
3
"cache_duration_seconds": 42,
4
"enable_auth": true,
5
"inserted_at": "2021-12-31T23:34:00Z",
6
"max_limit": 42,
7
"name": "lorem",
8
"proactive_requerying_seconds": 42,
9
"query": "lorem",
10
"sandboxable": true,
11
"source_mapping": {},
12
"token": "lorem",
13
"updated_at": "2021-12-31T23:34:00Z"
14
}
15
]

创建端点

post/api/endpoints

正文

  • cache_duration_seconds
    可选
    integer
  • enable_auth
    可选
    boolean
  • inserted_at
    可选
    字符串
  • max_limit
    可选
    integer
  • name
    必需
    字符串
  • proactive_requerying_seconds
    可选
    integer
  • query
    必需
    字符串
  • sandboxable
    可选
    boolean
  • source_mapping
    可选
    object
  • token
    可选
    字符串
  • updated_at
    可选
    字符串

响应代码

  • 201
  • 404

响应 (201)

1
{
2
"cache_duration_seconds": 42,
3
"enable_auth": true,
4
"inserted_at": "2021-12-31T23:34:00Z",
5
"max_limit": 42,
6
"name": "lorem",
7
"proactive_requerying_seconds": 42,
8
"query": "lorem",
9
"sandboxable": true,
10
"source_mapping": {},
11
"token": "lorem",
12
"updated_at": "2021-12-31T23:34:00Z"
13
}

删除端点

delete/api/endpoints/{token}

路径参数

  • token
    必需
    字符串

    端点令牌

响应代码

  • 204
  • 404

响应 (204)

1
{}

获取端点

get/api/endpoints/{token}

路径参数

  • token
    必需
    字符串

    端点令牌

响应代码

  • 200
  • 404

响应 (200)

1
{
2
"cache_duration_seconds": 42,
3
"enable_auth": true,
4
"inserted_at": "2021-12-31T23:34:00Z",
5
"max_limit": 42,
6
"name": "lorem",
7
"proactive_requerying_seconds": 42,
8
"query": "lorem",
9
"sandboxable": true,
10
"source_mapping": {},
11
"token": "lorem",
12
"updated_at": "2021-12-31T23:34:00Z"
13
}

更新端点

put/api/endpoints/{token}

路径参数

  • token
    必需
    字符串

    端点令牌

正文

  • cache_duration_seconds
    可选
    integer
  • enable_auth
    可选
    boolean
  • inserted_at
    可选
    字符串
  • max_limit
    可选
    integer
  • name
    必需
    字符串
  • proactive_requerying_seconds
    可选
    integer
  • query
    必需
    字符串
  • sandboxable
    可选
    boolean
  • source_mapping
    可选
    object
  • token
    可选
    字符串
  • updated_at
    可选
    字符串

响应代码

  • 201
  • 404

响应 (201)

1
{
2
"cache_duration_seconds": 42,
3
"enable_auth": true,
4
"inserted_at": "2021-12-31T23:34:00Z",
5
"max_limit": 42,
6
"name": "lorem",
7
"proactive_requerying_seconds": 42,
8
"query": "lorem",
9
"sandboxable": true,
10
"source_mapping": {},
11
"token": "lorem",
12
"updated_at": "2021-12-31T23:34:00Z"
13
}

列出源

get/api/sources

响应代码

  • 200

响应 (200)

1
{
2
"items": {
3
"properties": {
4
"api_quota": {
5
"type": "integer"
6
},
7
"bigquery_table_ttl": {
8
"type": "integer"
9
},
10
"bq_table_id": {
11
"type": "string"
12
},
13
"bq_table_schema": {
14
"type": "object"
15
},
16
"custom_event_message_keys": {
17
"type": "string"
18
},
19
"favorite": {
20
"type": "boolean"
21
},
22
"has_rejected_events": {
23
"type": "boolean"
24
},
25
"id": {},
26
"inserted_at": {
27
"format": "date-time",
28
"type": "string"
29
},
30
"metrics": {
31
"type": "object"
32
},
33
"name": {
34
"type": "string"
35
},
36
"notifications": {
37
"items": {
38
"properties": {
39
"other_email_notifications": {
40
"type": "string"
41
},
42
"team_user_ids_for_email": {
43
"allOf": {
44
"type": "string"
45
},
46
"type": "array"
47
},
48
"team_user_ids_for_schema_updates": {
49
"allOf": {
50
"type": "string"
51
},
52
"type": "array"
53
},
54
"team_user_ids_for_sms": {
55
"allOf": {
56
"type": "string"
57
},
58
"type": "array"
59
},
60
"user_email_notifications": {
61
"type": "boolean"
62
},
63
"user_schema_update_notifications": {
64
"type": "boolean"
65
},
66
"user_text_notifications": {
67
"type": "boolean"
68
}
69
},
70
"title": "Notification",
71
"type": "object"
72
},
73
"type": "array"
74
},
75
"public_token": {
76
"type": "string"
77
},
78
"slack_hook_url": {
79
"type": "string"
80
},
81
"token": {
82
"type": "string"
83
},
84
"updated_at": {
85
"format": "date-time",
86
"type": "string"
87
},
88
"webhook_notification_url": {
89
"type": "string"
90
}
91
},
92
"required": [
93
"name"
94
],
95
"title": "Source",
96
"type": "object"
97
},
98
"type": "array"
99
}

创建源

post/api/sources

正文

  • api_quota
    可选
    integer
  • bigquery_table_ttl
    可选
    integer
  • bq_table_id
    可选
    字符串
  • bq_table_schema
    可选
    object
  • custom_event_message_keys
    可选
    字符串
  • favorite
    可选
    boolean
  • has_rejected_events
    可选
    boolean
  • id
    可选
    未知
  • inserted_at
    可选
    字符串
  • metrics
    可选
    object
  • name
    必需
    字符串
  • notifications
    可选
    Array<object>
  • public_token
    可选
    字符串
  • slack_hook_url
    可选
    字符串
  • token
    可选
    字符串
  • updated_at
    可选
    字符串
  • webhook_notification_url
    可选
    字符串

响应代码

  • 201
  • 404

响应 (201)

1
{
2
"properties": {
3
"api_quota": {
4
"type": "integer"
5
},
6
"bigquery_table_ttl": {
7
"type": "integer"
8
},
9
"bq_table_id": {
10
"type": "string"
11
},
12
"bq_table_schema": {
13
"type": "object"
14
},
15
"custom_event_message_keys": {
16
"type": "string"
17
},
18
"favorite": {
19
"type": "boolean"
20
},
21
"has_rejected_events": {
22
"type": "boolean"
23
},
24
"id": {},
25
"inserted_at": {
26
"format": "date-time",
27
"type": "string"
28
},
29
"metrics": {
30
"type": "object"
31
},
32
"name": {
33
"type": "string"
34
},
35
"notifications": {
36
"items": {
37
"properties": {
38
"other_email_notifications": {
39
"type": "string"
40
},
41
"team_user_ids_for_email": {
42
"allOf": {
43
"type": "string"
44
},
45
"type": "array"
46
},
47
"team_user_ids_for_schema_updates": {
48
"allOf": {
49
"type": "string"
50
},
51
"type": "array"
52
},
53
"team_user_ids_for_sms": {
54
"allOf": {
55
"type": "string"
56
},
57
"type": "array"
58
},
59
"user_email_notifications": {
60
"type": "boolean"
61
},
62
"user_schema_update_notifications": {
63
"type": "boolean"
64
},
65
"user_text_notifications": {
66
"type": "boolean"
67
}
68
},
69
"title": "Notification",
70
"type": "object"
71
},
72
"type": "array"
73
},
74
"public_token": {
75
"type": "string"
76
},
77
"slack_hook_url": {
78
"type": "string"
79
},
80
"token": {
81
"type": "string"
82
},
83
"updated_at": {
84
"format": "date-time",
85
"type": "string"
86
},
87
"webhook_notification_url": {
88
"type": "string"
89
}
90
},
91
"required": [
92
"name"
93
],
94
"title": "Source",
95
"type": "object"
96
}

删除源

delete/api/sources/{token}

路径参数

  • token
    必需
    字符串

    源令牌

响应代码

  • 204
  • 404

响应 (204)

1
{}

获取源

get/api/sources/{token}

路径参数

  • token
    必需
    字符串

    源令牌

响应代码

  • 200
  • 404

响应 (200)

1
{
2
"properties": {
3
"api_quota": {
4
"type": "integer"
5
},
6
"bigquery_table_ttl": {
7
"type": "integer"
8
},
9
"bq_table_id": {
10
"type": "string"
11
},
12
"bq_table_schema": {
13
"type": "object"
14
},
15
"custom_event_message_keys": {
16
"type": "string"
17
},
18
"favorite": {
19
"type": "boolean"
20
},
21
"has_rejected_events": {
22
"type": "boolean"
23
},
24
"id": {},
25
"inserted_at": {
26
"format": "date-time",
27
"type": "string"
28
},
29
"metrics": {
30
"type": "object"
31
},
32
"name": {
33
"type": "string"
34
},
35
"notifications": {
36
"items": {
37
"properties": {
38
"other_email_notifications": {
39
"type": "string"
40
},
41
"team_user_ids_for_email": {
42
"allOf": {
43
"type": "string"
44
},
45
"type": "array"
46
},
47
"team_user_ids_for_schema_updates": {
48
"allOf": {
49
"type": "string"
50
},
51
"type": "array"
52
},
53
"team_user_ids_for_sms": {
54
"allOf": {
55
"type": "string"
56
},
57
"type": "array"
58
},
59
"user_email_notifications": {
60
"type": "boolean"
61
},
62
"user_schema_update_notifications": {
63
"type": "boolean"
64
},
65
"user_text_notifications": {
66
"type": "boolean"
67
}
68
},
69
"title": "Notification",
70
"type": "object"
71
},
72
"type": "array"
73
},
74
"public_token": {
75
"type": "string"
76
},
77
"slack_hook_url": {
78
"type": "string"
79
},
80
"token": {
81
"type": "string"
82
},
83
"updated_at": {
84
"format": "date-time",
85
"type": "string"
86
},
87
"webhook_notification_url": {
88
"type": "string"
89
}
90
},
91
"required": [
92
"name"
93
],
94
"title": "Source",
95
"type": "object"
96
}

更新源

put/api/sources/{token}

路径参数

  • token
    必需
    字符串

    源令牌

正文

  • api_quota
    可选
    integer
  • bigquery_table_ttl
    可选
    integer
  • bq_table_id
    可选
    字符串
  • bq_table_schema
    可选
    object
  • custom_event_message_keys
    可选
    字符串
  • favorite
    可选
    boolean
  • has_rejected_events
    可选
    boolean
  • id
    可选
    未知
  • inserted_at
    可选
    字符串
  • metrics
    可选
    object
  • name
    必需
    字符串
  • notifications
    可选
    Array<object>
  • public_token
    可选
    字符串
  • slack_hook_url
    可选
    字符串
  • token
    可选
    字符串
  • updated_at
    可选
    字符串
  • webhook_notification_url
    可选
    字符串

响应代码

  • 201
  • 404

响应 (201)

1
{
2
"properties": {
3
"api_quota": {
4
"type": "integer"
5
},
6
"bigquery_table_ttl": {
7
"type": "integer"
8
},
9
"bq_table_id": {
10
"type": "string"
11
},
12
"bq_table_schema": {
13
"type": "object"
14
},
15
"custom_event_message_keys": {
16
"type": "string"
17
},
18
"favorite": {
19
"type": "boolean"
20
},
21
"has_rejected_events": {
22
"type": "boolean"
23
},
24
"id": {},
25
"inserted_at": {
26
"format": "date-time",
27
"type": "string"
28
},
29
"metrics": {
30
"type": "object"
31
},
32
"name": {
33
"type": "string"
34
},
35
"notifications": {
36
"items": {
37
"properties": {
38
"other_email_notifications": {
39
"type": "string"
40
},
41
"team_user_ids_for_email": {
42
"allOf": {
43
"type": "string"
44
},
45
"type": "array"
46
},
47
"team_user_ids_for_schema_updates": {
48
"allOf": {
49
"type": "string"
50
},
51
"type": "array"
52
},
53
"team_user_ids_for_sms": {
54
"allOf": {
55
"type": "string"
56
},
57
"type": "array"
58
},
59
"user_email_notifications": {
60
"type": "boolean"
61
},
62
"user_schema_update_notifications": {
63
"type": "boolean"
64
},
65
"user_text_notifications": {
66
"type": "boolean"
67
}
68
},
69
"title": "Notification",
70
"type": "object"
71
},
72
"type": "array"
73
},
74
"public_token": {
75
"type": "string"
76
},
77
"slack_hook_url": {
78
"type": "string"
79
},
80
"token": {
81
"type": "string"
82
},
83
"updated_at": {
84
"format": "date-time",
85
"type": "string"
86
},
87
"webhook_notification_url": {
88
"type": "string"
89
}
90
},
91
"required": [
92
"name"
93
],
94
"title": "Source",
95
"type": "object"
96
}

列出团队

get/api/teams

响应代码

  • 200

响应 (200)

1
[
2
{
3
"name": "lorem",
4
"team_users": [
5
{
6
"email": "lorem",
7
"name": "lorem"
8
}
9
],
10
"token": "lorem",
11
"user": {
12
"api_key": "lorem",
13
"api_quota": 42,
14
"bigquery_dataset_id": "lorem",
15
"bigquery_dataset_location": "lorem",
16
"bigquery_project_id": "lorem",
17
"company": "lorem",
18
"email": "lorem",
19
"email_me_product": true,
20
"email_preferred": "lorem",
21
"image": "lorem",
22
"name": "lorem",
23
"phone": "lorem",
24
"provider": "lorem",
25
"token": "lorem"
26
}
27
}
28
]

创建团队

post/api/teams

正文

  • name
    必需
    字符串
  • team_users
    可选
    Array<object>
  • token
    可选
    字符串
  • user
    可选
    object

响应代码

  • 201
  • 404

响应 (201)

1
{
2
"name": "lorem",
3
"team_users": [
4
{
5
"email": "lorem",
6
"name": "lorem"
7
}
8
],
9
"token": "lorem",
10
"user": {
11
"api_key": "lorem",
12
"api_quota": 42,
13
"bigquery_dataset_id": "lorem",
14
"bigquery_dataset_location": "lorem",
15
"bigquery_project_id": "lorem",
16
"company": "lorem",
17
"email": "lorem",
18
"email_me_product": true,
19
"email_preferred": "lorem",
20
"image": "lorem",
21
"name": "lorem",
22
"phone": "lorem",
23
"provider": "lorem",
24
"token": "lorem"
25
}
26
}

删除团队

delete/api/teams/{token}

路径参数

  • token
    必需
    字符串

    团队令牌

响应代码

  • 204
  • 404

响应 (204)

1
{}

获取团队

get/api/teams/{token}

路径参数

  • token
    必需
    字符串

    团队令牌

响应代码

  • 200
  • 404

响应 (200)

1
{
2
"name": "lorem",
3
"team_users": [
4
{
5
"email": "lorem",
6
"name": "lorem"
7
}
8
],
9
"token": "lorem",
10
"user": {
11
"api_key": "lorem",
12
"api_quota": 42,
13
"bigquery_dataset_id": "lorem",
14
"bigquery_dataset_location": "lorem",
15
"bigquery_project_id": "lorem",
16
"company": "lorem",
17
"email": "lorem",
18
"email_me_product": true,
19
"email_preferred": "lorem",
20
"image": "lorem",
21
"name": "lorem",
22
"phone": "lorem",
23
"provider": "lorem",
24
"token": "lorem"
25
}
26
}

更新团队

put/api/teams/{token}

路径参数

  • token
    必需
    字符串

    团队令牌

正文

  • name
    必需
    字符串
  • team_users
    可选
    Array<object>
  • token
    可选
    字符串
  • user
    可选
    object

响应代码

  • 201
  • 404

响应 (201)

1
{
2
"name": "lorem",
3
"team_users": [
4
{
5
"email": "lorem",
6
"name": "lorem"
7
}
8
],
9
"token": "lorem",
10
"user": {
11
"api_key": "lorem",
12
"api_quota": 42,
13
"bigquery_dataset_id": "lorem",
14
"bigquery_dataset_location": "lorem",
15
"bigquery_project_id": "lorem",
16
"company": "lorem",
17
"email": "lorem",
18
"email_me_product": true,
19
"email_preferred": "lorem",
20
"image": "lorem",
21
"name": "lorem",
22
"phone": "lorem",
23
"provider": "lorem",
24
"token": "lorem"
25
}
26
}