add fb303 to thrift contrib

Summary: Add clean version of fb303 to thrift contrib readying for open sourcing scribe

Reviewed By: dreiss

Test Plan: bootstrap.sh, make, make install on a fresh machine and then try compiling and running scribe open source version.

Revert: OK

TracCamp Project: Thrift

DiffCamp Revision: 10841


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665634 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/contrib/fb303/cpp/ServiceTracker.h b/contrib/fb303/cpp/ServiceTracker.h
new file mode 100644
index 0000000..c8e4529
--- /dev/null
+++ b/contrib/fb303/cpp/ServiceTracker.h
@@ -0,0 +1,202 @@
+// Copyright (c) 2006- Facebook
+// Distributed under the Thrift Software License
+//
+// See accompanying file LICENSE or visit the Thrift site at:
+// http://developers.facebook.com/thrift/
+
+/**
+ * ServiceTracker is a utility class for logging and timing service
+ * calls to a fb303 Thrift server.  Currently, ServiceTracker offers
+ * the following features:
+ *
+ *   . Logging of service method start, end (and duration), and
+ *     optional steps in between.
+ *
+ *   . Automatic check of server status via fb303::getStatus()
+ *     with a ServiceException thrown if server not alive
+ *     (at method start).
+ *
+ *   . A periodic logged checkpoint reporting lifetime time, lifetime
+ *     service count, and per-method statistics since the last checkpoint
+ *     time (at method finish).
+ *
+ *   . Export of fb303 counters for lifetime and checkpoint statistics
+ *     (at method finish).
+ *
+ *   . For TThreadPoolServers, a logged warning when all server threads
+ *     are busy (at method start).  (Must call setThreadManager() after
+ *     ServiceTracker instantiation for this feature to be enabled.)
+ *
+ * Individual features may be enabled or disabled by arguments to the
+ * constructor.  The constructor also accepts a pointer to a logging
+ * method -- if no pointer is passed, the tracker will log to stdout.
+ *
+ * ServiceTracker defines private methods for service start, finish,
+ * and step, which are designed to be accessed by instantiating a
+ * friend ServiceMethod object, as in the following example:
+ *
+ *    #include <ServiceTracker.h>
+ *    class MyServiceHandler : virtual public MyServiceIf,
+ *                             public facebook::fb303::FacebookBase
+ *    {
+ *    public:
+ *      MyServiceHandler::MyServiceHandler() : mServiceTracker(this) {}
+ *      void MyServiceHandler::myServiceMethod(int userId) {
+ *        // note: Instantiating a ServiceMethod object starts a timer
+ *        // and tells the ServiceTracker to log the start.  Might throw
+ *        // a ServiceException.
+ *        ServiceMethod serviceMethod(&mServiceTracker,
+ *                                   "myServiceMethod",
+ *                                   userId);
+ *        ...
+ *        // note: Calling the step method tells the ServiceTracker to
+ *        // log the step, with a time elapsed since start.
+ *        serviceMethod.step("post parsing, begin processing");
+ *        ...
+ *        // note: When the ServiceMethod object goes out of scope, the
+ *        // ServiceTracker will log the total elapsed time of the method.
+ *      }
+ *      ...
+ *    private:
+ *      ServiceTracker mServiceTracker;
+ *    }
+ *
+ * The step() method call is optional; the startService() and
+ * finishService() methods are handled by the object's constructor and
+ * destructor.
+ *
+ * The ServiceTracker is (intended to be) thread-safe.
+ *
+ * Future:
+ *
+ *   . Come up with something better for logging than passing a
+ *     function pointer to the constructor.
+ *
+ *   . Add methods for tracking errors from service methods, e.g.
+ *     ServiceTracker::reportService().
+ */
+
+#ifndef SERVICETRACKER_H
+#define SERVICETRACKER_H
+
+
+#include <iostream>
+#include <string>
+#include <sstream>
+#include <exception>
+#include <map>
+#include <boost/shared_ptr.hpp>
+
+#include "thrift/concurrency/Mutex.h"
+
+
+namespace facebook { namespace thrift { namespace concurrency {
+  class ThreadManager;
+}}}
+
+
+namespace facebook { namespace fb303 {
+
+
+class FacebookBase;
+class ServiceMethod;
+
+
+class Stopwatch
+{
+public:
+  enum Unit { UNIT_SECONDS, UNIT_MILLISECONDS, UNIT_MICROSECONDS };
+  Stopwatch();
+  uint64_t elapsedUnits(Unit unit, std::string *label = NULL) const;
+  void reset();
+private:
+  timeval startTime_;
+};
+
+
+class ServiceTracker
+{
+  friend class ServiceMethod;
+
+public:
+
+  static uint64_t CHECKPOINT_MINIMUM_INTERVAL_SECONDS;
+  static int LOG_LEVEL;
+
+  ServiceTracker(facebook::fb303::FacebookBase *handler,
+                 void (*logMethod)(int, const std::string &)
+                 = &ServiceTracker::defaultLogMethod,
+                 bool featureCheckpoint = true,
+                 bool featureStatusCheck = true,
+                 bool featureThreadCheck = true,
+                 Stopwatch::Unit stopwatchUnit
+                 = Stopwatch::UNIT_MILLISECONDS);
+
+  void setThreadManager(boost::shared_ptr<facebook::thrift::concurrency::ThreadManager> threadManager);
+
+private:
+
+  facebook::fb303::FacebookBase *handler_;
+  void (*logMethod_)(int, const std::string &);
+  boost::shared_ptr<facebook::thrift::concurrency::ThreadManager> threadManager_;
+
+  bool featureCheckpoint_;
+  bool featureStatusCheck_;
+  bool featureThreadCheck_;
+  Stopwatch::Unit stopwatchUnit_;
+
+  facebook::thrift::concurrency::Mutex statisticsMutex_;
+  time_t checkpointTime_;
+  uint64_t checkpointServices_;
+  uint64_t checkpointDuration_;
+  std::map<std::string, std::pair<uint64_t, uint64_t> > checkpointServiceDuration_;
+
+  void startService(const ServiceMethod &serviceMethod);
+  int64_t stepService(const ServiceMethod &serviceMethod,
+                      const std::string &stepName);
+  void finishService(const ServiceMethod &serviceMethod);
+  void reportCheckpoint();
+  static void defaultLogMethod(int level, const std::string &message);
+};
+
+
+class ServiceMethod
+{
+  friend class ServiceTracker;
+public:
+  ServiceMethod(ServiceTracker *tracker,
+                const std::string &name,
+                const std::string &signature,
+                bool featureLogOnly = false);
+  ServiceMethod(ServiceTracker *tracker,
+                const std::string &name,
+                uint64_t id,
+                bool featureLogOnly = false);
+  ~ServiceMethod();
+  uint64_t step(const std::string &stepName);
+private:
+  ServiceTracker *tracker_;
+  std::string name_;
+  std::string signature_;
+  bool featureLogOnly_;
+  Stopwatch timer_;
+};
+
+
+class ServiceException : public std::exception
+{
+public:
+  explicit ServiceException(const std::string &message, int code = 0)
+    : message_(message), code_(code) {}
+  ~ServiceException() throw() {}
+  virtual const char *what() const throw() { return message_.c_str(); }
+  int code() const throw() { return code_; }
+private:
+  std::string message_;
+  int code_;
+};
+
+
+}} // facebook::fb303
+
+#endif