注册ErrorCollector或拦截有线格式的解析错误?

时间:2015-10-13 19:24:19

标签: c++ protocol-buffers

何时可以定义用于处理google::protobuf解析错误的自定义ErrorCollector

struct ErrorCollector : ::google::protobuf::io::ErrorCollector
{
    void AddError(int line, int column, const std::string& message) override
    {
        // log error
    }
    void AddWarning(int line, int column, const std::string& message) override
    {
        // log warning
    }
};

从文本文件解析时,您可以使用protobuf TextFormat类并注册自定义ErrorCollector

::google::protobuf::io::IstreamInputStream input_stream(&file);
::google::protobuf::TextFormat::Parser parser;

ErrorCollector error_collector;
parser.RecordErrorsTo(&error_collector);

if (parser.Parse(&input_stream, &msg))
{
    // handle msg
}

对于解析有线格式,我目前使用Message::ParseFromArray

if (msg.ParseFromArray(data, data_len))
{
    // handle msg
}

这并不允许我指定自定义ErrorCollector

我已经通过source code进行了搜索,但截至目前为止还无法找到是否可行。

  • 解析有线格式时是否可以使用ErrorCollector
  • 是否有其他方法可以拦截解析错误并将其提供给客户端代码?

1 个答案:

答案 0 :(得分:2)

解析有线格式有两种方法可能会失败:

  1. 字节不是有效的protobuf(例如,它们已损坏,或者格式完全不同)。
  2. 缺少必填字段。
  3. 对于案例1,protobuf不会提供任何比“它无效”更多的信息。这部分是为了简化代码(和速度),但也部分原因是任何提供更多信息的尝试通常都会产生误导而不是有用。详细的错误报告对于文本格式很有用,因为文本通常由人类编写,但是机器会产生非常不同的错误。在某些语言中,protobuf实际上会报告特定错误,例如“end-group tag与start-group tag不匹配”。在绝大多数情况下,这个错误实际上只是意味着“字节已被破坏”,但人们不可避免地认为错误试图告诉他们更深层次的东西他们不理解。然后他们将问题发布到堆栈溢出,例如“我如何确保我的起始组和结束组标签匹配?”当他们真的应该比较他们的源和目的地之间的字节来缩小他们被破坏的地方。甚至报告发生解析错误的字节位置也不是很有用:protobuf是一种密集编码,这意味着许多随机损坏的字节序列将成功解析,这意味着解析器可能只会在以后的某个地方发现问题,而不是在事情确实出错了。

    明显 区分的一个案例是案例2(缺少必填字段) - 至少,如果您使用必填字段(I personally recommend avoiding them)。这里有几个选项:

    • 通常,必需的字段检查将错误写入控制台(在stderr上)。您可以使用SetLogHandler拦截这些并以自己的方式记录它们,但这不会为您提供结构化信息,仅提供短信。
    • 要以编程方式更多地检查必填字段,可以将必需的字段检查与解析分开。使用MessageLite::ParsePartialFromArray()或其他Partial解析方法之一来解析消息,同时忽略缺少必填字段。然后,您可以使用MessageLite::IsInitialized()检查是否已设置所有必填字段。如果返回false,请使用Message::FindInitializationErrors()获取缺少的所有必填字段的路径列表。