Как я могу получить более подробную информацию об ошибках, возникающих при синтаксическом анализе 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.