Skip to content

Commit 22e2661

Browse files
committed
Provide zones and endpoints (ex local) stats via /v1/status
1 parent 3276cc9 commit 22e2661

File tree

4 files changed

+236
-0
lines changed

4 files changed

+236
-0
lines changed

lib/remote/endpoint.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
#include "remote/apilistener.hpp"
66
#include "remote/jsonrpcconnection.hpp"
77
#include "remote/zone.hpp"
8+
#include "base/perfdatavalue.hpp"
89
#include "base/configtype.hpp"
910
#include "base/utility.hpp"
1011
#include "base/exception.hpp"
1112
#include "base/convert.hpp"
13+
#include "base/statsfunction.hpp"
1214

1315
using namespace icinga;
1416

@@ -17,6 +19,8 @@ REGISTER_TYPE(Endpoint);
1719
boost::signals2::signal<void(const Endpoint::Ptr&, const JsonRpcConnection::Ptr&)> Endpoint::OnConnected;
1820
boost::signals2::signal<void(const Endpoint::Ptr&, const JsonRpcConnection::Ptr&)> Endpoint::OnDisconnected;
1921

22+
REGISTER_STATSFUNCTION(Endpoint, &Endpoint::StatsFunc);
23+
2024
void Endpoint::OnAllConfigLoaded()
2125
{
2226
ObjectImpl<Endpoint>::OnAllConfigLoaded();
@@ -101,6 +105,70 @@ Endpoint::Ptr Endpoint::GetLocalEndpoint()
101105
return listener->GetLocalEndpoint();
102106
}
103107

