Merge branch 'feature/cobra_metrics_to_statsd'

This commit is contained in:
Benjamin Sergeant 2020-06-08 18:34:18 -07:00
commit 2a1cd6bb3e
7 changed files with 195 additions and 8 deletions

View File

@ -8,6 +8,7 @@ set (IXBOTS_SOURCES
ixbots/IXCobraToSentryBot.cpp
ixbots/IXCobraToStatsdBot.cpp
ixbots/IXCobraToStdoutBot.cpp
ixbots/IXCobraMetricsToStatsdBot.cpp
ixbots/IXStatsdClient.cpp
)
@ -17,6 +18,7 @@ set (IXBOTS_HEADERS
ixbots/IXCobraToSentryBot.h
ixbots/IXCobraToStatsdBot.h
ixbots/IXCobraToStdoutBot.h
ixbots/IXCobraMetricsToStatsdBot.h
ixbots/IXStatsdClient.h
)

View File

@ -0,0 +1,127 @@
/*
* IXCobraMetricsToStatsdBot.cpp
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*/
#include "IXCobraMetricsToStatsdBot.h"
#include "IXCobraBot.h"
#include "IXStatsdClient.h"
#include <chrono>
#include <ixcobra/IXCobraConnection.h>
#include <ixcore/utils/IXCoreLogger.h>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cctype>
namespace
{
std::string removeSpaces(const std::string& str)
{
std::string out(str);
out.erase(
std::remove_if(out.begin(), out.end(), [](unsigned char x) { return std::isspace(x); }),
out.end());
return out;
}
}
namespace ix
{
bool processPerfMetricsEvent(const Json::Value& msg,
StatsdClient& statsdClient)
{
auto frameRateHistogram = msg["data"]["FrameRateHistogram"];
auto frameTimeTotal = msg["data"]["FrameTimeTotal"].asFloat();
auto gt_60 = 100 * frameRateHistogram[0].asFloat() / frameTimeTotal;
auto lt_60 = 100 * frameRateHistogram[1].asFloat() / frameTimeTotal;
auto lt_30 = 100 * frameRateHistogram[2].asFloat() / frameTimeTotal;
auto lt_20 = 100 * frameRateHistogram[3].asFloat() / frameTimeTotal;
auto lt_15 = 100 * frameRateHistogram[4].asFloat() / frameTimeTotal;
auto lt_12 = 100 * frameRateHistogram[5].asFloat() / frameTimeTotal;
auto lt_10 = 100 * frameRateHistogram[6].asFloat() / frameTimeTotal;
auto lt_08 = 100 * frameRateHistogram[7].asFloat() / frameTimeTotal;
std::stringstream ss;
ss << msg["id"].asString() << "."
<< msg["device"]["game"].asString() << "."
<< msg["device"]["os_name"].asString() << "."
<< removeSpaces(msg["data"]["Tag"].asString());
std::string id = ss.str();
statsdClient.gauge(id + ".lt_30", gt_60 + lt_60 + lt_30);
statsdClient.gauge(id + ".lt_20", lt_20);
statsdClient.gauge(id + ".lt_15", lt_15);
statsdClient.gauge(id + ".lt_12", lt_12);
statsdClient.gauge(id + ".lt_10", lt_10);
statsdClient.gauge(id + ".lt_08", lt_08);
return true;
}
bool processPerfMetricsEventSlowFrames(const Json::Value& msg,
StatsdClient& statsdClient)
{
auto frameRateHistogramCounts = msg["data"]["FrameRateHistogramCounts"];
int slowFrames = 0;
slowFrames += frameRateHistogramCounts[4].asInt();
slowFrames += frameRateHistogramCounts[5].asInt();
slowFrames += frameRateHistogramCounts[6].asInt();
slowFrames += frameRateHistogramCounts[7].asInt();
std::stringstream ss;
ss << msg["id"].asString() << "_slow_frames" << "."
<< msg["device"]["game"].asString() << "."
<< msg["device"]["os_name"].asString() << "."
<< removeSpaces(msg["data"]["Tag"].asString());
std::string id = ss.str();
statsdClient.gauge(id, slowFrames);
return true;
}
int64_t cobra_metrics_to_statsd_bot(const ix::CobraBotConfig& config,
StatsdClient& statsdClient,
bool verbose)
{
CobraBot bot;
bot.setOnBotMessageCallback(
[&statsdClient, &verbose](const Json::Value& msg,
const std::string& /*position*/,
std::atomic<bool>& /*throttled*/,
std::atomic<bool>& /*fatalCobraError*/,
std::atomic<uint64_t>& sentCount) -> void {
if (msg["device"].isNull() || msg["id"].isNull())
{
CoreLogger::info("no device or id entry, skipping event");
return;
}
//
// Display full message with
if (verbose)
{
CoreLogger::info(msg.toStyledString());
}
bool success = false;
if (msg["id"].asString() == "engine_performance_metrics_id")
{
success = processPerfMetricsEvent(msg, statsdClient);
success |= processPerfMetricsEventSlowFrames(msg, statsdClient);
}
if (success) sentCount++;
});
return bot.run(config);
}
}

View File

