Skip to content

Commit

Permalink
Prometheus naming + deduplication and use gersemi for CMake formatting (
Browse files Browse the repository at this point in the history
#325)

* allow naming of prometheus stats

* fix compile error

* fix naming

* deduplicate code

* fix issues

* move init to baseclass

* move to private

* init base variables

* add gersemi
  • Loading branch information
egecetin authored Sep 30, 2024
1 parent 6458bc2 commit 9d7c871
Show file tree
Hide file tree
Showing 13 changed files with 163 additions and 148 deletions.
5 changes: 5 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ repos:
hooks:
- id: detect-secrets
exclude: tests/data/config.json
- repo: https://github.com/BlankSpruce/gersemi
rev: 0.15.1
hooks:
- id: gersemi
args: ['--line-length', '120']
- repo: https://github.com/lovesegfault/beautysh
rev: v6.2.1
hooks:
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ file(GLOB ProjectSources
${PROJECT_SOURCE_DIR}/src/metrics/Status.cpp
${PROJECT_SOURCE_DIR}/src/telnet/TelnetServer.cpp
${PROJECT_SOURCE_DIR}/src/telnet/TelnetStats.cpp
${PROJECT_SOURCE_DIR}/src/utils/BaseServerStats.cpp
${PROJECT_SOURCE_DIR}/src/utils/ConfigParser.cpp
${PROJECT_SOURCE_DIR}/src/utils/ErrorHelpers.cpp
${PROJECT_SOURCE_DIR}/src/utils/Tracer.cpp
Expand Down
4 changes: 3 additions & 1 deletion include/telnet/TelnetServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,13 @@ class TelnetServer : public std::enable_shared_from_this<TelnetServer> {
* @param[in] listenPort Port to listen
* @param[in] promptString Prompt string for connected users
* @param[in] reg Prometheus registry for stats
* @param[in] prependName Prefix for Prometheus stats
* @return true If initialized
* @return false otherwise
*/
bool initialise(u_long listenPort, const std::shared_ptr<std::atomic_flag> &checkFlag,
std::string promptString = "", const std::shared_ptr<prometheus::Registry> &reg = nullptr);
std::string promptString = "", const std::shared_ptr<prometheus::Registry> &reg = nullptr,
const std::string &prependName = "");

/// Closes the Telnet Server
void shutdown();
Expand Down
14 changes: 6 additions & 8 deletions include/telnet/TelnetStats.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include "utils/BaseServerStats.hpp"

#include <prometheus/registry.h>

/**
Expand Down Expand Up @@ -28,18 +30,12 @@ struct TelnetServerStats {
/**
* Prometheus statistics for Telnet server
*/
class TelnetStats {
class TelnetStats : private BaseServerStats {
private:
prometheus::Family<prometheus::Info> *_infoFamily; ///< Information metric family
prometheus::Gauge *_activeConnection; ///< Number of active connections
prometheus::Counter *_refusedConnection; ///< Number of refused connections
prometheus::Counter *_totalConnection; ///< Number of total received connections
prometheus::Summary *_processingTime; ///< Value of the command processing performance
prometheus::Gauge *_maxProcessingTime; ///< Maximum value of the command processing performance
prometheus::Gauge *_minProcessingTime; ///< Minimum value of the command processing performance
prometheus::Counter *_succeededCommand; ///< Number of succeeded commands
prometheus::Counter *_failedCommand; ///< Number of failed commands
prometheus::Counter *_totalCommand; ///< Number of total received commands
prometheus::Counter *_totalUploadBytes; ///< Total uploaded bytes
prometheus::Counter *_totalDownloadBytes; ///< Total downloaded bytes
prometheus::Summary *_sessionDuration; ///< Value of the duration of sessions
Expand All @@ -51,8 +47,10 @@ class TelnetStats {
* Construct a new Telnet statistics
* @param[in] reg Prometheus registry
* @param[in] portNumber Telnet server port
* @param[in] prependName Prefix for Prometheus stats
*/
TelnetStats(const std::shared_ptr<prometheus::Registry> &reg, uint16_t portNumber);
TelnetStats(const std::shared_ptr<prometheus::Registry> &reg, uint16_t portNumber,
const std::string &prependName = "");

/**
* Updates statistics with session values
Expand Down
28 changes: 28 additions & 0 deletions include/utils/BaseServerStats.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <prometheus/registry.h>

#define QUANTILE_DEFAULTS \
prometheus::Summary::Quantiles \
{ \
{0.5, 0.1}, {0.9, 0.1}, { 0.99, 0.1 } \
}

/**
* @class BaseServerStats
* Represents the base statistics for a server.
*/
class BaseServerStats {
private:
prometheus::Summary *_processingTime{nullptr}; ///< Value of the command processing performance
prometheus::Gauge *_maxProcessingTime{nullptr}; ///< Maximum value of the command processing performance
prometheus::Gauge *_minProcessingTime{nullptr}; ///< Minimum value of the command processing performance
prometheus::Counter *_succeededCommand{nullptr}; ///< Number of succeeded commands
prometheus::Counter *_failedCommand{nullptr}; ///< Number of failed commands
prometheus::Counter *_totalCommand{nullptr}; ///< Number of total received commands

protected:
void initBaseStats(const std::shared_ptr<prometheus::Registry> &reg, const std::string &name);

void consumeBaseStats(uint64_t succeeded, uint64_t failed, double processingTime);
};
3 changes: 2 additions & 1 deletion include/zeromq/ZeroMQServer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ class ZeroMQServer : private ZeroMQ, private ZeroMQMonitor {
* @param[in] hostAddr Host address to connect. Can be anything supported by ZeroMQ reply socket
* @param[in] checkFlag Flag to check if the server is running
* @param[in] reg Prometheus registry for stats
* @param[in] prependName Prefix for Prometheus stats
*/
ZeroMQServer(const std::string &hostAddr, std::shared_ptr<std::atomic_flag> checkFlag,
const std::shared_ptr<prometheus::Registry> &reg = nullptr);
const std::shared_ptr<prometheus::Registry> &reg = nullptr, const std::string &prependName = "");

/// @brief Copy constructor
ZeroMQServer(const ZeroMQServer & /*unused*/) = delete;
Expand Down
13 changes: 5 additions & 8 deletions include/zeromq/ZeroMQStats.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include "utils/BaseServerStats.hpp"

#include <prometheus/registry.h>
#include <zmq.hpp>

Expand All @@ -17,15 +19,9 @@ struct ZeroMQServerStats {
* @class ZeroMQStats
* Represents the statistics of a ZeroMQ server.
*/
class ZeroMQStats {
class ZeroMQStats : private BaseServerStats {
private:
prometheus::Family<prometheus::Info> *_infoFamily; ///< Information metric family
prometheus::Summary *_processingTime; ///< Value of the command processing performance
prometheus::Gauge *_maxProcessingTime; ///< Maximum value of the command processing performance
prometheus::Gauge *_minProcessingTime; ///< Minimum value of the command processing performance
prometheus::Counter *_succeededCommand; ///< Number of succeeded commands
prometheus::Counter *_failedCommand; ///< Number of failed commands
prometheus::Counter *_totalCommand; ///< Number of total received commands
prometheus::Counter *_succeededCommandParts; ///< Number of received succeeded message parts
prometheus::Counter *_failedCommandParts; ///< Number of received failed message parts
prometheus::Counter *_totalCommandParts; ///< Number of received total message parts
Expand All @@ -36,8 +32,9 @@ class ZeroMQStats {
/**
* Construct a new ZeroMQStats object.
* @param[in] reg Prometheus registry.
* @param[in] prependName Prefix for Prometheus stats.
*/
explicit ZeroMQStats(const std::shared_ptr<prometheus::Registry> &reg);
explicit ZeroMQStats(const std::shared_ptr<prometheus::Registry> &reg, const std::string &prependName = "");

/**
* Updates the statistics with messages.
Expand Down
15 changes: 15 additions & 0 deletions scripts/runStaticAnalysis.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

set -e

echo "Running pre-commit checks"
pre-commit run --all-files

echo "Running clang-format"
clang-format include/**/*.hpp src/*.cpp src/**/*.cpp --verbose --dry-run --Werror

echo "Running cppcheck"
cppcheck -Iinclude/ src --verbose --enable=all --error-exitcode=1 --std=c++14 --language=c++ --suppressions-list=cppcheckSuppressions.txt --inline-suppr

echo "Running clang-tidy"
run-clang-tidy -j`nproc` -p=build -header-filter=`pwd`/include/ src/*.cpp src/**/*.cpp
5 changes: 3 additions & 2 deletions src/telnet/TelnetServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,8 @@ TelnetServer::~TelnetServer()
}

bool TelnetServer::initialise(u_long listenPort, const std::shared_ptr<std::atomic_flag> &checkFlag,
std::string promptString, const std::shared_ptr<prometheus::Registry> &reg)
std::string promptString, const std::shared_ptr<prometheus::Registry> &reg,
const std::string &prependName)
{
if (m_initialised)
{
Expand Down Expand Up @@ -616,7 +617,7 @@ bool TelnetServer::initialise(u_long listenPort, const std::shared_ptr<std::atom
// If prometheus registry is provided prepare statistics
if (reg)
{
m_stats = std::make_unique<TelnetStats>(reg, listenPort);
m_stats = std::make_unique<TelnetStats>(reg, listenPort, prependName);
}

m_shouldStop.clear();
Expand Down
83 changes: 19 additions & 64 deletions src/telnet/TelnetStats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@

#include <limits>

#define QUANTILE_DEFAULTS \
prometheus::Summary::Quantiles \
{ \
{0.5, 0.1}, {0.9, 0.1}, { 0.99, 0.1 } \
}

TelnetStats::TelnetStats(const std::shared_ptr<prometheus::Registry> &reg, uint16_t portNumber)
TelnetStats::TelnetStats(const std::shared_ptr<prometheus::Registry> &reg, uint16_t portNumber,
const std::string &prependName)
: BaseServerStats()
{
if (!reg)
{
throw std::invalid_argument("Can't init Telnet statistics. Registry is null");
}

const auto name = prependName.empty() ? "telnet_" : prependName + "_telnet_";

// Stats from base class
initBaseStats(reg, name);

// Basic information
_infoFamily = &prometheus::BuildInfo().Name("telnet").Help("Telnet server information").Register(*reg);
_infoFamily = &prometheus::BuildInfo().Name(name).Help("Telnet server information").Register(*reg);

_infoFamily->Add({{"server_port", std::to_string(portNumber)}});
_infoFamily->Add({{"init_time", date::format("%FT%TZ", date::floor<std::chrono::nanoseconds>(
Expand All @@ -31,91 +32,54 @@ TelnetStats::TelnetStats(const std::shared_ptr<prometheus::Registry> &reg, uint1

// Connection stats
_activeConnection = &prometheus::BuildGauge()
.Name("telnet_active_connections")
.Name(name + "active_connections")
.Help("Number of active connections")
.Register(*reg)
.Add({});
_refusedConnection = &prometheus::BuildCounter()
.Name("telnet_refused_connections")
.Name(name + "refused_connections")
.Help("Number of refused connections")
.Register(*reg)
.Add({});
_totalConnection = &prometheus::BuildCounter()
.Name("telnet_received_connections")
.Name(name + "received_connections")
.Help("Number of received connections")
.Register(*reg)
.Add({});

// Performance stats
_processingTime = &prometheus::BuildSummary()
.Name("telnet_processing_time")
.Help("Command processing performance")
.Register(*reg)
.Add({}, QUANTILE_DEFAULTS);
_maxProcessingTime = &prometheus::BuildGauge()
.Name("telnet_maximum_processing_time")
.Help("Maximum value of the command processing performance")
.Register(*reg)
.Add({});
_minProcessingTime = &prometheus::BuildGauge()
.Name("telnet_minimum_processing_time")
.Help("Minimum value of the command processing performance")
.Register(*reg)
.Add({});

// Command stats
_succeededCommand = &prometheus::BuildCounter()
.Name("telnet_succeeded_commands")
.Help("Number of succeeded commands")
.Register(*reg)
.Add({});
_failedCommand = &prometheus::BuildCounter()
.Name("telnet_failed_commands")
.Help("Number of failed commands")
.Register(*reg)
.Add({});
_totalCommand = &prometheus::BuildCounter()
.Name("telnet_received_commands")
.Help("Number of received commands")
.Register(*reg)
.Add({});

// Bandwidth stats
_totalUploadBytes =
&prometheus::BuildCounter().Name("telnet_uploaded_bytes").Help("Total uploaded bytes").Register(*reg).Add({});
&prometheus::BuildCounter().Name(name + "uploaded_bytes").Help("Total uploaded bytes").Register(*reg).Add({});
_totalDownloadBytes = &prometheus::BuildCounter()
.Name("telnet_downloaded_bytes")
.Name(name + "downloaded_bytes")
.Help("Total downloaded bytes")
.Register(*reg)
.Add({});

// Session durations
_sessionDuration = &prometheus::BuildSummary()
.Name("telnet_session_duration")
.Name(name + "session_duration")
.Help("Duration of sessions")
.Register(*reg)
.Add({}, QUANTILE_DEFAULTS);
_maxSessionDuration = &prometheus::BuildGauge()
.Name("telnet_maximum_session_duration")
.Name(name + "maximum_session_duration")
.Help("Maximum duration of sessions")
.Register(*reg)
.Add({});
_minSessionDuration = &prometheus::BuildGauge()
.Name("telnet_minimum_session_duration")
.Name(name + "minimum_session_duration")
.Help("Minimum duration of sessions")
.Register(*reg)
.Add({});

// Set defaults
_minProcessingTime->Set(std::numeric_limits<double>::max());
_minSessionDuration->Set(std::numeric_limits<double>::max());
}

void TelnetStats::consumeStats(const TelnetSessionStats &stat, bool sessionClosed)
{
_succeededCommand->Increment(static_cast<double>(stat.successCmdCtr));
_failedCommand->Increment(static_cast<double>(stat.failCmdCtr));
_totalCommand->Increment(static_cast<double>(stat.successCmdCtr + stat.failCmdCtr));
consumeBaseStats(stat.successCmdCtr, stat.failCmdCtr, 0);

_totalUploadBytes->Increment(static_cast<double>(stat.uploadBytes));
_totalDownloadBytes->Increment(static_cast<double>(stat.downloadBytes));
Expand Down Expand Up @@ -147,15 +111,6 @@ void TelnetStats::consumeStats(const TelnetServerStats &stat)
// Performance stats if there is an active connection
if (stat.activeConnectionCtr > 0)
{
const auto processTime = static_cast<double>((stat.processingTimeEnd - stat.processingTimeStart).count());
_processingTime->Observe(processTime);
if (processTime < _minProcessingTime->Value())
{
_minProcessingTime->Set(processTime);
}
if (processTime > _maxProcessingTime->Value())
{
_maxProcessingTime->Set(processTime);
}
consumeBaseStats(0, 0, static_cast<double>((stat.processingTimeEnd - stat.processingTimeStart).count()));
}
}
60 changes: 60 additions & 0 deletions src/utils/BaseServerStats.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include "utils/BaseServerStats.hpp"

#include <prometheus/counter.h>
#include <prometheus/summary.h>

void BaseServerStats::initBaseStats(const std::shared_ptr<prometheus::Registry> &reg, const std::string &name)
{
// Command stats
_succeededCommand = &prometheus::BuildCounter()
.Name(name + "succeeded_commands")
.Help("Number of succeeded commands")
.Register(*reg)
.Add({});
_failedCommand = &prometheus::BuildCounter()
.Name(name + "failed_commands")
.Help("Number of failed commands")
.Register(*reg)
.Add({});
_totalCommand = &prometheus::BuildCounter()
.Name(name + "received_commands")
.Help("Number of received commands")
.Register(*reg)
.Add({});

// Performance stats
_processingTime = &prometheus::BuildSummary()
.Name(name + "processing_time")
.Help("Command processing performance")
.Register(*reg)
.Add({}, QUANTILE_DEFAULTS);
_maxProcessingTime = &prometheus::BuildGauge()
.Name(name + "maximum_processing_time")
.Help("Maximum value of the command processing performance")
.Register(*reg)
.Add({});
_minProcessingTime = &prometheus::BuildGauge()
.Name(name + "minimum_processing_time")
.Help("Minimum value of the command processing performance")
.Register(*reg)
.Add({});

// Set defaults
_minProcessingTime->Set(std::numeric_limits<double>::max());
}

void BaseServerStats::consumeBaseStats(uint64_t succeeded, uint64_t failed, double processingTime)
{
// Command stats
_succeededCommand->Increment(static_cast<double>(succeeded));
_failedCommand->Increment(static_cast<double>(failed));
_totalCommand->Increment(static_cast<double>(succeeded + failed));

// Performance stats
if (processingTime > 0)
{
_processingTime->Observe(processingTime);
_maxProcessingTime->Set(std::max(_maxProcessingTime->Value(), processingTime));
_minProcessingTime->Set(std::min(_minProcessingTime->Value(), processingTime));
}
}
Loading

0 comments on commit 9d7c871

Please sign in to comment.