Skip to content

Commit

Permalink
Define debug method (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
awegrzyn authored Jul 9, 2018
1 parent 5e78256 commit 195c8fa
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ set(SRCS
src/Metric.cxx
src/Backends/InfoLoggerBackend.cxx
src/Backends/Flume.cxx
src/Backends/StdOut.cxx
src/DerivedMetrics.cxx
src/ProcessMonitor.cxx
src/ProcessDetails.cxx
Expand Down Expand Up @@ -139,6 +140,7 @@ enable_testing()

set(TEST_SRCS
test/testMonitoring.cxx
test/testMonitoringFactory.cxx
test/testDerived.cxx
test/testFlume.cxx
test/testMetric.cxx
Expand Down
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,18 @@ The library is accessible from `o2::monitoring` namespace.
```cpp
#include <MonitoringFactory.h>
using namespace o2::monitoring;
std::unique_ptr<Monitoring> monitoring = MonitoringFactory::Get("backend[-protocol]://host:port[?query]");
std::unique_ptr<Monitoring> monitoring = MonitoringFactory::Get("backend[-protocol]://host:port[/verbosity][?query]");
```
See table below to find out how to create `URI` for each backend:
| Backend name | Transport | URI backend[-protocol] | URI query |
| ------------ |:---------:|:----------------------:| ----------------:|
| InfluxDB | HTTP | `influxdb-http` | `/write?db=<db>` |
| InfluxDB | UDP | `influxdb-udp` | - |
| ApMon | UDP | `apmon` | - |
| InfoLogger | - | `infologger` | - |
| Flume | UDP | `flume` | - |
| Backend name | Transport | URI backend[-protocol] | URI query | Default verbosity |
| ------------ |:---------:|:----------------------:|:----------------:| -----------------:|
| InfluxDB | HTTP | `influxdb-http` | `/write?db=<db>` | `prod` |
| InfluxDB | UDP | `influxdb-udp` | - | `prod` |
| ApMon | UDP | `apmon` | - | `prod` |
| Local InfoLogger | - | `infologger://` | - | `debug` |
| InfoLogger | TCP | `infologger` | - | `prod` |
| Flume | UDP | `flume` | - | `prod` |
Multiple backends may be used at the same time, URLs should be separated by `,` (comma).
Expand All @@ -123,6 +124,19 @@ monitoring->send({10, "myMetricInt"});
Regarding `DerivedMetricMode` see [Calculating derived metrics](#calculating-derived-metrics).
### Debug metrics
Debug metrics can be send by a similar method to above's `send`:
```cpp
debug(Metric&& metric)
```

The difference is that debug metrics are only passed to backends which verbosity level is set to `debug`.

Each backend has its default verbosity (see backend in [Monitoring instance](#monitoring-instance) section). This can be changed by defining path of a backend URL:
- `/prod` - only `send` metrics are passed to the backend
- `/debug` - all the metrics are passed to the backend


### Customized metrics
Two additional methods can be chained the to `send(Metric&& metric)` in order to __insert custom tags__ or __set custom timestamp__:
+ `addTags(std::vector<Tag>&& tags)`
Expand Down
1 change: 1 addition & 0 deletions examples/5-Benchmark.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ int main(int argc, char *argv[]) {
monitoring->send({"string" + std::to_string(intDist(mt)), "stringMetric"});
monitoring->send({doubleDist(mt), "doubleMetric"});
monitoring->send({intDist(mt), "intMetric"});
monitoring->debug({intDist(mt), "intMetricDebug"});
std::this_thread::sleep_for(std::chrono::microseconds(sleep));
}
} else {
Expand Down
16 changes: 15 additions & 1 deletion include/Monitoring/Backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,32 @@ namespace o2
namespace monitoring
{

namespace backend
{
enum class Verbosity { PROD, DEBUG };
}
/// \brief Backend pure virtual interface
///
/// Interface that allows to send a metric to remote backend.
/// In addition, default tagset (for all handled metrics) can be created.
class Backend
{
private:
/// Verbosity level
backend::Verbosity verbosityLevel;

public:
/// Default constructor
Backend() = default;
Backend() { verbosityLevel = backend::Verbosity::PROD; }

/// Default destructor
virtual ~Backend() = default;

/// Set verbosity level
void setVerbosisty(backend::Verbosity level) { verbosityLevel = level; }

/// Get verbosity level
backend::Verbosity getVerbosity() { return verbosityLevel; }

/// Sends metric via backend
virtual void send(const Metric& metric) = 0;
Expand Down
4 changes: 2 additions & 2 deletions include/Monitoring/Monitoring.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class Monitoring
/// \param metric r-value to metric object
/// \param mode Derived metric mode
void send(Metric&& metric, DerivedMetricMode mode = DerivedMetricMode::NONE);

void debug(Metric&& metric);
/// Sends multiple (not related to each other) metrics
/// \param metrics vector of metrics
void send(std::vector<Metric>&& metrics);
Expand Down Expand Up @@ -86,7 +86,7 @@ class Monitoring

/// Enables metric buffering
/// \param size buffer size
void enableBuffering(const unsigned int size = 20);
void enableBuffering(const unsigned int size = 128);

/// Adds global tag
/// \param name tag name
Expand Down
3 changes: 3 additions & 0 deletions include/Monitoring/MonitoringFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class MonitoringFactory
private:
/// Private constructor disallows to create instance of Factory
MonitoringFactory() = default;

/// Sets backend verbosity based on the URL path
static void SetVerbosity(std::string selected, std::unique_ptr<Backend>& backend);
};

} // namespace monitoring
Expand Down
9 changes: 4 additions & 5 deletions src/Backends/InfoLoggerBackend.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ inline unsigned long InfoLoggerBackend::convertTimestamp(const std::chrono::time
).count();
}

InfoLoggerBackend::InfoLoggerBackend()
InfoLoggerBackend::InfoLoggerBackend(std::string /*host*/, int /*port*/)
{
MonLogger::Get() << "Local InfoLogger backend initialized" << MonLogger::End();
throw std::runtime_error("InfoLogger backend is not available");
}

void InfoLoggerBackend::addGlobalTag(std::string name, std::string value)
Expand Down Expand Up @@ -65,9 +65,8 @@ void InfoLoggerBackend::send(const Metric& metric)
if (!metricTags.empty()) {
metricTags = "," + metricTags;
}
MonLogger::Get() << "[METRIC] " << metric.getName() << "," << metric.getType() << " " << metric.getValue()
<< " " << convertTimestamp(metric.getTimestamp()) << " " << tagString << metricTags
<< MonLogger::End();

// Send over InfoLogger protocol
}

} // namespace backends
Expand Down
2 changes: 1 addition & 1 deletion src/Backends/InfoLoggerBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class InfoLoggerBackend final : public Backend
{
public:
/// Default constructor
InfoLoggerBackend();
InfoLoggerBackend(std::string /*host*/, int /*port*/);

/// Default destructor
~InfoLoggerBackend() = default;
Expand Down
76 changes: 76 additions & 0 deletions src/Backends/StdOut.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
///
/// \file StdOut.cxx
/// \author Adam Wegrzynek <[email protected]>
///

#include "StdOut.h"

#include <iostream>
#include "../MonLogger.h"

namespace o2
{
/// ALICE O2 Monitoring system
namespace monitoring
{
/// Monitoring backends
namespace backends
{

inline unsigned long StdOut::convertTimestamp(const std::chrono::time_point<std::chrono::system_clock>& timestamp)
{
return std::chrono::duration_cast <std::chrono::milliseconds>(
timestamp.time_since_epoch()
).count();
}

StdOut::StdOut()
{
setVerbosisty(backend::Verbosity::DEBUG);
MonLogger::Get() << "StdOut backend initialized" << MonLogger::End();
}

void StdOut::addGlobalTag(std::string name, std::string value)
{
if (!tagString.empty()) {
tagString += ",";
}
tagString += name + "=" + value;
}

void StdOut::send(std::vector<Metric>&& metrics) {
for (auto& m : metrics) {
send(m);
}
}

void StdOut::sendMultiple(std::string measurement, std::vector<Metric>&& metrics)
{
for (auto& m : metrics) {
std::string tempName = m.getName();
m.setName(measurement + "-" + m.getName());
send(m);
m.setName(tempName);
}
}

void StdOut::send(const Metric& metric)
{
std::string metricTags{};
for (const auto& tag : metric.getTags()) {
if (!metricTags.empty()) {
metricTags += ",";
}
metricTags += tag.name + "=" + tag.value;
}
if (!metricTags.empty()) {
metricTags = "," + metricTags;
}
MonLogger::Get() << "[METRIC] " << metric.getName() << "," << metric.getType() << " " << metric.getValue()
<< " " << convertTimestamp(metric.getTimestamp()) << " " << tagString << metricTags
<< MonLogger::End();
}

} // namespace backends
} // namespace monitoring
} // namespace o2
64 changes: 64 additions & 0 deletions src/Backends/StdOut.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
///
/// \file StdOut.h
/// \author Adam Wegrzynek <[email protected]>
///

#ifndef ALICEO2_MONITORING_BACKEND_STDOUT_H
#define ALICEO2_MONITORING_BACKEND_STDOUT_H

#include "Monitoring/Backend.h"
#include <string>

namespace o2
{
/// ALICE O2 Monitoring system
namespace monitoring
{
/// Monitoring backends
namespace backends
{

/// \brief Backend that injects metrics to InfoLogger
///
/// InfoLogger does not support std::chrono::time_point therefore timestamps is converted to unsigned long
class StdOut final : public Backend
{
public:
/// Default constructor
StdOut();

/// Default destructor
~StdOut() = default;

/// Sends metric to InfoLogger library
/// \param metric reference to metric object
void send(const Metric& metric) override;

/// Sends multiple metrics not related to each other
/// \@param metrics vector of metrics
void send(std::vector<Metric>&& metrics) override;

/// Sending multiple metrics is NOT supported by the InfoLogger therefore it falls back to sending metric one by one
/// \param measurement measurement name
/// \param metrics list of metrics
void sendMultiple(std::string measurement, std::vector<Metric>&& metrics) override;

/// Adds tag
/// \param name tag name
/// \param value tag value
void addGlobalTag(std::string name, std::string value) override;

private:
/// Converts timestamp to unsigned long (miliseconds from epoch)
/// \param timestamp timestamp in std::chrono::time_point format
/// \return timestamp as unsigned long (miliseconds from epoch)
unsigned long convertTimestamp(const std::chrono::time_point<std::chrono::system_clock>& timestamp);

std::string tagString; ///< Global tagset (common for each metric)
};

} // namespace backends
} // namespace monitoring
} // namespace o2

#endif // ALICEO2_MONITORING_BACKEND_STDOUT_H
9 changes: 9 additions & 0 deletions src/Monitoring.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ void Monitoring::send(std::vector<Metric>&& metrics)
}
}

void Monitoring::debug(Metric&& metric)
{
for (auto& b: mBackends) {
if (b->getVerbosity() == backend::Verbosity::DEBUG) {
b->send(metric);
}
}
}

void Monitoring::pushToBackends(Metric&& metric)
{
if (mBuffering) {
Expand Down
36 changes: 31 additions & 5 deletions src/MonitoringFactory.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "UriParser/UriParser.h"

#include "Backends/InfoLoggerBackend.h"
#include "Backends/StdOut.h"
#include "Backends/Flume.h"
#include "Backends/Noop.h"

Expand All @@ -22,14 +23,20 @@
#include "Backends/InfluxDB.h"
#endif

#include "MonLogger.h"

namespace o2
{
/// ALICE O2 Monitoring system
namespace monitoring
{

std::unique_ptr<Backend> getInfoLogger(http::url /*uri*/) {
return std::make_unique<backends::InfoLoggerBackend>();
std::unique_ptr<Backend> getInfoLogger(http::url uri) {
if (uri.host == "") {
return std::make_unique<backends::StdOut>();
} else {
return std::make_unique<backends::InfoLoggerBackend>(uri.host, uri.port);
}
}

std::unique_ptr<Backend> getInfluxDb(http::url uri) {
Expand Down Expand Up @@ -64,6 +71,21 @@ std::unique_ptr<Backend> getFlume(http::url uri) {
return std::make_unique<backends::Flume>(uri.host, uri.port);
}

void MonitoringFactory::SetVerbosity(std::string selected, std::unique_ptr<Backend>& backend) {
static const std::map<std::string, backend::Verbosity> verbosities = {
{"/prod", backend::Verbosity::PROD},
{"/debug", backend::Verbosity::DEBUG}
};

auto found = verbosities.find(selected);
if (found != verbosities.end()) {
backend->setVerbosisty(found->second);
MonLogger::Get() << "...verbosity set to "
<< static_cast<std::underlying_type<backend::Verbosity>::type>(found->second)
<< MonLogger::End();
}
}

std::unique_ptr<Backend> MonitoringFactory::GetBackend(std::string& url) {
static const std::map<std::string, std::function<std::unique_ptr<Backend>(const http::url&)>> map = {
{"infologger", getInfoLogger},
Expand All @@ -80,11 +102,15 @@ std::unique_ptr<Backend> MonitoringFactory::GetBackend(std::string& url) {
}

auto iterator = map.find(parsedUrl.protocol);
if (iterator != map.end()) {
return iterator->second(parsedUrl);
} else {
if (iterator == map.end()) {
throw std::runtime_error("Unrecognized backend " + parsedUrl.protocol);
}

auto backend = iterator->second(parsedUrl);
if (!parsedUrl.path.empty()) {
SetVerbosity(parsedUrl.path, backend);
}
return backend;
}

std::unique_ptr<Monitoring> MonitoringFactory::Get(std::string urlsString)
Expand Down
Loading

0 comments on commit 195c8fa

Please sign in to comment.