blob: c8e4529db71a6f3b7e0b3044ea96c7bf5038fe98 [file] [log] [blame]
pwyckoff99b000b2008-04-03 19:30:55 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
7/**
8 * ServiceTracker is a utility class for logging and timing service
9 * calls to a fb303 Thrift server. Currently, ServiceTracker offers
10 * the following features:
11 *
12 * . Logging of service method start, end (and duration), and
13 * optional steps in between.
14 *
15 * . Automatic check of server status via fb303::getStatus()
16 * with a ServiceException thrown if server not alive
17 * (at method start).
18 *
19 * . A periodic logged checkpoint reporting lifetime time, lifetime
20 * service count, and per-method statistics since the last checkpoint
21 * time (at method finish).
22 *
23 * . Export of fb303 counters for lifetime and checkpoint statistics
24 * (at method finish).
25 *
26 * . For TThreadPoolServers, a logged warning when all server threads
27 * are busy (at method start). (Must call setThreadManager() after
28 * ServiceTracker instantiation for this feature to be enabled.)
29 *
30 * Individual features may be enabled or disabled by arguments to the
31 * constructor. The constructor also accepts a pointer to a logging
32 * method -- if no pointer is passed, the tracker will log to stdout.
33 *
34 * ServiceTracker defines private methods for service start, finish,
35 * and step, which are designed to be accessed by instantiating a
36 * friend ServiceMethod object, as in the following example:
37 *
38 * #include <ServiceTracker.h>
39 * class MyServiceHandler : virtual public MyServiceIf,
40 * public facebook::fb303::FacebookBase
41 * {
42 * public:
43 * MyServiceHandler::MyServiceHandler() : mServiceTracker(this) {}
44 * void MyServiceHandler::myServiceMethod(int userId) {
45 * // note: Instantiating a ServiceMethod object starts a timer
46 * // and tells the ServiceTracker to log the start. Might throw
47 * // a ServiceException.
48 * ServiceMethod serviceMethod(&mServiceTracker,
49 * "myServiceMethod",
50 * userId);
51 * ...
52 * // note: Calling the step method tells the ServiceTracker to
53 * // log the step, with a time elapsed since start.
54 * serviceMethod.step("post parsing, begin processing");
55 * ...
56 * // note: When the ServiceMethod object goes out of scope, the
57 * // ServiceTracker will log the total elapsed time of the method.
58 * }
59 * ...
60 * private:
61 * ServiceTracker mServiceTracker;
62 * }
63 *
64 * The step() method call is optional; the startService() and
65 * finishService() methods are handled by the object's constructor and
66 * destructor.
67 *
68 * The ServiceTracker is (intended to be) thread-safe.
69 *
70 * Future:
71 *
72 * . Come up with something better for logging than passing a
73 * function pointer to the constructor.
74 *
75 * . Add methods for tracking errors from service methods, e.g.
76 * ServiceTracker::reportService().
77 */
78
79#ifndef SERVICETRACKER_H
80#define SERVICETRACKER_H
81
82
83#include <iostream>
84#include <string>
85#include <sstream>
86#include <exception>
87#include <map>
88#include <boost/shared_ptr.hpp>
89
90#include "thrift/concurrency/Mutex.h"
91
92
93namespace facebook { namespace thrift { namespace concurrency {
94 class ThreadManager;
95}}}
96
97
98namespace facebook { namespace fb303 {
99
100
101class FacebookBase;
102class ServiceMethod;
103
104
105class Stopwatch
106{
107public:
108 enum Unit { UNIT_SECONDS, UNIT_MILLISECONDS, UNIT_MICROSECONDS };
109 Stopwatch();
110 uint64_t elapsedUnits(Unit unit, std::string *label = NULL) const;
111 void reset();
112private:
113 timeval startTime_;
114};
115
116
117class ServiceTracker
118{
119 friend class ServiceMethod;
120
121public:
122
123 static uint64_t CHECKPOINT_MINIMUM_INTERVAL_SECONDS;
124 static int LOG_LEVEL;
125
126 ServiceTracker(facebook::fb303::FacebookBase *handler,
127 void (*logMethod)(int, const std::string &)
128 = &ServiceTracker::defaultLogMethod,
129 bool featureCheckpoint = true,
130 bool featureStatusCheck = true,
131 bool featureThreadCheck = true,
132 Stopwatch::Unit stopwatchUnit
133 = Stopwatch::UNIT_MILLISECONDS);
134
135 void setThreadManager(boost::shared_ptr<facebook::thrift::concurrency::ThreadManager> threadManager);
136
137private:
138
139 facebook::fb303::FacebookBase *handler_;
140 void (*logMethod_)(int, const std::string &);
141 boost::shared_ptr<facebook::thrift::concurrency::ThreadManager> threadManager_;
142
143 bool featureCheckpoint_;
144 bool featureStatusCheck_;
145 bool featureThreadCheck_;
146 Stopwatch::Unit stopwatchUnit_;
147
148 facebook::thrift::concurrency::Mutex statisticsMutex_;
149 time_t checkpointTime_;
150 uint64_t checkpointServices_;
151 uint64_t checkpointDuration_;
152 std::map<std::string, std::pair<uint64_t, uint64_t> > checkpointServiceDuration_;
153
154 void startService(const ServiceMethod &serviceMethod);
155 int64_t stepService(const ServiceMethod &serviceMethod,
156 const std::string &stepName);
157 void finishService(const ServiceMethod &serviceMethod);
158 void reportCheckpoint();
159 static void defaultLogMethod(int level, const std::string &message);
160};
161
162
163class ServiceMethod
164{
165 friend class ServiceTracker;
166public:
167 ServiceMethod(ServiceTracker *tracker,
168 const std::string &name,
169 const std::string &signature,
170 bool featureLogOnly = false);
171 ServiceMethod(ServiceTracker *tracker,
172 const std::string &name,
173 uint64_t id,
174 bool featureLogOnly = false);
175 ~ServiceMethod();
176 uint64_t step(const std::string &stepName);
177private:
178 ServiceTracker *tracker_;
179 std::string name_;
180 std::string signature_;
181 bool featureLogOnly_;
182 Stopwatch timer_;
183};
184
185
186class ServiceException : public std::exception
187{
188public:
189 explicit ServiceException(const std::string &message, int code = 0)
190 : message_(message), code_(code) {}
191 ~ServiceException() throw() {}
192 virtual const char *what() const throw() { return message_.c_str(); }
193 int code() const throw() { return code_; }
194private:
195 std::string message_;
196 int code_;
197};
198
199
200}} // facebook::fb303
201
202#endif