How can I get more details about errors generated during protobuf parsing? (C++)

11,265

Solution 1

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.

Solution 2

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.

Share:
11,265

Related videos on Youtube

Lennart Rolland
Author by

Lennart Rolland

I work as a IT consultant for a small but capable consulting firm in Bergen, Norway. I also enjoy technology in my spare time. My latest project is http://octomy.org

Updated on October 31, 2022

Comments

  • Lennart Rolland
    Lennart Rolland over 1 year

    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?
    }
    
  • Lennart Rolland
    Lennart Rolland about 10 years
    First: One should never (IMO) apologize for using C++11. Second: Thanks for a great answer :-)
  • Lennart Rolland
    Lennart Rolland about 10 years
    Thanks for the EOF tips!