Skip to content

Commit a4e4c9e

Browse files
authored
Add InfluxDB 2.x optional backend (#193)
* Add CURL to deps list * Add URL parsing * First working version * Clean up and docs
1 parent c169cc5 commit a4e4c9e

File tree

7 files changed

+178
-7
lines changed

7 files changed

+178
-7
lines changed

CMakeLists.txt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
5757
find_package(Boost REQUIRED COMPONENTS unit_test_framework program_options system filesystem)
5858
find_package(Git QUIET)
5959
find_package(ApMon MODULE)
60+
find_package(CURL MODULE)
6061
find_package(RdKafka CONFIG)
6162

6263
####################################
@@ -105,11 +106,12 @@ add_library(Monitoring SHARED
105106
src/Exceptions/MonitoringException.cxx
106107
$<$<BOOL:${ApMon_FOUND}>:src/Backends/ApMonBackend.cxx>
107108
$<$<BOOL:${RdKafka_FOUND}>:src/Transports/Kafka.cxx>
109+
$<$<BOOL:${CURL_FOUND}>:src/Transports/HTTP.cxx>
108110
)
109111

110112
target_include_directories(Monitoring
111-
PUBLIC
112-
$<INSTALL_INTERFACE:include>
113+
PUBLIC
114+
$<INSTALL_INTERFACE:include>
113115
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
114116
PRIVATE
115117
${CMAKE_CURRENT_SOURCE_DIR}/src
@@ -127,6 +129,7 @@ target_link_libraries(Monitoring
127129
pthread
128130
$<$<BOOL:${ApMon_FOUND}>:ApMon::ApMon>
129131
$<$<BOOL:${RdKafka_FOUND}>:RdKafka::rdkafka++>
132+
$<$<BOOL:${CURL_FOUND}>:CURL::libcurl>
130133
)
131134

132135
# Handle ApMon optional dependency
@@ -138,6 +141,10 @@ if(RdKafka_FOUND)
138141
message(STATUS " Compiling Kafka transport")
139142
endif()
140143

144+
if(CURL_FOUND)
145+
message(STATUS " Compiling HTTP transport/InfluxDB 2.x backend")
146+
endif()
147+
141148
# Detect operating system
142149
if (UNIX AND NOT APPLE)
143150
message(STATUS "Detected Linux: Process monitor enabled")
@@ -155,6 +162,7 @@ target_compile_definitions(Monitoring
155162
$<$<BOOL:${LINUX}>:O2_MONITORING_OS_LINUX>
156163
$<$<BOOL:${ApMon_FOUND}>:O2_MONITORING_WITH_APPMON>
157164
$<$<BOOL:${RdKafka_FOUND}>:O2_MONITORING_WITH_KAFKA>
165+
$<$<BOOL:${CURL_FOUND}>:O2_MONITORING_WITH_CURL>
158166
)
159167

160168
# Use C++17
@@ -217,7 +225,7 @@ foreach (test ${TEST_SRCS})
217225

218226
add_executable(${test_name} ${test})
219227
target_link_libraries(${test_name}
220-
PRIVATE
228+
PRIVATE
221229
Monitoring Boost::unit_test_framework Boost::filesystem
222230
)
223231
add_test(NAME ${test_name} COMMAND ${test_name})

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ See the table below to find `URI`s for supported backends:
4848
| InfluxDB | Unix socket | `influxdb-unix` | - | `info` |
4949
| InfluxDB | StdOut | `influxdb-stdout` | - | `info` |
5050
| InfluxDB | Kafka | `influxdb-kafka` | Kafka topic | `info` |
51+
| InfluxDB 2.x | HTTP | `influxdbv2` | `org=ORG&bucket=BUCKET&token=TOKEN` | `info` |
5152
| ApMon | UDP | `apmon` | - | `info` |
5253
| StdOut | - | `stdout`, `infologger` | [Prefix] | `debug` |
5354
@@ -62,7 +63,7 @@ A metric consist of 5 parameters:
6263
| Parameter name | Type | Required | Default |
6364
| -------------- |:--------------------------------:|:--------:| -----------------------:|
6465
| name | string | yes | - |
65-
| values | map&lt;string, int/double/string/uint64_t&gt; | no/1 | - |
66+
| values | map&lt;string, int/double/string/uint64_t&gt; | no/1 | - |
6667
| timestamp | time_point&lt;system_clock&gt; | no | current time |
6768
| verbosity | Enum (Debug/Info/Prod) | no | Verbosity::Info |
6869
| tags | map | no | host and process names |

src/MonitoringFactory.cxx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
#include "Transports/Kafka.h"
3737
#endif
3838

39+
#ifdef O2_MONITORING_WITH_CURL
40+
#include "Transports/HTTP.h"
41+
#endif
42+
3943
namespace o2
4044
{
4145
/// ALICE O2 Monitoring system
@@ -56,6 +60,37 @@ std::unique_ptr<Backend> getStdOut(http::url uri)
5660
}
5761
}
5862

63+
/// Extracts token from header add sets it as addition HTTP header
64+
/// http://localhost:9999/?org=YOUR_ORG&bucket=YOUR_BUCKET&token=AUTH_TOKEN
65+
/// ->
66+
/// http://localhost:9999/api/v2/write?org=YOUR_ORG&bucket=YOUR_BUCKET
67+
/// --header "Authorization: Token YOURAUTHTOKEN"
68+
std::unique_ptr<Backend> getInfluxDbv2(http::url uri)
69+
{
70+
#ifdef O2_MONITORING_WITH_CURL
71+
std::string tokenLabel = "token=";
72+
std::string path = "/api/v2/write";
73+
std::string query = uri.search;
74+
75+
auto tokenStart = query.find(tokenLabel);
76+
auto tokenEnd = query.find('&', tokenStart);
77+
if (tokenEnd == std::string::npos) {
78+
tokenEnd = query.length();
79+
}
80+
std::string token = query.substr(tokenStart + tokenLabel.length(), tokenEnd-(tokenStart + tokenLabel.length()));
81+
// make sure ampersand is removed
82+
if (tokenEnd < query.length() && query.at(tokenEnd) == '&') tokenEnd++;
83+
if (tokenStart > 0 && query.at(tokenStart-1) == '&') tokenStart--;
84+
query.erase(tokenStart, tokenEnd - tokenStart);
85+
86+
auto transport = std::make_unique<transports::HTTP>("http://" + uri.host + ':' + std::to_string(uri.port) + path + '?' + query);
87+
transport->addHeader("Authorization: Token " + token);
88+
return std::make_unique<backends::InfluxDB>(std::move(transport));
89+
#else
90+
throw std::runtime_error("HTTP transport is not enabled");
91+
#endif
92+
}
93+
5994
std::unique_ptr<Backend> getInfluxDb(http::url uri)
6095
{
6196
auto const position = uri.protocol.find_last_of('-');
@@ -129,6 +164,7 @@ std::unique_ptr<Backend> MonitoringFactory::GetBackend(std::string& url)
129164
{"influxdb-unix", getInfluxDb},
130165
{"influxdb-stdout", getInfluxDb},
131166
{"influxdb-kafka", getInfluxDb},
167+
{"influxdbv2", getInfluxDbv2},
132168
{"apmon", getApMon},
133169
{"no-op", getNoop}
134170
};

src/Transports/HTTP.cxx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
///
2+
/// \file HTTP.cxx
3+
/// \author Adam Wegrzynek <[email protected]>
4+
///
5+
6+
#include "HTTP.h"
7+
#include "../MonLogger.h"
8+
#include "../Exceptions/MonitoringException.h"
9+
#include <boost/algorithm/string.hpp>
10+
11+
namespace o2
12+
{
13+
/// ALICE O2 Monitoring system
14+
namespace monitoring
15+
{
16+
/// Monitoring transports
17+
namespace transports
18+
{
19+
20+
HTTP::HTTP(const std::string& url)
21+
{
22+
mHeaders = NULL;
23+
mCurl = curl_easy_init();
24+
curl_easy_setopt(mCurl, CURLOPT_URL, url.c_str());
25+
curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 0);
26+
curl_easy_setopt(mCurl, CURLOPT_CONNECTTIMEOUT, 10);
27+
curl_easy_setopt(mCurl, CURLOPT_TIMEOUT, 10);
28+
curl_easy_setopt(mCurl, CURLOPT_POST, 1);
29+
curl_easy_setopt(mCurl, CURLOPT_TCP_KEEPIDLE, 120L);
30+
curl_easy_setopt(mCurl, CURLOPT_TCP_KEEPINTVL, 60L);
31+
FILE *devnull = fopen("/dev/null", "w+");
32+
curl_easy_setopt(mCurl, CURLOPT_WRITEDATA, devnull);
33+
34+
MonLogger::Get() << "HTTP transport initialized (" << url << ")" << MonLogger::End();
35+
}
36+
37+
HTTP::~HTTP()
38+
{
39+
curl_slist_free_all(mHeaders);
40+
curl_easy_cleanup(mCurl);
41+
curl_global_cleanup();
42+
}
43+
44+
void HTTP::addHeader(const std::string& header)
45+
{
46+
mHeaders = curl_slist_append(mHeaders, header.c_str());
47+
curl_easy_setopt(mCurl, CURLOPT_HTTPHEADER, mHeaders);
48+
}
49+
50+
void HTTP::send(std::string&& post)
51+
{
52+
CURLcode response;
53+
long responseCode;
54+
curl_easy_setopt(mCurl, CURLOPT_POSTFIELDS, post.c_str());
55+
curl_easy_setopt(mCurl, CURLOPT_POSTFIELDSIZE, (long) post.length());
56+
response = curl_easy_perform(mCurl);
57+
curl_easy_getinfo(mCurl, CURLINFO_RESPONSE_CODE, &responseCode);
58+
if (response != CURLE_OK) {
59+
MonLogger::Get() << "HTTP Tranport " << curl_easy_strerror(response) << MonLogger::End();
60+
}
61+
if (responseCode < 200 || responseCode > 206) {
62+
MonLogger::Get() << "HTTP Transport: Response code : " << std::to_string(responseCode) << MonLogger::End();
63+
}
64+
}
65+
66+
} // namespace transports
67+
} // namespace monitoring
68+
} // namespace o2

