Как я могу получить более подробную информацию об ошибках, возникающих при синтаксическом анализе protobuf? (С++)

Я новичок в protobuf (С++), и мой код не работает во время разбора моих сообщений. Как я могу получить более подробную информацию об ошибках, которые произошли?

Пример

Следующий фрагмент иллюстрирует проблему:

const bool ok=my_message.ParseFromCodedStream(&stream);
if(ok){
    std::cout<< "message parsed. evidence:\n"<< my_message.DebugString();
}
else{
    std::cerr<< "error parsing protobuf\n";
    //HOW CAN I GET A REASON FOR THE FAILURE HERE?
}

Ответ 1

Если вы заглянете в код protobuf, вы найдете его с помощью собственной системы ведения журнала - на основе макросов. По умолчанию все эти сообщения отправляются на stderr, но вы можете записать их в своей программе с помощью SetLogHandler():

typedef void LogHandler(LogLevel level, const char* filename, int line,
                        const std::string& message);

Возможное решение - создать собственный errno -подобный механизм (извините за С++ 11-ishness):

typedef LogMessage std::tuple<LogLevel, std::string, int, std::string>;  // C++11
typedef LogStack std::list<LogMessage>;

namespace {

LogStack stack;
bool my_errno;

}  // namespace

void MyLogHandler(LogLevel level, const char* filename, int line,
                  const std::string& message) {
  stack.push_back({level, filename, line, message});  // C++11.
  my_errno = true;
}

protobuf::SetLogHandler(MyLogHandler);

bool GetError(LogStack* my_stack) {
  if (my_errno && my_stack) {
    // Dump collected logs.
    my_stack->assign(stack.begin(), stack.end());
  }

  stack.clear();
  bool old_errno = my_errno;
  my_errno = false;

  return old_errno;
}

И используйте его в своем коде:

...
else {
    std::cerr<< "error parsing protobuf" << std::endl;
    LogStack my_stack;
    if (GetError(&my_stack) {
      // Handle your errors here.
    }
}

Основной недостаток моего кода кода - он не работает с несколькими потоками. Но это может быть исправлено самостоятельно.

Ответ 2

Иногда информация об ошибке будет напечатана на консоли, но это будет. Нет никакого способа получить дополнительную информацию об ошибке через API.

Тем не менее, в любом случае есть только два вида ошибок:

  • Отсутствует обязательное поле. (В этом случае информация должна быть напечатана на консоли.)
  • Данные повреждены. Это не было создано действительной реализацией protobuf вообще - это даже не другой тип protobuf, это просто не protobuf.

Если вы видите последний случай, вам нужно сравнить свои данные со стороной отправки и получения и выяснить, почему она отличается. Помните, что данные, которые вы передаете парсеру protobuf, должны быть не только одинаковыми байтами, но должны заканчиваться в одном месте - анализатор protobuf не знает, где заканчивается сообщение, кроме как при получении EOF. Это означает, что если вы пишете несколько сообщений в поток, вам нужно записать размер перед данными и обязательно прочитать только то, что многие байты на принимающей стороне, прежде чем перейти к парсеру protobuf.