fix(metrics): 补齐媒体结果存储读取与兼容响应指标
增加对象存储 GET、结果 URL 签名和同步 Base64 限流指标,使生产轮询可直接验证零对象下载,并区分签名失败、容量等待超时和 20MiB 超限。\n\n验证:API 全量 go test、go vet、gofmt 与 git diff --check。
This commit is contained in:
@@ -109,11 +109,19 @@ type Metrics struct {
|
||||
storageChannelFailovers atomic.Uint64
|
||||
storageAllChannelsFailed atomic.Uint64
|
||||
storageObjectifiedBytes atomic.Uint64
|
||||
storageObjectReads atomic.Uint64
|
||||
storageObjectReadFailures atomic.Uint64
|
||||
storageObjectReadBytes atomic.Uint64
|
||||
resultSourceUpstreamURL atomic.Uint64
|
||||
resultSourceUploaded atomic.Uint64
|
||||
resultPollResponses atomic.Uint64
|
||||
resultPollResponseBytes atomic.Uint64
|
||||
resultPollOversized atomic.Uint64
|
||||
resultURLSignSuccess atomic.Uint64
|
||||
resultURLSignFailure atomic.Uint64
|
||||
syncBase64Success atomic.Uint64
|
||||
syncBase64CapacityTimeout atomic.Uint64
|
||||
syncBase64TooLarge atomic.Uint64
|
||||
taskAdmissionWaitBuckets [11]atomic.Uint64
|
||||
taskAdmissionWaitMicros atomic.Uint64
|
||||
}
|
||||
@@ -347,6 +355,13 @@ func (m *Metrics) ObserveObjectStorage(event string, provider string, bytes int6
|
||||
m.storageChannelFailovers.Add(1)
|
||||
case "all_failed":
|
||||
m.storageAllChannelsFailed.Add(1)
|
||||
case "read_success", "read_failure":
|
||||
m.storageObjectReads.Add(1)
|
||||
if event == "read_failure" {
|
||||
m.storageObjectReadFailures.Add(1)
|
||||
} else if bytes > 0 {
|
||||
m.storageObjectReadBytes.Add(uint64(bytes))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +386,26 @@ func (m *Metrics) ObserveResultDelivery(event string, bytes int64) {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Metrics) ObserveResultURLSigning(outcome string) {
|
||||
switch strings.ToLower(strings.TrimSpace(outcome)) {
|
||||
case "success":
|
||||
m.resultURLSignSuccess.Add(1)
|
||||
case "failure":
|
||||
m.resultURLSignFailure.Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Metrics) ObserveSynchronousBase64(outcome string) {
|
||||
switch strings.ToLower(strings.TrimSpace(outcome)) {
|
||||
case "success":
|
||||
m.syncBase64Success.Add(1)
|
||||
case "capacity_timeout":
|
||||
m.syncBase64CapacityTimeout.Add(1)
|
||||
case "too_large":
|
||||
m.syncBase64TooLarge.Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Metrics) ObserveTaskAdmissionWait(wait time.Duration) {
|
||||
if wait < 0 {
|
||||
wait = 0
|
||||
@@ -587,6 +622,9 @@ func (m *Metrics) Handler(provider MetricsSnapshotProvider, issuer, audience str
|
||||
plainCounter(w, "easyai_gateway_storage_channel_failovers_total", "Switches to the next configured storage channel.", m.storageChannelFailovers.Load())
|
||||
plainCounter(w, "easyai_gateway_storage_all_channels_failed_total", "Storage writes where every eligible channel failed.", m.storageAllChannelsFailed.Load())
|
||||
plainCounter(w, "easyai_gateway_storage_objectified_bytes_total", "Binary bytes successfully written through storage channels.", m.storageObjectifiedBytes.Load())
|
||||
plainCounter(w, "easyai_gateway_storage_object_get_attempts_total", "Object storage GET attempts, including synchronous compatibility hydration.", m.storageObjectReads.Load())
|
||||
plainCounter(w, "easyai_gateway_storage_object_get_failures_total", "Failed object storage GET attempts.", m.storageObjectReadFailures.Load())
|
||||
plainCounter(w, "easyai_gateway_storage_object_get_bytes_total", "Bytes read from object storage GET responses.", m.storageObjectReadBytes.Load())
|
||||
outcomeCounters(w, "easyai_gateway_result_storage_total", "Generated media results by canonical storage source.", []outcomeValue{
|
||||
{"upstream_url", m.resultSourceUpstreamURL.Load()},
|
||||
{"uploaded", m.resultSourceUploaded.Load()},
|
||||
@@ -594,6 +632,15 @@ func (m *Metrics) Handler(provider MetricsSnapshotProvider, issuer, audience str
|
||||
plainCounter(w, "easyai_gateway_result_poll_responses_total", "Successful URL-only task result responses.", m.resultPollResponses.Load())
|
||||
plainCounter(w, "easyai_gateway_result_poll_response_bytes_total", "Bytes written by successful URL-only task result responses.", m.resultPollResponseBytes.Load())
|
||||
plainCounter(w, "easyai_gateway_result_poll_oversized_total", "Task result responses rejected by the URL-only size gate.", m.resultPollOversized.Load())
|
||||
outcomeCounters(w, "easyai_gateway_result_url_signing_total", "Private result URL signing attempts by outcome.", []outcomeValue{
|
||||
{"success", m.resultURLSignSuccess.Load()},
|
||||
{"failure", m.resultURLSignFailure.Load()},
|
||||
})
|
||||
outcomeCounters(w, "easyai_gateway_sync_base64_responses_total", "Synchronous Base64 compatibility responses by bounded outcome.", []outcomeValue{
|
||||
{"success", m.syncBase64Success.Load()},
|
||||
{"capacity_timeout", m.syncBase64CapacityTimeout.Load()},
|
||||
{"too_large", m.syncBase64TooLarge.Load()},
|
||||
})
|
||||
publicErrorCounters(w, publicerror.MetricSnapshot())
|
||||
platformModelRateLimitUtilizationGauges(w, modelRateLimits)
|
||||
plainGauge(w, "easyai_gateway_postgres_pool_max_connections", "Maximum PostgreSQL connections in this process pool.", int64(postgresPool.MaxConnections))
|
||||
|
||||
@@ -57,10 +57,17 @@ func TestMetricsExposeBoundedOutcomesAndState(t *testing.T) {
|
||||
metrics.ObserveObjectStorage("retry", "s3", 0, 0)
|
||||
metrics.ObserveObjectStorage("failover", "s3", 0, 0)
|
||||
metrics.ObserveObjectStorage("all_failed", "", 0, 0)
|
||||
metrics.ObserveObjectStorage("read_success", "aliyun_oss", 256, 15*time.Millisecond)
|
||||
metrics.ObserveObjectStorage("read_failure", "aliyun_oss", 0, 5*time.Millisecond)
|
||||
metrics.ObserveResultStorage("upstream_url")
|
||||
metrics.ObserveResultStorage("uploaded")
|
||||
metrics.ObserveResultDelivery("poll_success", 512)
|
||||
metrics.ObserveResultDelivery("poll_oversized", 70<<10)
|
||||
metrics.ObserveResultURLSigning("success")
|
||||
metrics.ObserveResultURLSigning("failure")
|
||||
metrics.ObserveSynchronousBase64("success")
|
||||
metrics.ObserveSynchronousBase64("capacity_timeout")
|
||||
metrics.ObserveSynchronousBase64("too_large")
|
||||
metrics.ObserveAsyncWorkerResize("success")
|
||||
metrics.ObserveConcurrencyLeaseRenewal("success")
|
||||
metrics.ObserveConcurrencyLeaseRenewal("lost")
|
||||
@@ -121,11 +128,19 @@ func TestMetricsExposeBoundedOutcomesAndState(t *testing.T) {
|
||||
`easyai_gateway_storage_channel_failovers_total 1`,
|
||||
`easyai_gateway_storage_all_channels_failed_total 1`,
|
||||
`easyai_gateway_storage_objectified_bytes_total 128`,
|
||||
`easyai_gateway_storage_object_get_attempts_total 2`,
|
||||
`easyai_gateway_storage_object_get_failures_total 1`,
|
||||
`easyai_gateway_storage_object_get_bytes_total 256`,
|
||||
`easyai_gateway_result_storage_total{outcome="upstream_url"} 1`,
|
||||
`easyai_gateway_result_storage_total{outcome="uploaded"} 1`,
|
||||
`easyai_gateway_result_poll_responses_total 1`,
|
||||
`easyai_gateway_result_poll_response_bytes_total 512`,
|
||||
`easyai_gateway_result_poll_oversized_total 1`,
|
||||
`easyai_gateway_result_url_signing_total{outcome="success"} 1`,
|
||||
`easyai_gateway_result_url_signing_total{outcome="failure"} 1`,
|
||||
`easyai_gateway_sync_base64_responses_total{outcome="success"} 1`,
|
||||
`easyai_gateway_sync_base64_responses_total{outcome="capacity_timeout"} 1`,
|
||||
`easyai_gateway_sync_base64_responses_total{outcome="too_large"} 1`,
|
||||
`easyai_gateway_platform_model_rate_limit_utilization{platform_model_id="platform-model-1",metric="concurrent"} 0.750000`,
|
||||
`easyai_gateway_async_worker_resizes_total{outcome="success"} 1`,
|
||||
`easyai_gateway_concurrency_lease_renewals_total{outcome="success"} 1`,
|
||||
|
||||
Reference in New Issue
Block a user