我使用 FireStore 作为我的移动应用程序后端。该应用程序仍在开发中,尚未发布。它甚至还没有在我的手机上,只是我正在构建它时的笔记本电脑模拟器。我对 FireBase 在我的应用程序没有被使用时从我的应用程序中计数的读取和规则评估感到困惑。
根据 FireStore 控制台中的使用情况图表,我从中午 12 点到下午 2 点工作,并在晚上 7 点左右重新登录。
同样,当我查看另一张图时,我看到在我不处理它时发生了读取。
如果 FireBase/FireStore 在应用程序未使用时向我收费,我将不得不开始寻找其他后端解决方案。
正如 Doug 评论的那样,我们不可能根据您共享的信息知道读数来自哪里。但在我使用 Firestore 的所有时间里,我从未见过它对实际没有发生的读取进行计数。所以对我来说,这通常是找到源头的问题,而不是怀疑系统。
最近我开始使用 Firestore 的审核日志记录 功能来确定读取的来源。具体来说,数据访问审核日志允许您获取每个读/写操作的服务器端视图 - 包括其周围的元数据。
例如,在我的一项测试中,我想知道每个用户(由其 Firebase 身份验证 UID 标识)引起了多少次读取操作,最后我得到了以下图表:
每次操作记录的完整信息非常庞大。例如,这只是我为侦听操作找到的一个条目:
{
"protoPayload": {
"@type": "type.googleapis.com/google.cloud.audit.AuditLog",
"status": {},
"authenticationInfo": {
"principalEmail": "[email protected]",
"thirdPartyPrincipal": {
"@type": "type.googleapis.com/google.cloud.audit.ThirdPartyJwt",
"payload": {
"payload": {
"sign_in_provider": "anonymous",
"identities": {}
},
"iss": "https://securetoken.google.com/nanochat-20241022-mw8qu9",
"iat": 1731091820,
"aud": "nanochat-20241022-mw8qu9",
"provider_id": "anonymous",
"sub": "mzi2JtP9p1fxavXdVvuk2qMyIWB3",
"auth_time": 1731007799,
"user_id": "mzi2JtP9p1fxavXdVvuk2qMyIWB3",
"exp": 1731095420
},
"header": {
"typ": "JWT",
"alg": "RS256",
"kid": "b8cac95b4a5acde0b96572dee8c8c95eee48cccd"
}
}
},
"requestMetadata": {
"callerIp": "157.131.245.100",
"callerSuppliedUserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36,gzip(gfe),gzip(gfe)",
"requestAttributes": {
"time": "2024-11-08T19:14:57.226501Z",
"auth": {}
},
"destinationAttributes": {}
},
"serviceName": "firestore.googleapis.com",
"methodName": "google.firestore.v1.Firestore.Listen",
"authorizationInfo": [
{
"resource": "projects/nanochat-20241022-mw8qu9/databases/(default)",
"permission": "datastore.entities.get",
"granted": true,
"resourceAttributes": {
"service": "firestore.googleapis.com",
"name": "projects/nanochat-20241022-mw8qu9/databases/(default)",
"type": "firestore.googleapis.com/Database"
},
"permissionType": "DATA_READ"
},
{
"resource": "projects/nanochat-20241022-mw8qu9/databases/(default)",
"permission": "datastore.entities.list",
"granted": true,
"resourceAttributes": {
"service": "firestore.googleapis.com",
"name": "projects/nanochat-20241022-mw8qu9/databases/(default)",
"type": "firestore.googleapis.com/Database"
},
"permissionType": "DATA_READ"
}
],
"resourceName": "projects/nanochat-20241022-mw8qu9/databases/(default)",
"numResponseItems": "10",
"request": {
"@type": "type.googleapis.com/google.firestore.v1.ListenRequest",
"addTarget": {
"targetId": 102,
"query": {
"parent": "projects/nanochat-20241022-mw8qu9/databases/(default)/documents",
"structuredQuery": {
"limit": 10,
"from": [
{
"collectionId": "chat"
}
],
"orderBy": [
{
"direction": "DESCENDING",
"field": {
"fieldPath": "timestamp"
}
},
{
"direction": "DESCENDING",
"field": {
"fieldPath": "__name__"
}
}
]
}
}
}
},
"metadata": {
"@type": "type.googleapis.com/google.cloud.audit.DatastoreServiceData"
}
},
"insertId": "-itd58hf2gzijg",
"resource": {
"type": "audited_resource",
"labels": {
"project_id": "nanochat-20241022-mw8qu9",
"service": "firestore.googleapis.com",
"method": "google.firestore.v1.Firestore.Listen"
}
},
"timestamp": "2024-11-08T19:14:57.217715Z",
"severity": "INFO",
"logName": "projects/nanochat-20241022-mw8qu9/logs/cloudaudit.googleapis.com%2Fdata_access",
"operation": {
"id": "3c9374e7-6d46-4619-ad12-a0bfbfac16b1",
"producer": "firestore.googleapis.com",
"last": true
},
"receiveTimestamp": "2024-11-08T19:14:57.639965123Z"
}
根据这些条目,我使用以下 SQL 查询来生成聊天数据:
SELECT
JSON_VALUE(proto_payload.audit_log.authentication_info.third_party_principal.payload.user_id) as uid,
TIMESTAMP_TRUNC(timestamp, DAY) as day,
SUM(proto_payload.audit_log.num_response_items) as read_count
FROM `nanochat-20241022-mw8qu9.global._Default._AllLogs`
WHERE proto_payload.audit_log.authorization_info[0].permission_type IN ('DATA_READ', 'DATA_WRITE')
AND proto_payload.audit_log.method_name LIKE 'google.firestore.v1.Firestore%'
GROUP BY
JSON_VALUE(proto_payload.audit_log.authentication_info.third_party_principal.payload.user_id),
TIMESTAMP_TRUNC(timestamp, DAY)
要详细了解我如何创建图表以及如何进行设置,请阅读我撰写的完整文章:计算 Firestore 中每个用户的文档读取量。