Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

日志说明

orion-error 的日志能力围绕 OperationContextOperationScope 展开。

1. Feature

[dependencies]
orion-error = { version = "0.8.0", features = ["log"] }
# 或
orion-error = { version = "0.8.0", features = ["tracing"] }

默认 feature 已包含 log

行为规则:

  • 只启用 log:使用 log 宏输出
  • 启用 tracing:优先走 tracing
  • 同时启用:走 tracing

2. 基本用法

#![allow(unused)]
fn main() {
use orion_error::OperationContext;

let ctx = OperationContext::doing("order_processing")
    .with_field("order_id", "123")
    .with_field("amount", "100.0")
    .with_meta("component.name", "order_service");

ctx.info("start");
ctx.debug("payload prepared");
ctx.warn("slow upstream");
ctx.error("final failure");
ctx.trace("verbose trace");
}

也可以使用别名:

  • log_info
  • log_debug
  • log_warn
  • log_error
  • log_trace

3. 自动结果日志

#![allow(unused)]
fn main() {
use orion_error::OperationContext;

let mut ctx = OperationContext::doing("sync_user")
    .with_auto_log()
    .with_field("user_id", "42");

do_sync()?;
ctx.mark_suc();
}

默认结果是失败。

如果启用了 with_auto_log(),但离开作用域前没有调用:

  • mark_suc()
  • mark_cancel()

那么 Drop 时会输出失败日志。

4. OperationScope

OperationScope 是面向一个局部作用域的 guard。

#![allow(unused)]
fn main() {
use orion_error::OperationContext;

let mut ctx = OperationContext::doing("sync_user").with_auto_log();

{
    let mut scope = ctx.scope();
    scope.with_field("user_id", "42");
    validate()?;
    scope.mark_success();
}
}

方法:

  • scope():默认失败,只有显式 mark_success() 才会成功
  • scoped_success():创建后默认成功,除非后续显式 mark_failure()cancel()
  • mark_success():标记成功
  • mark_failure():恢复为失败
  • cancel():标记取消

5. scoped_success() 的使用边界

scoped_success() 适合这种场景:

  • 作用域里的逻辑已经自行处理完失败分支
  • 失败时会明确调用 mark_failure()
  • 或者这段逻辑本身不会通过 ? 提前返回

例如:

#![allow(unused)]
fn main() {
let mut ctx = OperationContext::doing("process_order").with_auto_log();

{
    let mut scope = ctx.scoped_success();
    let ok = validate_order();
    if !ok {
        scope.mark_failure();
    }
}
}

不推荐这样写:

let mut scope = ctx.scoped_success();
validate()?;

因为当前实现里 scoped_success() 一创建就默认成功,如果 ? 提前返回,Drop 仍会把该作用域标记为成功。

对可能早退的 fallible 流程,优先使用:

#![allow(unused)]
fn main() {
let mut scope = ctx.scope();
validate()?;
scope.mark_success();
}

6. op_context!

#![allow(unused)]
fn main() {
use orion_error::op_context;

let ctx = op_context!("load_config").with_auto_log().with_field("path", "config.toml");
}

这个宏会在调用点展开 module_path!(),让自动结果日志带上更准确的模块路径。

7. 推荐实践

  • doing(...) 命名操作
  • with_field(...) / with_meta(...) 做链式构建
  • record_field(...) / record_meta(...) 只在已有可变引用时使用
  • with_auto_log() 只包裹真正需要结果日志的作用域
  • 对可能 ? 提前返回的逻辑,优先 scope() + mark_success()
  • 只有在失败路径已被显式处理时,再使用 scoped_success()