mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-18 10:42:49 +00:00
The traffic topic now carries each server's rates with its split by peer (null for servers that report none), link statistics and gauges. New routes: /api/diagnostics/network, /network/server (message types and a 10 minute series) and /network/connections (remote ends grouped by address). Addresses need the new network_ips permission; without it each is a salted token. They stay in memory from the last report only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
5.6 KiB
C++
127 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <array>
|
|
#include <cstdint>
|
|
#include <deque>
|
|
#include <map>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "IServerTraffic.h"
|
|
#include "TrafficStats.h"
|
|
|
|
/**
|
|
* The traffic reports of every server, kept by the dashboard: the last hour at one second, the minutes that are not in
|
|
* the database yet, the busiest message types of the last hour and day, and totals since the dashboard started (for
|
|
* Prometheus). Pure (no database, network or clock), so it is unit tested; Traffic.cpp feeds it and writes the minutes.
|
|
*/
|
|
class TrafficHistory {
|
|
public:
|
|
static constexpr int64_t SECONDS_KEPT = 3600;
|
|
static constexpr int64_t MINUTE_SLACK = 20; // seconds a minute waits for late reports before it is final
|
|
static constexpr int64_t FORGET_AFTER = 86400; // a server silent this long is dropped
|
|
static constexpr size_t MESSAGE_MINUTES = 60; // per-minute message counts kept
|
|
static constexpr size_t MESSAGE_HOURS = 24; // per-hour message counts kept
|
|
static constexpr size_t MAX_TOTAL_MESSAGES = 256; // message types a server's totals keep
|
|
static constexpr size_t MAX_TOTAL_ROUTES = 128; // routes a server's totals keep
|
|
static constexpr size_t ROUTE_MINUTES = 60; // per-minute route stats kept
|
|
static constexpr int64_t SPLIT_SECONDS = 300; // per-second splits kept (memory only)
|
|
|
|
// One second (or a bucket of them) of one server
|
|
struct Point {
|
|
int64_t time{};
|
|
uint64_t packetsIn{}, packetsOut{}, bytesIn{}, bytesOut{};
|
|
uint64_t httpRequests{}, http4xx{}, http5xx{}, httpBytesOut{};
|
|
std::vector<std::pair<uint8_t, uint32_t>> latency; // sparse HTTP latency histogram, empty without requests
|
|
uint64_t latencySum{};
|
|
|
|
void Add(const TrafficStats::Second& second);
|
|
void Add(const Point& other);
|
|
TrafficStats::Histogram Latency() const;
|
|
};
|
|
|
|
struct Minute {
|
|
Point point;
|
|
uint64_t resends{};
|
|
};
|
|
|
|
using MessageCounts = std::map<uint64_t, TrafficStats::MessageCount>; // by MessageKey::Packed
|
|
|
|
// One second's packets split by peer, and its HTTP requests from and to other servers (the network page's links)
|
|
struct Split {
|
|
int64_t time{};
|
|
std::array<TrafficStats::PeerCounts, TrafficStats::PEER_CLASSES> peers{};
|
|
uint64_t httpRequests{}, httpBytesOut{}; // all HTTP requests answered
|
|
uint64_t httpFromServers{}, httpFromServersBytesOut{}; // of those, from other servers
|
|
uint64_t httpOutRequests{}, httpOutBytesIn{}; // made to other servers
|
|
|
|
void Add(const TrafficStats::Second& second);
|
|
void Add(const Split& other);
|
|
};
|
|
|
|
struct Totals {
|
|
uint64_t packetsIn{}, packetsOut{}, bytesIn{}, bytesOut{};
|
|
uint64_t datagramsSent{}, datagramsReceived{}, linkBytesSent{}, linkBytesReceived{}, resends{};
|
|
MessageCounts messages;
|
|
std::map<std::string, TrafficStats::RouteStats> routes;
|
|
};
|
|
|
|
struct Server {
|
|
std::string key;
|
|
uint16_t type{}; // ServiceType
|
|
uint32_t zoneId{};
|
|
uint32_t instanceId{};
|
|
int64_t firstSeen{};
|
|
int64_t lastSeen{};
|
|
std::deque<Point> seconds; // oldest first, up to SECONDS_KEPT
|
|
std::deque<Minute> minutes; // not written yet
|
|
int64_t writtenUntil{}; // minutes before this were handed out by TakeFinishedMinutes
|
|
TrafficStats::Link link; // the last report's
|
|
std::vector<std::pair<std::string, double>> gauges;
|
|
Totals totals;
|
|
std::deque<std::pair<int64_t, MessageCounts>> messageMinutes;
|
|
std::deque<std::pair<int64_t, MessageCounts>> messageHours;
|
|
std::deque<std::pair<int64_t, std::map<std::string, TrafficStats::RouteStats>>> routeMinutes;
|
|
bool peerSplit{}; // whether the last report had the split (older servers' don't)
|
|
std::deque<Split> splits; // oldest first, up to SPLIT_SECONDS
|
|
// The last report's remote ends (memory only, never written: they hold addresses)
|
|
bool hasConnections{};
|
|
std::vector<TrafficStats::Connection> connections;
|
|
TrafficStats::Connection otherConnections;
|
|
uint32_t otherConnectionCount{};
|
|
int64_t connectionsSeconds{}; // the seconds the last report covered, to make rates of them
|
|
};
|
|
|
|
// "master", "auth", "chat", "dashboard", "ugc", "world:<zone>:<instance>"
|
|
static std::string KeyFor(uint16_t serviceType, uint32_t zoneId, uint32_t instanceId);
|
|
|
|
void Ingest(uint16_t serviceType, uint32_t zoneId, uint32_t instanceId, const TrafficStats::Report& report, int64_t now);
|
|
|
|
// Minutes that are final (and not handed out before), as database rows
|
|
std::vector<IServerTraffic::TrafficMinute> TakeFinishedMinutes(int64_t now);
|
|
|
|
// Drop servers silent for FORGET_AFTER and seconds older than SECONDS_KEPT
|
|
void Forget(int64_t now);
|
|
|
|
const std::map<std::string, Server>& Servers() const { return m_Servers; }
|
|
|
|
/**
|
|
* The seconds from `from` (inclusive) to `to` (exclusive) summed into buckets of `step` seconds, per server:
|
|
* index i is the bucket starting at from + i * step. Servers with nothing in the range are left out.
|
|
*/
|
|
std::map<std::string, std::vector<Point>> Buckets(int64_t from, int64_t to, int64_t step) const;
|
|
|
|
// The busiest message types since `since` (minute counts for the last hour, hour counts before), one server or all ("")
|
|
std::vector<TrafficStats::MessageCount> TopMessages(const std::string& server, int64_t since, size_t limit) const;
|
|
|
|
// A server's seconds from `from` (inclusive) to `to` (exclusive) summed; whether any split was reported in them
|
|
bool SplitOf(const std::string& server, int64_t from, int64_t to, Split& out) const;
|
|
|
|
// The HTTP routes since `since` (the last hour at most) of every server with a web server, as (server, route); busiest first
|
|
std::vector<std::pair<std::string, TrafficStats::RouteStats>> Routes(int64_t since) const;
|
|
|
|
private:
|
|
std::map<std::string, Server> m_Servers;
|
|
};
|