4

我节省 IDL 文件,您可以定义自己的服务方法可能抛出的异常类型:

exception SampleException {
    1: list<string> failed
}

在日志中看到正确的异常消息的合同是什么?我见过这样的日志消息:Unhandled exception in foo.bar.Service my.package.SomeException: null. 我猜它在哪里说null这应该是异常消息?

不幸的是,异常没有很好的记录。我应该string message为此添加一个字段吗?是否有任何其他转换,如字段名称?

4

1 回答 1

3

节俭例外(一般)

在日志中看到正确的异常消息的合同是什么?

没有合约定义消息如何写入任何日志。Thrift 被设计为与协议无关和传输无关。例如,如果您构建的 HTTP 服务器将某些内容写入他的日志文件,这完全在 Thrift 之外,这只是您的 HTTP 服务器的问题。

我应该添加一个字符串消息字段以使其正常工作吗?是否有任何其他约定,如字段名称?

不,除了您选择的语言可能强加的内容外,没有任何约定或限制。从技术上讲,一个exception就像一个struct。例如,以下 IDL 取自ThriftTest.thrift文件。

exception Xception2 {
  1: i32 errorCode,
  2: Xtruct struct_thing
}

上面使用的Xtruct是另一个struct嵌套到异常中。你看,你几乎可以用结构体来处理 Thrift 异常。这使您可以向客户端发送丰富的错误信息,而不仅仅是“服务器上发生了一些丑陋的事情”之类的字符串。

区别struct在于系统如何处理它们:异常在服务器上序列化,然后在客户端重新引发。意外的例外是

  • 要么被捕获并重新抛出为通用的TApplicationException
  • 或根本没有抓到

后一种行为在某种程度上是一种依赖于语言的事情,它现在即将从“未捕获”缓慢转变为“作为通用重新抛出TApplicationException”方向。

不幸的是,异常没有很好的记录

这是Thrift Whitepaper关于异常的内容:

2.4 例外

异常在语法和功能上与结构等效,只是它们是使用exception关键字而不是struct关键字声明的。

生成的对象从每种目标编程语言中适当的异常基类继承,以便与任何给定语言的本机异常处理无缝集成。同样,设计重点是让应用程序开发人员熟悉代码。

如何确保Exception(string)调用 CTOR?

我见过这样的日志消息:

Unhandled exception in foo.bar.Service my.package.SomeException: null 

我猜它在哪里说null这应该是异常消息?[...] 对于生成到 Scala/Java 的已定义异常,确保调用此构造函数的正确方法是什么:public Exception(String message).

看起来很像“从不”,或者更准确地说是“没办法”。这些是 Thrift(主干版本)从上述 IDL 生成的所有 CTOR:

  public Xception() {
  }

  public Xception(
    int errorCode,
    String message)
  {
    this();
    this.errorCode = errorCode;
    setErrorCodeIsSet(true);
    this.message = message;
  }

  /**
   * Performs a deep copy on <i>other</i>.
   */
  public Xception(Xception other) {
    __isset_bitfield = other.__isset_bitfield;
    this.errorCode = other.errorCode;
    if (other.isSetMessage()) {
      this.message = other.message;
    }
  }

由于所有生成的异常都源自TException它们必须调用参数化 CTOR 之一来获取message和/或cause下降到Exception基础。但Xception显然没有这样做。原因可能是 Thrift 允许您将任何内容定义为异常成员,并且不保证(或假设)任何内容。换句话说,不能确定是否存在异常中的单个字段。因此,您总是会收到一条null错误消息。

底线(TL; DR)

我认为,一般来说你是对的,这种行为应该改变。目前,我看到的唯一解决方法是TException在它们进入日志之前显式捕获并使用toString()成员函数重新打包它们:

} catch (org.apache.thrift.TException te) {
  throw new Exception(te.toString());
}
于 2015-05-27T09:22:45.950 回答