mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-31 14:05:33 +00:00
[#3328] Output usecs; add permon-get-all-durations
Statistics and raw data return durations in microseconds instead of milliseconds. Add initial support for perfmon-get-all-durations. /doc/sphinx/arm/hooks-perfmon.rst Updated to microseconds Updated perfmon-control command /src/hooks/dhcp/perfmon/monitored_duration.* DurationKey::toElement() MonitoredDuration::toElement() - new functions /src/hooks/dhcp/perfmon/perfmon_callouts.cc int perfmon_control() int perfmon_get_all_durations() - new functions int load() - register commands /src/hooks/dhcp/perfmon/perfmon_config.cc PerfMonConfig::parse() - replace use of copy ctor PerfMonConfig::enable_monitoring_ PerfMonConfig::stats_mgr_reporting_ - made std::atomic /src/hooks/dhcp/perfmon/perfmon_messages.mes PERFMON_CMDS_CONTROL_ERROR PERFMON_CMDS_CONTROL_OK PERFMON_CMDS_GET_ALL_DURATIONS_ERROR PERFMON_CMDS_GET_ALL_DURATIONS_OK - new messages /src/hooks/dhcp/perfmon/perfmon_mgr.cc PerfMonMgr::perfmonControlHandler() PerfMonMgr::perfmonGetAllDurationsHandler() PerfMonMgr::formatDurationDataAsElements() PerfMonMgr::formatDurationDataAsResultSet() - new functions /src/hooks/dhcp/perfmon/tests/Makefile.am Added perfmon_cmds_unittests.cc /src/hooks/dhcp/perfmon/tests/perfmon_config_unittests.cc Replaced use of copy ctor /src/hooks/dhcp/perfmon/tests/perfmon_mgr_unittests.cc Updated tests for microseconds
This commit is contained in:
committed by
Francis Dupont
parent
58cc9eb76c
commit
4889c3f9a3
@@ -145,7 +145,7 @@ duration updates for each of the above:
|
|||||||
|
|
||||||
+--------------------------------------------------------------+--------------+
|
+--------------------------------------------------------------+--------------+
|
||||||
| Global Duration Keys | Update in |
|
| Global Duration Keys | Update in |
|
||||||
| | milliseconds |
|
| | microseconds |
|
||||||
+==============================================================+==============+
|
+==============================================================+==============+
|
||||||
| DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.0 | 247 |
|
| DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.0 | 247 |
|
||||||
+--------------------------------------------------------------+--------------+
|
+--------------------------------------------------------------+--------------+
|
||||||
@@ -170,29 +170,29 @@ statistic employs the following naming convention:
|
|||||||
{subnet-id[x]}.perfmon.<query type>-<response type>.<start event>-<end event>.<value-name>
|
{subnet-id[x]}.perfmon.<query type>-<response type>.<start event>-<end event>.<value-name>
|
||||||
|
|
||||||
There is both a global and a subnet-specific value for each. Currently, the only
|
There is both a global and a subnet-specific value for each. Currently, the only
|
||||||
value reported for a given duration key is ``average-ms``; this statistic is the average time
|
value reported for a given duration key is ``averages-usecs``; this statistic is the average time
|
||||||
between the duration's event pair over the most recently completed interval. In other
|
between the duration's event pair over the most recently completed interval. In other
|
||||||
words, if during a given interval there were seven occurrences (i.e. updates) totaling
|
words, if during a given interval there were seven occurrences (i.e. updates) totaling
|
||||||
350ms, the ``average-ms`` reported would be 50ms. Continuing with the example above, the
|
3500us, the ``average-usecs`` reported would be 500us. Continuing with the example above, the
|
||||||
statistics reported are named as follows for the subnet-level values:
|
statistics reported are named as follows for the subnet-level values:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.average-ms
|
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.average-usecs
|
||||||
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.average-ms
|
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.average-usecs
|
||||||
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.average-ms
|
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.average-usecs
|
||||||
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.process_started-process_completed.average-ms
|
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.process_started-process_completed.average-usecs
|
||||||
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.composite-total_response.average-ms
|
subnet[100].perfmon.DHCPDISCOVER.DHCPOFFER.composite-total_response.average-usecs
|
||||||
|
|
||||||
and as shown for global values:
|
and as shown for global values:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
perfmon.DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.average-ms
|
perfmon.DHCPDISCOVER.DHCPOFFER.socket_received-buffer_read.average-usecs
|
||||||
perfmon.DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.average-ms
|
perfmon.DHCPDISCOVER.DHCPOFFER.buffer_read-mt_queue.average-usecs
|
||||||
perfmon.DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.average-ms
|
perfmon.DHCPDISCOVER.DHCPOFFER.mt_queued-process_started.average-usecs
|
||||||
perfmon.DHCPDISCOVER.DHCPOFFER.process_started-process_completed.average-ms
|
perfmon.DHCPDISCOVER.DHCPOFFER.process_started-process_completed.average-usecs
|
||||||
perfmon.DHCPDISCOVER.DHCPOFFER.composite-total_response.average-ms
|
perfmon.DHCPDISCOVER.DHCPOFFER.composite-total_response.average-usecs
|
||||||
|
|
||||||
The results are reported to StatsMgr, an internal Kea component that reports data as statistics
|
The results are reported to StatsMgr, an internal Kea component that reports data as statistics
|
||||||
that can be retrieved using statistics commands. They can be fetched using the commands
|
that can be retrieved using statistics commands. They can be fetched using the commands
|
||||||
@@ -225,8 +225,34 @@ The alarm-cleared INFO log looks like this:
|
|||||||
API Commands
|
API Commands
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
Commands to enable or disable monitoring, clear or alter alarms, and fetch duration data
|
.. _command-perfmon-control:
|
||||||
are anticipated but not yet supported.
|
|
||||||
|
This command can be used to enable or disable active monitoring and statistics
|
||||||
|
reporting at runtime without altering or reloading configuration.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"command": "perfmon-control"
|
||||||
|
"arguments": {
|
||||||
|
"enable-monitoring": true,
|
||||||
|
"stats-mgr-reporting": false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Regardless of the arguments (if any) are supplied, the current values of both
|
||||||
|
flags are always returned:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
{
|
||||||
|
"result": 0,
|
||||||
|
"text": "perfmon-control success",
|
||||||
|
"arguments": {
|
||||||
|
"enable-monitoring": true,
|
||||||
|
"stats-mgr-reporting": false"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.. _perfmon-configuration:
|
.. _perfmon-configuration:
|
||||||
|
|
||||||
|
@@ -11,8 +11,11 @@
|
|||||||
#include <dhcp/dhcp6.h>
|
#include <dhcp/dhcp6.h>
|
||||||
#include <exceptions/exceptions.h>
|
#include <exceptions/exceptions.h>
|
||||||
#include <monitored_duration.h>
|
#include <monitored_duration.h>
|
||||||
|
#include <util/boost_time_utils.h>
|
||||||
|
|
||||||
using namespace isc::dhcp;
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::data;
|
||||||
|
using namespace isc::util;
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
@@ -194,6 +197,17 @@ DurationKey::getStatName(const std::string& value_name) const {
|
|||||||
return (oss.str());
|
return (oss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ElementPtr
|
||||||
|
DurationKey::toElement() const {
|
||||||
|
ElementPtr element = Element::createMap();
|
||||||
|
element->set("subnet-id", Element::create(static_cast<long long>(subnet_id_)));
|
||||||
|
element->set("query-type", Element::create(getMessageTypeLabel(family_, query_type_)));
|
||||||
|
element->set("response-type", Element::create(getMessageTypeLabel(family_, response_type_)));
|
||||||
|
element->set("start-event", Element::create(start_event_label_));
|
||||||
|
element->set("stop-event", Element::create(stop_event_label_));
|
||||||
|
return (element);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
DurationKey::operator==(const DurationKey& other) const {
|
DurationKey::operator==(const DurationKey& other) const {
|
||||||
return (
|
return (
|
||||||
@@ -309,5 +323,26 @@ MonitoredDuration::clear() {
|
|||||||
previous_interval_.reset();
|
previous_interval_.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ElementPtr
|
||||||
|
MonitoredDuration::toElement() const {
|
||||||
|
ElementPtr element = Element::createMap();
|
||||||
|
element->set("duration-key", DurationKey::toElement());
|
||||||
|
if (previous_interval_) {
|
||||||
|
element->set("start-time", Element::create(ptimeToText(previous_interval_->getStartTime())));
|
||||||
|
element->set("occurrences", Element::create(static_cast<long long>(previous_interval_->getOccurrences())));
|
||||||
|
element->set("min-duration-usecs", Element::create(previous_interval_->getMinDuration().total_microseconds()));
|
||||||
|
element->set("max-duration-usecs", Element::create(previous_interval_->getMaxDuration().total_microseconds()));
|
||||||
|
element->set("total-duration-usecs", Element::create(previous_interval_->getTotalDuration().total_microseconds()));
|
||||||
|
} else {
|
||||||
|
element->set("start-time", Element::create("<none>"));
|
||||||
|
element->set("occurrences", Element::create(0));
|
||||||
|
element->set("min-duration-usecs", Element::create(0));
|
||||||
|
element->set("max-duration-usecs", Element::create(0));
|
||||||
|
element->set("total-duration-usecs", Element::create(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (element);
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace perfmon
|
} // end of namespace perfmon
|
||||||
} // end of namespace isc
|
} // end of namespace isc
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
#ifndef _MONITORED_DURATION_H
|
#ifndef _MONITORED_DURATION_H
|
||||||
#define _MONITORED_DURATION_H
|
#define _MONITORED_DURATION_H
|
||||||
|
|
||||||
|
#include <cc/data.h>
|
||||||
#include <dhcp/pkt.h>
|
#include <dhcp/pkt.h>
|
||||||
#include <dhcpsrv/subnet_id.h>
|
#include <dhcpsrv/subnet_id.h>
|
||||||
|
|
||||||
@@ -226,7 +227,7 @@ public:
|
|||||||
|
|
||||||
/// @brief Get the StatsMgr formatted compatible name.
|
/// @brief Get the StatsMgr formatted compatible name.
|
||||||
///
|
///
|
||||||
/// @param value_name name of the specific value (e.g. "average-ms", "min-duration-ms").
|
/// @param value_name name of the specific value (e.g. "average-usecs", "min-duration-usecs").
|
||||||
/// The format of the string:
|
/// The format of the string:
|
||||||
///
|
///
|
||||||
/// @code
|
/// @code
|
||||||
@@ -235,15 +236,32 @@ public:
|
|||||||
///
|
///
|
||||||
/// Examples:
|
/// Examples:
|
||||||
///
|
///
|
||||||
/// perfmon.discover-offer.socket_received-buffer_read.average-ms
|
/// perfmon.discover-offer.socket_received-buffer_read.average-usecs
|
||||||
///
|
///
|
||||||
/// subnet[9].perfmon.discover-offer.socket_received-buffer_read.average-ms
|
/// subnet[9].perfmon.discover-offer.socket_received-buffer_read.average-usecs
|
||||||
///
|
///
|
||||||
/// @endcode
|
/// @endcode
|
||||||
///
|
///
|
||||||
/// @return the statistic name.
|
/// @return the statistic name.
|
||||||
std::string getStatName(const std::string& value_name) const;
|
std::string getStatName(const std::string& value_name) const;
|
||||||
|
|
||||||
|
/// @brief Renders the the duration key as an Element.
|
||||||
|
///
|
||||||
|
/// The element will appear as follows:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "query-type": "discover",
|
||||||
|
/// "response-type": "offer",
|
||||||
|
/// "start-event": "socket_received",
|
||||||
|
/// "stop-event": "buffer_read",
|
||||||
|
/// "subnet-id": 10
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// @return Element::map containing the duration key values.
|
||||||
|
virtual data::ElementPtr toElement() const;
|
||||||
|
|
||||||
/// @brief Validates that a query and response message type pair is sane.
|
/// @brief Validates that a query and response message type pair is sane.
|
||||||
///
|
///
|
||||||
/// @param family Protocol family of the key (AF_INET or AF_INET6)
|
/// @param family Protocol family of the key (AF_INET or AF_INET6)
|
||||||
@@ -379,6 +397,49 @@ public:
|
|||||||
/// @brief Deletes the current and previous intervals.
|
/// @brief Deletes the current and previous intervals.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
/// @brief Renders the the duration as an Element.
|
||||||
|
///
|
||||||
|
/// The element includes the duration key and the previous interval
|
||||||
|
/// content(if one) as follows:
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "duration-key": {
|
||||||
|
/// "query-type": "discover",
|
||||||
|
/// "response-type": "offer",
|
||||||
|
/// "start-event": "socket_received",
|
||||||
|
/// "stop-event": "buffer_read",
|
||||||
|
/// "subnet-id": 10
|
||||||
|
/// },
|
||||||
|
/// "start-time": "2024-01-18 10:11:19.498739",
|
||||||
|
/// "occurrences": 105,
|
||||||
|
/// "min-duration-usecs": 5300,
|
||||||
|
/// "max-duration-usecs": 9000,
|
||||||
|
/// "total-duration-usecs": 786500
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// If there is no previous interval, it will appears as follows:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "duration-key": {
|
||||||
|
/// "query-type": "discover",
|
||||||
|
/// "response-type": "offer",
|
||||||
|
/// "start-event": "socket_received",
|
||||||
|
/// "stop-event": "buffer_read",
|
||||||
|
/// "subnet-id": 10
|
||||||
|
/// },
|
||||||
|
/// "start-time": "<none>",
|
||||||
|
/// "occurrences": 0,
|
||||||
|
/// "min-duration-usecs": 0,
|
||||||
|
/// "max-duration-usecs": 0,
|
||||||
|
/// "total-duration-usecs": 0
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// @return Element::map containing the duration key values.
|
||||||
|
virtual data::ElementPtr toElement() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// @brief Length of the time of a single data interval.
|
/// @brief Length of the time of a single data interval.
|
||||||
Duration interval_duration_;
|
Duration interval_duration_;
|
||||||
|
@@ -115,6 +115,26 @@ int pkt6_send(CalloutHandle& handle) {
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief This is a command callout for 'perfmon-control' command.
|
||||||
|
///
|
||||||
|
/// @param handle Callout handle used to retrieve a command and
|
||||||
|
/// provide a response.
|
||||||
|
/// @return 0 if this callout has been invoked successfully,
|
||||||
|
/// 1 otherwise.
|
||||||
|
int perfmon_control(CalloutHandle& handle) {
|
||||||
|
return (mgr->perfmonControlHandler(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief This is a command callout for 'perfmon-get-all-durations' command.
|
||||||
|
///
|
||||||
|
/// @param handle Callout handle used to retrieve a command and
|
||||||
|
/// provide a response.
|
||||||
|
/// @return 0 if this callout has been invoked successfully,
|
||||||
|
/// 1 otherwise.
|
||||||
|
int perfmon_get_all_durations(CalloutHandle& handle) {
|
||||||
|
return (mgr->perfmonGetAllDurationsHandler(handle));
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief This function is called when the library is loaded.
|
/// @brief This function is called when the library is loaded.
|
||||||
///
|
///
|
||||||
/// @param handle library handle
|
/// @param handle library handle
|
||||||
@@ -141,8 +161,9 @@ int load(LibraryHandle& handle) {
|
|||||||
ConstElementPtr json = handle.getParameters();
|
ConstElementPtr json = handle.getParameters();
|
||||||
mgr->configure(json);
|
mgr->configure(json);
|
||||||
|
|
||||||
/// @todo register commands
|
/// Register commands.
|
||||||
/// handle.registerCommandCallout("command-here", handler_here);
|
handle.registerCommandCallout("perfmon-control", perfmon_control);
|
||||||
|
handle.registerCommandCallout("perfmon-get-all-durations", perfmon_get_all_durations);
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
LOG_ERROR(perfmon_logger, PERFMON_INIT_FAILED)
|
LOG_ERROR(perfmon_logger, PERFMON_INIT_FAILED)
|
||||||
.arg(ex.what());
|
.arg(ex.what());
|
||||||
|
@@ -324,8 +324,13 @@ PerfMonConfig::parse(data::ConstElementPtr config) {
|
|||||||
local.parseAlarms(elem);
|
local.parseAlarms(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
// All values good, shallow copy from local instance.
|
// All values good, copy them from local instance.
|
||||||
*this = local;
|
family_= local.getFamily();
|
||||||
|
enable_monitoring_ = local.getEnableMonitoring();
|
||||||
|
interval_width_secs_ = local.getIntervalWidthSecs();
|
||||||
|
stats_mgr_reporting_ = local.getStatsMgrReporting();
|
||||||
|
alarm_report_secs_ = local.getAlarmReportSecs();
|
||||||
|
alarm_store_= local.getAlarmStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
#include <alarm_store.h>
|
#include <alarm_store.h>
|
||||||
#include <monitored_duration.h>
|
#include <monitored_duration.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
namespace isc {
|
namespace isc {
|
||||||
namespace perfmon {
|
namespace perfmon {
|
||||||
|
|
||||||
@@ -238,7 +240,7 @@ protected:
|
|||||||
/// true. If false the library loads and configures but does nothing.
|
/// true. If false the library loads and configures but does nothing.
|
||||||
/// Gives users a way to keep the library loaded without it being active.
|
/// Gives users a way to keep the library loaded without it being active.
|
||||||
/// Should be accessible via explicit API command.
|
/// Should be accessible via explicit API command.
|
||||||
bool enable_monitoring_;
|
std::atomic<bool> enable_monitoring_;
|
||||||
|
|
||||||
/// @brief Number of seconds a duration accumulates samples until reporting.
|
/// @brief Number of seconds a duration accumulates samples until reporting.
|
||||||
/// Defaults to 60.
|
/// Defaults to 60.
|
||||||
@@ -246,7 +248,7 @@ protected:
|
|||||||
|
|
||||||
/// @brief If true durations report to StatsMgr at the end of each interval.
|
/// @brief If true durations report to StatsMgr at the end of each interval.
|
||||||
/// Defaults to true.
|
/// Defaults to true.
|
||||||
bool stats_mgr_reporting_;
|
std::atomic<bool> stats_mgr_reporting_;
|
||||||
|
|
||||||
/// @brief Number of seconds between reports of a raised alarm.
|
/// @brief Number of seconds between reports of a raised alarm.
|
||||||
/// Defaults to 300. A value of zero disables alarms.
|
/// Defaults to 300. A value of zero disables alarms.
|
||||||
|
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
extern const isc::log::MessageID PERFMON_ALARM_CLEARED = "PERFMON_ALARM_CLEARED";
|
extern const isc::log::MessageID PERFMON_ALARM_CLEARED = "PERFMON_ALARM_CLEARED";
|
||||||
extern const isc::log::MessageID PERFMON_ALARM_TRIGGERED = "PERFMON_ALARM_TRIGGERED";
|
extern const isc::log::MessageID PERFMON_ALARM_TRIGGERED = "PERFMON_ALARM_TRIGGERED";
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_CONTROL_ERROR = "PERFMON_CMDS_CONTROL_ERROR";
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_CONTROL_OK = "PERFMON_CMDS_CONTROL_OK";
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_GET_ALL_DURATIONS_ERROR = "PERFMON_CMDS_GET_ALL_DURATIONS_ERROR";
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_GET_ALL_DURATIONS_OK = "PERFMON_CMDS_GET_ALL_DURATIONS_OK";
|
||||||
extern const isc::log::MessageID PERFMON_DEINIT_FAILED = "PERFMON_DEINIT_FAILED";
|
extern const isc::log::MessageID PERFMON_DEINIT_FAILED = "PERFMON_DEINIT_FAILED";
|
||||||
extern const isc::log::MessageID PERFMON_DEINIT_OK = "PERFMON_DEINIT_OK";
|
extern const isc::log::MessageID PERFMON_DEINIT_OK = "PERFMON_DEINIT_OK";
|
||||||
extern const isc::log::MessageID PERFMON_DHCP4_PKT_EVENTS = "PERFMON_DHCP4_PKT_EVENTS";
|
extern const isc::log::MessageID PERFMON_DHCP4_PKT_EVENTS = "PERFMON_DHCP4_PKT_EVENTS";
|
||||||
@@ -22,6 +26,10 @@ namespace {
|
|||||||
const char* values[] = {
|
const char* values[] = {
|
||||||
"PERFMON_ALARM_CLEARED", "Alarm for %1 has been cleared, reported average duration %2 is now below low-water-ms: %3",
|
"PERFMON_ALARM_CLEARED", "Alarm for %1 has been cleared, reported average duration %2 is now below low-water-ms: %3",
|
||||||
"PERFMON_ALARM_TRIGGERED", "Alarm for %1 has been triggered since %2, reported average duration %3 exceeds high-water-ms: %4",
|
"PERFMON_ALARM_TRIGGERED", "Alarm for %1 has been triggered since %2, reported average duration %3 exceeds high-water-ms: %4",
|
||||||
|
"PERFMON_CMDS_CONTROL_ERROR", "perfmon-control command processing failed: %1",
|
||||||
|
"PERFMON_CMDS_CONTROL_OK", "perfmon-control command success: active monitoring: %1, stats-mgr-reporting: %2",
|
||||||
|
"PERFMON_CMDS_GET_ALL_DURATIONS_ERROR", "perfmon-get-all-durations command processing failed: %1",
|
||||||
|
"PERFMON_CMDS_GET_ALL_DURATIONS_OK", "perfmon-get-all-durations returning %1 durations",
|
||||||
"PERFMON_DEINIT_FAILED", "unloading PerfMon hooks library failed: %1",
|
"PERFMON_DEINIT_FAILED", "unloading PerfMon hooks library failed: %1",
|
||||||
"PERFMON_DEINIT_OK", "unloading PerfMon hooks library successful",
|
"PERFMON_DEINIT_OK", "unloading PerfMon hooks library successful",
|
||||||
"PERFMON_DHCP4_PKT_EVENTS", "query: %1 events=[%2]",
|
"PERFMON_DHCP4_PKT_EVENTS", "query: %1 events=[%2]",
|
||||||
|
@@ -7,6 +7,10 @@
|
|||||||
|
|
||||||
extern const isc::log::MessageID PERFMON_ALARM_CLEARED;
|
extern const isc::log::MessageID PERFMON_ALARM_CLEARED;
|
||||||
extern const isc::log::MessageID PERFMON_ALARM_TRIGGERED;
|
extern const isc::log::MessageID PERFMON_ALARM_TRIGGERED;
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_CONTROL_ERROR;
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_CONTROL_OK;
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_GET_ALL_DURATIONS_ERROR;
|
||||||
|
extern const isc::log::MessageID PERFMON_CMDS_GET_ALL_DURATIONS_OK;
|
||||||
extern const isc::log::MessageID PERFMON_DEINIT_FAILED;
|
extern const isc::log::MessageID PERFMON_DEINIT_FAILED;
|
||||||
extern const isc::log::MessageID PERFMON_DEINIT_OK;
|
extern const isc::log::MessageID PERFMON_DEINIT_OK;
|
||||||
extern const isc::log::MessageID PERFMON_DHCP4_PKT_EVENTS;
|
extern const isc::log::MessageID PERFMON_DHCP4_PKT_EVENTS;
|
||||||
|
@@ -70,3 +70,23 @@ the log message.
|
|||||||
% PERFMON_INIT_OK loading PerfMon hooks library successful
|
% PERFMON_INIT_OK loading PerfMon hooks library successful
|
||||||
This info message indicates that the PerfMon hooks library has been
|
This info message indicates that the PerfMon hooks library has been
|
||||||
loaded successfully. Enjoy!
|
loaded successfully. Enjoy!
|
||||||
|
|
||||||
|
% PERFMON_CMDS_CONTROL_ERROR perfmon-control command processing failed: %1
|
||||||
|
This error message is issued when the PerfMon hook library encounters an
|
||||||
|
error processing a perfmon-control command. The argument explains the
|
||||||
|
command error.
|
||||||
|
|
||||||
|
% PERFMON_CMDS_CONTROL_OK perfmon-control command success: active monitoring: %1, stats-mgr-reporting: %2
|
||||||
|
This info log is issued when perfmon-control command has successfully
|
||||||
|
enabled/disabled active monitoring and/or statistics mgr reporting.
|
||||||
|
Arguments reflect the current state of both.
|
||||||
|
|
||||||
|
% PERFMON_CMDS_GET_ALL_DURATIONS_ERROR perfmon-get-all-durations command processing failed: %1
|
||||||
|
This error message is issued when the PerfMon hook library encounters an
|
||||||
|
error processing a perfmon-get-all-durations command. The argument explains the
|
||||||
|
command error.
|
||||||
|
|
||||||
|
% PERFMON_CMDS_GET_ALL_DURATIONS_OK perfmon-get-all-durations returning %1 durations
|
||||||
|
This info log is issued when perfmon-get-all-durations command has
|
||||||
|
completed successfully. The argument contains the number of
|
||||||
|
durations returned.
|
||||||
|
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include <perfmon_log.h>
|
#include <perfmon_log.h>
|
||||||
#include <perfmon_mgr.h>
|
#include <perfmon_mgr.h>
|
||||||
|
#include <cc/simple_parser.h>
|
||||||
|
#include <config/cmd_response_creator.h>
|
||||||
#include <stats/stats_mgr.h>
|
#include <stats/stats_mgr.h>
|
||||||
#include <dhcp/dhcp6.h>
|
#include <dhcp/dhcp6.h>
|
||||||
#include <util/boost_time_utils.h>
|
#include <util/boost_time_utils.h>
|
||||||
@@ -18,6 +20,7 @@
|
|||||||
namespace isc {
|
namespace isc {
|
||||||
namespace perfmon {
|
namespace perfmon {
|
||||||
|
|
||||||
|
using namespace isc::config;
|
||||||
using namespace isc::data;
|
using namespace isc::data;
|
||||||
using namespace isc::dhcp;
|
using namespace isc::dhcp;
|
||||||
using namespace isc::log;
|
using namespace isc::log;
|
||||||
@@ -26,7 +29,7 @@ using namespace isc::util;
|
|||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
|
||||||
PerfMonMgr::PerfMonMgr(uint16_t family_)
|
PerfMonMgr::PerfMonMgr(uint16_t family_)
|
||||||
: PerfMonConfig(family_) {
|
: PerfMonConfig(family_), mutex_(new std::mutex) {
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,8 +176,8 @@ PerfMonMgr::reportToStatsMgr(MonitoredDurationPtr duration) {
|
|||||||
|
|
||||||
auto average = previous_interval->getAverageDuration();
|
auto average = previous_interval->getAverageDuration();
|
||||||
if (getStatsMgrReporting()) {
|
if (getStatsMgrReporting()) {
|
||||||
StatsMgr::instance().setValue(duration->getStatName("average-ms"),
|
StatsMgr::instance().setValue(duration->getStatName("average-usecs"),
|
||||||
static_cast<int64_t>(average.total_milliseconds()));
|
static_cast<int64_t>(average.total_microseconds()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @todo - decide if we want to report min and max values too.
|
/// @todo - decide if we want to report min and max values too.
|
||||||
@@ -219,5 +222,160 @@ PerfMonMgr::setNextReportExpiration() {
|
|||||||
isc_throw (NotImplemented, __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__);
|
isc_throw (NotImplemented, __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PerfMonMgr::perfmonControlHandler(hooks::CalloutHandle& handle) {
|
||||||
|
static SimpleKeywords keywords = {
|
||||||
|
{ "enable-monitoring", Element::boolean },
|
||||||
|
{ "stats-mgr-reporting", Element::boolean }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string txt = "(missing parameters)";
|
||||||
|
ElementPtr result = Element::createMap();
|
||||||
|
ConstElementPtr response;
|
||||||
|
|
||||||
|
// Extract the command and then the parameters
|
||||||
|
try {
|
||||||
|
extractCommand(handle);
|
||||||
|
if (cmd_args_) {
|
||||||
|
txt = cmd_args_->str();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd_args_) {
|
||||||
|
SimpleParser::checkKeywords(keywords, cmd_args_);
|
||||||
|
|
||||||
|
ConstElementPtr elem = cmd_args_->get("enable-monitoring");
|
||||||
|
if (elem) {
|
||||||
|
enable_monitoring_ = elem->boolValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
elem = cmd_args_->get("stats-mgr-reporting");
|
||||||
|
if (elem) {
|
||||||
|
stats_mgr_reporting_ = elem->boolValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(perfmon_logger, PERFMON_CMDS_CONTROL_OK)
|
||||||
|
.arg(enable_monitoring_ ? "enabled" : "disabled")
|
||||||
|
.arg(stats_mgr_reporting_ ? "enabled" : "disabled");
|
||||||
|
|
||||||
|
result->set("enable-monitoring", Element::create(enable_monitoring_));
|
||||||
|
result->set("stats-mgr-reporting", Element::create(stats_mgr_reporting_));
|
||||||
|
response = createAnswer(CONTROL_RESULT_SUCCESS, "perfmon-control success", result);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
LOG_ERROR(perfmon_logger, PERFMON_CMDS_CONTROL_ERROR)
|
||||||
|
.arg(ex.what());
|
||||||
|
setErrorResponse(handle, ex.what());
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setResponse(handle, response);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PerfMonMgr::perfmonGetAllDurationsHandler(hooks::CalloutHandle& handle) {
|
||||||
|
static SimpleKeywords keywords = {
|
||||||
|
{ "result-set-format", Element::boolean }
|
||||||
|
};
|
||||||
|
|
||||||
|
ElementPtr result = Element::createMap();
|
||||||
|
ConstElementPtr response;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Extract the command and then the parameters
|
||||||
|
bool result_set_format = false;
|
||||||
|
extractCommand(handle);
|
||||||
|
if (cmd_args_) {
|
||||||
|
SimpleParser::checkKeywords(keywords, cmd_args_);
|
||||||
|
|
||||||
|
ConstElementPtr elem = cmd_args_->get("result-set-format");
|
||||||
|
if (elem) {
|
||||||
|
result_set_format = elem->boolValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the durations from the store.
|
||||||
|
auto durations = duration_store_->getAll();
|
||||||
|
auto rows = durations->size();
|
||||||
|
ElementPtr formatted_durations;
|
||||||
|
|
||||||
|
// Format them either as a list of elements or as a result set
|
||||||
|
if (!result_set_format) {
|
||||||
|
formatted_durations = formatDurationDataAsElements(durations);
|
||||||
|
} else {
|
||||||
|
formatted_durations = formatDurationDataAsResultSet(durations);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the result
|
||||||
|
result->set("interval-width-secs", Element::create(getIntervalWidthSecs()));
|
||||||
|
result->set("timestamp", Element::create(isc::util::ptimeToText(PktEvent::now())));
|
||||||
|
result->set((result_set_format ? "durations-result-set" : "durations"), formatted_durations);
|
||||||
|
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "perfmon-get-all-durations: " << rows << " found";
|
||||||
|
|
||||||
|
response = createAnswer(CONTROL_RESULT_SUCCESS, oss.str(), result);
|
||||||
|
LOG_INFO(perfmon_logger, PERFMON_CMDS_GET_ALL_DURATIONS_OK)
|
||||||
|
.arg(rows);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
LOG_ERROR(perfmon_logger, PERFMON_CMDS_GET_ALL_DURATIONS_ERROR)
|
||||||
|
.arg(ex.what());
|
||||||
|
setErrorResponse(handle, ex.what());
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
setResponse(handle, response);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementPtr
|
||||||
|
PerfMonMgr::formatDurationDataAsElements(MonitoredDurationCollectionPtr durations) const {
|
||||||
|
// Create the list.
|
||||||
|
ElementPtr duration_list = Element::createList();
|
||||||
|
|
||||||
|
// Add in the duration elements.
|
||||||
|
for (auto const& d : *durations) {
|
||||||
|
ElementPtr element = d->toElement();
|
||||||
|
duration_list->add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (duration_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementPtr
|
||||||
|
PerfMonMgr::formatDurationDataAsResultSet(MonitoredDurationCollectionPtr /*durations */) const{
|
||||||
|
isc_throw (NotImplemented, "Not Implemented - " << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__);
|
||||||
|
#if 0
|
||||||
|
// Create the result-set map and add it to the wrapper.
|
||||||
|
ElementPtr result_set = Element::createMap();
|
||||||
|
result_wrapper->set("result-set", result_set);
|
||||||
|
|
||||||
|
// Create the list of column names and add it to the result set.
|
||||||
|
ElementPtr columns = Element::createList();
|
||||||
|
for (auto const& label : column_labels) {
|
||||||
|
columns->add(Element::create(label));
|
||||||
|
}
|
||||||
|
result_set->set("columns", columns);
|
||||||
|
|
||||||
|
// Create the empty value_rows list, add it and then return it.
|
||||||
|
ElementPtr value_rows = Element::createList();
|
||||||
|
result_set->set("rows", value_rows);
|
||||||
|
if (durations.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (value_rows);
|
||||||
|
for (auto const& d : *durations) {
|
||||||
|
const auto& reported_interval = d->getPreviousInterval();
|
||||||
|
if (reported_interval) {
|
||||||
|
std::string label = d->getLabel();
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // end of namespace perfmon
|
} // end of namespace perfmon
|
||||||
} // end of namespace isc
|
} // end of namespace isc
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
#define PERFMON_MGR_H
|
#define PERFMON_MGR_H
|
||||||
|
|
||||||
#include <perfmon_config.h>
|
#include <perfmon_config.h>
|
||||||
|
#include <config/command_mgr.h>
|
||||||
|
#include <config/cmds_impl.h>
|
||||||
#include <monitored_duration_store.h>
|
#include <monitored_duration_store.h>
|
||||||
#include <asiolink/io_service.h>
|
#include <asiolink/io_service.h>
|
||||||
#include <asiolink/interval_timer.h>
|
#include <asiolink/interval_timer.h>
|
||||||
@@ -24,7 +26,7 @@ namespace perfmon {
|
|||||||
/// the PerfMon hook library. It owns the MonitoredDurationStore and AlarmStore
|
/// the PerfMon hook library. It owns the MonitoredDurationStore and AlarmStore
|
||||||
/// instances and supplies callout and command API handlers. It derives from
|
/// instances and supplies callout and command API handlers. It derives from
|
||||||
/// PerfMonConfig.
|
/// PerfMonConfig.
|
||||||
class PerfMonMgr : public PerfMonConfig {
|
class PerfMonMgr : public PerfMonConfig, private config::CmdsImpl {
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor.
|
/// @brief Constructor.
|
||||||
///
|
///
|
||||||
@@ -46,7 +48,15 @@ public:
|
|||||||
|
|
||||||
/// @brief Processes the event stack of a query packet.
|
/// @brief Processes the event stack of a query packet.
|
||||||
///
|
///
|
||||||
/// @todo DETAILS TO FOLLOW
|
/// -# Emit a dump of packet stack to perfmon debug log at detail level.
|
||||||
|
/// -# Iterates over the query's event stack creating a DurationKey for each
|
||||||
|
/// adjacent event pair, computing the elapsed time between them and then calls
|
||||||
|
/// addDurationSample().
|
||||||
|
/// -# Generates composite duration updates. Durations that monitor total response
|
||||||
|
/// time for a given query/response pair will be computed using the first and last
|
||||||
|
/// events in the stack, with a begin event label of "composite" and an end label
|
||||||
|
/// of "total_response" for the DurationKey. These duration updates will be passed
|
||||||
|
/// into addDurationSample(). Other composite durations may be added in the future.
|
||||||
///
|
///
|
||||||
/// @param query query packet whose stack is to be processed.
|
/// @param query query packet whose stack is to be processed.
|
||||||
/// @param response response packet generated for the query.
|
/// @param response response packet generated for the query.
|
||||||
@@ -105,6 +115,151 @@ public:
|
|||||||
/// cancel report timer
|
/// cancel report timer
|
||||||
void setNextReportExpiration();
|
void setNextReportExpiration();
|
||||||
|
|
||||||
|
/// @brief perfmon-control command handler
|
||||||
|
///
|
||||||
|
/// This command sets enable-monitoring and/or stats-mgr-reporting (affects
|
||||||
|
/// in memory value(s) only).
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "command": "perfmon-control",
|
||||||
|
/// "arguments": {
|
||||||
|
/// "enable-monitoring": true,
|
||||||
|
/// "stats-mgr-reporting": true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// It extracts the command name and arguments from the given CalloutHandle,
|
||||||
|
/// attempts to process them, and then set's the handle's "response"
|
||||||
|
/// arguments accordingly. Regardless of which parameters were specified
|
||||||
|
/// in the command arguments (if any), it returns the values for both
|
||||||
|
/// parameters:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// "arguments": {
|
||||||
|
/// "enable-monitoring": false,
|
||||||
|
/// "stats-mgr-reporting": false
|
||||||
|
/// },
|
||||||
|
/// "result": 0,
|
||||||
|
/// "text": "perfmon-control success"
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// @param handle Callout context - which is expected to contain the
|
||||||
|
/// command JSON text in the "command" argument
|
||||||
|
/// @return result of the operation
|
||||||
|
int perfmonControlHandler(hooks::CalloutHandle& handle);
|
||||||
|
|
||||||
|
/// @brief perfmon-get-all-durations handler
|
||||||
|
///
|
||||||
|
/// This command fetches all of the monitored durations and their preivous
|
||||||
|
/// intervals (if one).
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "command": "perfmon-get-all-duations",
|
||||||
|
/// "arguments": {
|
||||||
|
/// "result-set-format": true
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// It extracts the command name and arguments from the given CalloutHandle,
|
||||||
|
/// attempts to process them, and then set's the handle's "response"
|
||||||
|
/// arguments accordingly. If result-set-format is false (the default) the
|
||||||
|
/// durations are returned as a list of Elements:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "result": 0,
|
||||||
|
/// "text": "perfmon-get-all-durations: n rows found",
|
||||||
|
/// "arguments": {
|
||||||
|
/// "result-set-format": false,
|
||||||
|
/// "interval-width-secs": 5,
|
||||||
|
/// "timestamp": "2024-01-18 10:11:20.594800"
|
||||||
|
/// "durations": [{
|
||||||
|
/// "duration-key": {
|
||||||
|
/// "query-type": "discover",
|
||||||
|
/// "response-type": "offer",
|
||||||
|
/// "start-event": "socket_received",
|
||||||
|
/// "stop-event": "buffer_read",
|
||||||
|
/// "subnet-id": 10
|
||||||
|
/// },
|
||||||
|
/// "start-time": "2024-01-18 10:11:19.498739",
|
||||||
|
/// "occurrences": 105,
|
||||||
|
/// "min-duration-usecs": 5300,
|
||||||
|
/// "max-duration-usecs": 9000,
|
||||||
|
/// "total-duration-usecs": 786500
|
||||||
|
/// },
|
||||||
|
/// ..
|
||||||
|
/// ]
|
||||||
|
/// },
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// If result-set-format is true, the durations are returned in a more compact format,
|
||||||
|
/// patterned after an SQL result set:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// {
|
||||||
|
/// "result": 0,
|
||||||
|
/// "text": "perfmon-get-all-durations: n rows found",
|
||||||
|
/// "arguments": {
|
||||||
|
/// "result-set-format": true,
|
||||||
|
/// "interval-width-secs": 5,
|
||||||
|
/// "timestamp": "2024-01-18 10:11:20.594800"
|
||||||
|
/// "durations-result-set": {
|
||||||
|
/// "columns": [
|
||||||
|
/// "subnet-id", "query-type", "response-type", "start-event", "end-event",
|
||||||
|
/// "interval start", "occurences", "min-duration-usecs", "max-duration-usecs",
|
||||||
|
/// "total-duration-usecs"
|
||||||
|
/// ],
|
||||||
|
/// "rows": [
|
||||||
|
/// [
|
||||||
|
/// 10, "discover", "offer", "socket_received", "buffer_read",
|
||||||
|
/// "2024-01-18 10:11:19.498739", 105, 5300, 9000, 786500
|
||||||
|
/// ],
|
||||||
|
/// ..
|
||||||
|
/// ]
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// @param handle Callout context - which is expected to contain the
|
||||||
|
/// command JSON text in the "command" argument
|
||||||
|
/// @return result of the operation
|
||||||
|
int perfmonGetAllDurationsHandler(hooks::CalloutHandle& handle);
|
||||||
|
|
||||||
|
/// @brief Renders a list of MonitoredDurations as a map of individual Elements
|
||||||
|
///
|
||||||
|
/// @param durations collection of durations to convert
|
||||||
|
data::ElementPtr formatDurationDataAsElements(MonitoredDurationCollectionPtr durations) const;
|
||||||
|
|
||||||
|
/// @brief Renders a list of MonitoredDurations as a result set
|
||||||
|
///
|
||||||
|
/// The result set Element will be as shown below:
|
||||||
|
///
|
||||||
|
/// @code
|
||||||
|
/// "durations-result-set": {
|
||||||
|
/// "columns": [
|
||||||
|
/// "subnet-id", "query-type", "response-type", "start-event", "end-event",
|
||||||
|
/// "interval start", "occurences", "min-duration-usecs", "max-duration-usecs",
|
||||||
|
/// "total-duration-usecs"
|
||||||
|
/// ],
|
||||||
|
/// "rows": [
|
||||||
|
/// [
|
||||||
|
/// 10, "discover", "offer", "socket_received", "buffer_read",
|
||||||
|
/// "2024-01-18 10:11:19.498739", 105, 5300, 9000, 786500
|
||||||
|
/// ],
|
||||||
|
/// ..
|
||||||
|
/// ]
|
||||||
|
/// @endcode
|
||||||
|
///
|
||||||
|
/// @param durations collection of durations to convert
|
||||||
|
data::ElementPtr formatDurationDataAsResultSet(MonitoredDurationCollectionPtr durations) const;
|
||||||
|
|
||||||
/// @brief Get the interval duration.
|
/// @brief Get the interval duration.
|
||||||
///
|
///
|
||||||
/// @return interval-width-secs as a Duration.
|
/// @return interval-width-secs as a Duration.
|
||||||
|
@@ -33,6 +33,7 @@ perfmon_unittests_SOURCES += monitored_duration_store_unittests.cc
|
|||||||
perfmon_unittests_SOURCES += alarm_store_unittests.cc
|
perfmon_unittests_SOURCES += alarm_store_unittests.cc
|
||||||
perfmon_unittests_SOURCES += perfmon_config_unittests.cc
|
perfmon_unittests_SOURCES += perfmon_config_unittests.cc
|
||||||
perfmon_unittests_SOURCES += perfmon_mgr_unittests.cc
|
perfmon_unittests_SOURCES += perfmon_mgr_unittests.cc
|
||||||
|
perfmon_unittests_SOURCES += perfmon_cmds_unittests.cc
|
||||||
perfmon_unittests_SOURCES += duration_key_parser_unittests.cc
|
perfmon_unittests_SOURCES += duration_key_parser_unittests.cc
|
||||||
perfmon_unittests_SOURCES += alarm_parser_unittests.cc
|
perfmon_unittests_SOURCES += alarm_parser_unittests.cc
|
||||||
|
|
||||||
|
441
src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc
Normal file
441
src/hooks/dhcp/perfmon/tests/perfmon_cmds_unittests.cc
Normal file
@@ -0,0 +1,441 @@
|
|||||||
|
// Copyright (C) 2024 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
//
|
||||||
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
/// @file This file contains tests which exercise the PerfmonMgr class.
|
||||||
|
#include <config.h>
|
||||||
|
#include <perfmon_mgr.h>
|
||||||
|
#include <dhcp/dhcp6.h>
|
||||||
|
#include <dhcp/pkt4.h>
|
||||||
|
#include <dhcp/pkt6.h>
|
||||||
|
#include <dhcpsrv/subnet.h>
|
||||||
|
#include <hooks/hooks_manager.h>
|
||||||
|
#include <stats/stats_mgr.h>
|
||||||
|
#include <testutils/log_utils.h>
|
||||||
|
#include <testutils/gtest_utils.h>
|
||||||
|
#include <testutils/multi_threading_utils.h>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <list>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace isc;
|
||||||
|
using namespace isc::asiolink;
|
||||||
|
using namespace isc::config;
|
||||||
|
using namespace isc::data;
|
||||||
|
using namespace isc::dhcp;
|
||||||
|
using namespace isc::hooks;
|
||||||
|
using namespace isc::perfmon;
|
||||||
|
using namespace isc::stats;
|
||||||
|
using namespace isc::test;
|
||||||
|
using namespace isc::dhcp::test;
|
||||||
|
using namespace boost::posix_time;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/// @brief Test fixture for testing PerfMonMgr
|
||||||
|
class PerfMonCmdTest : public LogContentTest {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
explicit PerfMonCmdTest(uint16_t family) : family_(family) {
|
||||||
|
StatsMgr::instance();
|
||||||
|
StatsMgr::instance().removeAll();
|
||||||
|
StatsMgr::instance().setMaxSampleCountAll(1);
|
||||||
|
if (family_ == AF_INET) {
|
||||||
|
subnet22_.reset(new Subnet4(IOAddress("192.0.22.0"), 8, 100, 200, 300, 22));
|
||||||
|
subnet33_.reset(new Subnet4(IOAddress("192.0.33.0"), 8, 100, 200, 300, 33));
|
||||||
|
} else {
|
||||||
|
subnet22_.reset(new Subnet6(IOAddress("3001:22::"), 64, 100, 200, 300, 300, 22));
|
||||||
|
subnet33_.reset(new Subnet6(IOAddress("3002:33::"), 64, 100, 200, 300, 300, 33));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetUp() {
|
||||||
|
std::string valid_config =
|
||||||
|
R"({
|
||||||
|
"enable-monitoring": false,
|
||||||
|
"interval-width-secs": 5000,
|
||||||
|
"stats-mgr-reporting": false,
|
||||||
|
"alarm-report-secs": 600000,
|
||||||
|
"alarms": [{
|
||||||
|
"duration-key": {
|
||||||
|
"query-type": "",
|
||||||
|
"response-type": "",
|
||||||
|
"start-event": "process-started",
|
||||||
|
"stop-event": "process-completed",
|
||||||
|
"subnet-id": 70
|
||||||
|
},
|
||||||
|
"enable-alarm": true,
|
||||||
|
"high-water-ms": 500,
|
||||||
|
"low-water-ms": 25
|
||||||
|
}]
|
||||||
|
})";
|
||||||
|
|
||||||
|
ASSERT_NO_THROW_LOG(createMgr(valid_config));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Destructor.
|
||||||
|
virtual ~PerfMonCmdTest() = default;
|
||||||
|
|
||||||
|
/// @brief Re-creates and then configures the PerfMonMgr instance with a
|
||||||
|
/// given configuration.
|
||||||
|
///
|
||||||
|
/// @param config JSON configuration text
|
||||||
|
void createMgr(const std::string& config) {
|
||||||
|
mgr_.reset(new PerfMonMgr(family_));
|
||||||
|
ConstElementPtr json_elements;
|
||||||
|
json_elements = Element::fromJSON(config);
|
||||||
|
mgr_->configure(json_elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Make a valid family-specific query.
|
||||||
|
///
|
||||||
|
/// @return if family is AF_INET return a pointer to a DHCPDISCOVER
|
||||||
|
/// otherwise a pointer to a DHCPV6_SOLICIT.
|
||||||
|
PktPtr makeFamilyQuery() {
|
||||||
|
if (family_ == AF_INET) {
|
||||||
|
return (PktPtr(new Pkt4(DHCPDISCOVER, 7788)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PktPtr(new Pkt6(DHCPV6_SOLICIT, 7788)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Make a valid family-specific response.
|
||||||
|
///
|
||||||
|
/// @return if family is AF_INET return a pointer to a DHCPOFFER
|
||||||
|
/// otherwise a pointer to a DHCPV6_ADVERTISE.
|
||||||
|
PktPtr makeFamilyResponse() {
|
||||||
|
if (family_ == AF_INET) {
|
||||||
|
return (PktPtr(new Pkt4(DHCPOFFER, 7788)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PktPtr(new Pkt6(DHCPV6_ADVERTISE, 7788)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Tests specified command and verifies response.
|
||||||
|
///
|
||||||
|
/// This method processes supplied command by invoking the
|
||||||
|
/// corresponding PerfMonMgr command handler and checks
|
||||||
|
/// if the expected response was returned.
|
||||||
|
///
|
||||||
|
/// @param cmd_txt JSON text command to be sent (must be valid JSON)
|
||||||
|
/// @param exp_result 0 - success, 1 - error, 2 - ...
|
||||||
|
/// @param exp_txt expected text response (optional)
|
||||||
|
/// @return full response returned by the command execution.
|
||||||
|
ConstElementPtr testCommand(string cmd_txt, int exp_result, string exp_txt,
|
||||||
|
ConstElementPtr exp_args = ConstElementPtr()) {
|
||||||
|
ConstElementPtr cmd;
|
||||||
|
EXPECT_NO_THROW(cmd = Element::fromJSON(cmd_txt));
|
||||||
|
if (!cmd) {
|
||||||
|
ADD_FAILURE() << cmd_txt << " is not a valid JSON, test broken";
|
||||||
|
return (ConstElementPtr());
|
||||||
|
}
|
||||||
|
return (testCommand(cmd, exp_result, exp_txt, exp_args));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Tests specified command and verifies response.
|
||||||
|
///
|
||||||
|
/// This method processes supplied command by invoking the
|
||||||
|
/// corresponding PerfMonMgr command handler.
|
||||||
|
///
|
||||||
|
/// @param cmd JSON command to be sent
|
||||||
|
/// @param exp_result 0 - success, 1 - error, 2 - ...
|
||||||
|
/// @param exp_txt expected text response (optional)
|
||||||
|
/// @return full response returned by the command execution.
|
||||||
|
ConstElementPtr testCommand(ConstElementPtr cmd,
|
||||||
|
int exp_result,
|
||||||
|
string exp_txt,
|
||||||
|
ConstElementPtr exp_args = ConstElementPtr()) {
|
||||||
|
string cmd_txt("...");
|
||||||
|
if (cmd) {
|
||||||
|
cmd_txt = prettyPrint(cmd);
|
||||||
|
}
|
||||||
|
SCOPED_TRACE(cmd_txt);
|
||||||
|
|
||||||
|
// Command must be a map.
|
||||||
|
if (!cmd || (cmd->getType() != Element::map)) {
|
||||||
|
ADD_FAILURE() << cmd_txt << " is not a map, test broken";
|
||||||
|
return (ConstElementPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to extract command name to select appropriate handler.
|
||||||
|
ConstElementPtr command_element = cmd->get("command");
|
||||||
|
if (!command_element || (command_element->getType() != Element::string)) {
|
||||||
|
ADD_FAILURE() << cmd_txt << " does not contain command parameter";
|
||||||
|
return (ConstElementPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command name found.
|
||||||
|
std::string command_name = command_element->stringValue();
|
||||||
|
|
||||||
|
// Need to encapsulate the command in CalloutHandle.
|
||||||
|
CalloutHandlePtr callout_handle = HooksManager::createCalloutHandle();
|
||||||
|
callout_handle->setArgument("command", cmd);
|
||||||
|
|
||||||
|
// Run the command handler appropriate for the given command name.
|
||||||
|
if (command_name == "perfmon-control") {
|
||||||
|
static_cast<void>(mgr_->perfmonControlHandler(*callout_handle));
|
||||||
|
} else {
|
||||||
|
ADD_FAILURE() << "unrecognized command '" << command_name << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the response.
|
||||||
|
ConstElementPtr rsp;
|
||||||
|
callout_handle->getArgument("response", rsp);
|
||||||
|
|
||||||
|
// Response must be present.
|
||||||
|
if (!rsp) {
|
||||||
|
ADD_FAILURE() << "no response returned for command '"
|
||||||
|
<< command_name << "'";
|
||||||
|
return (ConstElementPtr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the response against expected values.
|
||||||
|
checkAnswer(rsp, exp_result, exp_txt, exp_args);
|
||||||
|
|
||||||
|
return (rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Compares the status in the given parse result to a given value.
|
||||||
|
///
|
||||||
|
/// @param answer Element set containing an integer response and string
|
||||||
|
/// comment.
|
||||||
|
/// @param exp_status is an integer against which to compare the status.
|
||||||
|
/// @param exp_txt is expected text (not checked if "")
|
||||||
|
///
|
||||||
|
void checkAnswer(isc::data::ConstElementPtr answer,
|
||||||
|
int exp_status,
|
||||||
|
string exp_txt = "",
|
||||||
|
ConstElementPtr exp_args = ConstElementPtr()) {
|
||||||
|
int rcode = 0;
|
||||||
|
isc::data::ConstElementPtr comment;
|
||||||
|
comment = isc::config::parseAnswer(rcode, answer);
|
||||||
|
|
||||||
|
if (rcode != exp_status) {
|
||||||
|
ADD_FAILURE() << "Expected status code " << exp_status
|
||||||
|
<< " but received " << rcode << ", comment: "
|
||||||
|
<< (comment ? comment->str() : "(none)");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok, parseAnswer interface is weird. If there are no arguments,
|
||||||
|
// it returns content of text. But if there is an argument,
|
||||||
|
// it returns the argument and it's not possible to retrieve
|
||||||
|
// "text" (i.e. comment).
|
||||||
|
if (comment->getType() != Element::string) {
|
||||||
|
comment = answer->get("text");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exp_txt.empty()) {
|
||||||
|
EXPECT_EQ(exp_txt, comment->stringValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exp_args) {
|
||||||
|
ConstElementPtr args = answer->get("arguments");
|
||||||
|
ASSERT_TRUE(args);
|
||||||
|
EXPECT_EQ(*exp_args, *args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that invalid perfmon-control commands are caught.
|
||||||
|
void testInvalidPerfMonControl() {
|
||||||
|
struct Scenario {
|
||||||
|
int line_; // Scenario line number
|
||||||
|
std::string cmd_; // JSON command text
|
||||||
|
int exp_result_; // Expected result code
|
||||||
|
std::string exp_text_; // Expected result text
|
||||||
|
};
|
||||||
|
|
||||||
|
std::list<Scenario> scenarios = {
|
||||||
|
{
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control",
|
||||||
|
"arguments": {
|
||||||
|
"enable-monitoring": "bogus"
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_ERROR,
|
||||||
|
"'enable-monitoring' parameter is not a boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control",
|
||||||
|
"arguments": {
|
||||||
|
"bogus": 23
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_ERROR,
|
||||||
|
"spurious 'bogus' parameter"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& scenario : scenarios) {
|
||||||
|
stringstream oss;
|
||||||
|
oss << "scenario at line: " << scenario.line_;
|
||||||
|
SCOPED_TRACE(oss.str());
|
||||||
|
ConstElementPtr answer = testCommand(scenario.cmd_,
|
||||||
|
scenario.exp_result_,
|
||||||
|
scenario.exp_text_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that valid perfmon-control are processed correctly.
|
||||||
|
void testValidPerfMonControl() {
|
||||||
|
struct Scenario {
|
||||||
|
int line_; // Scenario line number
|
||||||
|
std::string cmd_; // JSON command text
|
||||||
|
int exp_result_; // Expected result code
|
||||||
|
std::string exp_text_; // Expected result text
|
||||||
|
bool exp_monitor_enabled_; // Expected state of monitoring
|
||||||
|
bool exp_stats_mgr_reporting_; // Expected state of monitoring
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify that monitoring is enabled.
|
||||||
|
ASSERT_EQ(mgr_->getEnableMonitoring(), false);
|
||||||
|
|
||||||
|
// Define valid scenarios.
|
||||||
|
std::list<Scenario> scenarios = {
|
||||||
|
{
|
||||||
|
// No arguments element should be ok.
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control"
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_SUCCESS,
|
||||||
|
"perfmon-control success",
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Empty arguments element should be ok.
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control",
|
||||||
|
"arguments": {
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_SUCCESS,
|
||||||
|
"perfmon-control success",
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Only enable-monitoring should be ok.
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control",
|
||||||
|
"arguments": {
|
||||||
|
"enable-monitoring": true
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_SUCCESS,
|
||||||
|
"perfmon-control success",
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Only stats-mgr-reporting should be ok.
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control",
|
||||||
|
"arguments": {
|
||||||
|
"stats-mgr-reporting": true
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_SUCCESS,
|
||||||
|
"perfmon-control success",
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Both enable-monitoring and stats-mgr-reporting should be ok.
|
||||||
|
__LINE__,
|
||||||
|
R"({
|
||||||
|
"command": "perfmon-control",
|
||||||
|
"arguments": {
|
||||||
|
"enable-monitoring": false,
|
||||||
|
"stats-mgr-reporting": false
|
||||||
|
}
|
||||||
|
})",
|
||||||
|
CONTROL_RESULT_SUCCESS,
|
||||||
|
"perfmon-control success",
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& scenario : scenarios) {
|
||||||
|
stringstream oss;
|
||||||
|
oss << "scenario at line: " << scenario.line_;
|
||||||
|
SCOPED_TRACE(oss.str());
|
||||||
|
ElementPtr exp_args(Element::createMap());
|
||||||
|
exp_args->set("enable-monitoring",
|
||||||
|
Element::create(scenario.exp_monitor_enabled_));
|
||||||
|
exp_args->set("stats-mgr-reporting",
|
||||||
|
Element::create(scenario.exp_stats_mgr_reporting_));
|
||||||
|
ConstElementPtr answer = testCommand(scenario.cmd_,
|
||||||
|
scenario.exp_result_,
|
||||||
|
scenario.exp_text_,
|
||||||
|
exp_args);
|
||||||
|
|
||||||
|
EXPECT_EQ(mgr_->getEnableMonitoring(), scenario.exp_monitor_enabled_);
|
||||||
|
EXPECT_EQ(mgr_->getStatsMgrReporting(), scenario.exp_stats_mgr_reporting_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Protocol family AF_INET or AF_INET6
|
||||||
|
uint16_t family_;
|
||||||
|
|
||||||
|
/// @brief PerfMonMgr instance used in test functions.
|
||||||
|
PerfMonMgrPtr mgr_;
|
||||||
|
|
||||||
|
/// @brief Family specific subnets.
|
||||||
|
SubnetPtr subnet22_;
|
||||||
|
SubnetPtr subnet33_;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Test fixture for testing PerfMonConfig for DHCPV4.
|
||||||
|
class PerfMonCmdTest4: public PerfMonCmdTest {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
explicit PerfMonCmdTest4() : PerfMonCmdTest(AF_INET) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Destructor.
|
||||||
|
virtual ~PerfMonCmdTest4() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Test fixture for testing PerfMonConfig for DHCPV6.
|
||||||
|
class PerfMonCmdTest6: public PerfMonCmdTest {
|
||||||
|
public:
|
||||||
|
/// @brief Constructor.
|
||||||
|
explicit PerfMonCmdTest6() : PerfMonCmdTest(AF_INET6) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief Destructor.
|
||||||
|
virtual ~PerfMonCmdTest6() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(PerfMonCmdTest4, invalidPerfMonControl) {
|
||||||
|
testInvalidPerfMonControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PerfMonCmdTest6, invalidPerfMonControl) {
|
||||||
|
testInvalidPerfMonControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PerfMonCmdTest4, validPerfMonControl) {
|
||||||
|
testValidPerfMonControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PerfMonCmdTest6, validPerfMonControl) {
|
||||||
|
testValidPerfMonControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end of anonymous namespace
|
@@ -62,14 +62,6 @@ public:
|
|||||||
|
|
||||||
EXPECT_NO_THROW_LOG(config->setAlarmReportSecs(120));
|
EXPECT_NO_THROW_LOG(config->setAlarmReportSecs(120));
|
||||||
EXPECT_EQ(config->getAlarmReportSecs(), 120);
|
EXPECT_EQ(config->getAlarmReportSecs(), 120);
|
||||||
|
|
||||||
// Verify shallow copy construction.
|
|
||||||
PerfMonConfigPtr config2(new PerfMonConfig(*config));
|
|
||||||
EXPECT_TRUE(config2->getEnableMonitoring());
|
|
||||||
EXPECT_EQ(config2->getIntervalWidthSecs(), 4);
|
|
||||||
EXPECT_FALSE(config2->getStatsMgrReporting());
|
|
||||||
EXPECT_EQ(config2->getAlarmReportSecs(), 120);
|
|
||||||
EXPECT_EQ(config2->getAlarmStore(), config->getAlarmStore());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Exercises PerfMonConfig parameter parsing with valid configuration
|
/// @brief Exercises PerfMonConfig parameter parsing with valid configuration
|
||||||
|
@@ -332,16 +332,16 @@ public:
|
|||||||
ASSERT_NO_THROW_LOG(average = mgr_->reportToStatsMgr(mond));
|
ASSERT_NO_THROW_LOG(average = mgr_->reportToStatsMgr(mond));
|
||||||
EXPECT_EQ(milliseconds(175), average);
|
EXPECT_EQ(milliseconds(175), average);
|
||||||
|
|
||||||
auto obs = StatsMgr::instance().getObservation(mond->getStatName("average-ms"));
|
auto obs = StatsMgr::instance().getObservation(mond->getStatName("average-usecs"));
|
||||||
ASSERT_TRUE(obs);
|
ASSERT_TRUE(obs);
|
||||||
EXPECT_EQ(175, obs->getInteger().first);
|
EXPECT_EQ(175000, obs->getInteger().first);
|
||||||
|
|
||||||
StatsMgr::instance().removeAll();
|
StatsMgr::instance().removeAll();
|
||||||
mgr_->setStatsMgrReporting(false);
|
mgr_->setStatsMgrReporting(false);
|
||||||
|
|
||||||
ASSERT_NO_THROW_LOG(average = mgr_->reportToStatsMgr(mond));
|
ASSERT_NO_THROW_LOG(average = mgr_->reportToStatsMgr(mond));
|
||||||
EXPECT_EQ(milliseconds(175), average);
|
EXPECT_EQ(milliseconds(175), average);
|
||||||
obs = StatsMgr::instance().getObservation(mond->getStatName("average-ms"));
|
obs = StatsMgr::instance().getObservation(mond->getStatName("average-usecs"));
|
||||||
ASSERT_FALSE(obs);
|
ASSERT_FALSE(obs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,9 +411,9 @@ public:
|
|||||||
|
|
||||||
// Should have one stat reported with a average value of 80.
|
// Should have one stat reported with a average value of 80.
|
||||||
EXPECT_EQ(1, StatsMgr::instance().count());
|
EXPECT_EQ(1, StatsMgr::instance().count());
|
||||||
auto obs = StatsMgr::instance().getObservation(key->getStatName("average-ms"));
|
auto obs = StatsMgr::instance().getObservation(key->getStatName("average-usecs"));
|
||||||
ASSERT_TRUE(obs);
|
ASSERT_TRUE(obs);
|
||||||
EXPECT_EQ(80, obs->getInteger().first);
|
EXPECT_EQ(80000, obs->getInteger().first);
|
||||||
|
|
||||||
// The alarm should have triggered and reported.
|
// The alarm should have triggered and reported.
|
||||||
beforeAndAfterAlarm(__LINE__, before_alarm, Alarm::TRIGGERED, true);
|
beforeAndAfterAlarm(__LINE__, before_alarm, Alarm::TRIGGERED, true);
|
||||||
@@ -450,9 +450,9 @@ public:
|
|||||||
|
|
||||||
// Should have one stat reported with a value of 100.
|
// Should have one stat reported with a value of 100.
|
||||||
EXPECT_EQ(1, StatsMgr::instance().count());
|
EXPECT_EQ(1, StatsMgr::instance().count());
|
||||||
obs = StatsMgr::instance().getObservation(key->getStatName("average-ms"));
|
obs = StatsMgr::instance().getObservation(key->getStatName("average-usecs"));
|
||||||
ASSERT_TRUE(obs);
|
ASSERT_TRUE(obs);
|
||||||
EXPECT_EQ(100, obs->getInteger().first);
|
EXPECT_EQ(100000, obs->getInteger().first);
|
||||||
|
|
||||||
// Sleep 100ms second to make sure the current interval duration elapses.
|
// Sleep 100ms second to make sure the current interval duration elapses.
|
||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
@@ -470,9 +470,9 @@ public:
|
|||||||
|
|
||||||
// Should have one stat reported with a value of 10.
|
// Should have one stat reported with a value of 10.
|
||||||
EXPECT_EQ(1, StatsMgr::instance().count());
|
EXPECT_EQ(1, StatsMgr::instance().count());
|
||||||
obs = StatsMgr::instance().getObservation(key->getStatName("average-ms"));
|
obs = StatsMgr::instance().getObservation(key->getStatName("average-usecs"));
|
||||||
ASSERT_TRUE(obs);
|
ASSERT_TRUE(obs);
|
||||||
EXPECT_EQ(10, obs->getInteger().first);
|
EXPECT_EQ(10000, obs->getInteger().first);
|
||||||
|
|
||||||
// Lastly, verify the log entries.
|
// Lastly, verify the log entries.
|
||||||
EXPECT_TRUE(checkFile());
|
EXPECT_TRUE(checkFile());
|
||||||
|
38
src/share/api/perfmon-control.json
Normal file
38
src/share/api/perfmon-control.json
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"access": "write",
|
||||||
|
"avail": "2.7.0",
|
||||||
|
"brief": [
|
||||||
|
"This command enables/disables active monitoring and statistics reporting."
|
||||||
|
],
|
||||||
|
"cmd-syntax": [
|
||||||
|
"{",
|
||||||
|
" \"command\": \"perfmon-control\",",
|
||||||
|
" \"arguments\": {",
|
||||||
|
" \"enable-monitoring\": true,",
|
||||||
|
" \"stats-mgr-reporting\": false",
|
||||||
|
" }",
|
||||||
|
"}",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"description": "See <xref linkend=\"command-perfmon-control\"/>",
|
||||||
|
"hook": "perfmon",
|
||||||
|
"name": "perfmon-control",
|
||||||
|
"resp-comment": [
|
||||||
|
"Result 0 is returned if command succeeds along with the resultant values of both flags.",
|
||||||
|
"Result is 1 when parameters are malformed or missing."
|
||||||
|
],
|
||||||
|
"resp-syntax": [
|
||||||
|
" {",
|
||||||
|
" \"arguments\": {",
|
||||||
|
" \"enable-monitoring\": true,",
|
||||||
|
" \"stats-mgr-reporting\": false",
|
||||||
|
" },",
|
||||||
|
" \"result\": 0,",
|
||||||
|
" \"text\": \"perfmon-control success.\"",
|
||||||
|
" }"
|
||||||
|
],
|
||||||
|
"support": [
|
||||||
|
"kea-dhcp4",
|
||||||
|
"kea-dhcp6"
|
||||||
|
]
|
||||||
|
}
|
Reference in New Issue
Block a user