osquery-1/osquery/numeric_monitoring/numeric_monitoring.cpp

213 lines
6.1 KiB
C++
Raw Normal View History

Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed as defined on the LICENSE file found in the
* root directory of this source tree.
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
*/
#include <unordered_map>
#include <boost/format.hpp>
#include <osquery/dispatcher.h>
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
#include <osquery/flags.h>
#include <osquery/logger.h>
#include <osquery/numeric_monitoring.h>
#include <osquery/numeric_monitoring/plugin_interface.h>
#include <osquery/numeric_monitoring/pre_aggregation_cache.h>
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
#include <osquery/registry_factory.h>
#include <osquery/utils/enum_class_hash.h>
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
namespace osquery {
FLAG(bool,
enable_numeric_monitoring,
false,
"Enable numeric monitoring system");
FLAG(string,
numeric_monitoring_plugins,
"filesystem",
"Comma separated numeric monitoring plugins names");
FLAG(uint64,
numeric_monitoring_pre_aggregation_time,
60,
"Time period in seconds for numeric monitoring pre-aggreagation buffer.");
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
namespace {
using monitoring::PreAggregationType;
template <typename KeyType, typename ValueType, typename... Other>
inline auto reverseMap(
const std::unordered_map<KeyType, ValueType, Other...>& straight) {
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
auto reversed = std::unordered_map<ValueType, KeyType>{};
for (const auto& item : straight) {
reversed.emplace(item.second, item.first);
}
return reversed;
}
const auto& getAggregationTypeToStringTable() {
const auto static table =
std::unordered_map<PreAggregationType, std::string, EnumClassHash>{
{PreAggregationType::None, "none"},
{PreAggregationType::Sum, "sum"},
{PreAggregationType::Min, "min"},
{PreAggregationType::Max, "max"},
{PreAggregationType::Avg, "avg"},
{PreAggregationType::Stddev, "stddev"},
{PreAggregationType::P10, "p10"},
{PreAggregationType::P50, "p50"},
{PreAggregationType::P95, "p95"},
{PreAggregationType::P99, "p99"}};
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
return table;
}
const auto& getStringToAggregationTypeTable() {
const auto static table = reverseMap(getAggregationTypeToStringTable());
return table;
}
} // namespace
template <>
std::string to<std::string>(const monitoring::PreAggregationType& from) {
auto it = getAggregationTypeToStringTable().find(from);
if (it == getAggregationTypeToStringTable().end()) {
LOG(ERROR) << "Unknown PreAggregationType "
<< static_cast<std::underlying_type<PreAggregationType>::type>(
from)
<< " could not be converted to the string";
return "";
}
return it->second;
}
template <>
Expected<monitoring::PreAggregationType, ConversionError>
tryTo<monitoring::PreAggregationType>(const std::string& from) {
auto it = getStringToAggregationTypeTable().find(from);
if (it == getStringToAggregationTypeTable().end()) {
return createError(
ConversionError::InvalidArgument,
boost::str(
boost::format(
"Wrong string representation of `PreAggregationType`: \"%s\"") %
from));
}
return it->second;
}
namespace monitoring {
namespace {
class FlusherIsScheduled {};
FlusherIsScheduled schedule();
class PreAggregationBuffer final {
public:
static PreAggregationBuffer& get() {
static PreAggregationBuffer instance{};
static auto const flusher_is_scheduled = schedule();
boost::ignore_unused(flusher_is_scheduled);
return instance;
}
void record(const std::string& path,
const ValueType& value,
const PreAggregationType& pre_aggregation,
const bool sync,
const TimePoint& time_point) {
if (0 == FLAGS_numeric_monitoring_pre_aggregation_time || sync) {
dispatchOne(path, value, pre_aggregation, sync, time_point);
} else {
std::lock_guard<std::mutex> lock(mutex_);
cache_.addPoint(Point(path, value, pre_aggregation, time_point));
}
}
void flush() {
auto points = takeCachedPoints();
for (const auto& pt : points) {
dispatchOne(
pt.path_, pt.value_, pt.pre_aggregation_type_, false, pt.time_point_);
}
}
private:
std::vector<Point> takeCachedPoints() {
std::lock_guard<std::mutex> lock(mutex_);
auto points = cache_.takePoints();
return points;
}
void dispatchOne(const std::string& path,
const ValueType& value,
const PreAggregationType& pre_aggregation,
const bool sync,
const TimePoint& time_point) {
auto status = Registry::call(
registryName(),
FLAGS_numeric_monitoring_plugins,
{
{recordKeys().path, path},
{recordKeys().value, std::to_string(value)},
{recordKeys().pre_aggregation, to<std::string>(pre_aggregation)},
{recordKeys().timestamp,
std::to_string(time_point.time_since_epoch().count())},
{recordKeys().sync, sync ? "true" : "false"},
});
if (!status.ok()) {
LOG(ERROR) << "Data loss. Numeric monitoring point dispatch failed: "
<< status.what();
}
}
private:
PreAggregationCache cache_;
std::mutex mutex_;
};
class PreAggregationFlusher : public InternalRunnable {
public:
explicit PreAggregationFlusher()
: InternalRunnable("numeric_monitoring_pre_aggregation_buffer_flusher") {}
void start() override {
while (!interrupted() &&
0 != FLAGS_numeric_monitoring_pre_aggregation_time) {
2018-08-02 15:57:02 +00:00
pause(
std::chrono::seconds(FLAGS_numeric_monitoring_pre_aggregation_time));
PreAggregationBuffer::get().flush();
}
}
};
FlusherIsScheduled schedule() {
Dispatcher::addService(std::make_shared<PreAggregationFlusher>());
return FlusherIsScheduled{};
}
} // namespace
void flush() {
PreAggregationBuffer::get().flush();
}
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
void record(const std::string& path,
ValueType value,
PreAggregationType pre_aggregation,
const bool sync,
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
TimePoint time_point) {
if (!FLAGS_enable_numeric_monitoring) {
return;
}
PreAggregationBuffer::get().record(
path, value, pre_aggregation, sync, std::move(time_point));
Numeric monitoring system concept (#4626) Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Brief Just an interface and simple implementation dumping points to file on disk. And I add also few monitoring records to some places of osquery code as an example. Motivation osquery can monitor system health. But at some point we need to monitor the condition of osquery itself. Vast majority of interesting parameters can be represented by numbers. How many queries it runs, how long does each query takes, what is the performance hit of each query, how long was last downtime and so on and so far. For obviou s reason it hard to measure most of this parameters by external instrument. And it is almost impossible to evaluate it on production. But we can do it from inside of osquery. What this PR is for The systems like graphite or RRDtool can store and plot time-series data for us. We just have to be able to feed data to it. We can create different plugins to be able to send data to different instruments. And we need some proper internal interface to all potential plugins. This PR is attempt to create generic interface. Interface description The most systems accept data as sequences of 2-dimensional points. One of the dimensions is value, the other is time. Each particular sequence has unique key, to be distinguished from the others. Data descriptions for carbon. I have used this three parameters as an attributes of one monitoring point. To send one point from some particular place in the code you just need to call the function record from namespace monitoring declared in the file include/osquery/num eric_monitoring.h with 3 arguments (path, value, time). Where path is the unique key of sequence; value is some interesting value to watch; time is the time of the point (can be omitted, current system time is the default vaule).
2018-07-09 12:19:50 +00:00
}
} // namespace monitoring
} // namespace osquery