Moving from govendor to dep, updated dependencies (#48)

* Moving from govendor to dep.

* Making the pull request template more friendly.

* Fixing akward space in PR template.

* goimports run on whole project using ` goimports -w $(find . -type f -name '*.go' -not -path "./vendor/*" -not -path "./gen-go/*")`

source of command: https://gist.github.com/bgentry/fd1ffef7dbde01857f66
This commit is contained in:
Renan DelValle 2018-01-07 13:13:47 -08:00 committed by GitHub
parent 9631aa3aab
commit 8d445c1c77
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2186 changed files with 400410 additions and 352 deletions

16
vendor/git.apache.org/thrift.git/contrib/fb303/LICENSE generated vendored Normal file
View file

@ -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.

View file

@ -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@

View file

@ -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

View file

@ -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

View file

@ -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_

View file

@ -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
])

View file

@ -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
])

View file

@ -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
])

View file

@ -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!).
])

26
vendor/git.apache.org/thrift.git/contrib/fb303/bootstrap.sh generated vendored Executable file
View file

@ -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 $*

View file

@ -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)

View file

@ -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_;
}

View file

@ -0,0 +1,103 @@
/*
* 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 <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_

View file

@ -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@

View file

@ -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);
}

View file

@ -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

View file

@ -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)

View file

@ -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-*

View file

@ -0,0 +1,112 @@
/*
* 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
/**
* 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(),
}

195
vendor/git.apache.org/thrift.git/contrib/fb303/java/build.xml generated vendored Executable file
View file

@ -0,0 +1,195 @@
<?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"/>
<!-- inherit from the java build file for version and other properties -->
<property file="${thrift.java.dir}/build.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="thrift.java.libthrift" value="${thrift.java.dir}/build/libthrift-${version}.jar"/>
<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>
<pathelement location="${thrift.java.libthrift}"/>
<fileset dir="${thrift.root}/lib/java/build/lib">
<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="pom"
>
<remoteRepository refid="central"/>
<remoteRepository refid="apache"/>
<license name="The Apache Software License, Version 2.0" url="${license}"/>
<scm connection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
developerConnection="scm:git:https://git-wip-us.apache.org/repos/asf/thrift.git"
url="https://git-wip-us.apache.org/repos/asf?p=thrift.git"
/>
<!-- 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>

View file

@ -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() {}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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

View file

@ -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']

View file

@ -0,0 +1,194 @@
#!/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
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
if (status == fb_status.ALIVE):
return 2
else:
return 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, 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()

View file

@ -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='0.10.0',
description='Python bindings for the Apache Thrift FB303',
author=['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 :: 5 - Production/Stable',
'Environment :: Console',
'Intended Audience :: Developers',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Topic :: Software Development :: Libraries',
'Topic :: System :: Networking'
],
)