108+
void Endpoint::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
109+
{
110+
auto localZone (Zone::GetLocalZone());
111+
auto parentZone (localZone->GetParent());
112+
auto unorderedZones (ConfigType::GetObjectsByType<Zone>());
113+
std::set<Zone::Ptr> zones (unorderedZones.begin(), unorderedZones.end());
114+
std::set<Endpoint::Ptr> endpoints;
115+
Dictionary::Ptr ourStatus = new Dictionary;
116+
117+
unorderedZones.clear();
118+
119+
for (auto zone (zones.begin()); zone != zones.end();) {
120+
if ((*zone)->GetParent() == localZone) {
121+
++zone;
122+
} else {
123+
zones.erase(zone++);
124+
}
125+
}
126+
127+
zones.emplace(localZone);
128+
129+
if (parentZone)
130+
zones.emplace(parentZone);
131+
132+
for (auto& zone : zones) {
133+
auto zoneEndpoints (zone->GetEndpoints());
134+
endpoints.insert(zoneEndpoints.begin(), zoneEndpoints.end());
135+
}
136+
137+
endpoints.erase(GetLocalEndpoint());
138+
139+
for (auto& endpoint : endpoints) {
140+
ourStatus->Set(endpoint->GetName(), new Dictionary({
141+
{"local_log_position", endpoint->GetLocalLogPosition()},
142+
{"remote_log_position", endpoint->GetRemoteLogPosition()},
143+
{"connecting", endpoint->GetConnecting()},
144+
{"syncing", endpoint->GetSyncing()},
145+
{"connected", endpoint->GetConnected()},
146+
{"last_message_sent", endpoint->GetLastMessageSent()},
147+
{"last_message_received", endpoint->GetLastMessageReceived()},
148+
{"messages_sent_per_second", endpoint->GetMessagesSentPerSecond()},
149+
{"messages_received_per_second", endpoint->GetMessagesReceivedPerSecond()},
150+
{"bytes_sent_per_second", endpoint->GetBytesSentPerSecond()},
151+
{"bytes_received_per_second", endpoint->GetBytesReceivedPerSecond()}
152+
}));
153+
}
154+
155+
{
156+
ObjectLock ourStatusLock (ourStatus);
157+
158+
for (auto& nameEndpointStatus : ourStatus) {
159+
Dictionary::Ptr endpointStatus = nameEndpointStatus.second;
160+
ObjectLock endpointStatusLock (endpointStatus);
161+
auto labelPrefix ("endpoint_" + nameEndpointStatus.first + "_");
162+
163+
for (auto& labelValue : endpointStatus) {
164+
perfdata->Add(new PerfdataValue(labelPrefix + labelValue.first, labelValue.second));
165+
}
166+
}
167+
}
168+
169+
status->Set("endpoint", ourStatus);
170+
}
171+
104172
void Endpoint::AddMessageSent(int bytes)
105173
{
106174
double time = Utility::GetTime();

lib/remote/endpoint.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
#include "remote/i2-remote.hpp"
77
#include "remote/endpoint-ti.hpp"
8+
#include "base/array.hpp"
9+
#include "base/dictionary.hpp"
810
#include "base/ringbuffer.hpp"
911
#include <set>
1012

@@ -37,6 +39,7 @@ class Endpoint final : public ObjectImpl<Endpoint>
3739
bool GetConnected() const override;
3840

3941
static Endpoint::Ptr GetLocalEndpoint();
42+
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
4043

4144
void SetCachedZone(const intrusive_ptr<Zone>& zone);
4245

lib/remote/zone.cpp

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@
44
#include "remote/zone-ti.cpp"
55
#include "remote/jsonrpcconnection.hpp"
66
#include "base/array.hpp"
7+
#include "base/perfdatavalue.hpp"
78
#include "base/objectlock.hpp"
89
#include "base/logger.hpp"
10+
#include "base/statsfunction.hpp"
11+
#include <limits>
912

1013
using namespace icinga;
1114

1215
REGISTER_TYPE(Zone);
1316

17+
REGISTER_STATSFUNCTION(Zone, &Zone::StatsFunc);
18+
1419
void Zone::OnAllConfigLoaded()
1520
{
1621
ObjectImpl<Zone>::OnAllConfigLoaded();
@@ -141,6 +146,163 @@ Zone::Ptr Zone::GetLocalZone()
141146
return local->GetZone();
142147
}
143148

149+
static std::set<String> l_StatsFuncAggregateSum ({
150+
"messages_sent_per_second", "messages_received_per_second", "bytes_sent_per_second", "bytes_received_per_second"
151+
});
152+
153+
static std::set<String> l_StatsFuncAggregateCount ({
154+
"connecting", "syncing", "connected"
155+
});
156+
157+
static std::set<String> l_StatsFuncAggregateMin ({
158+
"last_message_sent", "last_message_received"
159+
});
160+
161+
void Zone::StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata)
162+
{
163+
auto localZone (Zone::GetLocalZone());
164+
auto parentZone (localZone->GetParent());
165+
auto unorderedZones (ConfigType::GetObjectsByType<Zone>());
166+
std::set<Zone::Ptr> zones (unorderedZones.begin(), unorderedZones.end());
167+
Dictionary::Ptr ourStatus = new Dictionary;
168+
auto localEndpoint (Endpoint::GetLocalEndpoint());
169+
170+
unorderedZones.clear();
171+
172+
for (auto zone (zones.begin()); zone != zones.end();) {
173+
if ((*zone)->GetParent() == localZone) {
174+
++zone;
175+
} else {
176+
zones.erase(zone++);
177+
}
178+
}
179+
180+
zones.emplace(localZone);
181+
182+
if (parentZone)
183+
zones.emplace(parentZone);
184+
185+
for (auto& zone : zones) {
186+
Dictionary::Ptr endpointStats = new Dictionary({
187+
{"local_log_position", new Array},
188+
{"remote_log_position", new Array},
189+
{"connecting", new Array},
190+
{"syncing", new Array},
191+
{"connected", new Array},
192+
{"last_message_sent", new Array},
193+
{"last_message_received", new Array},
194+
{"messages_sent_per_second", new Array},
195+
{"messages_received_per_second", new Array},
196+
{"bytes_sent_per_second", new Array},
197+
{"bytes_received_per_second", new Array}
198+
});
199+
200+
auto endpoints (zone->GetEndpoints());
201+
202+
endpoints.erase(localEndpoint);
203+
204+
if (endpoints.empty())
205+
continue;
206+
207+
for (auto& endpoint : endpoints) {
208+
((Array::Ptr)endpointStats->Get("local_log_position"))->Add(endpoint->GetLocalLogPosition());
209+
((Array::Ptr)endpointStats->Get("remote_log_position"))->Add(endpoint->GetRemoteLogPosition());
210+
((Array::Ptr)endpointStats->Get("connecting"))->Add(endpoint->GetConnecting());
211+
((Array::Ptr)endpointStats->Get("syncing"))->Add(endpoint->GetSyncing());
212+
((Array::Ptr)endpointStats->Get("connected"))->Add(endpoint->GetConnected());
213+
((Array::Ptr)endpointStats->Get("last_message_sent"))->Add(endpoint->GetLastMessageSent());
214+
((Array::Ptr)endpointStats->Get("last_message_received"))->Add(endpoint->GetLastMessageReceived());
215+
((Array::Ptr)endpointStats->Get("messages_sent_per_second"))->Add(endpoint->GetMessagesSentPerSecond());
216+
((Array::Ptr)endpointStats->Get("messages_received_per_second"))->Add(endpoint->GetMessagesReceivedPerSecond());
217+
((Array::Ptr)endpointStats->Get("bytes_sent_per_second"))->Add(endpoint->GetBytesSentPerSecond());
218+
((Array::Ptr)endpointStats->Get("bytes_received_per_second"))->Add(endpoint->GetBytesReceivedPerSecond());
219+
}
220+
221+
for (auto& label : l_StatsFuncAggregateSum) {
222+
auto sum (0.0);
223+
Array::Ptr values = endpointStats->Get(label);
224+
ObjectLock valuesLock (values);
225+
226+
for (auto& value : values) {
227+
sum += value.Get<double>();
228+
}
229+
230+
endpointStats->Set(label, sum);
231+
}
232+
233+
for (auto& label : l_StatsFuncAggregateCount) {
234+
uintmax_t count = 0;
235+
Array::Ptr values = endpointStats->Get(label);
236+
ObjectLock valuesLock (values);
237+
238+
for (auto& value : values) {
239+
if (value.Get<bool>()) {
240+
++count;
241+
}
242+
}
243+
244+
endpointStats->Set(label, count);
245+
}
246+
247+
for (auto& label : l_StatsFuncAggregateMin) {
248+
auto min (std::numeric_limits<double>::infinity());
249+
Array::Ptr values = endpointStats->Get(label);
250+
ObjectLock valuesLock (values);
251+
252+
for (auto& value : values) {
253+
auto number (value.Get<double>());
254+
255+
if (number < min) {
256+
min = number;
257+
}
258+
}
259+
260+
endpointStats->Set(label, min);
261+
}
262+
263+
{
264+
auto maxDiff (-std::numeric_limits<double>::infinity());
265+
Array::Ptr remoteLogPositions = endpointStats->Get("remote_log_position");
266+
ObjectLock remoteLogPositionLock (remoteLogPositions);
267+
auto remoteLogPosition (begin(remoteLogPositions));
268+
Array::Ptr localLogPositions = endpointStats->Get("local_log_position");
269+
ObjectLock localLogPositionLock (localLogPositions);
270+
271+
for (auto& localLogPosition : localLogPositions) {
272+
auto diff (localLogPosition - *remoteLogPosition);
273+
274+
if (diff > maxDiff) {
275+
maxDiff = diff;
276+
}
277+
278+
++remoteLogPosition;
279+
}
280+
281+
endpointStats->Set("client_log_lag", maxDiff);
282+
endpointStats->Remove("local_log_position");
283+
endpointStats->Remove("remote_log_position");
284+
}
285+
286+
ourStatus->Set(zone->GetName(), endpointStats);
287+
}
288+
289+
{
290+
ObjectLock ourStatusLock (ourStatus);
291+
292+
for (auto& nameZoneStatus : ourStatus) {
293+
Dictionary::Ptr zoneStatus = nameZoneStatus.second;
294+
ObjectLock zoneStatusLock (zoneStatus);
295+
auto labelPrefix ("zone_" + nameZoneStatus.first + "_");
296+
297+
for (auto& labelValue : zoneStatus) {
298+
perfdata->Add(new PerfdataValue(labelPrefix + labelValue.first, labelValue.second));
299+
}
300+
}
301+
}
302+
303+
status->Set("zone", ourStatus);
304+
}
305+
144306
void Zone::ValidateEndpointsRaw(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils)
145307
{
146308
ObjectImpl<Zone>::ValidateEndpointsRaw(lvalue, utils);

lib/remote/zone.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#ifndef ZONE_H
44
#define ZONE_H
55

6+
#include "base/array.hpp"
7+
#include "base/dictionary.hpp"
68
#include "remote/i2-remote.hpp"
79
#include "remote/zone-ti.hpp"
810
#include "remote/endpoint.hpp"
@@ -32,6 +34,7 @@ class Zone final : public ObjectImpl<Zone>
3234
bool IsSingleInstance() const;
3335

3436
static Zone::Ptr GetLocalZone();
37+
static void StatsFunc(const Dictionary::Ptr& status, const Array::Ptr& perfdata);
3538

3639
protected:
3740
void ValidateEndpointsRaw(const Lazy<Array::Ptr>& lvalue, const ValidationUtils& utils) override;

0 commit comments

Comments
 (0)