IXWebSocket/ws/ws_cobra_to_sentry.cpp

198 lines
7.1 KiB
C++
Raw Normal View History

/*
* ws_cobra_to_sentry.cpp
* Author: Benjamin Sergeant
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <ixcobra/IXCobraConnection.h>
2019-06-06 03:47:48 +02:00
#include <spdlog/spdlog.h>
#include "IXSentryClient.h"
namespace ix
{
int ws_cobra_to_sentry_main(const std::string& appkey,
const std::string& endpoint,
const std::string& rolename,
const std::string& rolesecret,
const std::string& channel,
const std::string& dsn,
bool verbose,
bool strict,
int jobs)
{
ix::CobraConnection conn;
conn.configure(appkey, endpoint,
rolename, rolesecret,
ix::WebSocketPerMessageDeflateOptions(true));
conn.connect();
Json::FastWriter jsonWriter;
std::atomic<uint64_t> sentCount(0);
std::atomic<uint64_t> receivedCount(0);
std::atomic<bool> errorSending(false);
std::atomic<bool> stop(false);
std::mutex conditionVariableMutex;
std::condition_variable condition;
std::condition_variable progressCondition;
std::queue<Json::Value> queue;
SentryClient sentryClient(dsn);
auto sentrySender = [&condition, &progressCondition, &conditionVariableMutex,
&queue, verbose, &errorSending, &sentCount,
&stop, &sentryClient]
{
while (true)
{
Json::Value msg;
{
std::unique_lock<std::mutex> lock(conditionVariableMutex);
condition.wait(lock, [&queue, &stop]{ return !queue.empty() && !stop; });
msg = queue.front();
queue.pop();
}
2019-06-06 03:47:48 +02:00
auto ret = sentryClient.send(msg, verbose);
HttpResponsePtr response = ret.first;
if (response->statusCode != 200)
{
2019-06-06 03:47:48 +02:00
spdlog::error("Error sending data to sentry: {}", response->statusCode);
spdlog::error("Response: {}", response->payload);
spdlog::error("Log: {}", ret.second);
errorSending = true;
}
else
{
++sentCount;
}
progressCondition.notify_one();
if (stop) return;
}
};
// Create a thread pool
std::cerr << "Starting " << jobs << " sentry sender jobs" << std::endl;
std::vector<std::thread> pool;
for (int i = 0; i < jobs; i++)
{
pool.push_back(std::thread(sentrySender));
}
conn.setEventCallback(
2019-04-18 05:31:34 +02:00
[&conn, &channel, &jsonWriter,
verbose, &receivedCount, &sentCount,
2019-04-18 05:31:34 +02:00
&condition, &conditionVariableMutex,
&progressCondition, &queue]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId)
{
if (eventType == ix::CobraConnection_EventType_Open)
{
2019-06-06 03:47:48 +02:00
spdlog::info("Subscriber connected");
for (auto it : headers)
{
2019-06-06 03:47:48 +02:00
spdlog::info("{}: {}", it.first, it.second);
}
}
if (eventType == ix::CobraConnection_EventType_Closed)
{
2019-06-06 03:47:48 +02:00
spdlog::info("Subscriber closed");
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
std::cerr << "Subscriber authenticated" << std::endl;
conn.subscribe(channel,
2019-04-18 05:31:34 +02:00
[&jsonWriter, verbose,
&sentCount, &receivedCount,
&condition, &conditionVariableMutex,
&progressCondition, &queue]
(const Json::Value& msg)
{
if (verbose)
{
2019-06-06 03:47:48 +02:00
spdlog::info(jsonWriter.write(msg));
}
// If we cannot send to sentry fast enough, drop the message
const uint64_t scaleFactor = 2;
if (sentCount != 0 &&
receivedCount != 0 &&
(sentCount * scaleFactor < receivedCount))
{
2019-06-06 03:47:48 +02:00
spdlog::warn("message dropped: sending is backlogged !");
condition.notify_one();
progressCondition.notify_one();
return;
}
++receivedCount;
{
std::unique_lock<std::mutex> lock(conditionVariableMutex);
queue.push(msg);
}
condition.notify_one();
progressCondition.notify_one();
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
2019-06-06 03:47:48 +02:00
spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
2019-06-06 03:47:48 +02:00
spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
2019-06-06 03:47:48 +02:00
spdlog::error("Subscriber: error {}", errMsg);
}
}
);
std::mutex progressConditionVariableMutex;
while (true)
{
std::unique_lock<std::mutex> lock(progressConditionVariableMutex);
progressCondition.wait(lock);
2019-06-06 03:47:48 +02:00
spdlog::info("messages received {} sent {}", receivedCount, sentCount);
if (strict && errorSending) break;
}
conn.disconnect();
2019-06-06 03:47:48 +02:00
// join all the bg threads and stop them.
stop = true;
for (int i = 0; i < jobs; i++)
{
spdlog::error("joining thread {}", i);
pool[i].join();
}
return 0;
}
}