@ -0,0 +1,19 @@
/*
* IXCobraMetricsToStatsdBot.h
* Author: Benjamin Sergeant
* Copyright (c) 2020 Machine Zone, Inc. All rights reserved.
*/
#pragma once
#include <cstdint>
#include <ixbots/IXStatsdClient.h>
#include "IXCobraBotConfig.h"
#include <stddef.h>
#include <string>
namespace ix
{
int64_t cobra_metrics_to_statsd_bot(const ix::CobraBotConfig& config,
StatsdClient& statsdClient,
bool verbose);
} // namespace ix

View File

@ -48,11 +48,15 @@
namespace ix
{
StatsdClient::StatsdClient(const std::string& host, int port, const std::string& prefix)
StatsdClient::StatsdClient(const std::string& host,
int port,
const std::string& prefix,
bool verbose)
: _host(host)
, _port(port)
, _prefix(prefix)
, _stop(false)
, _verbose(verbose)
{
_thread = std::thread([this] {
setThreadName("Statsd");
@ -119,9 +123,14 @@ namespace ix
cleanup(key);
std::stringstream ss;
ss << _prefix << "." << key << ":" << value << "|" << type << "\n";
ss << _prefix << "." << key << ":" << value << "|" << type;
enqueue(ss.str());
if (_verbose)
{
CoreLogger::info(ss.str());
}
enqueue(ss.str() + "\n");
return 0;
}

View File

@ -20,7 +20,8 @@ namespace ix
public:
StatsdClient(const std::string& host = "127.0.0.1",
int port = 8125,
const std::string& prefix = "");
const std::string& prefix = "",
bool verbose = false);
~StatsdClient();
bool init(std::string& errMsg);
@ -52,6 +53,7 @@ namespace ix
std::mutex _mutex; // for the queue
std::deque<std::string> _queue;
bool _verbose;
};
} // end namespace ix

View File

@ -6,4 +6,4 @@
#pragma once
#define IX_WEBSOCKET_VERSION "9.6.6"
#define IX_WEBSOCKET_VERSION "9.6.8"

View File

@ -14,6 +14,7 @@
#include <ixbots/IXCobraToSentryBot.h>
#include <ixbots/IXCobraToStatsdBot.h>
#include <ixbots/IXCobraToStdoutBot.h>
#include <ixbots/IXCobraMetricsToStatsdBot.h>
#include <ixcore/utils/IXCoreLogger.h>
#include <ixsentry/IXSentryClient.h>
#include <ixwebsocket/IXNetSystem.h>
@ -326,7 +327,7 @@ int main(int argc, char** argv)
addTLSOptions(cobraMetricsPublish);
addCobraConfig(cobraMetricsPublish);
CLI::App* cobra2statsd = app.add_subcommand("cobra_to_statsd", "Cobra metrics to statsd");
CLI::App* cobra2statsd = app.add_subcommand("cobra_to_statsd", "Cobra to statsd");
cobra2statsd->fallthrough();
cobra2statsd->add_option("--host", hostname, "Statsd host");
cobra2statsd->add_option("--port", statsdPort, "Statsd port");
@ -341,7 +342,17 @@ int main(int argc, char** argv)
addTLSOptions(cobra2statsd);
addCobraBotConfig(cobra2statsd);
CLI::App* cobra2sentry = app.add_subcommand("cobra_to_sentry", "Cobra metrics to sentry");
CLI::App* cobraMetrics2statsd = app.add_subcommand("cobra_metrics_to_statsd", "Cobra metrics to statsd");
cobraMetrics2statsd->fallthrough();
cobraMetrics2statsd->add_option("--host", hostname, "Statsd host");
cobraMetrics2statsd->add_option("--port", statsdPort, "Statsd port");
cobraMetrics2statsd->add_option("--prefix", prefix, "Statsd prefix");
cobraMetrics2statsd->add_flag("-v", verbose, "Verbose");
cobraMetrics2statsd->add_option("--pidfile", pidfile, "Pid file");
addTLSOptions(cobraMetrics2statsd);
addCobraBotConfig(cobraMetrics2statsd);
CLI::App* cobra2sentry = app.add_subcommand("cobra_to_sentry", "Cobra to sentry");
cobra2sentry->fallthrough();
cobra2sentry->add_option("--dsn", dsn, "Sentry DSN");
cobra2sentry->add_flag("-v", verbose, "Verbose");
@ -552,7 +563,7 @@ int main(int argc, char** argv)
}
else
{
ix::StatsdClient statsdClient(hostname, statsdPort, prefix);
ix::StatsdClient statsdClient(hostname, statsdPort, prefix, verbose);
std::string errMsg;
bool initialized = statsdClient.init(errMsg);
@ -568,6 +579,23 @@ int main(int argc, char** argv)
}
}
}
else if (app.got_subcommand("cobra_metrics_to_statsd"))
{
ix::StatsdClient statsdClient(hostname, statsdPort, prefix, verbose);
std::string errMsg;
bool initialized = statsdClient.init(errMsg);
if (!initialized)
{
spdlog::error(errMsg);
ret = 1;
}
else
{
ret = (int) ix::cobra_metrics_to_statsd_bot(
cobraBotConfig, statsdClient, verbose);
}
}
else if (app.got_subcommand("cobra_to_sentry"))
{
ix::SentryClient sentryClient(dsn);