src/Transports/HTTP.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
///
2+
/// \file HTTP.h
3+
/// \author Adam Wegrzynek <[email protected]>
4+
///
5+
6+
#ifndef ALICEO2_MONITORING_TRANSPORTS_HTTP_H
7+
#define ALICEO2_MONITORING_TRANSPORTS_HTTP_H
8+
9+
#include "TransportInterface.h"
10+
11+
#include <curl/curl.h>
12+
#include <string>
13+
14+
namespace o2
15+
{
16+
/// ALICE O2 Monitoring system
17+
namespace monitoring
18+
{
19+
/// Monitoring transports
20+
namespace transports
21+
{
22+
23+
/// \brief HTTP POST transport
24+
///
25+
/// Allows to push string formatted metrics as HTTP POST requests via cURL
26+
class HTTP : public TransportInterface
27+
{
28+
public:
29+
/// Constructor
30+
/// \param url URL of HTTP server endpoint
31+
HTTP(const std::string& url);
32+
33+
/// Destructor
34+
~HTTP();
35+
36+
/// Sends metric via HTTP POST
37+
/// \param post r-value reference string formatted metric
38+
void send(std::string&& post);
39+
40+
/// Adds custom HTTP header
41+
void addHeader(const std::string& header);
42+
private:
43+
/// CURL pointers
44+
CURL *mCurl;
45+
46+
/// HTTP headers struct
47+
struct curl_slist *mHeaders;
48+
};
49+
50+
} // namespace transports
51+
} // namespace monitoring
52+
} // namespace o2
53+
54+
#endif // ALICEO2_MONITORING_TRANSPORTS_HTTP_H

