Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Counter and Histogram Aggregators #178

Merged
merged 34 commits into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5ff10e2
templated aggregators
ankit-bhargava Jul 15, 2020
302ca05
test files
ankit-bhargava Jul 15, 2020
0b78eb9
final specifier
ankit-bhargava Jul 15, 2020
c54651c
cleaning up for PR
ankit-bhargava Jul 16, 2020
4ba08e2
removing irrelevant test targets
ankit-bhargava Jul 16, 2020
0cd64d9
incorporating feedback
ankit-bhargava Jul 21, 2020
01afb81
adding virtual functions
ankit-bhargava Jul 24, 2020
7f32074
timestamp virtual function
ankit-bhargava Jul 26, 2020
47a58f8
remove unused import
ankit-bhargava Jul 27, 2020
98d80d1
user specified exceptions
ankit-bhargava Jul 28, 2020
f96c794
more virtuals for sketch aggregator
ankit-bhargava Jul 28, 2020
f23ca9a
typos
ankit-bhargava Jul 28, 2020
13f4677
Update sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_agg…
ankit-bhargava Jul 28, 2020
0779a49
Update sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_agg…
ankit-bhargava Jul 28, 2020
1458c6d
Merge branch 'master' into metrics-agg-ctrhist
reyang Jul 29, 2020
a41706f
Merge branch 'master' into metrics-agg-ctrhist
reyang Jul 29, 2020
2e79b0d
Merge branch 'master' into metrics-agg-ctrhist
reyang Jul 29, 2020
4e2aeee
Context helper functions (#225)
satac2 Jul 29, 2020
822e7b4
templated aggregators
ankit-bhargava Jul 15, 2020
bcd519d
test files
ankit-bhargava Jul 15, 2020
b8c2fba
final specifier
ankit-bhargava Jul 15, 2020
60865b3
cleaning up for PR
ankit-bhargava Jul 16, 2020
c6debd3
removing irrelevant test targets
ankit-bhargava Jul 16, 2020
161f719
incorporating feedback
ankit-bhargava Jul 21, 2020
739faa6
adding virtual functions
ankit-bhargava Jul 24, 2020
19f6643
timestamp virtual function
ankit-bhargava Jul 26, 2020
3a33a3c
remove unused import
ankit-bhargava Jul 27, 2020
c15942e
user specified exceptions
ankit-bhargava Jul 28, 2020
2bfd39a
more virtuals for sketch aggregator
ankit-bhargava Jul 28, 2020
72e437a
typos
ankit-bhargava Jul 28, 2020
73d1382
Update sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_agg…
ankit-bhargava Jul 28, 2020
75e48e1
Update sdk/include/opentelemetry/sdk/metrics/aggregator/histogram_agg…
ankit-bhargava Jul 28, 2020
f5e8149
Merge branch 'metrics-agg-ctrhist' of https://github.com/ankit-bharga…
ankit-bhargava Jul 29, 2020
8e7357e
formatting
ankit-bhargava Jul 29, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions api/include/opentelemetry/context/runtime_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,46 @@ class RuntimeContext

static RuntimeContext *context_handler_;

// Sets the Key and Value into the passed in context or if a context is not
// passed in, the RuntimeContext.
// Should be used to SetValues to the current RuntimeContext, is essentially
// equivalent to RuntimeContext::GetCurrent().SetValue(key,value). Keep in
// mind that the current RuntimeContext will not be changed, and the new
// context will be returned.
static Context SetValue(nostd::string_view key,
ContextValue value,
Context *context = nullptr) noexcept
{
Context temp_context;
if (context == nullptr)
{
temp_context = GetCurrent();
}
else
{
temp_context = *context;
}
return temp_context.SetValue(key, value);
}

// Returns the value associated with the passed in key and either the
// passed in context* or the runtime context if a context is not passed in.
// Should be used to get values from the current RuntimeContext, is
// essentially equivalent to RuntimeContext::GetCurrent().GetValue(key).
static ContextValue GetValue(nostd::string_view key, Context *context = nullptr) noexcept
{
Context temp_context;
if (context == nullptr)
{
temp_context = GetCurrent();
}
else
{
temp_context = *context;
}
return temp_context.GetValue(key);
}

protected:
// Provides a token with the passed in context
Token CreateToken(Context context) noexcept { return Token(context); }
Expand Down
41 changes: 41 additions & 0 deletions api/test/context/runtime_context_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,44 @@ TEST(RuntimeContextTest, ThreeAttachDetach)
EXPECT_TRUE(context::RuntimeContext::Detach(foo_context_token));
EXPECT_TRUE(context::RuntimeContext::Detach(test_context_token));
}

