| Crates.io | orion-error |
| lib.rs | orion-error |
| version | 0.5.5 |
| created_at | 2025-03-18 06:53:35.019856+00 |
| updated_at | 2025-09-20 16:07:14.535615+00 |
| description | Struct Error for Large Project |
| homepage | |
| repository | https://github.com/galaxy-sec/orion-error |
| max_upload_size | |
| id | 1596252 |
| size | 624,463 |
Structured error handling library for building large-scale applications, providing complete error context tracking and flexible aggregation strategies.
.owe() // Convert with specific reason
.owe_validation() // Convert to validation error
.owe_biz() // Convert to business error
.owe_sys() // Mark as system error
.err_conv() // Automatic type conversion
Add to Cargo.toml:
[dependencies]
orion-error = "0.3"
Define domain errors with enum and implement DomainReason:
#[derive(Debug, Display)]
enum OrderReason {
InsufficientFunds,
UserNotFound,
}
impl DomainReason for OrderReason {}
Build error context with chaining:
validate_user(user_id)
.want("Validate user") // Add operation description
.with_detail("uid:123") // Add debug details
.owe(OrderError::UserNotFound) // Convert to upper error type
| Method | Description |
|---|---|
.owe() |
Convert to specific biz error |
.owe_sys() |
Mark as system error |
.err_conv() |
Auto-detect error type conversion |
// Pattern 1: Direct conversion
parse_input().map_err(|e| e.owe(OrderError::ParseFailed))?;
// Pattern 2: Add context
db.query()
.want("Read order data")
.with_detail(format!("order_id={id}"))
.err_conv()?;
thiserror 专注于“定义错误类型”的派生与格式化;本库专注“结构化错误治理”,提供统一分类(UvsReason)、错误码(ErrorCode)、上下文(OperationContext/WithContext)与转换策略(ErrorOwe/ErrorConv)。thiserror 不提供错误码、重试性或严重级别;本库内建 error_code()、is_retryable()、is_high_severity()、category_name(),便于监控与告警。thiserror 不管理上下文;本库可在成功/失败路径记录目标与键值上下文,with_auto_log() 结合日志在 Drop 时输出。ErrorOwe 将任意 Result<T, E: Display> 规范化为 Result<T, StructError<R>>,快速映射为业务/系统/网络/超时等分类。推荐组合用法:用 thiserror 定义领域错误,用本库统一分类与治理。
use derive_more::From;
use thiserror::Error;
use orion_error::{StructError, ErrorOwe, ErrorCode, UvsReason, DomainReason};
#[derive(Debug, Error, From, serde::Serialize, PartialEq)]
enum AppError {
#[error("{0}")]
Uvs(UvsReason), // 透传统一分类
#[error("parse failed")]
Parse,
}
impl ErrorCode for AppError {
fn error_code(&self) -> i32 {
match self { AppError::Uvs(r) => r.error_code(), AppError::Parse => 100 }
}
}
// 满足 From<UvsReason> + Display + PartialEq + Serialize,自动实现 DomainReason
impl DomainReason for AppError {}
fn handle() -> Result<(), StructError<AppError>> {
do_io().owe_sys()?; // 映射为系统类错误
parse().owe_validation()?; // 映射为校验类错误
Ok(())
}
更多内容与实践建议:参见 docs/thiserror-comparison.md。
use orion_error::{UvsReason, StructError, ErrorWith, WithContext};
// Compose errors with rich context
fn complex_operation() -> Result<(), StructError<UvsReason>> {
let mut ctx = WithContext::want("complex_operation");
ctx.with("step", "validation");
ctx.with("input_type", "user_request");
// Validation error with context
validate_input(&request)
.want("input validation")
.with(&ctx)?;
ctx.with("step", "business_logic");
// Business error with context
check_business_rules(&request)
.want("business rules check")
.with(&ctx)?;
ctx.with("step", "persistence");
// System error with context
save_to_database(&processed_data)
.want("data persistence")
.with(&ctx)?;
Ok(())
}
use orion_error::{UvsReason, StructError, ErrorOwe};
// Different conversion strategies
fn process_with_strategies() -> Result<(), StructError<UvsReason>> {
// Strategy 1: Convert to validation error
let input = get_input().owe_validation()?;
// Strategy 2: Convert to business error
let validated = validate(input).owe_biz()?;
// Strategy 3: Convert to system error
let result = process(validated).owe_sys()?;
// Strategy 4: Convert with custom reason
let final_result = finalize(result).owe(UvsReason::business_error("finalization failed"))?;
Ok(final_result)
}
use orion_error::UvsReason;
fn robust_operation() -> Result<(), MyError> {
let mut attempts = 0;
let max_attempts = 3;
loop {
attempts += 1;
match attempt_operation() {
Ok(result) => return Ok(result),
Err(error) => {
// Check if error is retryable and within attempt limit
if error.is_retryable() && attempts < max_attempts {
log::warn!("Attempt {} failed, retrying: {}", attempts, error);
std::thread::sleep(std::time::Duration::from_secs(2));
continue;
} else {
return Err(error.into());
}
}
}
}
}
// Fallback pattern
fn operation_with_fallback() -> Result<String, MyError> {
// Try primary method
primary_method().map_err(|e| {
log::warn!("Primary method failed: {}", e);
// Convert to business error with fallback context
UvsReason::business_error("primary method unavailable, fallback not implemented")
})
}
use orion_error::UvsReason;
// Integration with monitoring systems
struct ErrorMonitor;
impl ErrorMonitor {
fn track_error(&self, error: &UvsReason) {
// Send to monitoring system
let event = MonitoringEvent {
error_code: error.error_code(),
category: error.category_name(),
severity: if error.is_high_severity() { "high" } else { "normal" },
retryable: error.is_retryable(),
message: error.to_string(),
timestamp: chrono::Utc::now(),
};
self.send_to_monitoring(event);
}
fn should_alert(&self, error: &UvsReason) -> bool {
error.is_high_severity() ||
error.error_code() >= 200 // Infrastructure layer errors
}
}
// Usage in application
fn handle_api_error(error: UvsReason) -> HttpResponse {
let monitor = ErrorMonitor::new();
monitor.track_error(&error);
if monitor.should_alert(&error) {
alert_team(&error);
}
// Convert error to HTTP response based on category
match error.category_name() {
"validation" => HttpResponse::BadRequest().json(error.to_string()),
"business" => HttpResponse::Conflict().json(error.to_string()),
"not_found" => HttpResponse::NotFound().json(error.to_string()),
"permission" => HttpResponse::Unauthorized().json(error.to_string()),
"system" | "network" | "timeout" | "resource" => {
HttpResponse::ServiceUnavailable().json(error.to_string())
}
_ => HttpResponse::InternalServerError().json(error.to_string()),
}
}
The error classification system has been significantly improved with a new hierarchical structure. Here's how to migrate:
// Old way (v0.2)
use orion_error::UvsReason;
let error = UvsReason::BizError("business logic failed".into());
let error = UvsReason::LogicError("logic error".into());
let error = UvsReason::Timeout("timeout occurred".into());
// New way (v0.3)
use orion_error::UvsReason;
let error = UvsReason::business_error("business logic failed");
let error = UvsReason::validation_error("logic error");
let error = UvsReason::timeout_error("timeout occurred");
// Old way (v0.2)
let error = string_value.from_biz();
let error = string_value.from_logic();
let error = string_value.from_rule();
// New way (v0.3)
let error = UvsReason::from_biz(string_value);
let error = UvsReason::from_validation(string_value);
// Note: Rule errors have been removed, use ValidationError instead
Error codes have been reorganized by layers:
// Old codes
BizError -> 101
LogicError -> 100
Timeout -> 109
// New codes
ValidationError -> 100
BusinessError -> 101
NotFoundError -> 102
PermissionError -> 103
TimeoutError -> 204
// Check retryability
if error.is_retryable() {
// Implement retry logic
}
// Check severity
if error.is_high_severity() {
// Send high priority alert
}
// Get category for metrics
let category = error.category_name();
See examples/order_case.rs for a comprehensive example showing all the new error classification features in action.
The UvsReason provides a comprehensive error classification system organized in three distinct layers:
These are user-facing errors that are expected in normal application operation.
| Error Type | Code | Description | When to Use |
|---|---|---|---|
ValidationError |
100 | Input validation failures | Invalid parameters, format errors, constraint violations |
BusinessError |
101 | Business logic violations | Rule violations, state conflicts, domain-specific errors |
NotFoundError |
102 | Resource not found | Database record missing, file not found, user doesn't exist |
PermissionError |
103 | Authorization failures | Access denied, authentication failed, insufficient permissions |
System-level failures that should be rare and often require operational attention.
| Error Type | Code | Description | When to Use |
|---|---|---|---|
DataError |
200 | Data processing errors | Database failures, data corruption, serialization errors |
SystemError |
201 | OS and file system errors | Disk full, file permission issues, OS-level failures |
NetworkError |
202 | Network connectivity errors | HTTP timeouts, connection failures, DNS resolution |
ResourceError |
203 | Resource exhaustion | Memory full, CPU overload, connection pool exhausted |
TimeoutError |
204 | Operation timeouts | Database query timeout, external service timeout |
Environment-related issues and third-party service failures.
| Error Type | Code | Description | When to Use |
|---|---|---|---|
ConfigError |
300 | Configuration issues | Missing config files, invalid configuration values |
ExternalError |
301 | Third-party service errors | Payment gateway failures, external API failures |
Built-in Display implementation shows full error chain:
[Error Code 500] Insufficient funds
Caused by:
0: User not found (code103)
Detail: uid:456
Context: "Validate funds"
1: Storage full (code500)
Context: "Save order"
Issues and PRs are welcome. Please follow existing code style.
MIT License
用于构建大型应用程序的结构化错误处理库,提供完整的错误上下文追踪和灵活的归集策略
结构化错误:支持多层错误归集,保留完整错误链
错误分类:
上下文追踪:支持添加多级上下文信息
错误代码:支持自定义错误代码体系
错误转换:提供多种错误转换策略:
.owe() // 转换为业务错误
.owe_sys() // 转换为系统错误
.err_conv() // 自动推导转换
在 Cargo.toml 中添加:
[dependencies]
orion-error = "0.2"
使用枚举定义领域错误类型,实现 DomainReason trait:
#[derive(Debug, Display)]
enum OrderReason {
InsufficientFunds,
UserNotFound,
}
impl DomainReason for OrderReason {}
使用链式调用构建错误上下文:
validate_user(user_id)
.want("验证用户") // 添加操作描述
.with_detail("uid:123") // 添加调试细节
.owe(OrderError::UserNotFound) // 转换为上层错误类型
| 方法 | 说明 |
|---|---|
.owe() |
转换为指定业务错误,保留原始错误链 |
.owe_sys() |
标记为系统级错误 |
.err_conv() |
自动推导错误类型转换 |
// 模式1:直接转换
parse_input().map_err(|e| e.owe(OrderError::ParseFailed))?;
// 模式2:添加上下文
db.query()
.want("读取订单数据")
.with_detail(format!("order_id={id}"))
.err_conv()?;
内置 Display 实现可展示完整错误链:
[错误代码 500] 账户余额不足
Caused by:
0: 用户不存在 (代码103)
详情: uid:456
上下文: "验证资金"
1: 存储空间不足 (代码500)
上下文: "保存订单"
欢迎提交 issue 和 PR,请遵循现有代码风格
MIT License