src/UriParser/UriParser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2929
namespace http
3030
{
3131
struct url {
32-
std::string protocol, user, password, host, path, search;
32+
std::string protocol, user, password, host, path, search, url;
3333
int port;
3434
};
3535

@@ -89,7 +89,7 @@ static inline url ParseHttpUrl(std::string& in)
8989
{
9090
url ret;
9191
ret.port = -1;
92-
92+
ret.url = in;
9393
ret.protocol = ExtractProtocol(in);
9494
ret.search = ExtractSearch(in);
9595
ret.path = ExtractPath(in);

test/testInfluxDb.cxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ namespace monitoring
1919
{
2020
namespace Test
2121
{
22-
2322
BOOST_AUTO_TEST_CASE(simplySendMetric)
2423
{
2524
auto monitoring = MonitoringFactory::Get("influxdb-udp://localhost:1000");
@@ -32,6 +31,11 @@ BOOST_AUTO_TEST_CASE(simplySendMetric2)
3231
monitoring->send(Metric{10, "myCrazyMetric"});
3332
}
3433

34+
BOOST_AUTO_TEST_CASE(InfluxDbv2)
35+
{
36+
auto monitoring = MonitoringFactory::Get("influxdbv2://localhost:9999?org=cern&bucket=test&token=TOKEN");
37+
}
38+
3539
} // namespace Test
3640
} // namespace monitoring
3741
} // namespace o2

0 commit comments

Comments
 (0)