diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:45:59 +0000 |
commit | 19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch) | |
tree | 42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/jaegertracing/thrift/contrib/fb303 | |
parent | Initial commit. (diff) | |
download | ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip |
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
29 files changed, 3499 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/contrib/fb303/LICENSE b/src/jaegertracing/thrift/contrib/fb303/LICENSE new file mode 100644 index 000000000..4eacb6431 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/LICENSE @@ -0,0 +1,16 @@ +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. diff --git a/src/jaegertracing/thrift/contrib/fb303/Makefile.am b/src/jaegertracing/thrift/contrib/fb303/Makefile.am new file mode 100644 index 000000000..e773e522c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/Makefile.am @@ -0,0 +1,46 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +@GLOBAL_HEADER_MK@ + +@PRODUCT_MK@ + +SUBDIRS = . + +if WITH_CPP +SUBDIRS += cpp +endif + +if WITH_JAVA +SUBDIRS += java +endif + +if WITH_PHP +SUBDIRS += php +endif + +if WITH_PYTHON +SUBDIRS += py +endif + +BUILT_SOURCES = + +clean-local: clean-common + +@GLOBAL_FOOTER_MK@ diff --git a/src/jaegertracing/thrift/contrib/fb303/README.md b/src/jaegertracing/thrift/contrib/fb303/README.md new file mode 100644 index 000000000..8ade560c9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/README.md @@ -0,0 +1,37 @@ +Project FB303: The Facebook Bassline +------------------------------------ + +* Curious about the 303? * +http://en.wikipedia.org/wiki/Roland_TB-303 + +* Why the name? * +The TB303 makes bass lines. +.Bass is what lies underneath any strong tune. +..fb303 is the shared root of all thrift services. +...fb303 => FacebookBase303. + +* How do I use this? * +Take a look at the examples to see how your backend project can +and should inherit from this service. + +* What does it provide? * +A standard interface to monitoring, dynamic options and configuration, +uptime reports, activity, etc. + +* I want more. * +Think carefully first about whether the functionality you are going to add +belongs here or in your application. If it can be abstracted and is generally +useful, then it probably belongs somewhere in the fb303 tree. Keep in mind, +not every product has to use ALL the functionality of fb303, but every product +CANNOT use functionality that is NOT in fb303. + +* Is this open source? * +Yes. fb303 is distributed under the Thrift Software License. See the +LICENSE file for more details. + +* Installation * +fb303 is configured/built/installed similar to Thrift. See the README +in the Thrift root directory for more information. + +* Who wrote this README? * +mcslee@facebook.com diff --git a/src/jaegertracing/thrift/contrib/fb303/TClientInfo.cpp b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.cpp new file mode 100644 index 000000000..1fc661251 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.cpp @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <thrift/server/TClientInfo.h> + +namespace apache { namespace thrift { namespace server { + +using namespace apache::thrift; +using namespace apache::thrift::transport; + +TClientInfoConnection::TClientInfoConnection() { + call_[kNameLen - 1] = '\0'; // insure NUL terminator is there + eraseAddr(); + eraseCall(); +} + +void TClientInfoConnection::recordAddr(const sockaddr* addr) { + eraseAddr(); + initTime(); + ncalls_ = 0; + if (addr != NULL) { + if (addr->sa_family == AF_INET) { + memcpy((void*)&addr_.ipv4, (const void *)addr, sizeof(sockaddr_in)); + } + else if (addr->sa_family == AF_INET6) { + memcpy((void*)&addr_.ipv6, (const void *)addr, sizeof(sockaddr_in6)); + } + } +} + +void TClientInfoConnection::eraseAddr() { + addr_.ipv4.sin_family = AF_UNSPEC; +} + +const char* TClientInfoConnection::getAddr(char* buf, int len) const { + switch (addr_.ipv4.sin_family) { + case AF_INET: + return inet_ntop(AF_INET, &addr_.ipv4.sin_addr, buf, len); + case AF_INET6: + return inet_ntop(AF_INET6, &addr_.ipv6.sin6_addr, buf, len); + default: + return NULL; + } +} + +void TClientInfoConnection::recordCall(const char* name) { + strncpy(call_, name, kNameLen - 1); // NUL terminator set in constructor + ncalls_++; +} + +void TClientInfoConnection::eraseCall() { + call_[0] = '\0'; +} + +const char* TClientInfoConnection::getCall() const { + if (call_[0] == '\0') { + return NULL; + } + return call_; +} + +void TClientInfoConnection::getTime(timespec* time) const { + *time = time_; +} + +uint64_t TClientInfoConnection::getNCalls() const { + return ncalls_; +} + +void TClientInfoConnection::initTime() { + clock_gettime(CLOCK_REALTIME, &time_); +} + + +TClientInfoConnection* TClientInfo::getConnection(int fd, bool grow) { + if (fd < 0 || (!grow && fd >= info_.size())) { + return NULL; + } + return &info_[fd]; +} + +size_t TClientInfo::size() const { + return info_.size(); +} + +void* TClientInfoServerHandler::createContext(boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output) { + (void)input; + (void)output; + return (void*) new Connect(&clientInfo_); +} + +void TClientInfoServerHandler::deleteContext(void* connectionContext, + boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output) { + Connect* call = static_cast<Connect*>(connectionContext); + if (call->callInfo_) { + call->callInfo_->eraseCall(); + } + delete call; +} + +void TClientInfoServerHandler::processContext(void* connectionContext, + shared_ptr<TTransport> transport) { + Connect* call = static_cast<Connect*>(connectionContext); + if (call->callInfo_ == NULL) { + if (typeid(*(transport.get())) == typeid(TSocket)) { + TSocket* tsocket = static_cast<TSocket*>(transport.get()); + int fd = tsocket->getSocketFD(); + if (fd < 0) { + return; + } + call->callInfo_ = call->clientInfo_->getConnection(fd, true); + assert(call->callInfo_ != NULL); + socklen_t len; + call->callInfo_->recordAddr(tsocket->getCachedAddress(&len)); + } + } +} + +void TClientInfoServerHandler::getStatsStrings(vector<string>& result) { + result.clear(); + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + + for (int i = 0; i < clientInfo_.size(); ++i) { + TClientInfoConnection* info = clientInfo_.getConnection(i, false); + const char* callStr = info->getCall(); + if (callStr == NULL) { + continue; + } + + char addrBuf[INET6_ADDRSTRLEN]; + const char* addrStr = info->getAddr(addrBuf, sizeof addrBuf); + if (addrStr == NULL) { + // cerr << "no addr!" << endl; + continue; + } + + timespec start; + info->getTime(&start); + double secs = (double)(now.tv_sec - start.tv_sec) + (now.tv_nsec - start.tv_nsec)*0.000000001; + + char buf[256]; + snprintf(buf, sizeof buf, "%d %s %s %.3f %llu", i, addrStr, callStr, secs, + (uint64_t)info->getNCalls()); + + result.push_back(buf); + } +} + +void* TClientInfoCallHandler::getContext(const char* fn_name, void* serverContext) { + if (serverContext) { + TClientInfoConnection* callInfo = static_cast<TClientInfoServerHandler::Connect*>(serverContext)->callInfo_; + if (callInfo != NULL) { + callInfo->recordCall(fn_name); + } + } + return NULL; +} + +} } } // namespace apache::thrift::server diff --git a/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h new file mode 100644 index 000000000..6668c1921 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/TClientInfo.h @@ -0,0 +1,320 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ +#define _FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ 1 + +// for inet_ntop -- +#include <arpa/inet.h> +#include <thrift/server/TServer.h> +#include <thrift/transport/TSocket.h> +#include <thrift/concurrency/Mutex.h> + +namespace apache { namespace thrift { namespace server { + +using namespace apache::thrift; +using namespace apache::thrift::transport; +using namespace apache::thrift::concurrency; +using boost::shared_ptr; +using std::string; +using std::vector; + +/** + * StableVector -- a minimal vector class where growth is automatic and + * vector elements never move as the vector grows. Allocates new space + * as needed, but does not copy old values. + * + * A level vector stores a list of storage vectors containing the actual + * elements. Levels are added as needed, doubling in size each time. + * Locking is only done when a level is added. Access is amortized + * constant time. + */ +template <typename T> +class StableVector { + /// The initial allocation as an exponent of 2 + static const uint32_t kInitialSizePowOf2 = 10; + /// The initial allocation size + static const uint32_t kInitialVectorSize = 1 << kInitialSizePowOf2; + /// This bound is guaranteed not to be exceeded on 64-bit archs + static const int kMaxLevels = 64; + + /// Values are kept in one or more of these + typedef vector<T> Vect; + /// One or more value vectors are kept in one of these + typedef vector<Vect*> LevelVector; + + Mutex mutex_; + /// current size + size_t size_; + _Atomic_word vectLvl_; + LevelVector vects_; + + public: + /** + * Constructor -- initialize the level vector and allocate the + * initial storage vector + */ + StableVector() + : size_(0) + , vectLvl_(0) { + vects_.reserve(kMaxLevels); + Vect* storageVector(new Vect(1 << kInitialSizePowOf2)); + vects_.push_back(storageVector); + } + + private: + /** + * make sure the requested number of storage levels have been allocated. + */ + void expand(uint32_t level) { + // we need the guard to insure that we only allocate once. + Guard g(mutex_); + while (level > vectLvl_) { + Vect* levelVect(new Vect(1 << (vectLvl_ + kInitialSizePowOf2))); + vects_.push_back(levelVect); + // we need to make sure this is done after levelVect is inserted + // (what we want is effectively a memory barrier here). + __gnu_cxx::__atomic_add(&vectLvl_, 1); + } + } + + /** + * Given an index, determine which level and element of that level is + * required. Grows if needed. + */ + void which(uint32_t n, uint32_t* vno, uint32_t* idx) { + if (n >= size_) { + size_ = n + 1; + } + if (n < kInitialVectorSize) { + *idx = n; + *vno = 0; + } else { + uint32_t upper = n >> kInitialSizePowOf2; + *vno = CHAR_BIT*sizeof(upper) - __builtin_clz(upper); + *idx = n - (1 << (*vno + kInitialSizePowOf2 - 1)); + if (*vno > vectLvl_) { + expand(*vno); + } + } + } + + public: + /** + * Given an index, return a reference to that element, perhaps after + * allocating additional space. + * + * @param n a positive integer + */ + T& operator[](uint32_t n) { + uint32_t vno; + uint32_t idx; + which(n, &vno, &idx); + return (*vects_[vno])[idx]; + } + + /** + * Return the present size of the vector. + */ + size_t size() const { return size_; } +}; + + +/** + * This class embodies the representation of a single connection during + * processing. We'll keep one of these per file descriptor in TClientInfo. + */ +class TClientInfoConnection { + public: + const static int kNameLen = 32; + + private: + typedef union IPAddrUnion { + sockaddr_in ipv4; + sockaddr_in6 ipv6; + }; + + char call_[kNameLen]; ///< The name of the thrift call + IPAddrUnion addr_; ///< The client's IP address + timespec time_; ///< Time processing started + uint64_t ncalls_; ///< # of calls processed + + public: + /** + * Constructor; insure that no client address or thrift call name is + * represented. + */ + TClientInfoConnection(); + + /** + * A connection has been made; record its address. Since this is the + * first we'll know of a connection we start the timer here as well. + */ + void recordAddr(const sockaddr* addr); + + /** + * Mark the address as empty/unknown. + */ + void eraseAddr(); + + /** + * Return a string representing the present address, or NULL if none. + * Copies the string into the buffer provided. + */ + const char* getAddr(char* buf, int len) const; + + /** + * A call has been made on this connection; record its name. Since this is + * called for every thrift call processed, we also do our call count here. + */ + void recordCall(const char* name); + + /** + * Invoked when processing has ended to clear the call name. + */ + void eraseCall(); + + /** + * Return as string the thrift call either currently being processed or + * most recently processed if the connection is still open for additional + * calls. Returns NULL if a call hasn't been made yet or processing + * has ended. + */ + const char* getCall() const; + + /** + * Get the timespec for the start of this connection (specifically, when + * recordAddr() was first called). + */ + void getTime(timespec* time) const; + + /** + * Return the number of calls made on this connection. + */ + uint64_t getNCalls() const; + + private: + void initTime(); +}; + + +/** + * Store for info about a server's clients -- specifically, the client's IP + * address and the call it is executing. This information is indexed by + * socket file descriptor and in the present implementation is updated + * asynchronously, so it may only approximate reality. + */ +class TClientInfo { + private: + StableVector<TClientInfoConnection> info_; + + public: + /** + * Return the info object for a given file descriptor. If "grow" is true + * extend the info vector if required (such as for a file descriptor not seen + * before). If "grow" is false and the info vector isn't large enough, + * or if "fd" is negative, return NULL. + */ + TClientInfoConnection* getConnection(int fd, bool grow); + + size_t size() const; +}; + +/** + * This derivation of TServerEventHandler encapsulates the main status vector + * and provides context to the server's processing loop via overrides. + * Together with TClientInfoCallHandler (derived from TProcessorEventHandler) + * it integrates client info collection into the server. + */ +class TClientInfoServerHandler : public TServerEventHandler { + private: + TClientInfo clientInfo_; + + public: + /** + * One of these is constructed for each open connection/descriptor and links + * to both the status vector (clientInfo_) and that descriptor's entry + * within it. + */ + struct Connect { + TClientInfo* clientInfo_; + TClientInfoConnection* callInfo_; + + explicit Connect(TClientInfo* clientInfo) + : clientInfo_(clientInfo) + , callInfo_(NULL) { + } + }; + + /** + * Generate processor context; we don't know what descriptor we belong to + * yet -- we'll get hooked up in contextProcess(). + */ + void* createContext(boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output); + + /** + * Mark our slot as unused and delete the context created in createContext(). + */ + void deleteContext(void* processorContext, + boost::shared_ptr<TProtocol> input, + boost::shared_ptr<TProtocol> output); + + /** + * Called in the processing loop just before the server invokes the + * processor itself, on the first call we establish which descriptor + * we correspond to and set it to that socket's peer IP address. This + * also has the side effect of initializing call counting and connection + * timing. We won't know which call we're handling until the handler + * first gets called in TClientInfoCallHandler::getContext(). + */ + void processContext(void* processorContext, + shared_ptr<TTransport> transport); + + /** + * Get status report for server in the form of a vector of strings. + * Each active client appears as one string in the format: + * + * FD IPADDR CALLNAME DURATION NCALLS + * + * where "FD" is the file descriptor for the client's socket, "IPADDR" + * is the IP address (as reported by accept()), "CALLNAME" is the + * current or most recent Thrift function name, "DURATION" is the + * duration of the connection, while NCALLS is the number of Thrift + * calls made since the connection was made. A single space separates + * fields. + */ + void getStatsStrings(vector<string>& result); +}; + +/** + * This class derives from TProcessorEventHandler to gain access to the + * function name for the current Thrift call. We need two versions of + * this -- TClientInfoCallStatsHandler is the other -- since in the latter + * case we pass through to TFunctionStatHandler to perform Thrift call + * stats. + */ +class TClientInfoCallHandler : public TProcessorEventHandler { + public: + virtual void* getContext(const char* fn_name, void* serverContext); +}; + +} } } // namespace apache::thrift::server + +#endif // !_FACEBOOK_THRIFT_SERVER_TCLIENTINFO_H_ diff --git a/src/jaegertracing/thrift/contrib/fb303/acinclude.m4 b/src/jaegertracing/thrift/contrib/fb303/acinclude.m4 new file mode 100644 index 000000000..faafba6b3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/acinclude.m4 @@ -0,0 +1,258 @@ +dnl Copyright (C) 2009 Facebook +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +AC_DEFUN([FB_INITIALIZE], +[ +AM_INIT_AUTOMAKE([ foreign 1.9.5 no-define ]) +if test "x$1" = "xlocalinstall"; then +wdir=`pwd` +# To use $wdir undef quote. +# +########## +AC_PREFIX_DEFAULT([`pwd`/install]) +echo +fi +AC_PROG_CC +AC_PROG_CXX +AC_PROG_RANLIB(RANLIB, ranlib) +AC_PATH_PROGS(BASH, bash) +AC_PATH_PROGS(PERL, perl) +AC_PATH_PROGS(PYTHON, python) +AC_PATH_PROGS(AR, ar) +AC_PATH_PROGS(ANT, ant) +PRODUCT_MK="" +]) + +AC_DEFUN([FB_WITH_EXTERNAL_PATH], +[ +cdir=`pwd` +AC_MSG_CHECKING([Checking EXTERNAL_PATH set to]) +AC_ARG_WITH([externalpath], + [ --with-externalpath=DIR User specified path to external facebook components.], + [ + if test "x${EXTERNAL_PATH}" != "x"; then + echo "" + echo "ERROR: You have already set EXTERNAL_PATH in your environment" + echo "Cannot override it using --with-externalpath. Unset EXTERNAL_PATH to use this option" + exit 1 + fi + EXTERNAL_PATH=$withval + ], + [ + if test "x${EXTERNAL_PATH}" = "x"; then + EXTERNAL_PATH=$1 + fi + ] +) +if test "x${EXTERNAL_PATH}" = "x"; then + export EXTERNAL_PATH="$cdir/external" + GLOBAL_HEADER_MK="include ${EXTERNAL_PATH}/global_header.mk" + GLOBAL_FOOTER_MK="include ${EXTERNAL_PATH}/global_footer.mk" +else + export EXTERNAL_PATH + GLOBAL_HEADER_MK="include ${EXTERNAL_PATH}/global_header.mk" + GLOBAL_FOOTER_MK="include ${EXTERNAL_PATH}/global_footer.mk" +fi +AC_MSG_RESULT($EXTERNAL_PATH) +if test ! -d ${EXTERNAL_PATH}; then + echo "" + echo "ERROR: EXTERNAL_PATH set to an nonexistent directory ${EXTERNAL_PATH}" + exit 1 +fi +AC_SUBST(EXTERNAL_PATH) +AC_SUBST(GLOBAL_HEADER_MK) +AC_SUBST(GLOBAL_FOOTER_MK) +]) + +# Set option to enable shared mode. Set DEBUG and OPT for use in Makefile.am. +AC_DEFUN([FB_ENABLE_DEFAULT_OPT_BUILD], +[ +AC_MSG_CHECKING([whether to enable optimized build]) +AC_ARG_ENABLE([opt], + [ --disable-opt Set up debug mode.], + [ + ENABLED_OPT=$enableval + ], + [ + ENABLED_OPT="yes" + ] +) +if test "$ENABLED_OPT" = "yes" +then + CFLAGS="-Wall -O3" + CXXFLAGS="-Wall -O3" +else + CFLAGS="-Wall -g" + CXXFLAGS="-Wall -g" +fi +AC_MSG_RESULT($ENABLED_OPT) +AM_CONDITIONAL([OPT], [test "$ENABLED_OPT" = yes]) +AM_CONDITIONAL([DEBUG], [test "$ENABLED_OPT" = no]) +]) + +# Set option to enable debug mode. Set DEBUG and OPT for use in Makefile.am. +AC_DEFUN([FB_ENABLE_DEFAULT_DEBUG_BUILD], +[ +AC_MSG_CHECKING([whether to enable debug build]) +AC_ARG_ENABLE([debug], + [ --disable-debug Set up opt mode.], + [ + ENABLED_DEBUG=$enableval + ], + [ + ENABLED_DEBUG="yes" + ] +) +if test "$ENABLED_DEBUG" = "yes" +then + CFLAGS="-Wall -g" + CXXFLAGS="-Wall -g" +else + CFLAGS="-Wall -O3" + CXXFLAGS="-Wall -O3" +fi +AC_MSG_RESULT($ENABLED_DEBUG) +AM_CONDITIONAL([DEBUG], [test "$ENABLED_DEBUG" = yes]) +AM_CONDITIONAL([OPT], [test "$ENABLED_DEBUG" = no]) +]) + +# Set option to enable static libs. +AC_DEFUN([FB_ENABLE_DEFAULT_STATIC], +[ +SHARED="" +STATIC="" +AC_MSG_CHECKING([whether to enable static mode]) +AC_ARG_ENABLE([static], + [ --disable-static Set up shared mode.], + [ + ENABLED_STATIC=$enableval + ], + [ + ENABLED_STATIC="yes" + ] +) +if test "$ENABLED_STATIC" = "yes" +then + LTYPE=".a" +else + LTYPE=".so" + SHARED_CXXFLAGS="-fPIC" + SHARED_CFLAGS="-fPIC" + SHARED_LDFLAGS="-shared -fPIC" + AC_SUBST(SHARED_CXXFLAGS) + AC_SUBST(SHARED_CFLAGS) + AC_SUBST(SHARED_LDFLAGS) +fi +AC_MSG_RESULT($ENABLED_STATIC) +AC_SUBST(LTYPE) +AM_CONDITIONAL([STATIC], [test "$ENABLED_STATIC" = yes]) +AM_CONDITIONAL([SHARED], [test "$ENABLED_STATIC" = no]) +]) + +# Set option to enable shared libs. +AC_DEFUN([FB_ENABLE_DEFAULT_SHARED], +[ +SHARED="" +STATIC="" +AC_MSG_CHECKING([whether to enable shared mode]) +AC_ARG_ENABLE([shared], + [ --disable-shared Set up static mode.], + [ + ENABLED_SHARED=$enableval + ], + [ + ENABLED_SHARED="yes" + ] +) +if test "$ENABLED_SHARED" = "yes" +then + LTYPE=".so" + SHARED_CXXFLAGS="-fPIC" + SHARED_CFLAGS="-fPIC" + SHARED_LDFLAGS="-shared -fPIC" + AC_SUBST(SHARED_CXXFLAGS) + AC_SUBST(SHARED_CFLAGS) + AC_SUBST(SHARED_LDFLAGS) +else + LTYPE=".a" +fi +AC_MSG_RESULT($ENABLED_SHARED) +AC_SUBST(LTYPE) +AM_CONDITIONAL([SHARED], [test "$ENABLED_SHARED" = yes]) +AM_CONDITIONAL([STATIC], [test "$ENABLED_SHARED" = no]) +]) + +# Generates define flags and conditionals as specified by user. +# This gets enabled *only* if user selects --enable-<FEATURE> otion. +AC_DEFUN([FB_ENABLE_FEATURE], +[ +ENABLE="" +flag="$1" +value="$3" +AC_MSG_CHECKING([whether to enable $1]) +AC_ARG_ENABLE([$2], + [ --enable-$2 Enable $2.], + [ + ENABLE=$enableval + ], + [ + ENABLE="no" + ] +) +AM_CONDITIONAL([$1], [test "$ENABLE" = yes]) +if test "$ENABLE" = "yes" +then + if test "x${value}" = "x" + then + AC_DEFINE([$1]) + else + AC_DEFINE_UNQUOTED([$1], [$value]) + fi +fi +AC_MSG_RESULT($ENABLE) +]) + + +# can also use eval $2=$withval;AC_SUBST($2) +AC_DEFUN([FB_WITH_PATH], +[ +USRFLAG="" +USRFLAG=$1 +AC_MSG_CHECKING([Checking $1 set to]) +AC_ARG_WITH([$2], + [ --with-$2=DIR User specified path.], + [ + LOC=$withval + eval $USRFLAG=$withval + ], + [ + LOC=$3 + eval $USRFLAG=$3 + ] +) +AC_SUBST([$1]) +AC_MSG_RESULT($LOC) +]) + +AC_DEFUN([FB_SET_FLAG_VALUE], +[ +SETFLAG="" +AC_MSG_CHECKING([Checking $1 set to]) +SETFLAG=$1 +eval $SETFLAG=\"$2\" +AC_SUBST([$SETFLAG]) +AC_MSG_RESULT($2) +]) + +# NOTES +# if using if else bourne stmt you must have more than a macro in it. +# EX1 is not correct. EX2 is correct +# EX1: if test "$XX" = "yes"; then +# AC_SUBST(xx) +# fi +# EX2: if test "$XX" = "yes"; then +# xx="foo" +# AC_SUBST(xx) +# fi diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_boost_base.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_boost_base.m4 new file mode 100644 index 000000000..e56bb7380 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_boost_base.m4 @@ -0,0 +1,198 @@ +##### http://autoconf-archive.cryp.to/ax_boost_base.html +# +# SYNOPSIS +# +# AX_BOOST_BASE([MINIMUM-VERSION]) +# +# DESCRIPTION +# +# Test for the Boost C++ libraries of a particular version (or newer) +# +# If no path to the installed boost library is given the macro +# searchs under /usr, /usr/local, /opt and /opt/local and evaluates +# the $BOOST_ROOT environment variable. Further documentation is +# available at <http://randspringer.de/boost/index.html>. +# +# This macro calls: +# +# AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) +# +# And sets: +# +# HAVE_BOOST +# +# LAST MODIFICATION +# +# 2007-07-28 +# +# COPYLEFT +# +# Copyright (c) 2007 Thomas Porschberg <thomas@randspringer.de> +# +# Copying and distribution of this file, with or without +# modification, are permitted in any medium without royalty provided +# the copyright notice and this notice are preserved. + +AC_DEFUN([AX_BOOST_BASE], +[ +AC_ARG_WITH([boost], + AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ac_boost_path="" + else + want_boost="yes" + ac_boost_path="$withval" + fi + ], + [want_boost="yes"]) + +if test "x$want_boost" = "xyes"; then + boost_lib_version_req=ifelse([$1], ,1.20.0,$1) + boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` + boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` + boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` + boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` + if test "x$boost_lib_version_req_sub_minor" = "x" ; then + boost_lib_version_req_sub_minor="0" + fi + WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` + AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) + succeeded=no + + dnl first we check the system location for boost libraries + dnl this location ist chosen if boost libraries are installed with the --layout=system option + dnl or if you install boost with RPM + if test "$ac_boost_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_path/lib" + BOOST_CPPFLAGS="-I$ac_boost_path/include" + else + for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then + BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib" + BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" + break; + fi + done + fi + + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include <boost/version.hpp> + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + + + + dnl if we found no boost with system layout we search for boost libraries + dnl built and installed without the --layout=system option or for a staged(not installed) version + if test "x$succeeded" != "xyes"; then + _version=0 + if test "$ac_boost_path" != ""; then + BOOST_LDFLAGS="-L$ac_boost_path/lib" + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + fi + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" + done + fi + else + for ac_boost_path in /usr /usr/local /opt /opt/local ; do + if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then + for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do + _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` + V_CHECK=`expr $_version_tmp \> $_version` + if test "$V_CHECK" = "1" ; then + _version=$_version_tmp + best_path=$ac_boost_path + fi + done + fi + done + + VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` + BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" + BOOST_LDFLAGS="-L$best_path/lib" + + if test "x$BOOST_ROOT" != "x"; then + if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then + version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` + stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` + stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` + V_CHECK=`expr $stage_version_shorten \>\= $_version` + if test "$V_CHECK" = "1" ; then + AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) + BOOST_CPPFLAGS="-I$BOOST_ROOT" + BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib" + fi + fi + fi + fi + + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_LANG_PUSH(C++) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + @%:@include <boost/version.hpp> + ]], [[ + #if BOOST_VERSION >= $WANT_BOOST_VERSION + // Everything is okay + #else + # error Boost version is too old + #endif + ]])],[ + AC_MSG_RESULT(yes) + succeeded=yes + found_system=yes + ],[ + ]) + AC_LANG_POP([C++]) + fi + + if test "$succeeded" != "yes" ; then + if test "$_version" = "0" ; then + AC_MSG_ERROR([[We could not detect the boost libraries (version $boost_lib_version_req_shorten or higher). If you have a staged boost library (still not installed) please specify \$BOOST_ROOT in your environment and do not give a PATH to --with-boost option. If you are sure you have boost installed, then check your version number looking in <boost/version.hpp>. See http://randspringer.de/boost for more documentation.]]) + else + AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) + fi + else + AC_SUBST(BOOST_CPPFLAGS) + AC_SUBST(BOOST_LDFLAGS) + AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" +fi + +]) diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 new file mode 100644 index 000000000..a4c9189c9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_cxx_compile_stdcxx_11.m4 @@ -0,0 +1,134 @@ +# ============================================================================ +# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) +# +# DESCRIPTION +# +# Check for baseline language coverage in the compiler for the C++11 +# standard; if necessary, add switches to CXXFLAGS to enable support. +# +# The first argument, if specified, indicates whether you insist on an +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. +# -std=c++11). If neither is specified, you get whatever works, with +# preference for an extended mode. +# +# The second argument, if specified 'mandatory' or if left unspecified, +# indicates that baseline C++11 support is required and that the macro +# should error out if no mode with that support is found. If specified +# 'optional', then configuration proceeds regardless, after defining +# HAVE_CXX11 if and only if a supporting mode is found. +# +# LICENSE +# +# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com> +# Copyright (c) 2012 Zack Weinberg <zackw@panix.com> +# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu> +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 3 + +m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ + template <typename T> + struct check + { + static_assert(sizeof(int) <= sizeof(T), "not big enough"); + }; + + typedef check<check<bool>> right_angle_brackets; + + int a; + decltype(a) b; + + typedef check<int> check_type; + check_type c; + check_type&& cr = static_cast<check_type&&>(c); + + auto d = a; +]) + +AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl + m4_if([$1], [], [], + [$1], [ext], [], + [$1], [noext], [], + [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl + m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], + [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], + [$2], [optional], [ax_cxx_compile_cxx11_required=false], + [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl + AC_LANG_PUSH([C++])dnl + ac_success=no + AC_CACHE_CHECK(whether $CXX supports C++11 features by default, + ax_cv_cxx_compile_cxx11, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [ax_cv_cxx_compile_cxx11=yes], + [ax_cv_cxx_compile_cxx11=no])]) + if test x$ax_cv_cxx_compile_cxx11 = xyes; then + ac_success=yes + fi + + m4_if([$1], [noext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=gnu++11; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + + m4_if([$1], [ext], [], [dnl + if test x$ac_success = xno; then + for switch in -std=c++11; do + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) + AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, + $cachevar, + [ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS $switch" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], + [eval $cachevar=yes], + [eval $cachevar=no]) + CXXFLAGS="$ac_save_CXXFLAGS"]) + if eval test x\$$cachevar = xyes; then + CXXFLAGS="$CXXFLAGS $switch" + ac_success=yes + break + fi + done + fi]) + AC_LANG_POP([C++]) + if test x$ax_cxx_compile_cxx11_required = xtrue; then + if test x$ac_success = xno; then + AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) + fi + else + if test x$ac_success = xno; then + HAVE_CXX11=0 + AC_MSG_NOTICE([No compiler with C++11 support was found]) + else + HAVE_CXX11=1 + AC_DEFINE(HAVE_CXX11,1, + [define if the compiler supports basic C++11 syntax]) + fi + + AC_SUBST(HAVE_CXX11) + fi +]) + diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_javac_and_java.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_javac_and_java.m4 new file mode 100644 index 000000000..581b45066 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_javac_and_java.m4 @@ -0,0 +1,121 @@ +dnl @synopsis AX_JAVAC_AND_JAVA +dnl @synopsis AX_CHECK_JAVA_CLASS(CLASSNAME) +dnl +dnl Test for the presence of a JDK, and (optionally) specific classes. +dnl +dnl If "JAVA" is defined in the environment, that will be the only +dnl java command tested. Otherwise, a hard-coded list will be used. +dnl Similarly for "JAVAC". +dnl +dnl AX_JAVAC_AND_JAVA does not currently support testing for a particular +dnl Java version, testing for only one of "java" and "javac", or +dnl compiling or running user-provided Java code. +dnl +dnl After AX_JAVAC_AND_JAVA runs, the shell variables "success" and +dnl "ax_javac_and_java" are set to "yes" or "no", and "JAVAC" and +dnl "JAVA" are set to the appropriate commands. +dnl +dnl AX_CHECK_JAVA_CLASS must be run after AX_JAVAC_AND_JAVA. +dnl It tests for the presence of a class based on a fully-qualified name. +dnl It sets the shell variable "success" to "yes" or "no". +dnl +dnl @category Java +dnl @version 2009-02-09 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + + +AC_DEFUN([AX_JAVAC_AND_JAVA], + [ + + dnl Hard-coded default commands to test. + JAVAC_PROGS="javac,jikes,gcj -C" + JAVA_PROGS="java,kaffe" + + dnl Allow the user to specify an alternative. + if test -n "$JAVAC" ; then + JAVAC_PROGS="$JAVAC" + fi + if test -n "$JAVA" ; then + JAVA_PROGS="$JAVA" + fi + + AC_MSG_CHECKING(for javac and java) + + echo "public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java + success=no + oIFS="$IFS" + + IFS="," + for JAVAC in $JAVAC_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD + if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then + + IFS="," + for JAVA in $JAVA_PROGS ; do + IFS="$oIFS" + + echo "Running \"$JAVA configtest_ax_javac_and_java\"" >&AS_MESSAGE_LOG_FD + if $JAVA configtest_ax_javac_and_java >&AS_MESSAGE_LOG_FD 2>&1 ; then + success=yes + break 2 + fi + + done + + fi + + done + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + + if test "$success" != "yes" ; then + AC_MSG_RESULT(no) + JAVAC="" + JAVA="" + else + AC_MSG_RESULT(yes) + fi + + ax_javac_and_java="$success" + + ]) + + +AC_DEFUN([AX_CHECK_JAVA_CLASS], + [ + AC_MSG_CHECKING(for Java class [$1]) + + echo "import $1; public class configtest_ax_javac_and_java { public static void main(String args@<:@@:>@) { } }" > configtest_ax_javac_and_java.java + + echo "Running \"$JAVAC configtest_ax_javac_and_java.java\"" >&AS_MESSAGE_LOG_FD + if $JAVAC configtest_ax_javac_and_java.java >&AS_MESSAGE_LOG_FD 2>&1 ; then + AC_MSG_RESULT(yes) + success=yes + else + AC_MSG_RESULT(no) + success=no + fi + + rm -f configtest_ax_javac_and_java.java configtest_ax_javac_and_java.class + ]) + + +AC_DEFUN([AX_CHECK_ANT_VERSION], + [ + AC_MSG_CHECKING(for ant version > $2) + ANT_VALID=`expr $($1 -version 2>/dev/null | sed -n 's/.*version \(@<:@0-9\.@:>@*\).*/\1/p') \>= $2` + if test "x$ANT_VALID" = "x1" ; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + ANT="" + fi + ]) + diff --git a/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_thrift_internal.m4 b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_thrift_internal.m4 new file mode 100644 index 000000000..8c0e3cbc1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/aclocal/ax_thrift_internal.m4 @@ -0,0 +1,28 @@ +dnl @synopsis AX_THRIFT_GEN(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) +dnl @synopsis AX_THRIFT_LIB(SHORT_LANGUAGE, LONG_LANGUAGE, DEFAULT) +dnl +dnl Allow a particular language generator to be disabled. +dnl Allow a particular language library to be disabled. +dnl +dnl These macros have poor error handling and are poorly documented. +dnl They are intended only for internal use by the Thrift compiler. +dnl +dnl @version 2008-02-20 +dnl @license AllPermissive +dnl +dnl Copyright (C) 2009 David Reiss +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty provided the copyright +dnl notice and this notice are preserved. + +AC_DEFUN([AX_THRIFT_LIB], + [ + AC_ARG_WITH($1, + AC_HELP_STRING([--with-$1], [build the $2 library @<:@default=$3@:>@]), + [with_$1="$withval"], + [with_$1=$3] + ) + have_$1=no + dnl What we do here is going to vary from library to library, + dnl so we can't really generalize (yet!). + ]) diff --git a/src/jaegertracing/thrift/contrib/fb303/bootstrap.sh b/src/jaegertracing/thrift/contrib/fb303/bootstrap.sh new file mode 100755 index 000000000..3cbeddb34 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/bootstrap.sh @@ -0,0 +1,26 @@ +#!/bin/sh + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# To be safe include -I flag +aclocal -I ./aclocal +automake -a +autoconf +./configure --config-cache $* diff --git a/src/jaegertracing/thrift/contrib/fb303/configure.ac b/src/jaegertracing/thrift/contrib/fb303/configure.ac new file mode 100644 index 000000000..73b35ba07 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/configure.ac @@ -0,0 +1,164 @@ +# Autoconf input file +# $Id$ + +# AC - autoconf +# FB - facebook + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +######################################################################### +# DO NOT TOUCH EXCEPT TO CHANGE REV# IN AC_INIT + +AC_PREREQ(2.52) +AC_INIT([libfb303],[20080209]) +#AC_CONFIG_AUX_DIR([/usr/share/automake-1.9]) +# To install locally +FB_INITIALIZE([localinstall]) +AC_PREFIX_DEFAULT([/usr/local]) + +############################################################################ +# User Configurable. Change With CAUTION! +# User can include custom makefile rules. Uncomment and update only <name> in PRODUCT_MK. +# Include where appropriate in any Makefile.am as @PRODUCT_MK@ + +#PRODUCT_MK="include ${EXTERNAL_PATH}/shared/build/<name>.mk" + +# Default path to external Facebook components and shared build toools I.e fb303 etc. +# To point to other locations set environment variable EXTERNAL_PATH. +# To change the current default you must change bootstrap.sh. +FB_WITH_EXTERNAL_PATH([`pwd`]) + +AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules. + (Normal --prefix is ignored for Python because + Python has different conventions.) + Default = "/usr"]) +AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"]) + +########################################################################## +# User Configurable + +# Pre-defined macro to set opt build mode. Run with --disable-shared option to turn off optimization. +FB_ENABLE_DEFAULT_OPT_BUILD + +# Predefined macro to set static library mode. Run with --disable-static option to turn off static lib mode. +FB_ENABLE_DEFAULT_STATIC + +# Personalized feature generator. Creates defines/conditionals and --enable --disable command line options. +# FB_ENABLE_FEATURE([FEATURE], [feature]) OR FB_ENABLE_FEATURE([FEATURE], [feature], [\"<value>\"]) + +# Example: Macro supplies -DFACEBOOK at compile time and "if FACEBOOK endif" capabilities. + +# Personalized path generator Sets default paths. Provides --with-xx=DIR options. +# FB_WITH_PATH([<var>_home], [<var>path], [<default location>] + +# Example: sets $(thrift_home) variable with default path set to /usr/local. +FB_WITH_PATH([thrift_home], [thriftpath], [/usr/local]) + +AX_CXX_COMPILE_STDCXX_11([noext]) +AX_THRIFT_LIB(cpp, [C++], yes) +have_cpp=no +if test "$with_cpp" = "yes"; then + # Require boost 1.40.0 or later + AX_BOOST_BASE([1.40.0]) + if test "x$succeeded" = "xyes"; then + have_cpp="yes" + fi +fi +AM_CONDITIONAL([WITH_CPP], [test "$have_cpp" = "yes"]) + +AX_THRIFT_LIB(java, [Java], yes) +if test "$with_java" = "yes"; then + AX_JAVAC_AND_JAVA + AC_PATH_PROG([ANT], [ant]) + AX_CHECK_ANT_VERSION($ANT, 1.7) + AC_SUBST(CLASSPATH) + AC_SUBST(ANT_FLAGS) + if test "x$JAVAC" != "x" && test "x$JAVAC" != "x" && test "x$ANT" != "x" ; then + have_java="yes" + fi +fi +AM_CONDITIONAL(WITH_JAVA, [test "$have_java" = "yes"]) + +AX_THRIFT_LIB(php, [PHP], yes) +if test "$with_php" = "yes"; then + AC_PATH_PROG([PHP], [php]) + if test "x$PHP" != "x" && test "x$PHP" != "x:" ; then + have_php="yes" + fi +fi +AM_CONDITIONAL(WITH_PHP, [test "$have_php" = "yes"]) + +AX_THRIFT_LIB(python, [Python], yes) +if test "$with_python" = "yes"; then + AM_PATH_PYTHON(2.4,, :) + if test "x$PYTHON" != "x" && test "x$PYTHON" != "x:" ; then + have_python="yes" + fi +fi +AM_CONDITIONAL(WITH_PYTHON, [test "$have_python" = "yes"]) + +# Generates Makefile from Makefile.am. Modify when new subdirs are added. +# Change Makefile.am also to add subdirectly. +AC_CONFIG_FILES(Makefile cpp/Makefile py/Makefile) + +# Check for headers +AC_CHECK_HEADERS([inttypes.h]) +AC_CHECK_HEADERS([netinet/in.h]) + +############################################################################ +# DO NOT TOUCH. + +AC_SUBST(PRODUCT_MK) +AC_OUTPUT + +############################################################################# +######### FINISH ############################################################ + +echo "EXTERNAL_PATH $EXTERNAL_PATH" +echo +echo "Building C++ Library ......... : $have_cpp" +echo "Building Java Library ........ : $have_java" +echo "Building Python Library ...... : $have_python" +echo "Building PHP Library ......... : $have_php" + + +# +# NOTES FOR USER +# Short cut to create conditional flags. +#enable_facebook="yes" +#AM_CONDITIONAL([FACEBOOK], [test "$enable_facebook" = yes]) +#enable_hdfs="yes" +#AM_CONDITIONAL([HDFS], [test "$enable_hdfs" = yes]) + +# Enable options with --enable and --disable configurable. +#AC_MSG_CHECKING([whether to enable FACEBOOK]) +#FACEBOOK="" +#AC_ARG_ENABLE([facebook], +# [ --enable-facebook Enable facebook.], +# [ +# ENABLE_FACEBOOK=$enableval +# ], +# [ +# ENABLE_FACEBOOK="no" +# ] +#) +#AM_CONDITIONAL([FACEBOOK], [test "$ENABLE_FACEBOOK" = yes]) +#AC_MSG_RESULT($ENABLE_FACEBOOK) + diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.cpp b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.cpp new file mode 100644 index 000000000..3c569759c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.cpp @@ -0,0 +1,124 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "FacebookBase.h" + +using namespace facebook::fb303; +using apache::thrift::concurrency::Guard; + +FacebookBase::FacebookBase(std::string name) : + name_(name) { + aliveSince_ = (int64_t) time(NULL); +} + +inline void FacebookBase::getName(std::string& _return) { + _return = name_; +} + +void FacebookBase::setOption(const std::string& key, const std::string& value) { + Guard g(optionsLock_); + options_[key] = value; +} + +void FacebookBase::getOption(std::string& _return, const std::string& key) { + Guard g(optionsLock_); + _return = options_[key]; +} + +void FacebookBase::getOptions(std::map<std::string, std::string> & _return) { + Guard g(optionsLock_); + _return = options_; +} + +int64_t FacebookBase::incrementCounter(const std::string& key, int64_t amount) { + counters_.acquireRead(); + + // if we didn't find the key, we need to write lock the whole map to create it + ReadWriteCounterMap::iterator it = counters_.find(key); + if (it == counters_.end()) { + counters_.release(); + counters_.acquireWrite(); + + // we need to check again to make sure someone didn't create this key + // already while we released the lock + it = counters_.find(key); + if(it == counters_.end()){ + counters_[key].value = amount; + counters_.release(); + return amount; + } + } + + it->second.acquireWrite(); + int64_t count = it->second.value + amount; + it->second.value = count; + it->second.release(); + counters_.release(); + return count; +} + +int64_t FacebookBase::setCounter(const std::string& key, int64_t value) { + counters_.acquireRead(); + + // if we didn't find the key, we need to write lock the whole map to create it + ReadWriteCounterMap::iterator it = counters_.find(key); + if (it == counters_.end()) { + counters_.release(); + counters_.acquireWrite(); + counters_[key].value = value; + counters_.release(); + return value; + } + + it->second.acquireWrite(); + it->second.value = value; + it->second.release(); + counters_.release(); + return value; +} + +void FacebookBase::getCounters(std::map<std::string, int64_t>& _return) { + // we need to lock the whole thing and actually build the map since we don't + // want our read/write structure to go over the wire + counters_.acquireRead(); + for(ReadWriteCounterMap::iterator it = counters_.begin(); + it != counters_.end(); ++it) + { + _return[it->first] = it->second.value; + } + counters_.release(); +} + +int64_t FacebookBase::getCounter(const std::string& key) { + int64_t rv = 0; + counters_.acquireRead(); + ReadWriteCounterMap::iterator it = counters_.find(key); + if (it != counters_.end()) { + it->second.acquireRead(); + rv = it->second.value; + it->second.release(); + } + counters_.release(); + return rv; +} + +inline int64_t FacebookBase::aliveSince() { + return aliveSince_; +} + diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.h b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.h new file mode 100644 index 000000000..daa524644 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/FacebookBase.h @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _FACEBOOK_TB303_FACEBOOKBASE_H_ +#define _FACEBOOK_TB303_FACEBOOKBASE_H_ 1 + +#include "FacebookService.h" + +#include <boost/shared_ptr.hpp> +#include <thrift/server/TServer.h> +#include <thrift/concurrency/Mutex.h> + +#include <time.h> +#include <string> +#include <map> + +namespace facebook { namespace fb303 { + +using apache::thrift::concurrency::Mutex; +using apache::thrift::concurrency::ReadWriteMutex; +using apache::thrift::server::TServer; + +struct ReadWriteInt : ReadWriteMutex {int64_t value;}; +struct ReadWriteCounterMap : ReadWriteMutex, + std::map<std::string, ReadWriteInt> {}; + +/** + * Base Facebook service implementation in C++. + * + */ +class FacebookBase : virtual public FacebookServiceIf { + protected: + FacebookBase(std::string name); + virtual ~FacebookBase() {} + + public: + void getName(std::string& _return); + virtual void getVersion(std::string& _return) { _return = ""; } + + virtual fb_status getStatus() = 0; + virtual void getStatusDetails(std::string& _return) { _return = ""; } + + void setOption(const std::string& key, const std::string& value); + void getOption(std::string& _return, const std::string& key); + void getOptions(std::map<std::string, std::string> & _return); + + int64_t aliveSince(); + + virtual void reinitialize() {} + + virtual void shutdown() { + if (server_.get() != NULL) { + server_->stop(); + } + } + + int64_t incrementCounter(const std::string& key, int64_t amount = 1); + int64_t setCounter(const std::string& key, int64_t value); + + void getCounters(std::map<std::string, int64_t>& _return); + int64_t getCounter(const std::string& key); + + /** + * Set server handle for shutdown method + */ + void setServer(boost::shared_ptr<TServer> server) { + server_ = server; + } + + void getCpuProfile(std::string& _return, int32_t durSecs) { _return = ""; } + + private: + + std::string name_; + int64_t aliveSince_; + + std::map<std::string, std::string> options_; + Mutex optionsLock_; + + ReadWriteCounterMap counters_; + + boost::shared_ptr<TServer> server_; + +}; + +}} // facebook::tb303 + +#endif // _FACEBOOK_TB303_FACEBOOKBASE_H_ diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/Makefile.am b/src/jaegertracing/thrift/contrib/fb303/cpp/Makefile.am new file mode 100644 index 000000000..748d3298d --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/Makefile.am @@ -0,0 +1,84 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +@GLOBAL_HEADER_MK@ + +@PRODUCT_MK@ + + +# User specified path variables set in configure.ac. +# thrift_home +# +THRIFT = $(thrift_home)/bin/thrift + +# User defined conditionals and conditonal statements set up in configure.ac. +if DEBUG + DEBUG_CPPFLAGS = -DDEBUG_TIMING +endif + +# Set common flags recognized by automake. +# DO NOT USE CPPFLAGS, CXXFLAGS, CFLAGS, LDFLAGS here! Set in configure.ac and|or override on command line. +# USE flags AM_CXXFLAGS, AM_CFLAGS, AM_CPPFLAGS, AM_LDFLAGS, LDADD in this section. + +AM_CPPFLAGS = -I.. +AM_CPPFLAGS += -Igen-cpp +AM_CPPFLAGS += -I$(thrift_home)/include/thrift +AM_CPPFLAGS += $(BOOST_CPPFLAGS) +AM_CPPFLAGS += $(FB_CPPFLAGS) $(DEBUG_CPPFLAGS) + +# GENERATE BUILD RULES +# Set Program/library specific flags recognized by automake. +# Use <progname|libname>_<FLAG> to set prog / lib specific flag s +# foo_CXXFLAGS foo_CPPFLAGS foo_LDFLAGS foo_LDADD + +fb303_lib = gen-cpp/FacebookService.cpp gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp FacebookBase.cpp ServiceTracker.cpp + +# Static -- multiple libraries can be defined +if STATIC +lib_LIBRARIES = libfb303.a +libfb303_a_SOURCES = $(fb303_lib) +INTERNAL_LIBS = libfb303.a +endif + +# Shared -- multiple libraries can be defined +if SHARED +shareddir = $(prefix)/lib +shared_PROGRAMS = libfb303.so +libfb303_so_SOURCES = $(fb303_lib) +libfb303_so_CXXFLAGS = $(SHARED_CXXFLAGS) +libfb303_so_LDFLAGS = $(SHARED_LDFLAGS) +INTERNAL_LIBS = libfb303.so +endif + +# Set up Thrift specific activity here. +# We assume that a <name>+types.cpp will always be built from <name>.thrift. +$(eval $(call thrift_template,.,../if/fb303.thrift,-I $(thrift_home)/share --gen cpp:pure_enums )) + +include_fb303dir = $(includedir)/thrift/fb303 +include_fb303_HEADERS = FacebookBase.h ServiceTracker.h gen-cpp/FacebookService.h gen-cpp/fb303_constants.h gen-cpp/fb303_types.h + +include_fb303ifdir = $(prefix)/share/fb303/if +include_fb303if_HEADERS = ../if/fb303.thrift + +BUILT_SOURCES = thriftstyle + +# Add to pre-existing target clean +clean-local: clean-common + +@GLOBAL_FOOTER_MK@ diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.cpp b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.cpp new file mode 100644 index 000000000..7a61b21a9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.cpp @@ -0,0 +1,481 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <sys/time.h> + +#include "FacebookBase.h" +#include "ServiceTracker.h" +#include <thrift/concurrency/ThreadManager.h> + +using namespace std; +using namespace facebook::fb303; +using namespace apache::thrift::concurrency; + + +uint64_t ServiceTracker::CHECKPOINT_MINIMUM_INTERVAL_SECONDS = 60; +int ServiceTracker::LOG_LEVEL = 5; + + +ServiceTracker::ServiceTracker(facebook::fb303::FacebookBase *handler, + void (*logMethod)(int, const string &), + bool featureCheckpoint, + bool featureStatusCheck, + bool featureThreadCheck, + Stopwatch::Unit stopwatchUnit) + : handler_(handler), logMethod_(logMethod), + featureCheckpoint_(featureCheckpoint), + featureStatusCheck_(featureStatusCheck), + featureThreadCheck_(featureThreadCheck), + stopwatchUnit_(stopwatchUnit), + checkpointServices_(0) +{ + if (featureCheckpoint_) { + time_t now = time(NULL); + checkpointTime_ = now; + } else { + checkpointTime_ = 0; + } +} + +/** + * Registers the beginning of a "service method": basically, any of + * the implementations of Thrift remote procedure calls that a + * FacebookBase handler is handling. Controls concurrent + * services and reports statistics (via log and via fb303 counters). + * Throws an exception if the server is not ready to handle service + * methods yet. + * + * note: The relationship between startService() and finishService() + * is currently defined so that a call to finishService() should only + * be matched to this call to startService() if this method returns + * without exception. It wouldn't be a problem to implement things + * the other way, so that *every* start needed a finish, but this + * convention was chosen to match the way an object's constructor and + * destructor work together, i.e. to work well with ServiceMethod + * objects. + * + * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod + * object instantiated at the start + * of the service method. + */ +void +ServiceTracker::startService(const ServiceMethod &serviceMethod) +{ + // note: serviceMethod.timer_ automatically starts at construction. + + // log service start + logMethod_(5, serviceMethod.signature_); + + // check handler ready + if (featureStatusCheck_ && !serviceMethod.featureLogOnly_) { + // note: Throwing exceptions before counting statistics. See note + // in method header. + // note: A STOPPING server is not accepting new connections, but it + // is still handling any already-connected threads -- so from the + // service method's point of view, a status of STOPPING is a green + // light. + facebook::fb303::fb_status status = handler_->getStatus(); + if (status != facebook::fb303::ALIVE + && status != facebook::fb303::STOPPING) { + if (status == facebook::fb303::STARTING) { + throw ServiceException("Server starting up; please try again later"); + } else { + throw ServiceException("Server not alive; please try again later"); + } + } + } + + // check server threads + if (featureThreadCheck_ && !serviceMethod.featureLogOnly_) { + // note: Might want to put these messages in reportCheckpoint() if + // log is getting spammed. + if (threadManager_ != NULL) { + size_t idle_count = threadManager_->idleWorkerCount(); + if (idle_count == 0) { + stringstream message; + message << "service " << serviceMethod.signature_ + << ": all threads (" << threadManager_->workerCount() + << ") in use"; + logMethod_(3, message.str()); + } + } + } +} + +/** + * Logs a significant step in the middle of a "service method"; see + * startService. + * + * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod + * object instantiated at the start + * of the service method. + * @return int64_t Elapsed units (see stopwatchUnit_) since ServiceMethod + * instantiation. + */ +int64_t +ServiceTracker::stepService(const ServiceMethod &serviceMethod, + const string &stepName) +{ + stringstream message; + string elapsed_label; + int64_t elapsed = serviceMethod.timer_.elapsedUnits(stopwatchUnit_, + &elapsed_label); + message << serviceMethod.signature_ + << ' ' << stepName + << " [" << elapsed_label << ']'; + logMethod_(5, message.str()); + return elapsed; +} + +/** + * Registers the end of a "service method"; see startService(). + * + * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod + * object instantiated at the start + * of the service method. + */ +void +ServiceTracker::finishService(const ServiceMethod &serviceMethod) +{ + // log end of service + stringstream message; + string duration_label; + int64_t duration = serviceMethod.timer_.elapsedUnits(stopwatchUnit_, + &duration_label); + message << serviceMethod.signature_ + << " finish [" << duration_label << ']'; + logMethod_(5, message.str()); + + // count, record, and maybe report service statistics + if (!serviceMethod.featureLogOnly_) { + + if (!featureCheckpoint_) { + + // lifetime counters + // (note: No need to lock statisticsMutex_ if not doing checkpoint; + // FacebookService::incrementCounter() is already thread-safe.) + handler_->incrementCounter("lifetime_services"); + + } else { + + statisticsMutex_.lock(); + // note: No exceptions expected from this code block. Wrap in a try + // just to be safe. + try { + + // lifetime counters + // note: Good to synchronize this with the increment of + // checkpoint services, even though incrementCounter() is + // already thread-safe, for the sake of checkpoint reporting + // consistency (i.e. since the last checkpoint, + // lifetime_services has incremented by checkpointServices_). + handler_->incrementCounter("lifetime_services"); + + // checkpoint counters + checkpointServices_++; + checkpointDuration_ += duration; + + // per-service timing + // note kjv: According to my tests it is very slightly faster to + // call insert() once (and detect not-found) than calling find() + // and then maybe insert (if not-found). However, the difference + // is tiny for small maps like this one, and the code for the + // faster solution is slightly less readable. Also, I wonder if + // the instantiation of the (often unused) pair to insert makes + // the first algorithm slower after all. + map<string, pair<uint64_t, uint64_t> >::iterator iter; + iter = checkpointServiceDuration_.find(serviceMethod.name_); + if (iter != checkpointServiceDuration_.end()) { + iter->second.first++; + iter->second.second += duration; + } else { + checkpointServiceDuration_.insert(make_pair(serviceMethod.name_, + make_pair(1, duration))); + } + + // maybe report checkpoint + // note: ...if it's been long enough since the last report. + time_t now = time(NULL); + uint64_t check_interval = now - checkpointTime_; + if (check_interval >= CHECKPOINT_MINIMUM_INTERVAL_SECONDS) { + reportCheckpoint(); + } + + } catch (...) { + statisticsMutex_.unlock(); + throw; + } + statisticsMutex_.unlock(); + + } + } +} + +/** + * Logs some statistics gathered since the last call to this method. + * + * note: Thread race conditions on this method could cause + * misreporting and/or undefined behavior; the caller must protect + * uses of the object variables (and calls to this method) with a + * mutex. + * + */ +void +ServiceTracker::reportCheckpoint() +{ + time_t now = time(NULL); + + uint64_t check_count = checkpointServices_; + uint64_t check_interval = now - checkpointTime_; + uint64_t check_duration = checkpointDuration_; + + // export counters for timing of service methods (by service name) + handler_->setCounter("checkpoint_time", check_interval); + map<string, pair<uint64_t, uint64_t> >::iterator iter; + uint64_t count; + for (iter = checkpointServiceDuration_.begin(); + iter != checkpointServiceDuration_.end(); + ++iter) { + count = iter->second.first; + handler_->setCounter(string("checkpoint_count_") + iter->first, count); + if (count == 0) { + handler_->setCounter(string("checkpoint_speed_") + iter->first, + 0); + } else { + handler_->setCounter(string("checkpoint_speed_") + iter->first, + iter->second.second / count); + } + } + + // reset checkpoint variables + // note: Clearing the map while other threads are using it might + // cause undefined behavior. + checkpointServiceDuration_.clear(); + checkpointTime_ = now; + checkpointServices_ = 0; + checkpointDuration_ = 0; + + // get lifetime variables + uint64_t life_count = handler_->getCounter("lifetime_services"); + uint64_t life_interval = now - handler_->aliveSince(); + + // log checkpoint + stringstream message; + message << "checkpoint_time:" << check_interval + << " checkpoint_services:" << check_count + << " checkpoint_speed_sum:" << check_duration + << " lifetime_time:" << life_interval + << " lifetime_services:" << life_count; + if (featureThreadCheck_ && threadManager_ != NULL) { + size_t worker_count = threadManager_->workerCount(); + size_t idle_count = threadManager_->idleWorkerCount(); + message << " total_workers:" << worker_count + << " active_workers:" << (worker_count - idle_count); + } + logMethod_(4, message.str()); +} + +/** + * Remembers the thread manager used in the server, for monitoring thread + * activity. + * + * @param shared_ptr<ThreadManager> threadManager The server's thread manager. + */ +void +ServiceTracker::setThreadManager(boost::shared_ptr<ThreadManager> + threadManager) +{ + threadManager_ = threadManager; +} + +/** + * Logs messages to stdout; the passed message will be logged if the + * passed level is less than or equal to LOG_LEVEL. + * + * This is the default logging method used by the ServiceTracker. An + * alternate logging method (that accepts the same parameters) may be + * specified to the constructor. + * + * @param int level A level associated with the message: higher levels + * are used to indicate higher levels of detail. + * @param string message The message to log. + */ +void +ServiceTracker::defaultLogMethod(int level, const string &message) +{ + if (level <= LOG_LEVEL) { + string level_string; + time_t now = time(NULL); + char now_pretty[26]; + ctime_r(&now, now_pretty); + now_pretty[24] = '\0'; + switch (level) { + case 1: + level_string = "CRITICAL"; + break; + case 2: + level_string = "ERROR"; + break; + case 3: + level_string = "WARNING"; + break; + case 5: + level_string = "DEBUG"; + break; + case 4: + default: + level_string = "INFO"; + break; + } + cout << '[' << level_string << "] [" << now_pretty << "] " + << message << endl; + } +} + + +/** + * Creates a Stopwatch, which can report the time elapsed since its + * creation. + * + */ +Stopwatch::Stopwatch() +{ + gettimeofday(&startTime_, NULL); +} + +void +Stopwatch::reset() +{ + gettimeofday(&startTime_, NULL); +} + +uint64_t +Stopwatch::elapsedUnits(Stopwatch::Unit unit, string *label) const +{ + timeval now_time; + gettimeofday(&now_time, NULL); + time_t duration_secs = now_time.tv_sec - startTime_.tv_sec; + + uint64_t duration_units; + switch (unit) { + case UNIT_SECONDS: + duration_units = duration_secs + + (now_time.tv_usec - startTime_.tv_usec + 500000) / 1000000; + if (NULL != label) { + stringstream ss_label; + ss_label << duration_units << " secs"; + label->assign(ss_label.str()); + } + break; + case UNIT_MICROSECONDS: + duration_units = duration_secs * 1000000 + + now_time.tv_usec - startTime_.tv_usec; + if (NULL != label) { + stringstream ss_label; + ss_label << duration_units << " us"; + label->assign(ss_label.str()); + } + break; + case UNIT_MILLISECONDS: + default: + duration_units = duration_secs * 1000 + + (now_time.tv_usec - startTime_.tv_usec + 500) / 1000; + if (NULL != label) { + stringstream ss_label; + ss_label << duration_units << " ms"; + label->assign(ss_label.str()); + } + break; + } + return duration_units; +} + +/** + * Creates a ServiceMethod, used for tracking a single service method + * invocation (via the ServiceTracker). The passed name of the + * ServiceMethod is used to group statistics (e.g. counts and durations) + * for similar invocations; the passed signature is used to uniquely + * identify the particular invocation in the log. + * + * note: A version of this constructor is provided that automatically + * forms a signature the name and a passed numeric id. Silly, sure, + * but commonly used, since it often saves the caller a line or two of + * code. + * + * @param ServiceTracker *tracker The service tracker that will track this + * ServiceMethod. + * @param const string &name The service method name (usually independent + * of service method parameters). + * @param const string &signature A signature uniquely identifying the method + * invocation (usually name plus parameters). + */ +ServiceMethod::ServiceMethod(ServiceTracker *tracker, + const string &name, + const string &signature, + bool featureLogOnly) + : tracker_(tracker), name_(name), signature_(signature), + featureLogOnly_(featureLogOnly) +{ + // note: timer_ automatically starts at construction. + + // invoke tracker to start service + // note: Might throw. If it throws, then this object's destructor + // won't be called, which is according to plan: finishService() is + // only supposed to be matched to startService() if startService() + // returns without error. + tracker_->startService(*this); +} + +ServiceMethod::ServiceMethod(ServiceTracker *tracker, + const string &name, + uint64_t id, + bool featureLogOnly) + : tracker_(tracker), name_(name), featureLogOnly_(featureLogOnly) +{ + // note: timer_ automatically starts at construction. + stringstream ss_signature; + ss_signature << name << " (" << id << ')'; + signature_ = ss_signature.str(); + + // invoke tracker to start service + // note: Might throw. If it throws, then this object's destructor + // won't be called, which is according to plan: finishService() is + // only supposed to be matched to startService() if startService() + // returns without error. + tracker_->startService(*this); +} + +ServiceMethod::~ServiceMethod() +{ + // invoke tracker to finish service + // note: Not expecting an exception from this code, but + // finishService() might conceivably throw an out-of-memory + // exception. + try { + tracker_->finishService(*this); + } catch (...) { + // don't throw + } +} + +uint64_t +ServiceMethod::step(const std::string &stepName) +{ + return tracker_->stepService(*this, stepName); +} diff --git a/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.h b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.h new file mode 100644 index 000000000..9a3edd8f1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/cpp/ServiceTracker.h @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * 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 apache { 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<apache::thrift::concurrency::ThreadManager> threadManager); + +private: + + facebook::fb303::FacebookBase *handler_; + void (*logMethod_)(int, const std::string &); + boost::shared_ptr<apache::thrift::concurrency::ThreadManager> threadManager_; + + bool featureCheckpoint_; + bool featureStatusCheck_; + bool featureThreadCheck_; + Stopwatch::Unit stopwatchUnit_; + + apache::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 diff --git a/src/jaegertracing/thrift/contrib/fb303/global_footer.mk b/src/jaegertracing/thrift/contrib/fb303/global_footer.mk new file mode 100644 index 000000000..96f82ebd2 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/global_footer.mk @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +thriftstyle : $(XBUILT_SOURCES) + diff --git a/src/jaegertracing/thrift/contrib/fb303/global_header.mk b/src/jaegertracing/thrift/contrib/fb303/global_header.mk new file mode 100644 index 000000000..77c9455ee --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/global_header.mk @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +#define thrift_template +# $(1) : $(2) +# $$(THRIFT) $(3) $(4) $(5) $(6) $(7) $(8) $$< +#endef + +define thrift_template +XTARGET := $(shell perl -e '@val = split("\/","$(2)"); $$last = pop(@val);split("\\.",$$last);print "$(1)/"."gen-cpp/"."@_[0]"."_types.cpp\n"' ) + +ifneq ($$(XBUILT_SOURCES),) + XBUILT_SOURCES := $$(XBUILT_SOURCES) $$(XTARGET) +else + XBUILT_SOURCES := $$(XTARGET) +endif +$$(XTARGET) : $(2) + $$(THRIFT) -o $1 $3 $$< +endef + +clean-common: + rm -rf gen-* diff --git a/src/jaegertracing/thrift/contrib/fb303/if/fb303.thrift b/src/jaegertracing/thrift/contrib/fb303/if/fb303.thrift new file mode 100644 index 000000000..89bd6eb7b --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/if/fb303.thrift @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * fb303.thrift + */ + +namespace java com.facebook.fb303 +namespace cpp facebook.fb303 +namespace perl Facebook.FB303 +namespace netcore Facebook.FB303.Test + +/** + * Common status reporting mechanism across all services + */ +enum fb_status { + DEAD = 0, + STARTING = 1, + ALIVE = 2, + STOPPING = 3, + STOPPED = 4, + WARNING = 5, +} + +/** + * Standard base service + */ +service FacebookService { + + /** + * Returns a descriptive name of the service + */ + string getName(), + + /** + * Returns the version of the service + */ + string getVersion(), + + /** + * Gets the status of this service + */ + fb_status getStatus(), + + /** + * User friendly description of status, such as why the service is in + * the dead or warning state, or what is being started or stopped. + */ + string getStatusDetails(), + + /** + * Gets the counters for this service + */ + map<string, i64> getCounters(), + + /** + * Gets the value of a single counter + */ + i64 getCounter(1: string key), + + /** + * Sets an option + */ + void setOption(1: string key, 2: string value), + + /** + * Gets an option + */ + string getOption(1: string key), + + /** + * Gets all options + */ + map<string, string> getOptions(), + + /** + * Returns a CPU profile over the given time interval (client and server + * must agree on the profile format). + */ + string getCpuProfile(1: i32 profileDurationInSec), + + /** + * Returns the unix time that the server has been running since + */ + i64 aliveSince(), + + /** + * Tell the server to reload its configuration, reopen log files, etc + */ + oneway void reinitialize(), + + /** + * Suggest a shutdown to the server + */ + oneway void shutdown(), + +} diff --git a/src/jaegertracing/thrift/contrib/fb303/java/build.properties b/src/jaegertracing/thrift/contrib/fb303/java/build.properties new file mode 100644 index 000000000..84636683c --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/java/build.properties @@ -0,0 +1,5 @@ +# Maven Ant tasks Jar details +mvn.ant.task.version=2.1.3 +mvn.repo=http://repo1.maven.org/maven2 +mvn.ant.task.url=${mvn.repo}/org/apache/maven/maven-ant-tasks/${mvn.ant.task.version} +mvn.ant.task.jar=maven-ant-tasks-${mvn.ant.task.version}.jar diff --git a/src/jaegertracing/thrift/contrib/fb303/java/build.xml b/src/jaegertracing/thrift/contrib/fb303/java/build.xml new file mode 100755 index 000000000..7a1b8f105 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/java/build.xml @@ -0,0 +1,199 @@ +<?xml version="1.0"?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + --> +<project name="libfb303" default="dist" basedir="." + xmlns:artifact="antlib:org.apache.maven.artifact.ant"> + + <!-- project wide settings. All directories relative to basedir --> + <property name="thrift.root" location="${basedir}/../../../"/> + <property name="fb303.artifactid" value="libfb303"/> + <property name="interface.dir" value="${basedir}/../if"/> + <property name="thrift.java.dir" location="${thrift.root}/lib/java"/> + <property name="build.tools.dir" location="${thrift.java.dir}/build/tools/"/> + <property name="thrift_compiler" value="${thrift.root}/compiler/cpp/thrift"/> + <property file="${basedir}/build.properties"/> + + <!-- inherit from the java build file for version and other properties --> + <property file="${thrift.java.dir}/gradle.properties" /> + + <property environment="env"/> + + <condition property="version" value="${thrift.version}"> + <isset property="release"/> + </condition> + <property name="version" value="${thrift.version}-SNAPSHOT"/> + + <property name="fb303.final.name" value="${fb303.artifactid}-${version}"/> + + <property name="src" value="${basedir}/src"/> + <property name="gen" value="${basedir}/gen-java"/> + <property name="build.dir" value="${basedir}/build"/> + <property name="build.lib.dir" value="${build.dir}/lib"/> + <property name="build.classes.dir" value="${build.dir}/classes"/> + + <property name="fb303.jar.file" location="${build.dir}/${fb303.final.name}.jar"/> + <property name="fb303.pom.xml" location="${build.dir}/${fb303.final.name}.pom"/> + + <target name="init" depends="setup.init,mvn.init" unless="init.finished"> + <property name="init.finished" value="true"/> + </target> + + <target name="setup.init"> + <tstamp/> + <mkdir dir="${build.dir}"/> + <mkdir dir="${build.classes.dir}"/> + <mkdir dir="${build.lib.dir}"/> + </target> + + <!-- generate fb303 thrift code --> + <target name="generate"> + <echo message="generating thrift fb303 files"/> + <exec executable="${thrift_compiler}" failonerror="true"> + <arg line="--gen java -o ${basedir} ${interface.dir}/fb303.thrift"/> + </exec> + </target> + + <!-- compile the base and thrift generated code and jar them --> + <target name="dist" depends="init,generate"> + <echo message="Building ${fb303.final.name}.jar"/> + <javac destdir="${build.classes.dir}" debug="on"> + <classpath> + <fileset dir="${thrift.java.dir}/build/libs"> + <include name="libthrift*.jar" /> + <exclude name="libthrift*javadoc.jar" /> + <exclude name="libthrift*sources.jar" /> + </fileset> + <fileset dir="${thrift.java.dir}/build/deps"> + <include name="*.jar"/> + </fileset> + </classpath> + <src path="${src}"/> + <src path="${gen}"/> + <include name="**/*.java"/> + </javac> + <jar jarfile="${build.dir}/${fb303.final.name}.jar" basedir="${build.classes.dir}"> + </jar> + </target> + + <!-- copy the build jar to the distribution library directory --> + <target name="install" depends="dist"> + <copy todir="${install.path}"> + <fileset dir="${build.lib.dir}" includes="*.jar"/> + <fileset dir="${build.lib.dir}" includes="${fb303.final.name}.jar"/> + </copy> + </target> + + <target name="clean"> + <delete dir="${build.dir}"/> + <delete dir="${gen}"/> + </target> + + <target name="mvn.ant.tasks.download" depends="setup.init,mvn.ant.tasks.check" unless="mvn.ant.tasks.found"> + <get src="${mvn.ant.task.url}/${mvn.ant.task.jar}" dest="${build.tools.dir}/${mvn.ant.task.jar}" usetimestamp="true"/> + </target> + + <target name="mvn.ant.tasks.check"> + <condition property="mvn.ant.tasks.found"> + <typefound uri="antlib:org.apache.maven.artifact.ant" name="artifact"/> + </condition> + </target> + + <target name="mvn.init" depends="mvn.ant.tasks.download" unless="mvn.finished"> + <echo message="${mvn.ant.task.jar}"/> + <!-- Download mvn ant tasks, download dependencies, and setup pom file --> + <typedef uri="antlib:org.apache.maven.artifact.ant" classpath="${build.tools.dir}/${mvn.ant.task.jar}"/> + + <!-- remote repositories used to download dependencies from --> + <artifact:remoteRepository id="central" url="${mvn.repo}"/> + <artifact:remoteRepository id="apache" url="${apache.repo}"/> + + <!-- Pom file information --> + <artifact:pom id="pom" + groupId="${thrift.groupid}" + artifactId="${fb303.artifactid}" + version="${version}" + url="http://thrift.apache.org" + name="Apache Thrift" + description="Thrift is a software framework for scalable cross-language services development." + packaging="jar" + > + <remoteRepository refid="central"/> + <remoteRepository refid="apache"/> + <license name="The Apache Software License, Version 2.0" url="${license}"/> + <scm connection="scm:git:https://github.com/apache/thrift.git" + developerConnection="scm:git:https://github.com/apache/thrift.git" + url="https://github.com/apache/thrift" + /> + <!-- Thrift Developers --> + <developer id="mcslee" name="Mark Slee"/> + <developer id="dreiss" name="David Reiss"/> + <developer id="aditya" name="Aditya Agarwal"/> + <developer id="marck" name="Marc Kwiatkowski"/> + <developer id="jwang" name="James Wang"/> + <developer id="cpiro" name="Chris Piro"/> + <developer id="bmaurer" name="Ben Maurer"/> + <developer id="kclark" name="Kevin Clark"/> + <developer id="jake" name="Jake Luciani"/> + <developer id="bryanduxbury" name="Bryan Duxbury"/> + <developer id="esteve" name="Esteve Fernandez"/> + <developer id="todd" name="Todd Lipcon"/> + <developer id="geechorama" name="Andrew McGeachie"/> + <developer id="molinaro" name="Anthony Molinaro"/> + <developer id="roger" name="Roger Meier"/> + <developer id="jfarrell" name="Jake Farrell"/> + <developer id="jensg" name="Jens Geyer"/> + <developer id="carl" name="Carl Yeksigian"/> + + <!-- Thrift dependencies list --> + <dependency groupId="org.apache.thrift" artifactId="libthrift" version="${version}"/> + </artifact:pom> + + <!-- Generate the pom file --> + <artifact:writepom pomRefId="pom" file="${fb303.pom.xml}"/> + + <property name="mvn.finished" value="true"/> + </target> + + <macrodef name="signAndDeploy"> + <!-- Sign and deploy jars to apache repo --> + <attribute name="file"/> + <attribute name="classifier" default=""/> + <attribute name="packaging" default="jar"/> + <attribute name="pom" default=""/> + <sequential> + <artifact:mvn fork="true"> + <arg value="org.apache.maven.plugins:maven-gpg-plugin:1.1:sign-and-deploy-file"/> + <arg value="-DrepositoryId=${maven-repository-id}"/> + <arg value="-Durl=${maven-repository-url}"/> + <arg value="-DpomFile=@{pom}"/> + <arg value="-Dfile=@{file}"/> + <arg value="-Dclassifier=@{classifier}"/> + <arg value="-Dpackaging=@{packaging}"/> + <arg value="-Pgpg"/> + </artifact:mvn> + </sequential> + </macrodef> + + <target name="publish" depends="clean,dist"> + <!-- Compile, packages and then send release to apache maven repo --> + <!-- run with: ant -Drelease=true publish--> + <signAndDeploy file="${fb303.pom.xml}" packaging="pom" classifier="" pom="${fb303.pom.xml}"/> + <signAndDeploy file="${fb303.jar.file}" packaging="jar" classifier="" pom="${fb303.pom.xml}"/> + </target> +</project> diff --git a/src/jaegertracing/thrift/contrib/fb303/java/src/FacebookBase.java b/src/jaegertracing/thrift/contrib/fb303/java/src/FacebookBase.java new file mode 100644 index 000000000..f8f26a318 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/java/src/FacebookBase.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.facebook.fb303; + +import java.util.AbstractMap; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class FacebookBase implements FacebookService.Iface { + + private String name_; + + private long alive_; + + private final ConcurrentHashMap<String,Long> counters_ = + new ConcurrentHashMap<String, Long>(); + + private final ConcurrentHashMap<String,String> options_ = + new ConcurrentHashMap<String, String>(); + + protected FacebookBase(String name) { + name_ = name; + alive_ = System.currentTimeMillis() / 1000; + } + + public String getName() { + return name_; + } + + public abstract fb_status getStatus(); + + public String getStatusDetails() { + return ""; + } + + public void deleteCounter(String key) { + counters_.remove(key); + } + + public void resetCounter(String key) { + counters_.put(key, 0L); + } + + public long incrementCounter(String key) { + long val = getCounter(key) + 1; + counters_.put(key, val); + return val; + } + + public long incrementCounter(String key, long increment) { + long val = getCounter(key) + increment; + counters_.put(key, val); + return val; + } + + public long setCounter(String key, long value) { + counters_.put(key, value); + return value; + } + + public AbstractMap<String,Long> getCounters() { + return counters_; + } + + public long getCounter(String key) { + Long val = counters_.get(key); + if (val == null) { + return 0; + } + return val.longValue(); + } + + public void setOption(String key, String value) { + options_.put(key, value); + } + + public String getOption(String key) { + return options_.get(key); + } + + public AbstractMap<String,String> getOptions() { + return options_; + } + + public long aliveSince() { + return alive_; + } + + public String getCpuProfile() { + return ""; + } + + public void reinitialize() {} + + public void shutdown() {} + +} diff --git a/src/jaegertracing/thrift/contrib/fb303/php/FacebookBase.php b/src/jaegertracing/thrift/contrib/fb303/php/FacebookBase.php new file mode 100644 index 000000000..2ac318fb3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/php/FacebookBase.php @@ -0,0 +1,89 @@ +<?php +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** + * Abstract Class providing null implementation for FacebookService + * methods. + */ +class FacebookBase implements FacebookServiceIf { + protected $name_ = ''; + + public function __construct($name) { + $this->name_ = $name; + } + + public function getName() { + return $this->name_; + } + + public function getVersion() { + return ''; + } + + public function getStatus() { + return null; + } + + public function getStatusDetails() { + return ''; + } + + public function getCounters() { + return array(); + } + + public function getCounter($key) { + return null; + } + + public function setOption($key, $value) { + return; + } + + public function getOption($key) { + return ''; + } + + public function getOptions() { + return array(); + } + + public function aliveSince() { + return 0; + } + + public function getCpuProfile($duration) { + return ''; + } + + public function getLimitedReflection() { + return array(); + } + + public function reinitialize() { + return; + } + + public function shutdown() { + return; + } + +} + diff --git a/src/jaegertracing/thrift/contrib/fb303/py/Makefile.am b/src/jaegertracing/thrift/contrib/fb303/py/Makefile.am new file mode 100644 index 000000000..060495e58 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/Makefile.am @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +DESTDIR ?= / +EXTRA_DIST = setup.py src + +all: + +all-local: + $(thrift_home)/bin/thrift --gen py $(top_srcdir)/if/fb303.thrift + mv gen-py/fb303/* fb303 + $(PYTHON) setup.py build + +# We're ignoring prefix here because site-packages seems to be +# the equivalent of /usr/local/lib in Python land. +# Old version (can't put inline because it's not portable). +#$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS) +install-exec-hook: + $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS) + + + +clean: clean-local + +clean-local: + $(RM) -r build + +check-local: all diff --git a/src/jaegertracing/thrift/contrib/fb303/py/fb303/FacebookBase.py b/src/jaegertracing/thrift/contrib/fb303/py/fb303/FacebookBase.py new file mode 100644 index 000000000..07db10cd3 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/fb303/FacebookBase.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import time +import FacebookService +import thrift.reflection.limited +from ttypes import fb_status + + +class FacebookBase(FacebookService.Iface): + + def __init__(self, name): + self.name = name + self.alive = int(time.time()) + self.counters = {} + + def getName(self, ): + return self.name + + def getVersion(self, ): + return '' + + def getStatus(self, ): + return fb_status.ALIVE + + def getCounters(self): + return self.counters + + def resetCounter(self, key): + self.counters[key] = 0 + + def getCounter(self, key): + if self.counters.has_key(key): + return self.counters[key] + return 0 + + def incrementCounter(self, key): + self.counters[key] = self.getCounter(key) + 1 + + def setOption(self, key, value): + pass + + def getOption(self, key): + return "" + + def getOptions(self): + return {} + + def getOptions(self): + return {} + + def aliveSince(self): + return self.alive + + def getCpuProfile(self, duration): + return "" + + def getLimitedReflection(self): + return thrift.reflection.limited.Service() + + def reinitialize(self): + pass + + def shutdown(self): + pass diff --git a/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/__init__.py b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/__init__.py new file mode 100644 index 000000000..f8e3a94b9 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/__init__.py @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +__all__ = ['fb303_simple_mgmt'] diff --git a/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py new file mode 100644 index 000000000..5c8f409c1 --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/fb303_scripts/fb303_simple_mgmt.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from __future__ import print_function +import sys +import os +from optparse import OptionParser + +from thrift.Thrift import * + +from thrift.transport import TSocket +from thrift.transport import TTransport +from thrift.protocol import TBinaryProtocol + +from fb303 import * +from fb303.ttypes import * + + +def service_ctrl( + command, + port, + trans_factory=None, + prot_factory=None): + """ + service_ctrl is a generic function to execute standard fb303 functions + + @param command: one of stop, start, reload, status, counters, name, alive + @param port: service's port + @param trans_factory: TTransportFactory to use for obtaining a TTransport. Default is + TBufferedTransportFactory + @param prot_factory: TProtocolFactory to use for obtaining a TProtocol. Default is + TBinaryProtocolFactory + """ + + if command in ["status"]: + try: + status = fb303_wrapper('status', port, trans_factory, prot_factory) + status_details = fb303_wrapper('get_status_details', port, trans_factory, prot_factory) + + msg = fb_status_string(status) + if (len(status_details)): + msg += " - %s" % status_details + print(msg) + return 2 if status == fb_status.ALIVE else 3 + except: + print("Failed to get status") + return 3 + + # scalar commands + if command in ["version", "alive", "name"]: + try: + result = fb303_wrapper(command, port, trans_factory, prot_factory) + print(result) + return 0 + except: + print("failed to get ", command) + return 3 + + # counters + if command in ["counters"]: + try: + counters = fb303_wrapper('counters', port, trans_factory, prot_factory) + for counter in counters: + print("%s: %d" % (counter.encode('utf-8'), counters[counter])) + return 0 + except: + print("failed to get counters") + return 3 + + # Only root should be able to run the following commands + if os.getuid() == 0: + # async commands + if command in ["stop", "reload"]: + try: + fb303_wrapper(command, port, trans_factory, prot_factory) + return 0 + except: + print("failed to tell the service to ", command) + return 3 + else: + if command in ["stop", "reload"]: + print("root privileges are required to stop or reload the service.") + return 4 + + print("The following commands are available:") + for command in ["counters", "name", "version", "alive", "status"]: + print("\t%s" % command) + print("The following commands are available for users with root privileges:") + for command in ["stop", "reload"]: + print("\t%s" % command) + + return 0 + + +def fb303_wrapper(command, port, trans_factory=None, prot_factory=None): + sock = TSocket.TSocket('localhost', port) + + # use input transport factory if provided + if (trans_factory is None): + trans = TTransport.TBufferedTransport(sock) + else: + trans = trans_factory.getTransport(sock) + + # use input protocol factory if provided + if (prot_factory is None): + prot = TBinaryProtocol.TBinaryProtocol(trans) + else: + prot = prot_factory.getProtocol(trans) + + # initialize client and open transport + fb303_client = FacebookService.Client(prot, prot) + trans.open() + + if (command == 'reload'): + fb303_client.reinitialize() + + elif (command == 'stop'): + fb303_client.shutdown() + + elif (command == 'status'): + return fb303_client.getStatus() + + elif (command == 'version'): + return fb303_client.getVersion() + + elif (command == 'get_status_details'): + return fb303_client.getStatusDetails() + + elif (command == 'counters'): + return fb303_client.getCounters() + + elif (command == 'name'): + return fb303_client.getName() + + elif (command == 'alive'): + return fb303_client.aliveSince() + + trans.close() + + +def fb_status_string(status_enum): + if (status_enum == fb_status.DEAD): + return "DEAD" + if (status_enum == fb_status.STARTING): + return "STARTING" + if (status_enum == fb_status.ALIVE): + return "ALIVE" + if (status_enum == fb_status.STOPPING): + return "STOPPING" + if (status_enum == fb_status.STOPPED): + return "STOPPED" + if (status_enum == fb_status.WARNING): + return "WARNING" + + +def main(): + + # parse command line options + parser = OptionParser() + commands = ["stop", "counters", "status", "reload", "version", "name", "alive"] + + parser.add_option("-c", "--command", dest="command", help="execute this API", + choices=commands, default="status") + parser.add_option("-p", "--port", dest="port", help="the service's port", + default=9082) + + (options, args) = parser.parse_args() + status = service_ctrl(options.command, options.port) + sys.exit(status) + + +if __name__ == '__main__': + main() diff --git a/src/jaegertracing/thrift/contrib/fb303/py/setup.py b/src/jaegertracing/thrift/contrib/fb303/py/setup.py new file mode 100644 index 000000000..d27c2962f --- /dev/null +++ b/src/jaegertracing/thrift/contrib/fb303/py/setup.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import sys +try: + from setuptools import setup, Extension +except: + from distutils.core import setup, Extension, Command + +setup(name='thrift_fb303', + version='1.0.0', + description='Python bindings for the Apache Thrift FB303', + author=['Apache Thrift Developers'], + author_email=['dev@thrift.apache.org'], + url='http://thrift.apache.org', + license='Apache License 2.0', + packages=[ + 'fb303', + 'fb303_scripts', + ], + classifiers=[ + 'Development Status :: 7 - Inactive', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Topic :: Software Development :: Libraries', + 'Topic :: System :: Networking' + ], + ) |