// Tests that SetValue returns a context with the passed in data and the
// RuntimeContext data when a context is not passed into the
// RuntimeContext::SetValue method.
TEST(RuntimeContextTest, SetValueRuntimeContext)
{
context::Context foo_context = context::Context("foo_key", (int64_t)596);
context::RuntimeContext::Token old_context_token = context::RuntimeContext::Attach(foo_context);
context::Context test_context = context::RuntimeContext::SetValue("test_key", (int64_t)123);
EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("test_key")), 123);
EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("foo_key")), 596);
}

// Tests that SetValue returns a context with the passed in data and the
// passed in context data when a context* is passed into the
// RuntimeContext::SetValue method.
TEST(RuntimeContextTest, SetValueOtherContext)
{
context::Context foo_context = context::Context("foo_key", (int64_t)596);
context::Context test_context =
context::RuntimeContext::SetValue("test_key", (int64_t)123, &foo_context);
EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("test_key")), 123);
EXPECT_EQ(nostd::get<int64_t>(test_context.GetValue("foo_key")), 596);
}

// Tests that SetValue returns the ContextValue associated with the
// passed in string and the current Runtime Context
TEST(RuntimeContextTest, GetValueRuntimeContext)
{
context::Context foo_context = context::Context("foo_key", (int64_t)596);
context::RuntimeContext::Token old_context_token = context::RuntimeContext::Attach(foo_context);
EXPECT_EQ(nostd::get<int64_t>(context::RuntimeContext::GetValue("foo_key")), 596);
}

// Tests that SetValue returns the ContextValue associated with the
// passed in string and the passed in context
TEST(RuntimeContextTest, GetValueOtherContext)
{
context::Context foo_context = context::Context("foo_key", (int64_t)596);
EXPECT_EQ(nostd::get<int64_t>(context::RuntimeContext::GetValue("foo_key", &foo_context)), 596);
}
141 changes: 141 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/aggregator/aggregator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#pragma once

#include <mutex>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - is there a reason these are not alphabetically sorted? If not, I would suggest to sort them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the format tools seem to reorder these

#include <vector>
#include "opentelemetry/core/timestamp.h"
#include "opentelemetry/metrics/instrument.h"
#include "opentelemetry/version.h"

