diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..6636d39 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required (VERSION 3.2) +project (StatsdClient) + +set (StatsdClient_VERSION_MAJOR 1) +set (StatsdClient_VERSION_MINOR 0) + +include_directories ("${PROJECT_SOURCE_DIR}/src") +add_subdirectory (src) + +configure_file ( + "${PROJECT_SOURCE_DIR}/src/StatsdClientConfig.h.in" + "${PROJECT_BINARY_DIR}/StatsdClientConfig.h" + ) + +target_compile_features(StatsdClient PRIVATE cxx_nullptr) + +include_directories("${PROJECT_BINARY_DIR}") + +install (FILES "${PROJECT_BINARY_DIR}/StatsdClientConfig.h" + DESTINATION include) + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..8c67f93 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(StatsdClient statsd_client.cpp) + +install (TARGETS StatsdClient DESTINATION lib) +install (FILES statsd_client.h DESTINATION include) diff --git a/src/Makefile b/src/Makefile deleted file mode 100644 index bfeb08f..0000000 --- a/src/Makefile +++ /dev/null @@ -1,21 +0,0 @@ - -CXX=g++ -CPPFLAGS += -Wall -g - -TARGET = statsd_client -TARGET_LIB = lib$(TARGET).a -TARGET_HEADER = $(TARGET).h -TARGET_SOURCE = $(TARGET).cpp -TARGET_OBJ = $(TARGET).o - -all: $(TARGET_LIB) - -$(TARGET_LIB): $(TARGET_OBJ) - ar crus $@ $< - -$(TARGET_OBJ): $(TARGET_SOURCE) $(TARGET_HEADER) - $(CXX) -c -o $@ $< $(CPPFLAGS) - -clean: - rm -f $(TARGET_OBJ) $(TARGET_LIB) - diff --git a/src/StatsdClientConfig.h.in b/src/StatsdClientConfig.h.in new file mode 100644 index 0000000..37dc48d --- /dev/null +++ b/src/StatsdClientConfig.h.in @@ -0,0 +1,2 @@ +#define StatsdClient_VERSION_MAJOR @StatsdClient_VERSION_MAJOR@ +#define StatsdClient_VERSION_MINOR @StatsdClient_VERSION_MINOR@ diff --git a/src/statsd_client.cpp b/src/statsd_client.cpp index 1fbadfa..8eb3d87 100644 --- a/src/statsd_client.cpp +++ b/src/statsd_client.cpp @@ -1,15 +1,26 @@ - #include -#include #include -#include #include #include #include #include -#include +#include #include "statsd_client.h" -#include + + +/* platform-specific headers */ +#ifdef _WIN32 + #include + #include + #define CLOSE_SOCKET(s) closesocket(s) +#else + #include + #include + #include /* Needed for getaddrinfo() and freeaddrinfo() */ + #include /* Needed for close() */ + + #define CLOSE_SOCKET(s) close(s) +#endif using namespace std; namespace statsd { @@ -20,17 +31,6 @@ inline bool fequal(float a, float b) return ( fabs(a - b) < epsilon ); } -inline bool should_send(float sample_rate) -{ - if ( fequal(sample_rate, 1.0) ) - { - return true; - } - - float p = ((float)random() / RAND_MAX); - return sample_rate > p; -} - struct _StatsdClientData { int sock; struct sockaddr_in server; @@ -40,25 +40,44 @@ struct _StatsdClientData { short port; bool init; + std::default_random_engine rng_engine; + std::uniform_real_distribution<> rng_dist; + + char errmsg[1024]; }; +inline bool should_send(_StatsdClientData* d, float sample_rate) +{ + if ( fequal(sample_rate, 1.0) ) + { + return true; + } + + float p = d->rng_dist(d->rng_engine); + return sample_rate > p; +} + StatsdClient::StatsdClient(const string& host, int port, const string& ns) { d = new _StatsdClientData; + d->sock = -1; + std::random_device rd; + d->rng_engine = std::default_random_engine(rd () ); + d->rng_dist = std::uniform_real_distribution<>(0.0f, 1.0f); + config(host, port, ns); - srandom(time(NULL)); } StatsdClient::~StatsdClient() { // close socket if (d->sock >= 0) { - close(d->sock); + CLOSE_SOCKET(d->sock); d->sock = -1; delete d; - d = NULL; + d = nullptr; } } @@ -69,7 +88,7 @@ void StatsdClient::config(const string& host, int port, const string& ns) d->port = port; d->init = false; if ( d->sock >= 0 ) { - close(d->sock); + CLOSE_SOCKET(d->sock); } d->sock = -1; } @@ -88,25 +107,22 @@ int StatsdClient::init() d->server.sin_family = AF_INET; d->server.sin_port = htons(d->port); - int ret = inet_aton(d->host.c_str(), &d->server.sin_addr); - if ( ret == 0 ) - { - // host must be a domain, get it from internet - struct addrinfo hints, *result = NULL; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - - ret = getaddrinfo(d->host.c_str(), NULL, &hints, &result); - if ( ret ) { - snprintf(d->errmsg, sizeof(d->errmsg), - "getaddrinfo fail, error=%d, msg=%s", ret, gai_strerror(ret) ); - return -2; - } - struct sockaddr_in* host_addr = (struct sockaddr_in*)result->ai_addr; - memcpy(&d->server.sin_addr, &host_addr->sin_addr, sizeof(struct in_addr)); - freeaddrinfo(result); + // host must be a domain, get it from internet + struct addrinfo hints, *result = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + // looks up IPv4/IPv6 address by host name or stringized IP address + int ret = getaddrinfo(d->host.c_str(), NULL, &hints, &result); + if ( ret ) { + snprintf(d->errmsg, sizeof(d->errmsg), + "getaddrinfo fail, error=%d, msg=%s", ret, gai_strerror(ret) ); + return -2; } + struct sockaddr_in* host_addr = (struct sockaddr_in*)result->ai_addr; + memcpy(&d->server.sin_addr, &host_addr->sin_addr, sizeof(struct in_addr)); + freeaddrinfo(result); d->init = true; return 0; @@ -150,7 +166,7 @@ int StatsdClient::timing(const string& key, size_t ms, float sample_rate) int StatsdClient::send(string key, size_t value, const string &type, float sample_rate) { - if (!should_send(sample_rate)) { + if (!should_send(this->d, sample_rate)) { return 0; } diff --git a/src/statsd_client.h b/src/statsd_client.h index 9e97e83..874b023 100644 --- a/src/statsd_client.h +++ b/src/statsd_client.h @@ -2,11 +2,11 @@ #ifndef STATSD_CLIENT_H #define STATSD_CLIENT_H -#include -#include -#include +#include "../StatsdClientConfig.h" + #include + namespace statsd { struct _StatsdClientData;