Search code examples
c++thrift

Where does the Apache Thrift C++ GlobalOutput output to?


I am using Apache Thrift TSimpleServer in my C++ projects. Once started, the server will be listening to clients connection and handling requests. All are fine, but occasionally the server stopped without any sign.

I follow the source of thrift library and can see the GlobalOutput(error_message) being created when TTransportException or TException are caught. I need to understand this so that I can create a recovery mechanism when the server dies.

Here is the source code I am talking about:

void TSimpleServer::serve() {

  shared_ptr<TTransport> client;
  shared_ptr<TTransport> inputTransport;
  shared_ptr<TTransport> outputTransport;
  shared_ptr<TProtocol> inputProtocol;
  shared_ptr<TProtocol> outputProtocol;

  // Start the server listening
  serverTransport_->listen();

  // Run the preServe event
  if (eventHandler_) {
    eventHandler_->preServe();
  }

  // Fetch client from server
  while (!stop_) {
    try {
      client = serverTransport_->accept();
      inputTransport = inputTransportFactory_->getTransport(client);
      outputTransport = outputTransportFactory_->getTransport(client);
      inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
      outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
    } catch (TTransportException& ttx) {
      if (inputTransport) { inputTransport->close(); }
      if (outputTransport) { outputTransport->close(); }
      if (client) { client->close(); }
      if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED) {
          string errStr = string("TServerTransport died on accept: ") + ttx.what();
          GlobalOutput(errStr.c_str());
      }
      continue;
    } catch (TException& tx) {
      if (inputTransport) { inputTransport->close(); }
      if (outputTransport) { outputTransport->close(); }
      if (client) { client->close(); }
      string errStr = string("Some kind of accept exception: ") + tx.what();
      GlobalOutput(errStr.c_str());
      continue;
    } catch (string s) {
      if (inputTransport) { inputTransport->close(); }
      if (outputTransport) { outputTransport->close(); }
      if (client) { client->close(); }
      string errStr = string("Some kind of accept exception: ") + s;
      GlobalOutput(errStr.c_str());
      break;
    }

    // Get the processor
    shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
                                                    outputProtocol, client);

    void* connectionContext = NULL;
    if (eventHandler_) {
      connectionContext = eventHandler_->createContext(inputProtocol, outputProtocol);
    }
    try {
      for (;;) {
        if (eventHandler_) {
          eventHandler_->processContext(connectionContext, client);
        }
        if (!processor->process(inputProtocol, outputProtocol,
                                connectionContext) ||
          // Peek ahead, is the remote side closed?
            !inputProtocol->getTransport()->peek()) {
          break;
        }
      }
    } catch (const TTransportException& ttx) {
      string errStr = string("TSimpleServer client died: ") + ttx.what();
      GlobalOutput(errStr.c_str());
    } catch (const std::exception& x) {
      GlobalOutput.printf("TSimpleServer exception: %s: %s",
                          typeid(x).name(), x.what());
    } catch (...) {
      GlobalOutput("TSimpleServer uncaught exception.");
    }
    if (eventHandler_) {
      eventHandler_->deleteContext(connectionContext, inputProtocol, outputProtocol);
    }

    try {
      inputTransport->close();
    } catch (const TTransportException& ttx) {
      string errStr = string("TSimpleServer input close failed: ")
        + ttx.what();
      GlobalOutput(errStr.c_str());
    }
    try {
      outputTransport->close();
    } catch (const TTransportException& ttx) {
      string errStr = string("TSimpleServer output close failed: ")
        + ttx.what();
      GlobalOutput(errStr.c_str());
    }
    try {
      client->close();
    } catch (const TTransportException& ttx) {
      string errStr = string("TSimpleServer client close failed: ")
        + ttx.what();
      GlobalOutput(errStr.c_str());
    }
  }

  if (stop_) {
    try {
      serverTransport_->close();
    } catch (TTransportException &ttx) {
      string errStr = string("TServerTransport failed on close: ") + ttx.what();
      GlobalOutput(errStr.c_str());
    }
    stop_ = false;
  }
}

Solution

  • Deep inside TOutput.cpp there's line fprintf(stderr, "Thrift: %s %s\n", dbgtime, msg); (source here) and that's where by default all Thrift GlobalOutput messages end up (in standard error).

    But you can change it (if for any reason you can't use stderr) by providing own handler to GlobalOutput in form of function pointer:

    void myOutputFunction(const char* x)
    {
      fprintf(myLogFile, "Thrift internal message: %s\n", x);
    }
    
    // Inside some init function or main
    GlobalOutput.setOutputFunction(myOutputFunction);