namespace metrics_api = opentelemetry::metrics;

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{

enum class AggregatorKind
{
Counter = 0,
MinMaxSumCount = 1,
Gauge = 2,
Sketch = 3,
Histogram = 4,
Exact = 5,
};

/*
* Performs calculations necessary to combine updates from instruments into an
* insightful value.
* Also stores current instrument values and checkpoints collected at intervals
* governing the entire pipeline.
*/
template <typename T>
class Aggregator
{
public:
Aggregator() = default;

virtual ~Aggregator() = default;

/**
* Receives a captured value from the instrument and applies it to the current aggregator value.
*
* @param val, the raw value used in aggregation
* @return none
*/
virtual void update(T val) = 0;

/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @param none
* @return none
*/
virtual void checkpoint() = 0;

/**
* Merges the values of two aggregators in a semantically accurate manner.
* Merging will occur differently for different aggregators depending on the
* way values are tracked.
*
* @param other, the aggregator with merge with
* @return none
*/
void merge(Aggregator *other);

/**
* Returns the checkpointed value
*
* @param none
* @return the value of the checkpoint
*/
virtual std::vector<T> get_checkpoint() = 0;

/**
* Returns the current value
*
* @param none
* @return the present aggregator value
*/
virtual std::vector<T> get_values() = 0;

/**
* Returns the instrument kind which this aggregator is associated with
*
* @param none
* @return the InstrumentKind of the aggregator's owner
*/
virtual opentelemetry::metrics::InstrumentKind get_instrument_kind() final { return kind_; }

/**
* Returns the type of this aggregator
*
* @param none
* @return the AggregatorKind of this instrument
*/
virtual AggregatorKind get_aggregator_kind() final { return agg_kind_; }

// virtual function to be overriden for the Histogram Aggregator
virtual std::vector<double> get_boundaries() { return std::vector<double>(); }

// virtual function to be overriden for the Histogram Aggregator
virtual std::vector<int> get_counts() { return std::vector<int>(); }

// virtual function to be overriden for Exact and Sketch Aggregators
virtual bool get_quant_estimation() { return false; }

// virtual function to be overriden for Exact and Sketch Aggregators
virtual T get_quantiles(double q) { return values_[0]; }

// virtual function to be overriden for Sketch Aggregator
virtual double get_error_bound() { return 0; }

// virtual function to be overriden for Sketch Aggregator
virtual size_t get_max_buckets() { return 0; }

// virtual function to be overriden for Gauge Aggregator
virtual core::SystemTimestamp get_checkpoint_timestamp() { return core::SystemTimestamp(); }

// Custom copy constructor to handle the mutex
Aggregator(const Aggregator &cp)
{
values_ = cp.values_;
checkpoint_ = cp.checkpoint_;
kind_ = cp.kind_;
agg_kind_ = cp.agg_kind_;
// use default initialized mutex as they cannot be copied
}

protected:
std::vector<T> values_;
std::vector<T> checkpoint_;
opentelemetry::metrics::InstrumentKind kind_;
std::mutex mu_;
AggregatorKind agg_kind_;
};

} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
101 changes: 101 additions & 0 deletions sdk/include/opentelemetry/sdk/metrics/aggregator/counter_aggregator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#pragma once

#include <mutex>
#include <vector>
#include "opentelemetry/metrics/instrument.h"
#include "opentelemetry/sdk/metrics/aggregator/aggregator.h"
#include "opentelemetry/version.h"

namespace metrics_api = opentelemetry::metrics;

OPENTELEMETRY_BEGIN_NAMESPACE
namespace sdk
{
namespace metrics
{

template <class T>
class CounterAggregator final : public Aggregator<T>
{

public:
CounterAggregator(metrics_api::InstrumentKind kind)
{
this->kind_ = kind;
this->values_ = std::vector<T>(1, 0);
this->checkpoint_ = std::vector<T>(1, 0);
this->agg_kind_ = AggregatorKind::Counter;
}

/**
* Recieves a captured value from the instrument and applies it to the current aggregator value.
*
* @param val, the raw value used in aggregation
* @return none
*/
void update(T val) override
{
this->mu_.lock();
this->values_[0] += val; // atomic operation
this->mu_.unlock();
}

/**
* Checkpoints the current value. This function will overwrite the current checkpoint with the
* current value.
*
* @param none
* @return none
*/
void checkpoint() override
{
this->checkpoint_ = this->values_;
this->values_[0] = 0;
}

/**
* Merges the values of two aggregators in a semantically accurate manner.
* In this case, merging only requires the the current values of the two aggregators be summed.
*
* @param other, the aggregator with merge with
* @return none
*/
void merge(CounterAggregator other)
{
if (this->agg_kind_ == other.agg_kind_)
{
this->mu_.lock();
this->values_[0] += other.values_[0];
this->checkpoint_[0] += other.checkpoint_[0];
this->mu_.unlock();
}
else
{
#if __EXCEPTIONS
throw std::invalid_argument("Aggregators of different types cannot be merged.");
#else
std::terminate();
#endif
}
}

/**
* Returns the checkpointed value
*
* @param none
* @return the value of the checkpoint
*/
virtual std::vector<T> get_checkpoint() override { return this->checkpoint_; }

/**
* Returns the current values
*
* @param none
* @return the present aggregator values
*/
virtual std::vector<T> get_values() override { return this->values_; }
};

} // namespace metrics
} // namespace sdk
OPENTELEMETRY_END_NAMESPACE
Loading