stats: deduplicate send and sendDouble logic

Additionally, let's remove the key sanitation logic since keys are
hardcoded.

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
Kittywhiskers Van Gogh 2024-09-12 16:43:39 +00:00
parent bf44fc3bf6
commit 3e12ac0e09
No known key found for this signature in database
GPG Key ID: 30CD0C065E5C4AAD
2 changed files with 28 additions and 64 deletions

View File

@ -43,26 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdio> #include <cstdio>
#include <random> #include <random>
namespace {
/** Threshold below which a value is considered effectively zero */
static constexpr float EPSILON{0.0001f};
/** Delimiter segmenting two fully formed Statsd messages */ /** Delimiter segmenting two fully formed Statsd messages */
static constexpr char STATSD_MSG_DELIMITER{'\n'}; static constexpr char STATSD_MSG_DELIMITER{'\n'};
} // anonymous namespace
std::unique_ptr<StatsdClient> g_stats_client; std::unique_ptr<StatsdClient> g_stats_client;
bool StatsdClient::ShouldSend(float sample_rate)
{
sample_rate = std::clamp(sample_rate, 0.f, 1.f);
constexpr float EPSILON{0.0001f};
/* If sample rate is 1, we should always send */
if (std::fabs(sample_rate - 1.f) < EPSILON) return true;
/* If sample rate is 0, we should never send */
if (std::fabs(sample_rate) < EPSILON) return false;
/* Sample rate is >0 and <1, roll the dice */
LOCK(cs);
return sample_rate > std::uniform_real_distribution<float>(0.f, 1.f)(insecure_rand);
}
StatsdClient::StatsdClient(const std::string& host, uint16_t port, uint64_t batch_size, uint64_t interval_ms, StatsdClient::StatsdClient(const std::string& host, uint16_t port, uint64_t batch_size, uint64_t interval_ms,
const std::string& nodename, const std::string& ns, bool enabled) : const std::string& nodename, const std::string& ns, bool enabled) :
m_nodename{nodename}, m_nodename{nodename},
@ -88,16 +78,6 @@ StatsdClient::StatsdClient(const std::string& host, uint16_t port, uint64_t batc
StatsdClient::~StatsdClient() {} StatsdClient::~StatsdClient() {}
/* will change the original string */
void StatsdClient::cleanup(std::string& key)
{
auto pos = key.find_first_of(":|@");
while (pos != std::string::npos) {
key[pos] = '_';
pos = key.find_first_of(":|@");
}
}
bool StatsdClient::dec(const std::string& key, float sample_rate) { return count(key, -1, sample_rate); } bool StatsdClient::dec(const std::string& key, float sample_rate) { return count(key, -1, sample_rate); }
bool StatsdClient::inc(const std::string& key, float sample_rate) { return count(key, 1, sample_rate); } bool StatsdClient::inc(const std::string& key, float sample_rate) { return count(key, 1, sample_rate); }
@ -122,56 +102,34 @@ bool StatsdClient::timing(const std::string& key, int64_t ms, float sample_rate)
return send(key, ms, "ms", sample_rate); return send(key, ms, "ms", sample_rate);
} }
bool StatsdClient::send(std::string key, int64_t value, const std::string& type, float sample_rate) template <typename T1>
bool StatsdClient::Send(const std::string& key, T1 value, const std::string& type, float sample_rate)
{ {
static_assert(std::is_arithmetic<T1>::value, "Must specialize to an arithmetic type");
if (!m_sender) { if (!m_sender) {
return false; return false;
} }
if (!ShouldSend(sample_rate)) { // Determine if we should send the message at all but claim that we did even if we don't
// Not our turn to send but report that we have sample_rate = std::clamp(sample_rate, 0.f, 1.f);
bool always_send = std::fabs(sample_rate - 1.f) < EPSILON;
bool never_send = std::fabs(sample_rate) < EPSILON;
if (never_send || (!always_send &&
WITH_LOCK(cs, return sample_rate < std::uniform_real_distribution<float>(0.f, 1.f)(insecure_rand)))) {
return true; return true;
} }
// partition stats by node name if set // partition stats by node name if set
if (!m_nodename.empty()) key = key + "." + m_nodename; if (!m_nodename.empty()) key = key + "." + m_nodename;
cleanup(key); // Construct the message and if our message isn't always-send, report the sample rate
RawMessage msg{strprintf("%s%s:%d|%s", m_ns, key, value, type)};
if (sample_rate < 1.f) {
msg += strprintf("|@%.2f", sample_rate);
}
if (auto error_opt = m_sender->Send(msg); error_opt.has_value()) {
LogPrintf("ERROR: %s.\n", error_opt.value());
return false;
}
return true;
}
bool StatsdClient::sendDouble(std::string key, double value, const std::string& type, float sample_rate)
{
if (!m_sender) {
return false;
}
if (!ShouldSend(sample_rate)) {
// Not our turn to send but report that we have
return true;
}
// partition stats by node name if set
if (!m_nodename.empty()) key = key + "." + m_nodename;
cleanup(key);
RawMessage msg{strprintf("%s%s:%f|%s", m_ns, key, value, type)}; RawMessage msg{strprintf("%s%s:%f|%s", m_ns, key, value, type)};
if (sample_rate < 1.f) { if (!always_send) {
msg += strprintf("|@%.2f", sample_rate); msg += strprintf("|@%.2f", sample_rate);
} }
// Send it and report an error if we encounter one
if (auto error_opt = m_sender->Send(msg); error_opt.has_value()) { if (auto error_opt = m_sender->Send(msg); error_opt.has_value()) {
LogPrintf("ERROR: %s.\n", error_opt.value()); LogPrintf("ERROR: %s.\n", error_opt.value());
return false; return false;

View File

@ -50,12 +50,18 @@ public:
/* (Low Level Api) manually send a message /* (Low Level Api) manually send a message
* type = "c", "g" or "ms" * type = "c", "g" or "ms"
*/ */
bool send(std::string key, int64_t value, const std::string& type, float sample_rate); bool send(const std::string& key, int64_t value, const std::string& type, float sample_rate = 1.f)
bool sendDouble(std::string key, double value, const std::string& type, float sample_rate); {
return Send(key, value, type, sample_rate);
}
bool sendDouble(const std::string& key, double value, const std::string& type, float sample_rate = 1.f)
{
return Send(key, value, type, sample_rate);
}
private: private:
void cleanup(std::string& key); template <typename T1>
bool ShouldSend(float sample_rate); bool Send(const std::string& key, T1 value, const std::string& type, float sample_rate);
private: private:
mutable Mutex cs; mutable Mutex cs;