Refactor/simplify proxy logs (#585)

* refactor(proxy): simplify logging for better readability

- Delete 17 verbose debug logs from handlers, streaming, and response_processor
- Convert excessive INFO logs to DEBUG level for internal processing details
- Add 2 critical INFO logs in forwarder.rs for failover scenarios:
  - Log when switching to next provider after failure
  - Log when all providers have been exhausted
- Fix clippy uninlined_format_args warning

This reduces log noise while maintaining visibility into key user-facing decisions.

* fix: replace unsafe unwrap() calls with proper error handling

- database/dao/mcp.rs: Use map_err for serde_json serialization
- database/dao/providers.rs: Use map_err for settings_config and meta serialization
- commands/misc.rs: Use expect() for compile-time regex pattern
- services/prompt.rs: Use unwrap_or_default() for SystemTime
- deeplink/provider.rs: Replace unwrap() with is_none_or pattern for Option checks

Reduces potential panic points from 26 to 1 (static regex init, safe).

* refactor(proxy): simplify verbose logging output

- Remove response JSON full output logging in response_processor
- Remove per-request INFO logs in provider_router (failover status, provider selection)
- Change model mapping log from INFO to DEBUG
- Change usage logging failure from INFO to WARN
- Remove redundant debug logs for circuit breaker operations

Reduces log noise significantly while preserving important warnings and errors.

* feat(proxy): add structured log codes for i18n support

Add error code system to proxy module logs for multi-language support:

- CB-001~006: Circuit breaker state transitions and triggers
- SRV-001~004: Proxy server lifecycle events
- FWD-001~002: Request forwarding and failover
- FO-001~005: Failover switch operations
- USG-001~002: Usage logging errors

Log format: [CODE] Chinese message
Frontend/log tools can map codes to any language.

New file: src/proxy/log_codes.rs - centralized code definitions

* chore: bump version to 3.9.1

* style: format code with prettier and rustfmt

* fix(ui): allow number inputs to be fully cleared before saving

- Convert numeric state to string type for controlled inputs
- Use isNaN() check instead of || fallback to allow 0 values
- Apply fix to ProxyPanel, CircuitBreakerConfigPanel,
  AutoFailoverConfigPanel, and ModelTestConfigPanel

* feat(pricing): support @ separator in model name matching

- Refactor model name cleaning into chained method calls
- Add @ to - replacement (e.g., gpt-5.2-codex@low → gpt-5.2-codex-low)
- Add test case for @ separator matching

* fix(proxy): improve validation and error handling in proxy config panels

- Add StopTimeout/StopFailed error types for proper stop() error reporting
- Replace silent clamp with validation-and-block in config panels
- Add listenAddress format validation in ProxyPanel
- Use log_codes constants instead of hardcoded strings
- Use once_cell::Lazy for regex precompilation

* fix(proxy): harden error handling and input validation

- Handle RwLock poisoning in settings.rs with unwrap_or_else
- Add fallback for dirs::home_dir() in config modules
- Normalize localhost to 127.0.0.1 in ProxyPanel
- Format IPv6 addresses with brackets for valid URLs
- Strict port validation with pure digit regex
- Treat NaN as validation failure in config panels
- Log warning on cost_multiplier parse failure
- Align timeoutSeconds range to [0, 300] across all panels
This commit is contained in:
Dex Miller
2026-01-11 20:50:54 +08:00
committed by GitHub
parent 76fa830688
commit 6dd809701b
35 changed files with 737 additions and 492 deletions
+1 -1
View File
@@ -85,7 +85,7 @@ impl PromptService {
if !content_exists {
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.unwrap_or_default()
.as_secs() as i64;
let backup_id = format!("backup-{timestamp}");
let backup_prompt = Prompt {
+1 -1
View File
@@ -160,7 +160,7 @@ impl SkillService {
.user_agent("cc-switch")
.timeout(std::time::Duration::from_secs(10))
.build()
.expect("Failed to create HTTP client"),
.unwrap_or_else(|_| Client::new()),
}
}
+16 -9
View File
@@ -802,25 +802,25 @@ pub(crate) fn find_model_pricing_row(
conn: &Connection,
model_id: &str,
) -> Result<Option<(String, String, String, String)>, AppError> {
// 1) 去除供应商前缀(/ 之前)与冒号后缀(: 之后),例如 moonshotai/kimi-k2-0905:exa → kimi-k2-0905
let without_prefix = model_id
// 清洗模型名称:去前缀(/)、去后缀(:)、@ 替换为 -
// 例如 moonshotai/gpt-5.2-codex@low:v2 → gpt-5.2-codex-low
let cleaned = model_id
.rsplit_once('/')
.map(|(_, rest)| rest)
.unwrap_or(model_id);
let cleaned = without_prefix
.map_or(model_id, |(_, r)| r)
.split(':')
.next()
.map(str::trim)
.unwrap_or(without_prefix);
.unwrap_or(model_id)
.trim()
.replace('@', "-");
// 2) 精确匹配清洗后的名称
// 精确匹配清洗后的名称
let exact = conn
.query_row(
"SELECT input_cost_per_million, output_cost_per_million,
cache_read_cost_per_million, cache_creation_cost_per_million
FROM model_pricing
WHERE model_id = ?1",
[cleaned],
[&cleaned],
|row| {
Ok((
row.get::<_, String>(0)?,
@@ -952,6 +952,13 @@ mod tests {
"带前缀+冒号后缀的模型应清洗后匹配到 kimi-k2-0905"
);
// 清洗:@ 替换为 -seed_model_pricing 已预置 gpt-5.2-codex-low
let result = find_model_pricing_row(&conn, "gpt-5.2-codex@low")?;
assert!(
result.is_some(),
"带 @ 分隔符的模型 gpt-5.2-codex@low 应能匹配到 gpt-5.2-codex-low"
);
// 测试不存在的模型
let result = find_model_pricing_row(&conn, "unknown-model-123")?;
assert!(result.is_none(), "不应该匹配不存在的模型");