Question

I am new to protobuf (C++) and my code fails during parse of my messages. How can I get more details about the errors that occurred?

Example

The following snippet illustrates the problem:

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?
}
Was it helpful?

Solution

If you look inside protobuf code, you will find it's using its own logging system - based on macros. By default all these messages goes to stderr, but you can capture them in your program with SetLogHandler():

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

The possible solution is to make your own errno-like mechanism (sorry for C++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;
}

And use it in your code:

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

The main drawback of my sample code - it doesn't work well with multiple threads. But that can be fixed on your own.

OTHER TIPS

Sometimes error information will be printed to the console, but that's it. There's no way to get extra error info through the API.

That said, there are only two kinds of errors anyway:

  1. A required field was missing. (Information should be printed to the console in this case.)
  2. The data is corrupt. It was not generated by a valid protobuf implementation at all -- it's not even a different type of protobuf, it's simply not a protobuf.

If you are seeing the latter case, you need to compare your data on the sending and receiving side and figure out why it's different. Remember that the data you feed to the protobuf parser not only must be the same bytes, but it must end at the same place -- the protobuf parser does not know where the message ends except by receiving EOF. This means that if you are writing multiple messages to a stream, you need to write the size before the data, and make sure to read only that many bytes on the receiving end before passing on to the protobuf parser.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top