Skip to content

Commit c0d19aa

Browse files
authored
Merge pull request #366 from robertpaulp/backend/apmon_backend
Backhends/ApMonBackend: batch metrics and restructure payload organization
2 parents fe168bb + a1accf5 commit c0d19aa

2 files changed

Lines changed: 126 additions & 54 deletions

File tree

src/Backends/ApMonBackend.cxx

Lines changed: 115 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@
1717
#include "ApMonBackend.h"
1818
#include <iostream>
1919
#include <sstream>
20+
#include <vector>
21+
#include <map>
22+
#include <unistd.h>
23+
#include <limits.h>
24+
#include <cstdlib>
2025
#include "../MonLogger.h"
2126
#include "../Exceptions/MonitoringException.h"
2227

@@ -59,69 +64,125 @@ void ApMonBackend::addGlobalTag(std::string_view /*name*/, std::string_view valu
5964
mEntity += value;
6065
}
6166

62-
void ApMonBackend::send(const Metric& metric)
67+
std::string ApMonBackend::getNodeName()
6368
{
64-
std::string name = metric.getName();
65-
std::string entity = mEntity;
66-
for (const auto& [key, value] : metric.getTags()) {
67-
entity += ',';
68-
entity += tags::TAG_KEY[key];
69-
entity += '=';
70-
(value > 0) ? entity += tags::GetValue(value) : entity += std::to_string(0 - value);
69+
const char* env_p = std::getenv("ALIEN_PROC_ID");
70+
if (env_p) {
71+
return std::string(env_p);
7172
}
72-
if (mRunNumber != 0) entity += (",run=" + std::to_string(mRunNumber));
73-
74-
int valueSize = metric.getValuesSize();
75-
char **paramNames, **paramValues;
76-
int* valueTypes;
77-
paramNames = (char**)std::malloc(valueSize * sizeof(char*));
78-
paramValues = (char**)std::malloc(valueSize * sizeof(char*));
79-
valueTypes = (int*)std::malloc(valueSize * sizeof(int));
80-
// the scope of values must be the same as sendTimedParameters method
81-
int intValue;
82-
double doubleValue;
83-
std::string stringValue;
84-
85-
auto& values = metric.getValues();
86-
87-
for (int i = 0; i < valueSize; i++) {
88-
paramNames[i] = const_cast<char*>(values[i].first.c_str());
89-
std::visit(overloaded{
90-
[&](int value) {
91-
valueTypes[i] = XDR_INT32;
92-
intValue = value;
93-
paramValues[i] = reinterpret_cast<char*>(&intValue);
94-
},
95-
[&](double value) {
96-
valueTypes[i] = XDR_REAL64;
97-
doubleValue = value;
98-
paramValues[i] = reinterpret_cast<char*>(&doubleValue);
99-
},
100-
[&](const std::string& value) {
101-
valueTypes[i] = XDR_STRING;
102-
stringValue = value;
103-
paramValues[i] = const_cast<char*>(stringValue.c_str());
104-
},
105-
[&](uint64_t value) {
106-
valueTypes[i] = XDR_REAL64;
107-
doubleValue = static_cast<double>(value);
108-
paramValues[i] = reinterpret_cast<char*>(&doubleValue);
109-
},
110-
}, values[i].second);
73+
74+
char hostname[HOST_NAME_MAX];
75+
if (gethostname(hostname, sizeof(hostname)) == 0) {
76+
hostname[sizeof(hostname) - 1] = '\0';
77+
return std::string(hostname);
11178
}
11279

113-
mApMon->sendTimedParameters(const_cast<char*>(name.c_str()), const_cast<char*>(entity.c_str()),
114-
valueSize, paramNames, valueTypes, paramValues, convertTimestamp(metric.getTimestamp()));
80+
MonLogger::Get(Severity::Error) << "Failed to get hostname, using 'unknown'" << MonLogger::End();
81+
return "unknown";
82+
}
83+
84+
void ApMonBackend::sendBatch(const std::vector<reference_wrapper<const Metric>>& metrics)
85+
{
86+
std::string clusterName(mClusterName);
87+
std::string nodeName = getNodeName();
88+
89+
int totalValues = 0;
90+
for (const auto& metric : metrics) {
91+
totalValues += metric.get().getValuesSize();
92+
}
93+
const int totalParams = totalValues * 2;
94+
std::vector<int> intValues;
95+
std::vector<double> doubleValues;
96+
std::vector<std::string> stringValues;
97+
std::vector<char*> paramNames;
98+
std::vector<char*> paramValues;
99+
std::vector<int> valueTypes;
100+
101+
intValues.reserve(totalValues);
102+
doubleValues.reserve(totalValues);
103+
stringValues.reserve(metrics.size() * 3 + totalValues);
104+
paramNames.reserve(totalParams);
105+
paramValues.reserve(totalParams);
106+
valueTypes.reserve(totalParams);
107+
108+
for (const auto& metric : metrics) {
109+
std::string entity = mEntity;
110+
for (const auto& [key, value] : metric.get().getTags()) {
111+
entity += ',';
112+
entity += tags::TAG_KEY[key];
113+
entity += '=';
114+
(value > 0) ? entity += tags::GetValue(value) : entity += std::to_string(0 - value);
115+
}
116+
if (mRunNumber != 0) entity += (",run=" + std::to_string(mRunNumber));
117+
118+
auto& values = metric.get().getValues();
119+
const int valueSize = metric.get().getValuesSize();
120+
121+
const std::string_view metricName = metric.get().getName();
122+
stringValues.emplace_back(metricName);
123+
const char* metriNamePtr = stringValues.back().c_str();
124+
stringValues.emplace_back(std::string(metricName) + "_src");
125+
const char* metriNameSrcPtr = stringValues.back().c_str();
126+
stringValues.push_back(std::move(entity));
127+
const char* entityPtr = stringValues.back().c_str();
128+
129+
for (int i = 0; i < valueSize; ++i) {
130+
paramNames.push_back(const_cast<char*>(metriNamePtr));
131+
std::visit(overloaded{
132+
[&](int value) {
133+
valueTypes.push_back(XDR_INT32);
134+
intValues.push_back(value);
135+
paramValues.push_back(reinterpret_cast<char*>(&intValues.back()));
136+
},
137+
[&](double value) {
138+
valueTypes.push_back(XDR_REAL64);
139+
doubleValues.push_back(value);
140+
paramValues.push_back(reinterpret_cast<char*>(&doubleValues.back()));
141+
},
142+
[&](const std::string& value) {
143+
valueTypes.push_back(XDR_STRING);
144+
stringValues.push_back(value);
145+
paramValues.push_back(const_cast<char*>(stringValues.back().c_str()));
146+
},
147+
[&](uint64_t value) {
148+
valueTypes.push_back(XDR_REAL64);
149+
doubleValues.push_back(static_cast<double>(value));
150+
paramValues.push_back(reinterpret_cast<char*>(&doubleValues.back()));
151+
},
152+
}, values[i].second);
115153

116-
std::free(paramNames);
117-
std::free(paramValues);
118-
std::free(valueTypes);
154+
paramNames.push_back(const_cast<char*>(metriNameSrcPtr));
155+
valueTypes.push_back(XDR_STRING);
156+
paramValues.push_back(const_cast<char*>(entityPtr));
157+
}
158+
}
159+
160+
mApMon->sendTimedParameters(
161+
const_cast<char*>(clusterName.c_str()),
162+
const_cast<char*>(nodeName.c_str()),
163+
totalParams, paramNames.data(), valueTypes.data(), paramValues.data(),
164+
convertTimestamp(metrics[0].get().getTimestamp())
165+
);
166+
}
167+
168+
void ApMonBackend::send(const Metric& metric)
169+
{
170+
sendBatch(std::vector<std::reference_wrapper<const Metric>>{std::cref(metric)});
119171
}
120172

121173
void ApMonBackend::send(std::vector<Metric>&& metrics)
122174
{
123-
for (auto& metric : metrics) {
124-
send(metric);
175+
if (metrics.empty()) {
176+
return;
177+
}
178+
179+
std::map<int, std::vector<std::reference_wrapper<const Metric>>> metricsByTimestamp;
180+
for (const auto& metric : metrics) {
181+
metricsByTimestamp[convertTimestamp(metric.getTimestamp())].push_back(std::cref(metric));
182+
}
183+
184+
for (const auto& [timestamp, metricsGroup] : metricsByTimestamp) {
185+
sendBatch(metricsGroup);
125186
}
126187
}
127188

src/Backends/ApMonBackend.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <string>
2323
#include <chrono>
2424
#include <memory>
25+
#include <functional>
2526

2627
namespace o2
2728
{
@@ -63,13 +64,23 @@ class ApMonBackend final : public Backend
6364
void addGlobalTag(std::string_view name, std::string_view value) override;
6465

6566
private:
67+
/// Sends batch of metrics
68+
/// \param metrics vector of metrics
69+
void sendBatch(const std::vector<std::reference_wrapper<const Metric>>& metrics);
70+
6671
/// Converts timestamp to format supported by ApMonBackend
6772
/// \param timestamp timestamp in std::chrono::time_point format
6873
/// \return timestamp as integer (milliseconds from epoch)
6974
int convertTimestamp(const std::chrono::time_point<std::chrono::system_clock>& timestamp);
7075

76+
/// Gets node name
77+
/// It looks for environment variable ALIEN_PROC_ID and if it is not set, it uses hostname as node name
78+
/// \return node name as string
79+
std::string getNodeName();
80+
7181
std::unique_ptr<ApMon> mApMon; ///< ApMon object
7282
std::string mEntity; ///< MonALISA entity, created out of global tags
83+
inline static constexpr std::string_view mClusterName = "O2Monitoring_Nodes"; ///< MonALISA cluster name
7384
};
7485

7586
} // namespace backends

0 commit comments

Comments
 (0)