├── .gitignore ├── LICENSE ├── Makefile.am ├── README ├── acinclude.m4 ├── aclocal └── ax_boost_base.m4 ├── bootstrap.sh ├── build.log ├── configure.ac ├── cpp ├── FacebookBase.cpp ├── FacebookBase.h ├── Makefile.am ├── ServiceTracker.cpp └── ServiceTracker.h ├── debian ├── README ├── README.Debian ├── changelog ├── compat ├── control ├── copyright ├── dirs ├── docs ├── rules └── source │ └── format ├── global_footer.mk ├── global_header.mk ├── if └── fb303.thrift ├── java ├── FacebookBase.java └── build.xml ├── php └── FacebookBase.php └── py ├── Makefile.am ├── fb303 └── FacebookBase.py ├── fb303_scripts ├── __init__.py └── fb303_simple_mgmt.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | config.guess 2 | config.sub 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Licensed to the Apache Software Foundation (ASF) under one 2 | or more contributor license agreements. See the NOTICE file 3 | distributed with this work for additional information 4 | regarding copyright ownership. The ASF licenses this file 5 | to you under the Apache License, Version 2.0 (the 6 | "License"); you may not use this file except in compliance 7 | with the License. You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, 12 | software distributed under the License is distributed on an 13 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | KIND, either express or implied. See the License for the 15 | specific language governing permissions and limitations 16 | under the License. 17 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | @GLOBAL_HEADER_MK@ 21 | 22 | @PRODUCT_MK@ 23 | 24 | SUBDIRS = . cpp py 25 | 26 | BUILT_SOURCES = 27 | 28 | 29 | clean-local: clean-common 30 | 31 | @GLOBAL_FOOTER_MK@ 32 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Project FB303: The Facebook Bassline 2 | ------------------------------------ 3 | 4 | * Curious about the 303? * 5 | http://en.wikipedia.org/wiki/Roland_TB-303 6 | 7 | * Why the name? * 8 | The TB303 makes bass lines. 9 | .Bass is what lies underneath any strong tune. 10 | ..fb303 is the shared root of all thrift services. 11 | ...fb303 => FacebookBase303. 12 | 13 | * How do I use this? * 14 | Take a look at the examples to see how your backend project can 15 | and should inherit from this service. 16 | 17 | * What does it provide? * 18 | A standard interface to monitoring, dynamic options and configuration, 19 | uptime reports, activity, etc. 20 | 21 | * I want more. * 22 | Think carefully first about whether the functionality you are going to add 23 | belongs here or in your application. If it can be abstracted and is generally 24 | useful, then it probably belongs somewhere in the fb303 tree. Keep in mind, 25 | not every product has to use ALL the functionality of fb303, but every product 26 | CANNOT use functionality that is NOT in fb303. 27 | 28 | * Is this open source? * 29 | Yes. fb303 is distributed under the Thrift Software License. See the 30 | LICENSE file for more details. 31 | 32 | * Installation * 33 | fb303 is configured/built/installed similar to Thrift. See the README 34 | in the Thrift root directory for more information. 35 | 36 | * Who wrote this README? * 37 | mcslee@facebook.com 38 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | dnl Copyright (C) 2009 Facebook 2 | dnl Copying and distribution of this file, with or without modification, 3 | dnl are permitted in any medium without royalty provided the copyright 4 | dnl notice and this notice are preserved. 5 | 6 | AC_DEFUN([FB_INITIALIZE], 7 | [ 8 | AM_INIT_AUTOMAKE([ foreign 1.9.5 no-define ]) 9 | if test "x$1" = "xlocalinstall"; then 10 | wdir=`pwd` 11 | # To use $wdir undef quote. 12 | # 13 | ########## 14 | AC_PREFIX_DEFAULT([`pwd`/install]) 15 | echo 16 | fi 17 | AC_PROG_CC 18 | AC_PROG_CXX 19 | AC_PROG_RANLIB(RANLIB, ranlib) 20 | AC_PATH_PROGS(BASH, bash) 21 | AC_PATH_PROGS(PERL, perl) 22 | AC_PATH_PROGS(PYTHON, python) 23 | AC_PATH_PROGS(AR, ar) 24 | AC_PATH_PROGS(ANT, ant) 25 | PRODUCT_MK="" 26 | ]) 27 | 28 | AC_DEFUN([FB_WITH_EXTERNAL_PATH], 29 | [ 30 | cdir=`pwd` 31 | AC_MSG_CHECKING([Checking EXTERNAL_PATH set to]) 32 | AC_ARG_WITH([externalpath], 33 | [ --with-externalpath=DIR User specified path to external facebook components.], 34 | [ 35 | if test "x${EXTERNAL_PATH}" != "x"; then 36 | echo "" 37 | echo "ERROR: You have already set EXTERNAL_PATH in your environment" 38 | echo "Cannot override it using --with-externalpath. Unset EXTERNAL_PATH to use this option" 39 | exit 1 40 | fi 41 | EXTERNAL_PATH=$withval 42 | ], 43 | [ 44 | if test "x${EXTERNAL_PATH}" = "x"; then 45 | EXTERNAL_PATH=$1 46 | fi 47 | ] 48 | ) 49 | if test "x${EXTERNAL_PATH}" = "x"; then 50 | export EXTERNAL_PATH="$cdir/external" 51 | GLOBAL_HEADER_MK="include ${EXTERNAL_PATH}/global_header.mk" 52 | GLOBAL_FOOTER_MK="include ${EXTERNAL_PATH}/global_footer.mk" 53 | else 54 | export EXTERNAL_PATH 55 | GLOBAL_HEADER_MK="include ${EXTERNAL_PATH}/global_header.mk" 56 | GLOBAL_FOOTER_MK="include ${EXTERNAL_PATH}/global_footer.mk" 57 | fi 58 | AC_MSG_RESULT($EXTERNAL_PATH) 59 | if test ! -d ${EXTERNAL_PATH}; then 60 | echo "" 61 | echo "ERROR: EXTERNAL_PATH set to an nonexistent directory ${EXTERNAL_PATH}" 62 | exit 1 63 | fi 64 | AC_SUBST(EXTERNAL_PATH) 65 | AC_SUBST(GLOBAL_HEADER_MK) 66 | AC_SUBST(GLOBAL_FOOTER_MK) 67 | ]) 68 | 69 | # Set option to enable shared mode. Set DEBUG and OPT for use in Makefile.am. 70 | AC_DEFUN([FB_ENABLE_DEFAULT_OPT_BUILD], 71 | [ 72 | AC_MSG_CHECKING([whether to enable optimized build]) 73 | AC_ARG_ENABLE([opt], 74 | [ --disable-opt Set up debug mode.], 75 | [ 76 | ENABLED_OPT=$enableval 77 | ], 78 | [ 79 | ENABLED_OPT="yes" 80 | ] 81 | ) 82 | if test "$ENABLED_OPT" = "yes" 83 | then 84 | CFLAGS="-Wall -O3" 85 | CXXFLAGS="-Wall -O3" 86 | else 87 | CFLAGS="-Wall -g" 88 | CXXFLAGS="-Wall -g" 89 | fi 90 | AC_MSG_RESULT($ENABLED_OPT) 91 | AM_CONDITIONAL([OPT], [test "$ENABLED_OPT" = yes]) 92 | AM_CONDITIONAL([DEBUG], [test "$ENABLED_OPT" = no]) 93 | ]) 94 | 95 | # Set option to enable debug mode. Set DEBUG and OPT for use in Makefile.am. 96 | AC_DEFUN([FB_ENABLE_DEFAULT_DEBUG_BUILD], 97 | [ 98 | AC_MSG_CHECKING([whether to enable debug build]) 99 | AC_ARG_ENABLE([debug], 100 | [ --disable-debug Set up opt mode.], 101 | [ 102 | ENABLED_DEBUG=$enableval 103 | ], 104 | [ 105 | ENABLED_DEBUG="yes" 106 | ] 107 | ) 108 | if test "$ENABLED_DEBUG" = "yes" 109 | then 110 | CFLAGS="-Wall -g" 111 | CXXFLAGS="-Wall -g" 112 | else 113 | CFLAGS="-Wall -O3" 114 | CXXFLAGS="-Wall -O3" 115 | fi 116 | AC_MSG_RESULT($ENABLED_DEBUG) 117 | AM_CONDITIONAL([DEBUG], [test "$ENABLED_DEBUG" = yes]) 118 | AM_CONDITIONAL([OPT], [test "$ENABLED_DEBUG" = no]) 119 | ]) 120 | 121 | # Set option to enable static libs. 122 | AC_DEFUN([FB_ENABLE_DEFAULT_STATIC], 123 | [ 124 | SHARED="" 125 | STATIC="" 126 | AC_MSG_CHECKING([whether to enable static mode]) 127 | AC_ARG_ENABLE([static], 128 | [ --disable-static Set up shared mode.], 129 | [ 130 | ENABLED_STATIC=$enableval 131 | ], 132 | [ 133 | ENABLED_STATIC="yes" 134 | ] 135 | ) 136 | if test "$ENABLED_STATIC" = "yes" 137 | then 138 | LTYPE=".a" 139 | else 140 | LTYPE=".so" 141 | SHARED_CXXFLAGS="-fPIC" 142 | SHARED_CFLAGS="-fPIC" 143 | SHARED_LDFLAGS="-shared -fPIC" 144 | AC_SUBST(SHARED_CXXFLAGS) 145 | AC_SUBST(SHARED_CFLAGS) 146 | AC_SUBST(SHARED_LDFLAGS) 147 | fi 148 | AC_MSG_RESULT($ENABLED_STATIC) 149 | AC_SUBST(LTYPE) 150 | AM_CONDITIONAL([STATIC], [test "$ENABLED_STATIC" = yes]) 151 | AM_CONDITIONAL([SHARED], [test "$ENABLED_STATIC" = no]) 152 | ]) 153 | 154 | # Set option to enable shared libs. 155 | AC_DEFUN([FB_ENABLE_DEFAULT_SHARED], 156 | [ 157 | SHARED="" 158 | STATIC="" 159 | AC_MSG_CHECKING([whether to enable shared mode]) 160 | AC_ARG_ENABLE([shared], 161 | [ --disable-shared Set up static mode.], 162 | [ 163 | ENABLED_SHARED=$enableval 164 | ], 165 | [ 166 | ENABLED_SHARED="yes" 167 | ] 168 | ) 169 | if test "$ENABLED_SHARED" = "yes" 170 | then 171 | LTYPE=".so" 172 | SHARED_CXXFLAGS="-fPIC" 173 | SHARED_CFLAGS="-fPIC" 174 | SHARED_LDFLAGS="-shared -fPIC" 175 | AC_SUBST(SHARED_CXXFLAGS) 176 | AC_SUBST(SHARED_CFLAGS) 177 | AC_SUBST(SHARED_LDFLAGS) 178 | else 179 | LTYPE=".a" 180 | fi 181 | AC_MSG_RESULT($ENABLED_SHARED) 182 | AC_SUBST(LTYPE) 183 | AM_CONDITIONAL([SHARED], [test "$ENABLED_SHARED" = yes]) 184 | AM_CONDITIONAL([STATIC], [test "$ENABLED_SHARED" = no]) 185 | ]) 186 | 187 | # Generates define flags and conditionals as specified by user. 188 | # This gets enabled *only* if user selects --enable- otion. 189 | AC_DEFUN([FB_ENABLE_FEATURE], 190 | [ 191 | ENABLE="" 192 | flag="$1" 193 | value="$3" 194 | AC_MSG_CHECKING([whether to enable $1]) 195 | AC_ARG_ENABLE([$2], 196 | [ --enable-$2 Enable $2.], 197 | [ 198 | ENABLE=$enableval 199 | ], 200 | [ 201 | ENABLE="no" 202 | ] 203 | ) 204 | AM_CONDITIONAL([$1], [test "$ENABLE" = yes]) 205 | if test "$ENABLE" = "yes" 206 | then 207 | if test "x${value}" = "x" 208 | then 209 | AC_DEFINE([$1]) 210 | else 211 | AC_DEFINE_UNQUOTED([$1], [$value]) 212 | fi 213 | fi 214 | AC_MSG_RESULT($ENABLE) 215 | ]) 216 | 217 | 218 | # can also use eval $2=$withval;AC_SUBST($2) 219 | AC_DEFUN([FB_WITH_PATH], 220 | [ 221 | USRFLAG="" 222 | USRFLAG=$1 223 | AC_MSG_CHECKING([Checking $1 set to]) 224 | AC_ARG_WITH([$2], 225 | [ --with-$2=DIR User specified path.], 226 | [ 227 | LOC=$withval 228 | eval $USRFLAG=$withval 229 | ], 230 | [ 231 | LOC=$3 232 | eval $USRFLAG=$3 233 | ] 234 | ) 235 | AC_SUBST([$1]) 236 | AC_MSG_RESULT($LOC) 237 | ]) 238 | 239 | AC_DEFUN([FB_SET_FLAG_VALUE], 240 | [ 241 | SETFLAG="" 242 | AC_MSG_CHECKING([Checking $1 set to]) 243 | SETFLAG=$1 244 | eval $SETFLAG=\"$2\" 245 | AC_SUBST([$SETFLAG]) 246 | AC_MSG_RESULT($2) 247 | ]) 248 | 249 | # NOTES 250 | # if using if else bourne stmt you must have more than a macro in it. 251 | # EX1 is not correct. EX2 is correct 252 | # EX1: if test "$XX" = "yes"; then 253 | # AC_SUBST(xx) 254 | # fi 255 | # EX2: if test "$XX" = "yes"; then 256 | # xx="foo" 257 | # AC_SUBST(xx) 258 | # fi 259 | -------------------------------------------------------------------------------- /aclocal/ax_boost_base.m4: -------------------------------------------------------------------------------- 1 | ##### http://autoconf-archive.cryp.to/ax_boost_base.html 2 | # 3 | # SYNOPSIS 4 | # 5 | # AX_BOOST_BASE([MINIMUM-VERSION]) 6 | # 7 | # DESCRIPTION 8 | # 9 | # Test for the Boost C++ libraries of a particular version (or newer) 10 | # 11 | # If no path to the installed boost library is given the macro 12 | # searchs under /usr, /usr/local, /opt and /opt/local and evaluates 13 | # the $BOOST_ROOT environment variable. Further documentation is 14 | # available at . 15 | # 16 | # This macro calls: 17 | # 18 | # AC_SUBST(BOOST_CPPFLAGS) / AC_SUBST(BOOST_LDFLAGS) 19 | # 20 | # And sets: 21 | # 22 | # HAVE_BOOST 23 | # 24 | # LAST MODIFICATION 25 | # 26 | # 2007-07-28 27 | # 28 | # COPYLEFT 29 | # 30 | # Copyright (c) 2007 Thomas Porschberg 31 | # 32 | # Copying and distribution of this file, with or without 33 | # modification, are permitted in any medium without royalty provided 34 | # the copyright notice and this notice are preserved. 35 | 36 | AC_DEFUN([AX_BOOST_BASE], 37 | [ 38 | AC_ARG_WITH([boost], 39 | AS_HELP_STRING([--with-boost@<:@=DIR@:>@], [use boost (default is yes) - it is possible to specify the root directory for boost (optional)]), 40 | [ 41 | if test "$withval" = "no"; then 42 | want_boost="no" 43 | elif test "$withval" = "yes"; then 44 | want_boost="yes" 45 | ac_boost_path="" 46 | else 47 | want_boost="yes" 48 | ac_boost_path="$withval" 49 | fi 50 | ], 51 | [want_boost="yes"]) 52 | 53 | if test "x$want_boost" = "xyes"; then 54 | boost_lib_version_req=ifelse([$1], ,1.20.0,$1) 55 | boost_lib_version_req_shorten=`expr $boost_lib_version_req : '\([[0-9]]*\.[[0-9]]*\)'` 56 | boost_lib_version_req_major=`expr $boost_lib_version_req : '\([[0-9]]*\)'` 57 | boost_lib_version_req_minor=`expr $boost_lib_version_req : '[[0-9]]*\.\([[0-9]]*\)'` 58 | boost_lib_version_req_sub_minor=`expr $boost_lib_version_req : '[[0-9]]*\.[[0-9]]*\.\([[0-9]]*\)'` 59 | if test "x$boost_lib_version_req_sub_minor" = "x" ; then 60 | boost_lib_version_req_sub_minor="0" 61 | fi 62 | WANT_BOOST_VERSION=`expr $boost_lib_version_req_major \* 100000 \+ $boost_lib_version_req_minor \* 100 \+ $boost_lib_version_req_sub_minor` 63 | AC_MSG_CHECKING(for boostlib >= $boost_lib_version_req) 64 | succeeded=no 65 | 66 | dnl first we check the system location for boost libraries 67 | dnl this location ist chosen if boost libraries are installed with the --layout=system option 68 | dnl or if you install boost with RPM 69 | if test "$ac_boost_path" != ""; then 70 | BOOST_LDFLAGS="-L$ac_boost_path/lib" 71 | BOOST_CPPFLAGS="-I$ac_boost_path/include" 72 | else 73 | for ac_boost_path_tmp in /usr /usr/local /opt /opt/local ; do 74 | if test -d "$ac_boost_path_tmp/include/boost" && test -r "$ac_boost_path_tmp/include/boost"; then 75 | BOOST_LDFLAGS="-L$ac_boost_path_tmp/lib" 76 | BOOST_CPPFLAGS="-I$ac_boost_path_tmp/include" 77 | break; 78 | fi 79 | done 80 | fi 81 | 82 | CPPFLAGS_SAVED="$CPPFLAGS" 83 | CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" 84 | export CPPFLAGS 85 | 86 | LDFLAGS_SAVED="$LDFLAGS" 87 | LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" 88 | export LDFLAGS 89 | 90 | AC_LANG_PUSH(C++) 91 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ 92 | @%:@include 93 | ]], [[ 94 | #if BOOST_VERSION >= $WANT_BOOST_VERSION 95 | // Everything is okay 96 | #else 97 | # error Boost version is too old 98 | #endif 99 | ]])],[ 100 | AC_MSG_RESULT(yes) 101 | succeeded=yes 102 | found_system=yes 103 | ],[ 104 | ]) 105 | AC_LANG_POP([C++]) 106 | 107 | 108 | 109 | dnl if we found no boost with system layout we search for boost libraries 110 | dnl built and installed without the --layout=system option or for a staged(not installed) version 111 | if test "x$succeeded" != "xyes"; then 112 | _version=0 113 | if test "$ac_boost_path" != ""; then 114 | BOOST_LDFLAGS="-L$ac_boost_path/lib" 115 | if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then 116 | for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do 117 | _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` 118 | V_CHECK=`expr $_version_tmp \> $_version` 119 | if test "$V_CHECK" = "1" ; then 120 | _version=$_version_tmp 121 | fi 122 | VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` 123 | BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE" 124 | done 125 | fi 126 | else 127 | for ac_boost_path in /usr /usr/local /opt /opt/local ; do 128 | if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then 129 | for i in `ls -d $ac_boost_path/include/boost-* 2>/dev/null`; do 130 | _version_tmp=`echo $i | sed "s#$ac_boost_path##" | sed 's/\/include\/boost-//' | sed 's/_/./'` 131 | V_CHECK=`expr $_version_tmp \> $_version` 132 | if test "$V_CHECK" = "1" ; then 133 | _version=$_version_tmp 134 | best_path=$ac_boost_path 135 | fi 136 | done 137 | fi 138 | done 139 | 140 | VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'` 141 | BOOST_CPPFLAGS="-I$best_path/include/boost-$VERSION_UNDERSCORE" 142 | BOOST_LDFLAGS="-L$best_path/lib" 143 | 144 | if test "x$BOOST_ROOT" != "x"; then 145 | if test -d "$BOOST_ROOT" && test -r "$BOOST_ROOT" && test -d "$BOOST_ROOT/stage/lib" && test -r "$BOOST_ROOT/stage/lib"; then 146 | version_dir=`expr //$BOOST_ROOT : '.*/\(.*\)'` 147 | stage_version=`echo $version_dir | sed 's/boost_//' | sed 's/_/./g'` 148 | stage_version_shorten=`expr $stage_version : '\([[0-9]]*\.[[0-9]]*\)'` 149 | V_CHECK=`expr $stage_version_shorten \>\= $_version` 150 | if test "$V_CHECK" = "1" ; then 151 | AC_MSG_NOTICE(We will use a staged boost library from $BOOST_ROOT) 152 | BOOST_CPPFLAGS="-I$BOOST_ROOT" 153 | BOOST_LDFLAGS="-L$BOOST_ROOT/stage/lib" 154 | fi 155 | fi 156 | fi 157 | fi 158 | 159 | CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" 160 | export CPPFLAGS 161 | LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" 162 | export LDFLAGS 163 | 164 | AC_LANG_PUSH(C++) 165 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ 166 | @%:@include 167 | ]], [[ 168 | #if BOOST_VERSION >= $WANT_BOOST_VERSION 169 | // Everything is okay 170 | #else 171 | # error Boost version is too old 172 | #endif 173 | ]])],[ 174 | AC_MSG_RESULT(yes) 175 | succeeded=yes 176 | found_system=yes 177 | ],[ 178 | ]) 179 | AC_LANG_POP([C++]) 180 | fi 181 | 182 | if test "$succeeded" != "yes" ; then 183 | if test "$_version" = "0" ; then 184 | 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 . See http://randspringer.de/boost for more documentation.]]) 185 | else 186 | AC_MSG_NOTICE([Your boost libraries seems to old (version $_version).]) 187 | fi 188 | else 189 | AC_SUBST(BOOST_CPPFLAGS) 190 | AC_SUBST(BOOST_LDFLAGS) 191 | AC_DEFINE(HAVE_BOOST,,[define if the Boost library is available]) 192 | fi 193 | 194 | CPPFLAGS="$CPPFLAGS_SAVED" 195 | LDFLAGS="$LDFLAGS_SAVED" 196 | fi 197 | 198 | ]) 199 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, 15 | # software distributed under the License is distributed on an 16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | # KIND, either express or implied. See the License for the 18 | # specific language governing permissions and limitations 19 | # under the License. 20 | # 21 | 22 | # To be safe include -I flag 23 | aclocal -I ./aclocal 24 | automake -a 25 | autoconf 26 | -------------------------------------------------------------------------------- /build.log: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # Autoconf input file 2 | # $Id$ 3 | 4 | # AC - autoconf 5 | # FB - facebook 6 | 7 | # 8 | # Licensed to the Apache Software Foundation (ASF) under one 9 | # or more contributor license agreements. See the NOTICE file 10 | # distributed with this work for additional information 11 | # regarding copyright ownership. The ASF licenses this file 12 | # to you under the Apache License, Version 2.0 (the 13 | # "License"); you may not use this file except in compliance 14 | # with the License. You may obtain a copy of the License at 15 | # 16 | # http://www.apache.org/licenses/LICENSE-2.0 17 | # 18 | # Unless required by applicable law or agreed to in writing, 19 | # software distributed under the License is distributed on an 20 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 | # KIND, either express or implied. See the License for the 22 | # specific language governing permissions and limitations 23 | # under the License. 24 | # 25 | 26 | ######################################################################### 27 | # DO NOT TOUCH EXCEPT TO CHANGE REV# IN AC_INIT 28 | 29 | AC_PREREQ(2.52) 30 | AC_INIT([libfb303],[20080209]) 31 | #AC_CONFIG_AUX_DIR([/usr/share/automake-1.9]) 32 | # To install locally 33 | FB_INITIALIZE([localinstall]) 34 | AC_PREFIX_DEFAULT([/usr/local]) 35 | 36 | ############################################################################ 37 | # User Configurable. Change With CAUTION! 38 | # User can include custom makefile rules. Uncomment and update only in PRODUCT_MK. 39 | # Include where appropriate in any Makefile.am as @PRODUCT_MK@ 40 | 41 | #PRODUCT_MK="include ${EXTERNAL_PATH}/shared/build/.mk" 42 | 43 | # Default path to external Facebook components and shared build toools I.e fb303 etc. 44 | # To point to other locations set environment variable EXTERNAL_PATH. 45 | # To change the current default you must change bootstrap.sh. 46 | FB_WITH_EXTERNAL_PATH([`pwd`]) 47 | 48 | AC_ARG_VAR([PY_PREFIX], [Prefix for installing Python modules. 49 | (Normal --prefix is ignored for Python because 50 | Python has different conventions.) 51 | Default = "/usr"]) 52 | AS_IF([test "x$PY_PREFIX" = x], [PY_PREFIX="/usr"]) 53 | 54 | ########################################################################## 55 | # User Configurable 56 | 57 | # Pre-defined macro to set opt build mode. Run with --disable-shared option to turn off optimization. 58 | FB_ENABLE_DEFAULT_OPT_BUILD 59 | 60 | # Predefined macro to set static library mode. Run with --disable-static option to turn off static lib mode. 61 | FB_ENABLE_DEFAULT_STATIC 62 | 63 | # Personalized feature generator. Creates defines/conditionals and --enable --disable command line options. 64 | # FB_ENABLE_FEATURE([FEATURE], [feature]) OR FB_ENABLE_FEATURE([FEATURE], [feature], [\"\"]) 65 | 66 | # Example: Macro supplies -DFACEBOOK at compile time and "if FACEBOOK endif" capabilities. 67 | 68 | # Personalized path generator Sets default paths. Provides --with-xx=DIR options. 69 | # FB_WITH_PATH([_home], [path], [] 70 | 71 | # Example: sets $(thrift_home) variable with default path set to /usr/local. 72 | FB_WITH_PATH([thrift_home], [thriftpath], [/usr/local]) 73 | 74 | # Require boost 1.33.1 or later 75 | AX_BOOST_BASE([1.33.1]) 76 | 77 | # Generates Makefile from Makefile.am. Modify when new subdirs are added. 78 | # Change Makefile.am also to add subdirectly. 79 | AC_CONFIG_FILES(Makefile cpp/Makefile py/Makefile) 80 | 81 | ############################################################################ 82 | # DO NOT TOUCH. 83 | 84 | AC_SUBST(PRODUCT_MK) 85 | AC_OUTPUT 86 | 87 | ############################################################################# 88 | ######### FINISH ############################################################ 89 | 90 | echo "EXTERNAL_PATH $EXTERNAL_PATH" 91 | 92 | 93 | # 94 | # NOTES FOR USER 95 | # Short cut to create conditional flags. 96 | #enable_facebook="yes" 97 | #AM_CONDITIONAL([FACEBOOK], [test "$enable_facebook" = yes]) 98 | #enable_hdfs="yes" 99 | #AM_CONDITIONAL([HDFS], [test "$enable_hdfs" = yes]) 100 | 101 | # Enable options with --enable and --disable configurable. 102 | #AC_MSG_CHECKING([whether to enable FACEBOOK]) 103 | #FACEBOOK="" 104 | #AC_ARG_ENABLE([facebook], 105 | # [ --enable-facebook Enable facebook.], 106 | # [ 107 | # ENABLE_FACEBOOK=$enableval 108 | # ], 109 | # [ 110 | # ENABLE_FACEBOOK="no" 111 | # ] 112 | #) 113 | #AM_CONDITIONAL([FACEBOOK], [test "$ENABLE_FACEBOOK" = yes]) 114 | #AC_MSG_RESULT($ENABLE_FACEBOOK) 115 | 116 | -------------------------------------------------------------------------------- /cpp/FacebookBase.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | #include "FacebookBase.h" 21 | 22 | using namespace facebook::fb303; 23 | using apache::thrift::concurrency::Guard; 24 | 25 | FacebookBase::FacebookBase(std::string name) : 26 | name_(name) { 27 | aliveSince_ = (int64_t) time(NULL); 28 | } 29 | 30 | inline void FacebookBase::getName(std::string& _return) { 31 | _return = name_; 32 | } 33 | 34 | void FacebookBase::setOption(const std::string& key, const std::string& value) { 35 | Guard g(optionsLock_); 36 | options_[key] = value; 37 | } 38 | 39 | void FacebookBase::getOption(std::string& _return, const std::string& key) { 40 | Guard g(optionsLock_); 41 | _return = options_[key]; 42 | } 43 | 44 | void FacebookBase::getOptions(std::map & _return) { 45 | Guard g(optionsLock_); 46 | _return = options_; 47 | } 48 | 49 | int64_t FacebookBase::incrementCounter(const std::string& key, int64_t amount) { 50 | counters_.acquireRead(); 51 | 52 | // if we didn't find the key, we need to write lock the whole map to create it 53 | ReadWriteCounterMap::iterator it = counters_.find(key); 54 | if (it == counters_.end()) { 55 | counters_.release(); 56 | counters_.acquireWrite(); 57 | 58 | // we need to check again to make sure someone didn't create this key 59 | // already while we released the lock 60 | it = counters_.find(key); 61 | if(it == counters_.end()){ 62 | counters_[key].value = amount; 63 | counters_.release(); 64 | return amount; 65 | } 66 | } 67 | 68 | it->second.acquireWrite(); 69 | int64_t count = it->second.value + amount; 70 | it->second.value = count; 71 | it->second.release(); 72 | counters_.release(); 73 | return count; 74 | } 75 | 76 | int64_t FacebookBase::setCounter(const std::string& key, int64_t value) { 77 | counters_.acquireRead(); 78 | 79 | // if we didn't find the key, we need to write lock the whole map to create it 80 | ReadWriteCounterMap::iterator it = counters_.find(key); 81 | if (it == counters_.end()) { 82 | counters_.release(); 83 | counters_.acquireWrite(); 84 | counters_[key].value = value; 85 | counters_.release(); 86 | return value; 87 | } 88 | 89 | it->second.acquireWrite(); 90 | it->second.value = value; 91 | it->second.release(); 92 | counters_.release(); 93 | return value; 94 | } 95 | 96 | void FacebookBase::getCounters(std::map& _return) { 97 | // we need to lock the whole thing and actually build the map since we don't 98 | // want our read/write structure to go over the wire 99 | counters_.acquireRead(); 100 | for(ReadWriteCounterMap::iterator it = counters_.begin(); 101 | it != counters_.end(); it++) 102 | { 103 | _return[it->first] = it->second.value; 104 | } 105 | counters_.release(); 106 | } 107 | 108 | int64_t FacebookBase::getCounter(const std::string& key) { 109 | int64_t rv = 0; 110 | counters_.acquireRead(); 111 | ReadWriteCounterMap::iterator it = counters_.find(key); 112 | if (it != counters_.end()) { 113 | it->second.acquireRead(); 114 | rv = it->second.value; 115 | it->second.release(); 116 | } 117 | counters_.release(); 118 | return rv; 119 | } 120 | 121 | inline int64_t FacebookBase::aliveSince() { 122 | return aliveSince_; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /cpp/FacebookBase.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | #ifndef _FACEBOOK_TB303_FACEBOOKBASE_H_ 21 | #define _FACEBOOK_TB303_FACEBOOKBASE_H_ 1 22 | 23 | #include "FacebookService.h" 24 | 25 | #include "server/TServer.h" 26 | #include "concurrency/Mutex.h" 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | namespace facebook { namespace fb303 { 33 | 34 | using apache::thrift::concurrency::Mutex; 35 | using apache::thrift::concurrency::ReadWriteMutex; 36 | using apache::thrift::server::TServer; 37 | 38 | struct ReadWriteInt : ReadWriteMutex {int64_t value;}; 39 | struct ReadWriteCounterMap : ReadWriteMutex, 40 | std::map {}; 41 | 42 | /** 43 | * Base Facebook service implementation in C++. 44 | * 45 | */ 46 | class FacebookBase : virtual public FacebookServiceIf { 47 | protected: 48 | FacebookBase(std::string name); 49 | virtual ~FacebookBase() {} 50 | 51 | public: 52 | void getName(std::string& _return); 53 | virtual void getVersion(std::string& _return) { _return = ""; } 54 | 55 | virtual fb_status getStatus() = 0; 56 | virtual void getStatusDetails(std::string& _return) { _return = ""; } 57 | 58 | void setOption(const std::string& key, const std::string& value); 59 | void getOption(std::string& _return, const std::string& key); 60 | void getOptions(std::map & _return); 61 | 62 | int64_t aliveSince(); 63 | 64 | virtual void reinitialize() {} 65 | 66 | virtual void shutdown() { 67 | if (server_.get() != NULL) { 68 | server_->stop(); 69 | } 70 | } 71 | 72 | int64_t incrementCounter(const std::string& key, int64_t amount = 1); 73 | int64_t setCounter(const std::string& key, int64_t value); 74 | 75 | void getCounters(std::map& _return); 76 | int64_t getCounter(const std::string& key); 77 | 78 | /** 79 | * Set server handle for shutdown method 80 | */ 81 | void setServer(boost::shared_ptr server) { 82 | server_ = server; 83 | } 84 | 85 | void getCpuProfile(std::string& _return, int32_t durSecs) { _return = ""; } 86 | 87 | private: 88 | 89 | std::string name_; 90 | int64_t aliveSince_; 91 | 92 | std::map options_; 93 | Mutex optionsLock_; 94 | 95 | ReadWriteCounterMap counters_; 96 | 97 | boost::shared_ptr server_; 98 | 99 | }; 100 | 101 | }} // facebook::tb303 102 | 103 | #endif // _FACEBOOK_TB303_FACEBOOKBASE_H_ 104 | -------------------------------------------------------------------------------- /cpp/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | @GLOBAL_HEADER_MK@ 21 | 22 | @PRODUCT_MK@ 23 | 24 | 25 | # User specified path variables set in configure.ac. 26 | # thrift_home 27 | # 28 | THRIFT = $(thrift_home)/bin/thrift 29 | 30 | # User defined conditionals and conditonal statements set up in configure.ac. 31 | if DEBUG 32 | DEBUG_CPPFLAGS = -DDEBUG_TIMING 33 | endif 34 | 35 | # Set common flags recognized by automake. 36 | # DO NOT USE CPPFLAGS, CXXFLAGS, CFLAGS, LDFLAGS here! Set in configure.ac and|or override on command line. 37 | # USE flags AM_CXXFLAGS, AM_CFLAGS, AM_CPPFLAGS, AM_LDFLAGS, LDADD in this section. 38 | 39 | AM_CPPFLAGS = -I.. 40 | AM_CPPFLAGS += -Igen-cpp 41 | AM_CPPFLAGS += -I$(thrift_home)/include/thrift 42 | AM_CPPFLAGS += $(BOOST_CPPFLAGS) 43 | AM_CPPFLAGS += $(FB_CPPFLAGS) $(DEBUG_CPPFLAGS) 44 | 45 | # GENERATE BUILD RULES 46 | # Set Program/library specific flags recognized by automake. 47 | # Use _ to set prog / lib specific flag s 48 | # foo_CXXFLAGS foo_CPPFLAGS foo_LDFLAGS foo_LDADD 49 | 50 | fb303_lib = gen-cpp/FacebookService.cpp gen-cpp/fb303_constants.cpp gen-cpp/fb303_types.cpp FacebookBase.cpp ServiceTracker.cpp 51 | 52 | # Static -- multiple libraries can be defined 53 | if STATIC 54 | lib_LIBRARIES = libfb303.a 55 | libfb303_a_SOURCES = $(fb303_lib) 56 | INTERNAL_LIBS = libfb303.a 57 | endif 58 | 59 | # Shared -- multiple libraries can be defined 60 | if SHARED 61 | shareddir = lib 62 | shared_PROGRAMS = libfb303.so 63 | libfb303_so_SOURCES = $(fb303_lib) 64 | libfb303_so_CXXFLAGS = $(SHARED_CXXFLAGS) 65 | libfb303_so_LDFLAGS = $(SHARED_LDFLAGS) 66 | INTERNAL_LIBS = libfb303.so 67 | endif 68 | 69 | # Set up Thrift specific activity here. 70 | # We assume that a +types.cpp will always be built from .thrift. 71 | $(eval $(call thrift_template,.,../if/fb303.thrift,-I $(thrift_home)/share --gen cpp )) 72 | 73 | include_fb303dir = $(includedir)/thrift/fb303 74 | include_fb303_HEADERS = FacebookBase.h ServiceTracker.h gen-cpp/FacebookService.h gen-cpp/fb303_constants.h gen-cpp/fb303_types.h 75 | 76 | include_fb303ifdir = $(prefix)/share/fb303/if 77 | include_fb303if_HEADERS = ../if/fb303.thrift 78 | 79 | BUILT_SOURCES = thriftstyle 80 | 81 | # Add to pre-existing target clean 82 | clean-local: clean-common 83 | 84 | @GLOBAL_FOOTER_MK@ 85 | -------------------------------------------------------------------------------- /cpp/ServiceTracker.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | #include 21 | 22 | #include "FacebookBase.h" 23 | #include "ServiceTracker.h" 24 | #include "concurrency/ThreadManager.h" 25 | 26 | using namespace std; 27 | using namespace facebook::fb303; 28 | using namespace apache::thrift::concurrency; 29 | 30 | 31 | uint64_t ServiceTracker::CHECKPOINT_MINIMUM_INTERVAL_SECONDS = 60; 32 | int ServiceTracker::LOG_LEVEL = 5; 33 | 34 | 35 | ServiceTracker::ServiceTracker(facebook::fb303::FacebookBase *handler, 36 | void (*logMethod)(int, const string &), 37 | bool featureCheckpoint, 38 | bool featureStatusCheck, 39 | bool featureThreadCheck, 40 | Stopwatch::Unit stopwatchUnit) 41 | : handler_(handler), logMethod_(logMethod), 42 | featureCheckpoint_(featureCheckpoint), 43 | featureStatusCheck_(featureStatusCheck), 44 | featureThreadCheck_(featureThreadCheck), 45 | stopwatchUnit_(stopwatchUnit), 46 | checkpointServices_(0) 47 | { 48 | if (featureCheckpoint_) { 49 | time_t now = time(NULL); 50 | checkpointTime_ = now; 51 | } else { 52 | checkpointTime_ = 0; 53 | } 54 | } 55 | 56 | /** 57 | * Registers the beginning of a "service method": basically, any of 58 | * the implementations of Thrift remote procedure calls that a 59 | * FacebookBase handler is handling. Controls concurrent 60 | * services and reports statistics (via log and via fb303 counters). 61 | * Throws an exception if the server is not ready to handle service 62 | * methods yet. 63 | * 64 | * note: The relationship between startService() and finishService() 65 | * is currently defined so that a call to finishService() should only 66 | * be matched to this call to startService() if this method returns 67 | * without exception. It wouldn't be a problem to implement things 68 | * the other way, so that *every* start needed a finish, but this 69 | * convention was chosen to match the way an object's constructor and 70 | * destructor work together, i.e. to work well with ServiceMethod 71 | * objects. 72 | * 73 | * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod 74 | * object instantiated at the start 75 | * of the service method. 76 | */ 77 | void 78 | ServiceTracker::startService(const ServiceMethod &serviceMethod) 79 | { 80 | // note: serviceMethod.timer_ automatically starts at construction. 81 | 82 | // log service start 83 | logMethod_(5, serviceMethod.signature_); 84 | 85 | // check handler ready 86 | if (featureStatusCheck_ && !serviceMethod.featureLogOnly_) { 87 | // note: Throwing exceptions before counting statistics. See note 88 | // in method header. 89 | // note: A STOPPING server is not accepting new connections, but it 90 | // is still handling any already-connected threads -- so from the 91 | // service method's point of view, a status of STOPPING is a green 92 | // light. 93 | facebook::fb303::fb_status status = handler_->getStatus(); 94 | if (status != facebook::fb303::ALIVE 95 | && status != facebook::fb303::STOPPING) { 96 | if (status == facebook::fb303::STARTING) { 97 | throw ServiceException("Server starting up; please try again later"); 98 | } else { 99 | throw ServiceException("Server not alive; please try again later"); 100 | } 101 | } 102 | } 103 | 104 | // check server threads 105 | if (featureThreadCheck_ && !serviceMethod.featureLogOnly_) { 106 | // note: Might want to put these messages in reportCheckpoint() if 107 | // log is getting spammed. 108 | if (threadManager_ != NULL) { 109 | size_t idle_count = threadManager_->idleWorkerCount(); 110 | if (idle_count == 0) { 111 | stringstream message; 112 | message << "service " << serviceMethod.signature_ 113 | << ": all threads (" << threadManager_->workerCount() 114 | << ") in use"; 115 | logMethod_(3, message.str()); 116 | } 117 | } 118 | } 119 | } 120 | 121 | /** 122 | * Logs a significant step in the middle of a "service method"; see 123 | * startService. 124 | * 125 | * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod 126 | * object instantiated at the start 127 | * of the service method. 128 | * @return int64_t Elapsed units (see stopwatchUnit_) since ServiceMethod 129 | * instantiation. 130 | */ 131 | int64_t 132 | ServiceTracker::stepService(const ServiceMethod &serviceMethod, 133 | const string &stepName) 134 | { 135 | stringstream message; 136 | string elapsed_label; 137 | int64_t elapsed = serviceMethod.timer_.elapsedUnits(stopwatchUnit_, 138 | &elapsed_label); 139 | message << serviceMethod.signature_ 140 | << ' ' << stepName 141 | << " [" << elapsed_label << ']'; 142 | logMethod_(5, message.str()); 143 | return elapsed; 144 | } 145 | 146 | /** 147 | * Registers the end of a "service method"; see startService(). 148 | * 149 | * @param const ServiceMethod &serviceMethod A reference to the ServiceMethod 150 | * object instantiated at the start 151 | * of the service method. 152 | */ 153 | void 154 | ServiceTracker::finishService(const ServiceMethod &serviceMethod) 155 | { 156 | // log end of service 157 | stringstream message; 158 | string duration_label; 159 | int64_t duration = serviceMethod.timer_.elapsedUnits(stopwatchUnit_, 160 | &duration_label); 161 | message << serviceMethod.signature_ 162 | << " finish [" << duration_label << ']'; 163 | logMethod_(5, message.str()); 164 | 165 | // count, record, and maybe report service statistics 166 | if (!serviceMethod.featureLogOnly_) { 167 | 168 | if (!featureCheckpoint_) { 169 | 170 | // lifetime counters 171 | // (note: No need to lock statisticsMutex_ if not doing checkpoint; 172 | // FacebookService::incrementCounter() is already thread-safe.) 173 | handler_->incrementCounter("lifetime_services"); 174 | 175 | } else { 176 | 177 | statisticsMutex_.lock(); 178 | // note: No exceptions expected from this code block. Wrap in a try 179 | // just to be safe. 180 | try { 181 | 182 | // lifetime counters 183 | // note: Good to synchronize this with the increment of 184 | // checkpoint services, even though incrementCounter() is 185 | // already thread-safe, for the sake of checkpoint reporting 186 | // consistency (i.e. since the last checkpoint, 187 | // lifetime_services has incremented by checkpointServices_). 188 | handler_->incrementCounter("lifetime_services"); 189 | 190 | // checkpoint counters 191 | checkpointServices_++; 192 | checkpointDuration_ += duration; 193 | 194 | // per-service timing 195 | // note kjv: According to my tests it is very slightly faster to 196 | // call insert() once (and detect not-found) than calling find() 197 | // and then maybe insert (if not-found). However, the difference 198 | // is tiny for small maps like this one, and the code for the 199 | // faster solution is slightly less readable. Also, I wonder if 200 | // the instantiation of the (often unused) pair to insert makes 201 | // the first algorithm slower after all. 202 | map >::iterator iter; 203 | iter = checkpointServiceDuration_.find(serviceMethod.name_); 204 | if (iter != checkpointServiceDuration_.end()) { 205 | iter->second.first++; 206 | iter->second.second += duration; 207 | } else { 208 | checkpointServiceDuration_.insert(make_pair(serviceMethod.name_, 209 | make_pair(1, duration))); 210 | } 211 | 212 | // maybe report checkpoint 213 | // note: ...if it's been long enough since the last report. 214 | time_t now = time(NULL); 215 | uint64_t check_interval = now - checkpointTime_; 216 | if (check_interval >= CHECKPOINT_MINIMUM_INTERVAL_SECONDS) { 217 | reportCheckpoint(); 218 | } 219 | 220 | } catch (...) { 221 | statisticsMutex_.unlock(); 222 | throw; 223 | } 224 | statisticsMutex_.unlock(); 225 | 226 | } 227 | } 228 | } 229 | 230 | /** 231 | * Logs some statistics gathered since the last call to this method. 232 | * 233 | * note: Thread race conditions on this method could cause 234 | * misreporting and/or undefined behavior; the caller must protect 235 | * uses of the object variables (and calls to this method) with a 236 | * mutex. 237 | * 238 | */ 239 | void 240 | ServiceTracker::reportCheckpoint() 241 | { 242 | time_t now = time(NULL); 243 | 244 | uint64_t check_count = checkpointServices_; 245 | uint64_t check_interval = now - checkpointTime_; 246 | uint64_t check_duration = checkpointDuration_; 247 | 248 | // export counters for timing of service methods (by service name) 249 | handler_->setCounter("checkpoint_time", check_interval); 250 | map >::iterator iter; 251 | uint64_t count; 252 | for (iter = checkpointServiceDuration_.begin(); 253 | iter != checkpointServiceDuration_.end(); 254 | iter++) { 255 | count = iter->second.first; 256 | handler_->setCounter(string("checkpoint_count_") + iter->first, count); 257 | if (count == 0) { 258 | handler_->setCounter(string("checkpoint_speed_") + iter->first, 259 | 0); 260 | } else { 261 | handler_->setCounter(string("checkpoint_speed_") + iter->first, 262 | iter->second.second / count); 263 | } 264 | } 265 | 266 | // reset checkpoint variables 267 | // note: Clearing the map while other threads are using it might 268 | // cause undefined behavior. 269 | checkpointServiceDuration_.clear(); 270 | checkpointTime_ = now; 271 | checkpointServices_ = 0; 272 | checkpointDuration_ = 0; 273 | 274 | // get lifetime variables 275 | uint64_t life_count = handler_->getCounter("lifetime_services"); 276 | uint64_t life_interval = now - handler_->aliveSince(); 277 | 278 | // log checkpoint 279 | stringstream message; 280 | message << "checkpoint_time:" << check_interval 281 | << " checkpoint_services:" << check_count 282 | << " checkpoint_speed_sum:" << check_duration 283 | << " lifetime_time:" << life_interval 284 | << " lifetime_services:" << life_count; 285 | if (featureThreadCheck_ && threadManager_ != NULL) { 286 | size_t worker_count = threadManager_->workerCount(); 287 | size_t idle_count = threadManager_->idleWorkerCount(); 288 | message << " total_workers:" << worker_count 289 | << " active_workers:" << (worker_count - idle_count); 290 | } 291 | logMethod_(4, message.str()); 292 | } 293 | 294 | /** 295 | * Remembers the thread manager used in the server, for monitoring thread 296 | * activity. 297 | * 298 | * @param shared_ptr threadManager The server's thread manager. 299 | */ 300 | void 301 | ServiceTracker::setThreadManager(boost::shared_ptr 302 | threadManager) 303 | { 304 | threadManager_ = threadManager; 305 | } 306 | 307 | /** 308 | * Logs messages to stdout; the passed message will be logged if the 309 | * passed level is less than or equal to LOG_LEVEL. 310 | * 311 | * This is the default logging method used by the ServiceTracker. An 312 | * alternate logging method (that accepts the same parameters) may be 313 | * specified to the constructor. 314 | * 315 | * @param int level A level associated with the message: higher levels 316 | * are used to indicate higher levels of detail. 317 | * @param string message The message to log. 318 | */ 319 | void 320 | ServiceTracker::defaultLogMethod(int level, const string &message) 321 | { 322 | if (level <= LOG_LEVEL) { 323 | string level_string; 324 | time_t now = time(NULL); 325 | char now_pretty[26]; 326 | ctime_r(&now, now_pretty); 327 | now_pretty[24] = '\0'; 328 | switch (level) { 329 | case 1: 330 | level_string = "CRITICAL"; 331 | break; 332 | case 2: 333 | level_string = "ERROR"; 334 | break; 335 | case 3: 336 | level_string = "WARNING"; 337 | break; 338 | case 5: 339 | level_string = "DEBUG"; 340 | break; 341 | case 4: 342 | default: 343 | level_string = "INFO"; 344 | break; 345 | } 346 | cout << '[' << level_string << "] [" << now_pretty << "] " 347 | << message << endl; 348 | } 349 | } 350 | 351 | 352 | /** 353 | * Creates a Stopwatch, which can report the time elapsed since its 354 | * creation. 355 | * 356 | */ 357 | Stopwatch::Stopwatch() 358 | { 359 | gettimeofday(&startTime_, NULL); 360 | } 361 | 362 | void 363 | Stopwatch::reset() 364 | { 365 | gettimeofday(&startTime_, NULL); 366 | } 367 | 368 | uint64_t 369 | Stopwatch::elapsedUnits(Stopwatch::Unit unit, string *label) const 370 | { 371 | timeval now_time; 372 | gettimeofday(&now_time, NULL); 373 | time_t duration_secs = now_time.tv_sec - startTime_.tv_sec; 374 | 375 | uint64_t duration_units; 376 | switch (unit) { 377 | case UNIT_SECONDS: 378 | duration_units = duration_secs 379 | + (now_time.tv_usec - startTime_.tv_usec + 500000) / 1000000; 380 | if (NULL != label) { 381 | stringstream ss_label; 382 | ss_label << duration_units << " secs"; 383 | label->assign(ss_label.str()); 384 | } 385 | break; 386 | case UNIT_MICROSECONDS: 387 | duration_units = duration_secs * 1000000 388 | + now_time.tv_usec - startTime_.tv_usec; 389 | if (NULL != label) { 390 | stringstream ss_label; 391 | ss_label << duration_units << " us"; 392 | label->assign(ss_label.str()); 393 | } 394 | break; 395 | case UNIT_MILLISECONDS: 396 | default: 397 | duration_units = duration_secs * 1000 398 | + (now_time.tv_usec - startTime_.tv_usec + 500) / 1000; 399 | if (NULL != label) { 400 | stringstream ss_label; 401 | ss_label << duration_units << " ms"; 402 | label->assign(ss_label.str()); 403 | } 404 | break; 405 | } 406 | return duration_units; 407 | } 408 | 409 | /** 410 | * Creates a ServiceMethod, used for tracking a single service method 411 | * invocation (via the ServiceTracker). The passed name of the 412 | * ServiceMethod is used to group statistics (e.g. counts and durations) 413 | * for similar invocations; the passed signature is used to uniquely 414 | * identify the particular invocation in the log. 415 | * 416 | * note: A version of this constructor is provided that automatically 417 | * forms a signature the name and a passed numeric id. Silly, sure, 418 | * but commonly used, since it often saves the caller a line or two of 419 | * code. 420 | * 421 | * @param ServiceTracker *tracker The service tracker that will track this 422 | * ServiceMethod. 423 | * @param const string &name The service method name (usually independent 424 | * of service method parameters). 425 | * @param const string &signature A signature uniquely identifying the method 426 | * invocation (usually name plus parameters). 427 | */ 428 | ServiceMethod::ServiceMethod(ServiceTracker *tracker, 429 | const string &name, 430 | const string &signature, 431 | bool featureLogOnly) 432 | : tracker_(tracker), name_(name), signature_(signature), 433 | featureLogOnly_(featureLogOnly) 434 | { 435 | // note: timer_ automatically starts at construction. 436 | 437 | // invoke tracker to start service 438 | // note: Might throw. If it throws, then this object's destructor 439 | // won't be called, which is according to plan: finishService() is 440 | // only supposed to be matched to startService() if startService() 441 | // returns without error. 442 | tracker_->startService(*this); 443 | } 444 | 445 | ServiceMethod::ServiceMethod(ServiceTracker *tracker, 446 | const string &name, 447 | uint64_t id, 448 | bool featureLogOnly) 449 | : tracker_(tracker), name_(name), featureLogOnly_(featureLogOnly) 450 | { 451 | // note: timer_ automatically starts at construction. 452 | stringstream ss_signature; 453 | ss_signature << name << " (" << id << ')'; 454 | signature_ = ss_signature.str(); 455 | 456 | // invoke tracker to start service 457 | // note: Might throw. If it throws, then this object's destructor 458 | // won't be called, which is according to plan: finishService() is 459 | // only supposed to be matched to startService() if startService() 460 | // returns without error. 461 | tracker_->startService(*this); 462 | } 463 | 464 | ServiceMethod::~ServiceMethod() 465 | { 466 | // invoke tracker to finish service 467 | // note: Not expecting an exception from this code, but 468 | // finishService() might conceivably throw an out-of-memory 469 | // exception. 470 | try { 471 | tracker_->finishService(*this); 472 | } catch (...) { 473 | // don't throw 474 | } 475 | } 476 | 477 | uint64_t 478 | ServiceMethod::step(const std::string &stepName) 479 | { 480 | return tracker_->stepService(*this, stepName); 481 | } 482 | -------------------------------------------------------------------------------- /cpp/ServiceTracker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * ServiceTracker is a utility class for logging and timing service 22 | * calls to a fb303 Thrift server. Currently, ServiceTracker offers 23 | * the following features: 24 | * 25 | * . Logging of service method start, end (and duration), and 26 | * optional steps in between. 27 | * 28 | * . Automatic check of server status via fb303::getStatus() 29 | * with a ServiceException thrown if server not alive 30 | * (at method start). 31 | * 32 | * . A periodic logged checkpoint reporting lifetime time, lifetime 33 | * service count, and per-method statistics since the last checkpoint 34 | * time (at method finish). 35 | * 36 | * . Export of fb303 counters for lifetime and checkpoint statistics 37 | * (at method finish). 38 | * 39 | * . For TThreadPoolServers, a logged warning when all server threads 40 | * are busy (at method start). (Must call setThreadManager() after 41 | * ServiceTracker instantiation for this feature to be enabled.) 42 | * 43 | * Individual features may be enabled or disabled by arguments to the 44 | * constructor. The constructor also accepts a pointer to a logging 45 | * method -- if no pointer is passed, the tracker will log to stdout. 46 | * 47 | * ServiceTracker defines private methods for service start, finish, 48 | * and step, which are designed to be accessed by instantiating a 49 | * friend ServiceMethod object, as in the following example: 50 | * 51 | * #include 52 | * class MyServiceHandler : virtual public MyServiceIf, 53 | * public facebook::fb303::FacebookBase 54 | * { 55 | * public: 56 | * MyServiceHandler::MyServiceHandler() : mServiceTracker(this) {} 57 | * void MyServiceHandler::myServiceMethod(int userId) { 58 | * // note: Instantiating a ServiceMethod object starts a timer 59 | * // and tells the ServiceTracker to log the start. Might throw 60 | * // a ServiceException. 61 | * ServiceMethod serviceMethod(&mServiceTracker, 62 | * "myServiceMethod", 63 | * userId); 64 | * ... 65 | * // note: Calling the step method tells the ServiceTracker to 66 | * // log the step, with a time elapsed since start. 67 | * serviceMethod.step("post parsing, begin processing"); 68 | * ... 69 | * // note: When the ServiceMethod object goes out of scope, the 70 | * // ServiceTracker will log the total elapsed time of the method. 71 | * } 72 | * ... 73 | * private: 74 | * ServiceTracker mServiceTracker; 75 | * } 76 | * 77 | * The step() method call is optional; the startService() and 78 | * finishService() methods are handled by the object's constructor and 79 | * destructor. 80 | * 81 | * The ServiceTracker is (intended to be) thread-safe. 82 | * 83 | * Future: 84 | * 85 | * . Come up with something better for logging than passing a 86 | * function pointer to the constructor. 87 | * 88 | * . Add methods for tracking errors from service methods, e.g. 89 | * ServiceTracker::reportService(). 90 | */ 91 | 92 | #ifndef SERVICETRACKER_H 93 | #define SERVICETRACKER_H 94 | 95 | 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | 103 | #include "concurrency/Mutex.h" 104 | 105 | 106 | namespace apache { namespace thrift { namespace concurrency { 107 | class ThreadManager; 108 | }}} 109 | 110 | 111 | namespace facebook { namespace fb303 { 112 | 113 | 114 | class FacebookBase; 115 | class ServiceMethod; 116 | 117 | 118 | class Stopwatch 119 | { 120 | public: 121 | enum Unit { UNIT_SECONDS, UNIT_MILLISECONDS, UNIT_MICROSECONDS }; 122 | Stopwatch(); 123 | uint64_t elapsedUnits(Unit unit, std::string *label = NULL) const; 124 | void reset(); 125 | private: 126 | timeval startTime_; 127 | }; 128 | 129 | 130 | class ServiceTracker 131 | { 132 | friend class ServiceMethod; 133 | 134 | public: 135 | 136 | static uint64_t CHECKPOINT_MINIMUM_INTERVAL_SECONDS; 137 | static int LOG_LEVEL; 138 | 139 | ServiceTracker(facebook::fb303::FacebookBase *handler, 140 | void (*logMethod)(int, const std::string &) 141 | = &ServiceTracker::defaultLogMethod, 142 | bool featureCheckpoint = true, 143 | bool featureStatusCheck = true, 144 | bool featureThreadCheck = true, 145 | Stopwatch::Unit stopwatchUnit 146 | = Stopwatch::UNIT_MILLISECONDS); 147 | 148 | void setThreadManager(boost::shared_ptr threadManager); 149 | 150 | private: 151 | 152 | facebook::fb303::FacebookBase *handler_; 153 | void (*logMethod_)(int, const std::string &); 154 | boost::shared_ptr threadManager_; 155 | 156 | bool featureCheckpoint_; 157 | bool featureStatusCheck_; 158 | bool featureThreadCheck_; 159 | Stopwatch::Unit stopwatchUnit_; 160 | 161 | apache::thrift::concurrency::Mutex statisticsMutex_; 162 | time_t checkpointTime_; 163 | uint64_t checkpointServices_; 164 | uint64_t checkpointDuration_; 165 | std::map > checkpointServiceDuration_; 166 | 167 | void startService(const ServiceMethod &serviceMethod); 168 | int64_t stepService(const ServiceMethod &serviceMethod, 169 | const std::string &stepName); 170 | void finishService(const ServiceMethod &serviceMethod); 171 | void reportCheckpoint(); 172 | static void defaultLogMethod(int level, const std::string &message); 173 | }; 174 | 175 | 176 | class ServiceMethod 177 | { 178 | friend class ServiceTracker; 179 | public: 180 | ServiceMethod(ServiceTracker *tracker, 181 | const std::string &name, 182 | const std::string &signature, 183 | bool featureLogOnly = false); 184 | ServiceMethod(ServiceTracker *tracker, 185 | const std::string &name, 186 | uint64_t id, 187 | bool featureLogOnly = false); 188 | ~ServiceMethod(); 189 | uint64_t step(const std::string &stepName); 190 | private: 191 | ServiceTracker *tracker_; 192 | std::string name_; 193 | std::string signature_; 194 | bool featureLogOnly_; 195 | Stopwatch timer_; 196 | }; 197 | 198 | 199 | class ServiceException : public std::exception 200 | { 201 | public: 202 | explicit ServiceException(const std::string &message, int code = 0) 203 | : message_(message), code_(code) {} 204 | ~ServiceException() throw() {} 205 | virtual const char *what() const throw() { return message_.c_str(); } 206 | int code() const throw() { return code_; } 207 | private: 208 | std::string message_; 209 | int code_; 210 | }; 211 | 212 | 213 | }} // facebook::fb303 214 | 215 | #endif 216 | -------------------------------------------------------------------------------- /debian/README: -------------------------------------------------------------------------------- 1 | The Debian Package thrift-fb303 2 | ---------------------------- 3 | 4 | Comments regarding the Package 5 | 6 | -- goffinet Mon, 13 Apr 2009 19:32:45 -0700 7 | -------------------------------------------------------------------------------- /debian/README.Debian: -------------------------------------------------------------------------------- 1 | thrift-fb303 for Debian 2 | ----------------------- 3 | 4 | 5 | 6 | -- goffinet Mon, 13 Apr 2009 19:32:45 -0700 7 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | thrift-fb303 (0.1-4) unstable; urgency=low 2 | 3 | * Okay, it really should have been any. 4 | 5 | -- Ian Eure Mon, 14 Jun 2010 12:46:52 -0700 6 | 7 | thrift-fb303 (0.1-3) unstable; urgency=low 8 | 9 | * Architecture: all, not any. 10 | 11 | -- Ian Eure Mon, 14 Jun 2010 12:40:27 -0700 12 | 13 | thrift-fb303 (0.1-2) unstable; urgency=low 14 | 15 | * Don't install .pyc files, clean up build artifacts. 16 | 17 | -- Ian Eure Wed, 26 May 2010 09:47:45 -0700 18 | 19 | thrift-fb303 (0.1-1) unstable; urgency=low 20 | 21 | * Initial Release. 22 | 23 | -- goffinet Mon, 13 Apr 2009 19:32:45 -0700 24 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 5 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: thrift-fb303 2 | Section: misc 3 | Priority: extra 4 | Maintainer: goffinet 5 | Build-Depends: debhelper (>= 5), autotools-dev, autoconf, automake, libtool, libthrift-dev, libboost-dev, thrift-compiler, python, python-thrift 6 | Standards-Version: 3.8.4 7 | 8 | Package: thrift-fb303 9 | Architecture: any 10 | Depends: ${shlibs:Depends}, ${misc:Depends} 11 | Description: Facebook's contrib fb303 library 12 | A standard interface to monitoring, dynamic options and 13 | configuration, uptime reports, activity, etc. 14 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | This is thrift-fb303, written and maintained by goffinet 2 | on Mon, 13 Apr 2009 19:32:45 -0700. 3 | 4 | The original source can always be found at: 5 | ftp://ftp.debian.org/dists/unstable/main/source/ 6 | 7 | Copyright Holder: goffinet 8 | 9 | License: 10 | 11 | This program is free software; you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation; either version 2 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this package; if not, write to the Free Software 23 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 24 | 25 | On Debian systems, the complete text of the GNU General 26 | Public License can be found in `/usr/share/common-licenses/GPL'. 27 | -------------------------------------------------------------------------------- /debian/dirs: -------------------------------------------------------------------------------- 1 | usr/bin 2 | usr/sbin 3 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | README 2 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # Uncomment this to turn on verbose mode. 10 | #export DH_VERBOSE=1 11 | 12 | 13 | # These are used for cross-compiling and for saving the configure script 14 | # from having to guess our platform (since we know it already) 15 | DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) 16 | DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) 17 | 18 | 19 | CFLAGS = -Wall -g 20 | 21 | ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) 22 | CFLAGS += -O0 23 | else 24 | CFLAGS += -O2 25 | endif 26 | 27 | configure: configure-stamp 28 | configure-stamp: 29 | dh_testdir 30 | # Add here commands to configure the package. 31 | $(CURDIR)/bootstrap.sh 32 | $(CURDIR)/configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --with-thriftpath=/usr CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs" 33 | touch configure-stamp 34 | 35 | 36 | build: build-stamp 37 | 38 | build-stamp: configure-stamp 39 | dh_testdir 40 | 41 | # Add here commands to compile the package. 42 | $(MAKE) 43 | #docbook-to-man debian/thrift-fb303.sgml > thrift-fb303.1 44 | 45 | touch $@ 46 | 47 | clean: 48 | dh_testdir 49 | dh_testroot 50 | rm -f build-stamp 51 | 52 | # Add here commands to clean up after the build process. 53 | -$(MAKE) distclean 54 | ifneq "$(wildcard /usr/share/misc/config.sub)" "" 55 | cp -f /usr/share/misc/config.sub config.sub 56 | endif 57 | ifneq "$(wildcard /usr/share/misc/config.guess)" "" 58 | cp -f /usr/share/misc/config.guess config.guess 59 | endif 60 | 61 | 62 | dh_clean 63 | 64 | install: build 65 | dh_testdir 66 | dh_testroot 67 | dh_clean -k 68 | dh_installdirs 69 | 70 | # Add here commands to install the package into debian/thrift-fb303. 71 | $(MAKE) DESTDIR=$(CURDIR)/debian/thrift-fb303 install 72 | # Hackety hack hack 73 | find $(CURDIR)/debian/thrift-fb303 -type f -name \*pyc -exec rm {} \; 74 | 75 | 76 | # Build architecture-independent files here. 77 | binary-indep: build install 78 | # We have nothing to do by default. 79 | 80 | # Build architecture-dependent files here. 81 | binary-arch: build install 82 | dh_testdir 83 | dh_testroot 84 | dh_installchangelogs 85 | dh_installdocs 86 | dh_installexamples 87 | # dh_install 88 | # dh_installmenu 89 | # dh_installdebconf 90 | # dh_installlogrotate 91 | # dh_installemacsen 92 | # dh_installpam 93 | # dh_installmime 94 | # dh_python 95 | # dh_installinit 96 | # dh_installcron 97 | # dh_installinfo 98 | dh_installman 99 | dh_link 100 | dh_strip 101 | dh_compress 102 | dh_fixperms 103 | # dh_perl 104 | # dh_makeshlibs 105 | dh_installdeb 106 | dh_shlibdeps 107 | dh_gencontrol 108 | dh_md5sums 109 | dh_builddeb 110 | 111 | binary: binary-indep binary-arch 112 | .PHONY: build clean binary-indep binary-arch binary install configure 113 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) -------------------------------------------------------------------------------- /global_footer.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | thriftstyle : $(XBUILT_SOURCES) 21 | 22 | -------------------------------------------------------------------------------- /global_header.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | #define thrift_template 21 | # $(1) : $(2) 22 | # $$(THRIFT) $(3) $(4) $(5) $(6) $(7) $(8) $$< 23 | #endef 24 | 25 | define thrift_template 26 | XTARGET := $(shell perl -e '@val = split("\/","$(2)"); $$last = pop(@val);split("\\.",$$last);print "$(1)/"."gen-cpp/"."@_[0]"."_types.cpp\n"' ) 27 | 28 | ifneq ($$(XBUILT_SOURCES),) 29 | XBUILT_SOURCES := $$(XBUILT_SOURCES) $$(XTARGET) 30 | else 31 | XBUILT_SOURCES := $$(XTARGET) 32 | endif 33 | $$(XTARGET) : $(2) 34 | $$(THRIFT) -o $1 $3 $$< 35 | endef 36 | 37 | clean-common: 38 | rm -rf gen-* 39 | -------------------------------------------------------------------------------- /if/fb303.thrift: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /** 21 | * fb303.thrift 22 | */ 23 | 24 | namespace java com.facebook.fb303 25 | namespace cpp facebook.fb303 26 | 27 | /** 28 | * Common status reporting mechanism across all services 29 | */ 30 | enum fb_status { 31 | DEAD = 0, 32 | STARTING = 1, 33 | ALIVE = 2, 34 | STOPPING = 3, 35 | STOPPED = 4, 36 | WARNING = 5, 37 | } 38 | 39 | /** 40 | * Standard base service 41 | */ 42 | service FacebookService { 43 | 44 | /** 45 | * Returns a descriptive name of the service 46 | */ 47 | string getName(), 48 | 49 | /** 50 | * Returns the version of the service 51 | */ 52 | string getVersion(), 53 | 54 | /** 55 | * Gets the status of this service 56 | */ 57 | fb_status getStatus(), 58 | 59 | /** 60 | * User friendly description of status, such as why the service is in 61 | * the dead or warning state, or what is being started or stopped. 62 | */ 63 | string getStatusDetails(), 64 | 65 | /** 66 | * Gets the counters for this service 67 | */ 68 | map getCounters(), 69 | 70 | /** 71 | * Gets the value of a single counter 72 | */ 73 | i64 getCounter(1: string key), 74 | 75 | /** 76 | * Sets an option 77 | */ 78 | void setOption(1: string key, 2: string value), 79 | 80 | /** 81 | * Gets an option 82 | */ 83 | string getOption(1: string key), 84 | 85 | /** 86 | * Gets all options 87 | */ 88 | map getOptions(), 89 | 90 | /** 91 | * Returns a CPU profile over the given time interval (client and server 92 | * must agree on the profile format). 93 | */ 94 | string getCpuProfile(1: i32 profileDurationInSec), 95 | 96 | /** 97 | * Returns the unix time that the server has been running since 98 | */ 99 | i64 aliveSince(), 100 | 101 | /** 102 | * Tell the server to reload its configuration, reopen log files, etc 103 | */ 104 | oneway void reinitialize(), 105 | 106 | /** 107 | * Suggest a shutdown to the server 108 | */ 109 | oneway void shutdown(), 110 | 111 | } 112 | -------------------------------------------------------------------------------- /java/FacebookBase.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.facebook.fb303; 21 | 22 | import java.util.AbstractMap; 23 | import java.util.HashMap; 24 | import java.util.concurrent.ConcurrentHashMap; 25 | 26 | public abstract class FacebookBase implements FacebookService.Iface { 27 | 28 | private String name_; 29 | 30 | private long alive_; 31 | 32 | private final ConcurrentHashMap counters_ = 33 | new ConcurrentHashMap(); 34 | 35 | private final ConcurrentHashMap options_ = 36 | new ConcurrentHashMap(); 37 | 38 | protected FacebookBase(String name) { 39 | name_ = name; 40 | alive_ = System.currentTimeMillis() / 1000; 41 | } 42 | 43 | public String getName() { 44 | return name_; 45 | } 46 | 47 | public abstract int getStatus(); 48 | 49 | public String getStatusDetails() { 50 | return ""; 51 | } 52 | 53 | public void deleteCounter(String key) { 54 | counters_.remove(key); 55 | } 56 | 57 | public void resetCounter(String key) { 58 | counters_.put(key, 0L); 59 | } 60 | 61 | public long incrementCounter(String key) { 62 | long val = getCounter(key) + 1; 63 | counters_.put(key, val); 64 | return val; 65 | } 66 | 67 | public AbstractMap getCounters() { 68 | return counters_; 69 | } 70 | 71 | public long getCounter(String key) { 72 | Long val = counters_.get(key); 73 | if (val == null) { 74 | return 0; 75 | } 76 | return val.longValue(); 77 | } 78 | 79 | public void setOption(String key, String value) { 80 | options_.put(key, value); 81 | } 82 | 83 | public String getOption(String key) { 84 | return options_.get(key); 85 | } 86 | 87 | public AbstractMap getOptions() { 88 | return options_; 89 | } 90 | 91 | public long aliveSince() { 92 | return alive_; 93 | } 94 | 95 | public String getCpuProfile() { 96 | return ""; 97 | } 98 | 99 | public void reinitialize() {} 100 | 101 | public void shutdown() {} 102 | 103 | } 104 | -------------------------------------------------------------------------------- /java/build.xml: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | generating thrift fb303 files 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | Building libfb303.jar .... 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Cleaning old stuff .... 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /php/FacebookBase.php: -------------------------------------------------------------------------------- 1 | name_ = $name; 30 | } 31 | 32 | public function getName() { 33 | return $this->name_; 34 | } 35 | 36 | public function getVersion() { 37 | return ''; 38 | } 39 | 40 | public function getStatus() { 41 | return null; 42 | } 43 | 44 | public function getStatusDetails() { 45 | return ''; 46 | } 47 | 48 | public function getCounters() { 49 | return array(); 50 | } 51 | 52 | public function getCounter($key) { 53 | return null; 54 | } 55 | 56 | public function setOption($key, $value) { 57 | return; 58 | } 59 | 60 | public function getOption($key) { 61 | return ''; 62 | } 63 | 64 | public function getOptions() { 65 | return array(); 66 | } 67 | 68 | public function aliveSince() { 69 | return 0; 70 | } 71 | 72 | public function getCpuProfile($duration) { 73 | return ''; 74 | } 75 | 76 | public function getLimitedReflection() { 77 | return array(); 78 | } 79 | 80 | public function reinitialize() { 81 | return; 82 | } 83 | 84 | public function shutdown() { 85 | return; 86 | } 87 | 88 | } 89 | 90 | -------------------------------------------------------------------------------- /py/Makefile.am: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | DESTDIR ?= / 21 | EXTRA_DIST = setup.py src 22 | 23 | all: 24 | 25 | all-local: 26 | $(thrift_home)/bin/thrift --gen py $(top_srcdir)/if/fb303.thrift 27 | mv gen-py/fb303/* fb303 28 | $(PYTHON) setup.py build 29 | 30 | # We're ignoring prefix here because site-packages seems to be 31 | # the equivalent of /usr/local/lib in Python land. 32 | # Old version (can't put inline because it's not portable). 33 | #$(PYTHON) setup.py install --prefix=$(prefix) --root=$(DESTDIR) $(PYTHON_SETUPUTIL_ARGS) 34 | install-exec-hook: 35 | $(PYTHON) setup.py install --root=$(DESTDIR) --prefix=$(PY_PREFIX) $(PYTHON_SETUPUTIL_ARGS) 36 | 37 | 38 | 39 | clean: clean-local 40 | 41 | clean-local: 42 | $(RM) -r build 43 | 44 | check-local: all 45 | -------------------------------------------------------------------------------- /py/fb303/FacebookBase.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, 15 | # software distributed under the License is distributed on an 16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | # KIND, either express or implied. See the License for the 18 | # specific language governing permissions and limitations 19 | # under the License. 20 | # 21 | 22 | import time 23 | import FacebookService 24 | import thrift.reflection.limited 25 | from ttypes import fb_status 26 | 27 | class FacebookBase(FacebookService.Iface): 28 | 29 | def __init__(self, name): 30 | self.name = name 31 | self.alive = int(time.time()) 32 | self.counters = {} 33 | 34 | def getName(self, ): 35 | return self.name 36 | 37 | def getVersion(self, ): 38 | return '' 39 | 40 | def getStatus(self, ): 41 | return fb_status.ALIVE 42 | 43 | def getCounters(self): 44 | return self.counters 45 | 46 | def resetCounter(self, key): 47 | self.counters[key] = 0 48 | 49 | def getCounter(self, key): 50 | if self.counters.has_key(key): 51 | return self.counters[key] 52 | return 0 53 | 54 | def incrementCounter(self, key): 55 | self.counters[key] = self.getCounter(key) + 1 56 | 57 | def setOption(self, key, value): 58 | pass 59 | 60 | def getOption(self, key): 61 | return "" 62 | 63 | def getOptions(self): 64 | return {} 65 | 66 | def getOptions(self): 67 | return {} 68 | 69 | def aliveSince(self): 70 | return self.alive 71 | 72 | def getCpuProfile(self, duration): 73 | return "" 74 | 75 | def getLimitedReflection(self): 76 | return thrift.reflection.limited.Service() 77 | 78 | def reinitialize(self): 79 | pass 80 | 81 | def shutdown(self): 82 | pass 83 | -------------------------------------------------------------------------------- /py/fb303_scripts/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | __all__ = ['fb303_simple_mgmt'] 21 | -------------------------------------------------------------------------------- /py/fb303_scripts/fb303_simple_mgmt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # 4 | # Licensed to the Apache Software Foundation (ASF) under one 5 | # or more contributor license agreements. See the NOTICE file 6 | # distributed with this work for additional information 7 | # regarding copyright ownership. The ASF licenses this file 8 | # to you under the Apache License, Version 2.0 (the 9 | # "License"); you may not use this file except in compliance 10 | # with the License. You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, 15 | # software distributed under the License is distributed on an 16 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17 | # KIND, either express or implied. See the License for the 18 | # specific language governing permissions and limitations 19 | # under the License. 20 | # 21 | 22 | import sys, os 23 | from optparse import OptionParser 24 | 25 | from thrift.Thrift import * 26 | 27 | from thrift.transport import TSocket 28 | from thrift.transport import TTransport 29 | from thrift.protocol import TBinaryProtocol 30 | 31 | from fb303 import * 32 | from fb303.ttypes import * 33 | 34 | def service_ctrl( 35 | command, 36 | port, 37 | trans_factory = None, 38 | prot_factory = None): 39 | """ 40 | service_ctrl is a generic function to execute standard fb303 functions 41 | 42 | @param command: one of stop, start, reload, status, counters, name, alive 43 | @param port: service's port 44 | @param trans_factory: TTransportFactory to use for obtaining a TTransport. Default is 45 | TBufferedTransportFactory 46 | @param prot_factory: TProtocolFactory to use for obtaining a TProtocol. Default is 47 | TBinaryProtocolFactory 48 | """ 49 | 50 | if command in ["status"]: 51 | try: 52 | status = fb303_wrapper('status', port, trans_factory, prot_factory) 53 | status_details = fb303_wrapper('get_status_details', port, trans_factory, prot_factory) 54 | 55 | msg = fb_status_string(status) 56 | if (len(status_details)): 57 | msg += " - %s" % status_details 58 | print msg 59 | 60 | if (status == fb_status.ALIVE): 61 | return 2 62 | else: 63 | return 3 64 | except: 65 | print "Failed to get status" 66 | return 3 67 | 68 | # scalar commands 69 | if command in ["version","alive","name"]: 70 | try: 71 | result = fb303_wrapper(command, port, trans_factory, prot_factory) 72 | print result 73 | return 0 74 | except: 75 | print "failed to get ",command 76 | return 3 77 | 78 | # counters 79 | if command in ["counters"]: 80 | try: 81 | counters = fb303_wrapper('counters', port, trans_factory, prot_factory) 82 | for counter in counters: 83 | print "%s: %d" % (counter, counters[counter]) 84 | return 0 85 | except: 86 | print "failed to get counters" 87 | return 3 88 | 89 | 90 | # Only root should be able to run the following commands 91 | if os.getuid() == 0: 92 | # async commands 93 | if command in ["stop","reload"] : 94 | try: 95 | fb303_wrapper(command, port, trans_factory, prot_factory) 96 | return 0 97 | except: 98 | print "failed to tell the service to ", command 99 | return 3 100 | else: 101 | if command in ["stop","reload"]: 102 | print "root privileges are required to stop or reload the service." 103 | return 4 104 | 105 | print "The following commands are available:" 106 | for command in ["counters","name","version","alive","status"]: 107 | print "\t%s" % command 108 | print "The following commands are available for users with root privileges:" 109 | for command in ["stop","reload"]: 110 | print "\t%s" % command 111 | 112 | 113 | 114 | return 0; 115 | 116 | 117 | def fb303_wrapper(command, port, trans_factory = None, prot_factory = None): 118 | sock = TSocket.TSocket('localhost', port) 119 | 120 | # use input transport factory if provided 121 | if (trans_factory is None): 122 | trans = TTransport.TBufferedTransport(sock) 123 | else: 124 | trans = trans_factory.getTransport(sock) 125 | 126 | # use input protocol factory if provided 127 | if (prot_factory is None): 128 | prot = TBinaryProtocol.TBinaryProtocol(trans) 129 | else: 130 | prot = prot_factory.getProtocol(trans) 131 | 132 | # initialize client and open transport 133 | fb303_client = FacebookService.Client(prot, prot) 134 | trans.open() 135 | 136 | if (command == 'reload'): 137 | fb303_client.reinitialize() 138 | 139 | elif (command == 'stop'): 140 | fb303_client.shutdown() 141 | 142 | elif (command == 'status'): 143 | return fb303_client.getStatus() 144 | 145 | elif (command == 'version'): 146 | return fb303_client.getVersion() 147 | 148 | elif (command == 'get_status_details'): 149 | return fb303_client.getStatusDetails() 150 | 151 | elif (command == 'counters'): 152 | return fb303_client.getCounters() 153 | 154 | elif (command == 'name'): 155 | return fb303_client.getName() 156 | 157 | elif (command == 'alive'): 158 | return fb303_client.aliveSince() 159 | 160 | trans.close() 161 | 162 | 163 | def fb_status_string(status_enum): 164 | if (status_enum == fb_status.DEAD): 165 | return "DEAD" 166 | if (status_enum == fb_status.STARTING): 167 | return "STARTING" 168 | if (status_enum == fb_status.ALIVE): 169 | return "ALIVE" 170 | if (status_enum == fb_status.STOPPING): 171 | return "STOPPING" 172 | if (status_enum == fb_status.STOPPED): 173 | return "STOPPED" 174 | if (status_enum == fb_status.WARNING): 175 | return "WARNING" 176 | 177 | 178 | def main(): 179 | 180 | # parse command line options 181 | parser = OptionParser() 182 | commands=["stop","counters","status","reload","version","name","alive"] 183 | 184 | parser.add_option("-c", "--command", dest="command", help="execute this API", 185 | choices=commands, default="status") 186 | parser.add_option("-p","--port",dest="port",help="the service's port", 187 | default=9082) 188 | 189 | (options, args) = parser.parse_args() 190 | status = service_ctrl(options.command, options.port) 191 | sys.exit(status) 192 | 193 | 194 | if __name__ == '__main__': 195 | main() 196 | -------------------------------------------------------------------------------- /py/setup.py: -------------------------------------------------------------------------------- 1 | # 2 | # Licensed to the Apache Software Foundation (ASF) under one 3 | # or more contributor license agreements. See the NOTICE file 4 | # distributed with this work for additional information 5 | # regarding copyright ownership. The ASF licenses this file 6 | # to you under the Apache License, Version 2.0 (the 7 | # "License"); you may not use this file except in compliance 8 | # with the License. You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, 13 | # software distributed under the License is distributed on an 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | # KIND, either express or implied. See the License for the 16 | # specific language governing permissions and limitations 17 | # under the License. 18 | # 19 | 20 | from distutils.core import setup 21 | 22 | setup(name='fb303', 23 | version='1.0', 24 | packages=['fb303', 'fb303_scripts'], 25 | ) 26 | 27 | 28 | --------------------------------------------------------------------------------