diff --git a/docs/changelog/index.md b/docs/changelog/index.md index 25a47431..8636e499 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -26,8 +26,21 @@ sidebar: false - Pages 现支持上传 zip、tar.gz、tar.xz、tar.bz2、tar、7z 等常用压缩格式的部署包。 - 管理员可在运维设置中配置 Pages 部署包大小上限与每个项目的历史部署保留数量。 +### 修复 + +- 修复数据看板「OpenResty 入站/出站」近 24 小时趋势严重偏低的问题:边缘侧改为上报进程累计字节,并与访问日志中的已提供数据(响应体字节)口径对齐,避免按 60 秒窗口计数做差分导致流量被大量丢弃。 + ### 变更 +- Agent 离线观测补传默认保留窗口由 15 分钟调整为 60 分钟,断线恢复后可补报更长时间范围内的访问与指标数据。 +- Agent 默认心跳/上报间隔由 10 秒调整为 3 秒,节点离线判定默认阈值由 120 秒调整为 60 秒,状态与观测数据刷新更及时。 +- 边缘观测按「访问日志为业务唯一真相」收敛:Agent 上报访问明细、主机指标与 OpenResty 健康/连接,不再上报业务预聚合;看板请求趋势与已提供/接收数据改由访问日志聚合,宿主机网卡单独展示。 +- 本机 `/openflare/observability` 改为返回探活与当前连接快照;访问日志增加 `request_length` / `request_time_ms` 字段用于接收数据与耗时统计。 +- 看板全局 UV 改为窗口内真正去重;状态码/Top 域名分布与节点行请求量均改为访问日志聚合;网络趋势 API 增加 `bytes_provided` / `bytes_received` 字段。 +- 观测协议与 API 去掉兼容层(Agent 销毁重建升级):心跳仅 `host_metrics` / `edge_health` / `access_logs` / `buffered`;管理端不再返回 `traffic_reports` 与 `openresty_rx|tx`;网络趋势仅 `bytes_provided` / `bytes_received` + 宿主机网卡。 +- 观测存储 M5:新增 `of_node_edge_health` 与 `of_access_log_hourly`;移除已废弃的请求预聚合表与 OpenResty 吞吐观测表,业务趋势优先读访问日志小时汇总。 +- 观测清理目标对齐为 `node_edge_health`;边缘健康完整写入 status;提供历史小时汇总回填 SQL。 +- 看板与节点 UV 文案改为「24h / 查询窗口独立访客」(整窗 `uniqExact`);小时趋势图仅展示请求/错误,不绘分时 UV。 - Pages 部署包上传体积限制改为系统动态配置,默认仍为 100 MiB,可按环境调整。 - 上传新部署后会按保留策略自动清理超出数量的历史部署包,减少磁盘占用。 - Agent 在同步 Pages 部署时信任控制面已完成的包校验,不再重复限制文件数与展开体积,仅校验下载完整性并安全解压到本地。 diff --git a/docs/docs.go b/docs/docs.go index 76715016..64cbd786 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -8382,7 +8382,7 @@ const docTemplate = `{ "SessionCookie": [] } ], - "description": "从用户提供的 HTTP(S) 链接下载部署包并创建部署记录;服务端使用浏览器伪装请求头拉取,需要管理员权限", + "description": "从用户提供的 HTTP(S) 链接下载部署包并创建部署记录;服务端使用浏览器伪装请求头拉取,允许内网地址与不安全 TLS 证书,需要管理员权限", "consumes": [ "application/json" ], @@ -13316,7 +13316,7 @@ const docTemplate = `{ "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog" } }, - "buffered_observability": { + "buffered": { "type": "array", "items": { "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.BufferedObservabilityRecord" @@ -13325,6 +13325,9 @@ const docTemplate = `{ "current_version": { "type": "string" }, + "edge_health": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth" + }, "ext_version": { "type": "string" }, @@ -13334,6 +13337,9 @@ const docTemplate = `{ "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeHealthEvent" } }, + "host_metrics": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" + }, "ip": { "type": "string" }, @@ -13349,20 +13355,14 @@ const docTemplate = `{ "openresty_message": { "type": "string" }, - "openresty_observation": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation" - }, "openresty_status": { "type": "string" }, "profile": { "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeSystemProfile" }, - "snapshot": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" - }, - "traffic_report": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport" + "schema_version": { + "type": "integer" }, "version": { "type": "string" @@ -14204,17 +14204,14 @@ const docTemplate = `{ "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog" } }, - "openresty_observation": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation" - }, - "snapshot": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" - }, - "traffic_report": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport" - }, - "window_started_at_unix": { + "captured_at_unix": { "type": "integer" + }, + "edge_health": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth" + }, + "host_metrics": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" } } }, @@ -14222,6 +14219,7 @@ const docTemplate = `{ "type": "object", "properties": { "bytes_sent": { + "description": "body bytes = 已提供数据", "type": "integer" }, "host": { @@ -14236,11 +14234,36 @@ const docTemplate = `{ "remote_addr": { "type": "string" }, + "request_length": { + "description": "接收数据", + "type": "integer" + }, + "request_time_ms": { + "description": "optional", + "type": "integer" + }, "status_code": { "type": "integer" } } }, + "github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth": { + "type": "object", + "properties": { + "captured_at_unix": { + "type": "integer" + }, + "connections": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "github_com_Rain-kl_Wavelet_pkg_protocol.NodeHealthEvent": { "type": "object", "properties": { @@ -14299,23 +14322,6 @@ const docTemplate = `{ } } }, - "github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation": { - "type": "object", - "properties": { - "captured_at_unix": { - "type": "integer" - }, - "openresty_connections": { - "type": "integer" - }, - "openresty_rx_bytes": { - "type": "integer" - }, - "openresty_tx_bytes": { - "type": "integer" - } - } - }, "github_com_Rain-kl_Wavelet_pkg_protocol.NodeSystemProfile": { "type": "object", "properties": { @@ -14354,47 +14360,6 @@ const docTemplate = `{ } } }, - "github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport": { - "type": "object", - "properties": { - "error_count": { - "type": "integer" - }, - "request_count": { - "type": "integer" - }, - "source_countries": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - }, - "status_codes": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - }, - "top_domains": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - }, - "unique_visitor_count": { - "type": "integer" - }, - "window_ended_at_unix": { - "type": "integer" - }, - "window_started_at_unix": { - "type": "integer" - } - } - }, "github_com_Rain-kl_Wavelet_pkg_protocol.PagesDeploymentHashResponse": { "type": "object", "properties": { @@ -15163,44 +15128,6 @@ const docTemplate = `{ } } }, - "model.OpenFlareRequestReport": { - "type": "object", - "properties": { - "created_at": { - "type": "string" - }, - "error_count": { - "type": "integer" - }, - "id": { - "type": "integer" - }, - "node_id": { - "type": "string" - }, - "request_count": { - "type": "integer" - }, - "source_countries_json": { - "type": "string" - }, - "status_codes_json": { - "type": "string" - }, - "top_domains_json": { - "type": "string" - }, - "unique_visitor_count": { - "type": "integer" - }, - "window_ended_at": { - "type": "string" - }, - "window_started_at": { - "type": "string" - } - } - }, "model.PushChannel": { "type": "object", "properties": { @@ -15873,12 +15800,6 @@ const docTemplate = `{ "relay_dashboard": { "$ref": "#/definitions/observability.RelayDashboardSnapshot" }, - "traffic_reports": { - "type": "array", - "items": { - "$ref": "#/definitions/model.OpenFlareRequestReport" - } - }, "trends": { "$ref": "#/definitions/observability.NodeTrends" } @@ -16461,18 +16382,20 @@ const docTemplate = `{ "bucket_started_at": { "type": "string" }, + "bytes_provided": { + "description": "sum(bytes_sent)", + "type": "integer" + }, + "bytes_received": { + "description": "sum(request_length)", + "type": "integer" + }, "network_rx_bytes": { "type": "integer" }, "network_tx_bytes": { "type": "integer" }, - "openresty_rx_bytes": { - "type": "integer" - }, - "openresty_tx_bytes": { - "type": "integer" - }, "reported_nodes": { "type": "integer" } @@ -16528,12 +16451,6 @@ const docTemplate = `{ "openresty_connections": { "type": "integer" }, - "openresty_rx_bytes": { - "type": "integer" - }, - "openresty_tx_bytes": { - "type": "integer" - }, "storage_total_bytes": { "type": "integer" }, diff --git a/docs/swagger.json b/docs/swagger.json index 3b9a4146..8f928898 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -8375,7 +8375,7 @@ "SessionCookie": [] } ], - "description": "从用户提供的 HTTP(S) 链接下载部署包并创建部署记录;服务端使用浏览器伪装请求头拉取,需要管理员权限", + "description": "从用户提供的 HTTP(S) 链接下载部署包并创建部署记录;服务端使用浏览器伪装请求头拉取,允许内网地址与不安全 TLS 证书,需要管理员权限", "consumes": [ "application/json" ], @@ -13309,7 +13309,7 @@ "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog" } }, - "buffered_observability": { + "buffered": { "type": "array", "items": { "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.BufferedObservabilityRecord" @@ -13318,6 +13318,9 @@ "current_version": { "type": "string" }, + "edge_health": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth" + }, "ext_version": { "type": "string" }, @@ -13327,6 +13330,9 @@ "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeHealthEvent" } }, + "host_metrics": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" + }, "ip": { "type": "string" }, @@ -13342,20 +13348,14 @@ "openresty_message": { "type": "string" }, - "openresty_observation": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation" - }, "openresty_status": { "type": "string" }, "profile": { "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeSystemProfile" }, - "snapshot": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" - }, - "traffic_report": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport" + "schema_version": { + "type": "integer" }, "version": { "type": "string" @@ -14197,17 +14197,14 @@ "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog" } }, - "openresty_observation": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation" - }, - "snapshot": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" - }, - "traffic_report": { - "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport" - }, - "window_started_at_unix": { + "captured_at_unix": { "type": "integer" + }, + "edge_health": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth" + }, + "host_metrics": { + "$ref": "#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot" } } }, @@ -14215,6 +14212,7 @@ "type": "object", "properties": { "bytes_sent": { + "description": "body bytes = 已提供数据", "type": "integer" }, "host": { @@ -14229,11 +14227,36 @@ "remote_addr": { "type": "string" }, + "request_length": { + "description": "接收数据", + "type": "integer" + }, + "request_time_ms": { + "description": "optional", + "type": "integer" + }, "status_code": { "type": "integer" } } }, + "github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth": { + "type": "object", + "properties": { + "captured_at_unix": { + "type": "integer" + }, + "connections": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, "github_com_Rain-kl_Wavelet_pkg_protocol.NodeHealthEvent": { "type": "object", "properties": { @@ -14292,23 +14315,6 @@ } } }, - "github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation": { - "type": "object", - "properties": { - "captured_at_unix": { - "type": "integer" - }, - "openresty_connections": { - "type": "integer" - }, - "openresty_rx_bytes": { - "type": "integer" - }, - "openresty_tx_bytes": { - "type": "integer" - } - } - }, "github_com_Rain-kl_Wavelet_pkg_protocol.NodeSystemProfile": { "type": "object", "properties": { @@ -14347,47 +14353,6 @@ } } }, - "github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport": { - "type": "object", - "properties": { - "error_count": { - "type": "integer" - }, - "request_count": { - "type": "integer" - }, - "source_countries": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - }, - "status_codes": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - }, - "top_domains": { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "int64" - } - }, - "unique_visitor_count": { - "type": "integer" - }, - "window_ended_at_unix": { - "type": "integer" - }, - "window_started_at_unix": { - "type": "integer" - } - } - }, "github_com_Rain-kl_Wavelet_pkg_protocol.PagesDeploymentHashResponse": { "type": "object", "properties": { @@ -15156,44 +15121,6 @@ } } }, - "model.OpenFlareRequestReport": { - "type": "object", - "properties": { - "created_at": { - "type": "string" - }, - "error_count": { - "type": "integer" - }, - "id": { - "type": "integer" - }, - "node_id": { - "type": "string" - }, - "request_count": { - "type": "integer" - }, - "source_countries_json": { - "type": "string" - }, - "status_codes_json": { - "type": "string" - }, - "top_domains_json": { - "type": "string" - }, - "unique_visitor_count": { - "type": "integer" - }, - "window_ended_at": { - "type": "string" - }, - "window_started_at": { - "type": "string" - } - } - }, "model.PushChannel": { "type": "object", "properties": { @@ -15866,12 +15793,6 @@ "relay_dashboard": { "$ref": "#/definitions/observability.RelayDashboardSnapshot" }, - "traffic_reports": { - "type": "array", - "items": { - "$ref": "#/definitions/model.OpenFlareRequestReport" - } - }, "trends": { "$ref": "#/definitions/observability.NodeTrends" } @@ -16454,18 +16375,20 @@ "bucket_started_at": { "type": "string" }, + "bytes_provided": { + "description": "sum(bytes_sent)", + "type": "integer" + }, + "bytes_received": { + "description": "sum(request_length)", + "type": "integer" + }, "network_rx_bytes": { "type": "integer" }, "network_tx_bytes": { "type": "integer" }, - "openresty_rx_bytes": { - "type": "integer" - }, - "openresty_tx_bytes": { - "type": "integer" - }, "reported_nodes": { "type": "integer" } @@ -16521,12 +16444,6 @@ "openresty_connections": { "type": "integer" }, - "openresty_rx_bytes": { - "type": "integer" - }, - "openresty_tx_bytes": { - "type": "integer" - }, "storage_total_bytes": { "type": "integer" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 25ea1cc8..8c14e1bf 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -60,18 +60,22 @@ definitions: items: $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog' type: array - buffered_observability: + buffered: items: $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.BufferedObservabilityRecord' type: array current_version: type: string + edge_health: + $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth' ext_version: type: string health_events: items: $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeHealthEvent' type: array + host_metrics: + $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot' ip: type: string last_error: @@ -82,16 +86,12 @@ definitions: type: string openresty_message: type: string - openresty_observation: - $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation' openresty_status: type: string profile: $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeSystemProfile' - snapshot: - $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot' - traffic_report: - $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport' + schema_version: + type: integer version: type: string waf_ip_group_checksums: @@ -645,18 +645,17 @@ definitions: items: $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog' type: array - openresty_observation: - $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation' - snapshot: - $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot' - traffic_report: - $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport' - window_started_at_unix: + captured_at_unix: type: integer + edge_health: + $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth' + host_metrics: + $ref: '#/definitions/github_com_Rain-kl_Wavelet_pkg_protocol.NodeMetricSnapshot' type: object github_com_Rain-kl_Wavelet_pkg_protocol.NodeAccessLog: properties: bytes_sent: + description: body bytes = 已提供数据 type: integer host: type: string @@ -666,9 +665,26 @@ definitions: type: string remote_addr: type: string + request_length: + description: 接收数据 + type: integer + request_time_ms: + description: optional + type: integer status_code: type: integer type: object + github_com_Rain-kl_Wavelet_pkg_protocol.NodeEdgeHealth: + properties: + captured_at_unix: + type: integer + connections: + type: integer + message: + type: string + status: + type: string + type: object github_com_Rain-kl_Wavelet_pkg_protocol.NodeHealthEvent: properties: event_type: @@ -707,17 +723,6 @@ definitions: storage_used_bytes: type: integer type: object - github_com_Rain-kl_Wavelet_pkg_protocol.NodeOpenrestyObservation: - properties: - captured_at_unix: - type: integer - openresty_connections: - type: integer - openresty_rx_bytes: - type: integer - openresty_tx_bytes: - type: integer - type: object github_com_Rain-kl_Wavelet_pkg_protocol.NodeSystemProfile: properties: architecture: @@ -743,34 +748,6 @@ definitions: uptime_seconds: type: integer type: object - github_com_Rain-kl_Wavelet_pkg_protocol.NodeTrafficReport: - properties: - error_count: - type: integer - request_count: - type: integer - source_countries: - additionalProperties: - format: int64 - type: integer - type: object - status_codes: - additionalProperties: - format: int64 - type: integer - type: object - top_domains: - additionalProperties: - format: int64 - type: integer - type: object - unique_visitor_count: - type: integer - window_ended_at_unix: - type: integer - window_started_at_unix: - type: integer - type: object github_com_Rain-kl_Wavelet_pkg_protocol.PagesDeploymentHashResponse: properties: deployment_id: @@ -1276,31 +1253,6 @@ definitions: value: type: string type: object - model.OpenFlareRequestReport: - properties: - created_at: - type: string - error_count: - type: integer - id: - type: integer - node_id: - type: string - request_count: - type: integer - source_countries_json: - type: string - status_codes_json: - type: string - top_domains_json: - type: string - unique_visitor_count: - type: integer - window_ended_at: - type: string - window_started_at: - type: string - type: object model.PushChannel: properties: created_at: @@ -1757,10 +1709,6 @@ definitions: $ref: '#/definitions/model.OpenFlareNodeSystemProfile' relay_dashboard: $ref: '#/definitions/observability.RelayDashboardSnapshot' - traffic_reports: - items: - $ref: '#/definitions/model.OpenFlareRequestReport' - type: array trends: $ref: '#/definitions/observability.NodeTrends' type: object @@ -2142,14 +2090,16 @@ definitions: properties: bucket_started_at: type: string + bytes_provided: + description: sum(bytes_sent) + type: integer + bytes_received: + description: sum(request_length) + type: integer network_rx_bytes: type: integer network_tx_bytes: type: integer - openresty_rx_bytes: - type: integer - openresty_tx_bytes: - type: integer reported_nodes: type: integer type: object @@ -2186,10 +2136,6 @@ definitions: type: string openresty_connections: type: integer - openresty_rx_bytes: - type: integer - openresty_tx_bytes: - type: integer storage_total_bytes: type: integer storage_used_bytes: @@ -9056,7 +9002,7 @@ paths: post: consumes: - application/json - description: 从用户提供的 HTTP(S) 链接下载部署包并创建部署记录;服务端使用浏览器伪装请求头拉取,需要管理员权限 + description: 从用户提供的 HTTP(S) 链接下载部署包并创建部署记录;服务端使用浏览器伪装请求头拉取,允许内网地址与不安全 TLS 证书,需要管理员权限 parameters: - description: 项目 ID in: path diff --git a/frontend/lib/theme/themes.json b/frontend/lib/theme/themes.json index 9818de0f..40c4d4ba 100644 --- a/frontend/lib/theme/themes.json +++ b/frontend/lib/theme/themes.json @@ -4559,4 +4559,4 @@ } } } -] \ No newline at end of file +]