These two classes do not use the same mechanism to protect the stats from mult-threaded
access. Should maybe be revisited. Recursor has an instance per pthread, don't know
about dnsdist.
RemoteLoggerInterface::Result FrameStreamLogger::queueData(const std::string& data)
{
if (!d_ioqueue || !d_iothr) {
+ ++d_permanentFailures;
return Result::OtherError;
}
uint8_t *frame = (uint8_t*)malloc(data.length());
if (!frame) {
+ ++d_queueFullDrops; // XXX separate count?
return Result::TooLarge;
}
memcpy(frame, data.c_str(), data.length());
[[nodiscard]] RemoteLoggerInterface::Result queueData(const std::string& data) override;
const std::string name() const override
{
- return "framestream";
+ return "dnstap";
}
std::string toString() const override
{
return "FrameStreamLogger to " + d_address + " (" + std::to_string(d_framesSent) + " frames sent, " + std::to_string(d_queueFullDrops) + " dropped, " + std::to_string(d_permanentFailures) + " permanent failures)";
}
+ RemoteLoggerInterface::Stats getStats() const override
+ {
+ return Stats{.d_queued = d_framesSent,
+ .d_pipeFull = d_queueFullDrops,
+ .d_otherError = d_permanentFailures,
+ .d_tooLarge = 0
+ };
+ }
+
private:
const int d_family;
RemoteLoggerInterface::Result RemoteLogger::queueData(const std::string& data)
{
+ auto runtime = d_runtime.lock();
+
if (data.size() > std::numeric_limits<uint16_t>::max()) {
+ ++runtime->d_stats.d_tooLarge;
return Result::TooLarge;
}
- auto runtime = d_runtime.lock();
-
if (!runtime->d_writer.hasRoomFor(data)) {
/* not connected, queue is full, just drop */
if (!runtime->d_socket) {
- ++d_drops;
+ ++runtime->d_stats.d_pipeFull;
return Result::PipeFull;
}
try {
/* we try to flush some data */
if (!runtime->d_writer.flush(runtime->d_socket->getHandle())) {
/* but failed, let's just drop */
- ++d_drops;
+ ++runtime->d_stats.d_pipeFull;
return Result::PipeFull;
}
/* see if we freed enough data */
if (!runtime->d_writer.hasRoomFor(data)) {
/* we didn't */
- ++d_drops;
+ ++runtime->d_stats.d_pipeFull;
return Result::PipeFull;
}
}
catch(const std::exception& e) {
// cout << "Got exception writing: "<<e.what()<<endl;
- ++d_drops;
runtime->d_socket.reset();
- return Result::PipeFull;
+ ++runtime->d_stats.d_otherError;
+ return Result::OtherError;
}
}
runtime->d_writer.write(data);
- ++d_processed;
+ ++runtime->d_stats.d_queued;
return Result::Queued;
}
enum class Result : uint8_t { Queued, PipeFull, TooLarge, OtherError };
static const std::string& toErrorString(Result r);
+
virtual ~RemoteLoggerInterface() {};
virtual Result queueData(const std::string& data) = 0;
virtual std::string toString() const = 0;
void setLogQueries(bool flag) { d_logQueries = flag; }
void setLogResponses(bool flag) { d_logResponses = flag; }
+ struct Stats
+ {
+ uint64_t d_queued{};
+ uint64_t d_pipeFull{};
+ uint64_t d_tooLarge{};
+ uint64_t d_otherError{};
+ };
+
+ virtual Stats getStats() const = 0;
+
private:
bool d_logQueries{true};
bool d_logResponses{true};
}
std::string toString() const override
{
- return d_remote.toStringWithPort() + " (" + std::to_string(d_processed) + " processed, " + std::to_string(d_drops) + " dropped)";
+ auto runtime = d_runtime.lock();
+ return d_remote.toStringWithPort() + " (" + std::to_string(runtime->d_stats.d_queued) + " processed, " + std::to_string(runtime->d_stats.d_pipeFull + runtime->d_stats.d_tooLarge + runtime->d_stats.d_otherError) + " dropped)";
}
+
+ virtual RemoteLoggerInterface::Stats getStats() const override
+ {
+ return d_runtime.lock()->d_stats;
+ }
+
void stop()
{
d_exiting = true;
{
CircularWriteBuffer d_writer;
std::unique_ptr<Socket> d_socket{nullptr};
+ RemoteLoggerInterface::Stats d_stats{};
};
ComboAddress d_remote;
- std::atomic<uint64_t> d_drops{0};
- std::atomic<uint64_t> d_processed{0};
uint16_t d_timeout;
uint8_t d_reconnectWaitTime;
std::atomic<bool> d_exiting{false};
bool d_asyncConnect{false};
- LockGuarded<RuntimeData> d_runtime;
+ mutable LockGuarded<RuntimeData> d_runtime;
std::thread d_thread;
};