-
Notifications
You must be signed in to change notification settings - Fork 502
[Metrics] Perform async Re-Aggregation when Spatial Attributes are dropped #3691
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
base: main
Are you sure you want to change the base?
Changes from 2 commits
095da8d
c48f6e1
5487b02
36d47c2
a6cbbbd
880567f
881c1e7
f12966d
927c117
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,14 +3,13 @@ | |
|
|
||
| #pragma once | ||
|
|
||
| #include <unordered_map> | ||
| #include <memory> | ||
|
|
||
| #include "opentelemetry/common/attribute_value.h" | ||
| #include "opentelemetry/common/key_value_iterable.h" | ||
| #include "opentelemetry/metrics/observer_result.h" | ||
| #include "opentelemetry/nostd/string_view.h" | ||
| #include "opentelemetry/sdk/metrics/state/attributes_hashmap.h" | ||
| #include "opentelemetry/sdk/metrics/view/attributes_processor.h" | ||
| #include "opentelemetry/sdk/metrics/state/measurement_attributes_map.h" | ||
| #include "opentelemetry/version.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
|
|
@@ -22,32 +21,33 @@ template <class T> | |
| class ObserverResultT final : public opentelemetry::metrics::ObserverResultT<T> | ||
| { | ||
| public: | ||
| explicit ObserverResultT(const AttributesProcessor *attributes_processor = nullptr) | ||
| : attributes_processor_(attributes_processor) | ||
| {} | ||
| explicit ObserverResultT() = default; | ||
|
|
||
| ~ObserverResultT() override = default; | ||
|
|
||
| void Observe(T value) noexcept override | ||
| { | ||
| data_[MetricAttributes{{}, attributes_processor_}] = value; | ||
| std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue> empty; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be replaced with new type |
||
| data_[empty] += value; | ||
| } | ||
|
|
||
| void Observe(T value, const opentelemetry::common::KeyValueIterable &attributes) noexcept override | ||
| { | ||
| data_[MetricAttributes{attributes, attributes_processor_}] = | ||
| value; // overwrites the previous value if present | ||
| std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue> attr_map; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. replace with new type |
||
| attributes.ForEachKeyValue( | ||
| [&](nostd::string_view key, opentelemetry::common::AttributeValue val) noexcept { | ||
| attr_map.emplace(key, val); | ||
| return true; | ||
| }); | ||
| data_[attr_map] += value; | ||
| } | ||
|
|
||
| const std::unordered_map<MetricAttributes, T, AttributeHashGenerator> &GetMeasurements() | ||
| { | ||
| return data_; | ||
| } | ||
| const MeasurementAttributes<T> &GetMeasurements() { return data_; } | ||
|
|
||
| private: | ||
| std::unordered_map<MetricAttributes, T, AttributeHashGenerator> data_; | ||
| const AttributesProcessor *attributes_processor_; | ||
| MeasurementAttributes<T> data_; | ||
| }; | ||
|
|
||
| } // namespace metrics | ||
| } // namespace sdk | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <cstring> | ||
| #include <string> | ||
| #include <unordered_map> | ||
| #include <utility> | ||
|
|
||
| #include "opentelemetry/common/attribute_value.h" | ||
| #include "opentelemetry/common/key_value_iterable.h" | ||
| #include "opentelemetry/nostd/string_view.h" | ||
| #include "opentelemetry/sdk/common/custom_hash_equality.h" | ||
| #include "opentelemetry/sdk/metrics/state/filtered_ordered_attribute_map.h" | ||
| #include "opentelemetry/version.h" | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace metrics | ||
| { | ||
|
|
||
| // Hash function for AttributeValue (int and string only) | ||
| struct AttributeValueHash | ||
| { | ||
| size_t operator()(const opentelemetry::common::AttributeValue &value) const noexcept | ||
| { | ||
| if (nostd::holds_alternative<int32_t>(value)) | ||
| { | ||
| return std::hash<int32_t>{}(nostd::get<int32_t>(value)); | ||
| } | ||
| else if (nostd::holds_alternative<int64_t>(value)) | ||
| { | ||
| return std::hash<int64_t>{}(nostd::get<int64_t>(value)); | ||
| } | ||
| else if (nostd::holds_alternative<const char *>(value)) | ||
| { | ||
| return std::hash<nostd::string_view>{}(nostd::string_view(nostd::get<const char *>(value))); | ||
| } | ||
| else if (nostd::holds_alternative<nostd::string_view>(value)) | ||
| { | ||
| return std::hash<nostd::string_view>{}(nostd::get<nostd::string_view>(value)); | ||
| } | ||
|
|
||
| return 0; // fallback for other types | ||
nikhilbhatia08 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| }; | ||
|
|
||
| // Equality function for AttributeValue (int and string only) | ||
| struct AttributeValueEqual | ||
| { | ||
| bool operator()(const opentelemetry::common::AttributeValue &a, | ||
| const opentelemetry::common::AttributeValue &b) const noexcept | ||
| { | ||
| if (a.index() != b.index()) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| // Compare int32_t | ||
| if (nostd::holds_alternative<int32_t>(a)) | ||
| { | ||
| return nostd::get<int32_t>(a) == nostd::get<int32_t>(b); | ||
| } | ||
| // Compare int64_t | ||
| else if (nostd::holds_alternative<int64_t>(a)) | ||
| { | ||
| return nostd::get<int64_t>(a) == nostd::get<int64_t>(b); | ||
| } | ||
| // Compare const char* | ||
| else if (nostd::holds_alternative<const char *>(a)) | ||
| { | ||
| return nostd::string_view(nostd::get<const char *>(a)) == | ||
| nostd::string_view(nostd::get<const char *>(b)); | ||
| } | ||
| // Compare string_view | ||
| else if (nostd::holds_alternative<nostd::string_view>(a)) | ||
| { | ||
| return nostd::get<nostd::string_view>(a) == nostd::get<nostd::string_view>(b); | ||
| } | ||
|
|
||
| return false; | ||
nikhilbhatia08 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| }; | ||
|
|
||
| // Hash function for unordered_map of key-value pairs | ||
| // This Custom Hash is only applied to strings and int for now | ||
| struct AttributeMapHash | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see |
||
| { | ||
| size_t operator()( | ||
| const std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue> &map) | ||
| const noexcept | ||
| { | ||
| size_t hash = 0; | ||
| AttributeValueHash value_hasher; | ||
|
|
||
| for (const auto &pair : map) | ||
| { | ||
| // Combine key hash | ||
| size_t key_hash = std::hash<nostd::string_view>{}(pair.first); | ||
| hash ^= key_hash + 0x9e3779b9 + (hash << 6) + (hash >> 2); | ||
|
|
||
| // Combine value hash | ||
| size_t value_hash = value_hasher(pair.second); | ||
| hash ^= value_hash + 0x9e3779b9 + (hash << 6) + (hash >> 2); | ||
| } | ||
|
|
||
| return hash; | ||
| } | ||
| }; | ||
|
|
||
| // Equality function for unordered_map of key-value pairs | ||
| // This Custom Equal is only applied to strings and int for now | ||
| struct AttributeMapEqual | ||
| { | ||
| bool operator()( | ||
| const std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue> &a, | ||
| const std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue> &b) | ||
| const noexcept | ||
| { | ||
| if (a.size() != b.size()) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| AttributeValueEqual value_equal; | ||
|
|
||
| for (const auto &pair_a : a) | ||
| { | ||
| auto it = b.find(pair_a.first); | ||
| if (it == b.end()) | ||
| { | ||
| return false; // key not found in b | ||
| } | ||
|
|
||
| // Compare values | ||
| if (!value_equal(pair_a.second, it->second)) | ||
| { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
| }; | ||
|
|
||
| template <class T> | ||
| using MeasurementAttributes = std::unordered_map< | ||
| std::unordered_map<nostd::string_view, opentelemetry::common::AttributeValue>, | ||
| T, | ||
| AttributeMapHash, | ||
| AttributeMapEqual>; | ||
|
|
||
| } // namespace metrics | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add another type here for use in AsyncMetricStorage: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure that it's worth, adding another runtime expensive associative container just for a list of some attributes. Unordered_map gets efficient with thousands and thousands of entries. But still very slow in comparison to a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. with the type |
||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
explicit not required for default constructor. Here it can also be removed (rule of 0)