-
Notifications
You must be signed in to change notification settings - Fork 560
Fix: 1712 - Validate Instrument meta data (name, unit, description) #1713
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
Changes from all commits
05c0575
6e0dda6
f06d877
5c42903
f9938cd
0616147
766c2dd
cbfceae
c191e69
c22da62
c5ef46d
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 |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| #pragma once | ||
| #ifndef ENABLE_METRICS_PREVIEW | ||
| # include <string> | ||
| # include "opentelemetry/common/macros.h" | ||
| # include "opentelemetry/nostd/string_view.h" | ||
| # include "opentelemetry/version.h" | ||
|
|
||
| # if HAVE_WORKING_REGEX | ||
| # include <regex> | ||
| # endif | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace metrics | ||
| { | ||
| class InstrumentMetaDataValidator | ||
| { | ||
| public: | ||
| InstrumentMetaDataValidator(); | ||
| bool ValidateName(nostd::string_view name) const; | ||
| bool ValidateUnit(nostd::string_view unit) const; | ||
| bool ValidateDescription(nostd::string_view description) const; | ||
|
|
||
| private: | ||
| # if HAVE_WORKING_REGEX | ||
| const std::regex name_reg_key_; | ||
| const std::regex unit_reg_key_; | ||
| # endif | ||
| }; | ||
|
|
||
| } // namespace metrics | ||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| // Copyright The OpenTelemetry Authors | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| #ifndef ENABLE_METRICS_PREVIEW | ||
| # include "opentelemetry/sdk/metrics/instrument_metadata_validator.h" | ||
| # include "opentelemetry/common/macros.h" | ||
| # include "opentelemetry/nostd/string_view.h" | ||
|
|
||
| # include <algorithm> | ||
| # include <iostream> | ||
|
|
||
| OPENTELEMETRY_BEGIN_NAMESPACE | ||
| namespace sdk | ||
| { | ||
| namespace metrics | ||
| { | ||
| // instrument-name = ALPHA 0*62 ("_" / "." / "-" / ALPHA / DIGIT) | ||
| const std::string kInstrumentNamePattern = "[a-zA-Z][-_.a-zA-Z0-9]{0,62}"; | ||
| // | ||
| const std::string kInstrumentUnitPattern = "[\x01-\x7F]{0,63}"; | ||
| // instrument-unit = It can have a maximum length of 63 ASCII chars | ||
|
|
||
| InstrumentMetaDataValidator::InstrumentMetaDataValidator() | ||
| # if HAVE_WORKING_REGEX | ||
| // clang-format off | ||
| : name_reg_key_{kInstrumentNamePattern}, | ||
| unit_reg_key_{kInstrumentUnitPattern} | ||
| // clang-format on | ||
| # endif | ||
| {} | ||
|
Contributor
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. Should this be put under
Member
Author
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. no it's fine actually. The part of code was somewhat confusing with clang-format. It should be more clear now. |
||
|
|
||
| bool InstrumentMetaDataValidator::ValidateName(nostd::string_view name) const | ||
| { | ||
|
|
||
| # if HAVE_WORKING_REGEX | ||
| return std::regex_match(name.data(), name_reg_key_); | ||
| # else | ||
| const size_t kMaxSize = 63; | ||
| // size atmost 63 chars | ||
| if (name.size() > kMaxSize) | ||
| { | ||
| return false; | ||
| } | ||
| // first char should be alpha | ||
| if (!isalpha(name[0])) | ||
| { | ||
| return false; | ||
| } | ||
| // subsequent chars should be either of alphabets, digits, underscore, minus, dot | ||
| return !std::any_of(std::next(name.begin()), name.end(), | ||
| [](char c) { return !isalnum(c) && c != '-' && c != '_' && c != '.'; }); | ||
| # endif | ||
| } | ||
|
|
||
| bool InstrumentMetaDataValidator::ValidateUnit(nostd::string_view unit) const | ||
| { | ||
| # if HAVE_WORKING_REGEX | ||
| return std::regex_match(unit.data(), unit_reg_key_); | ||
| # else | ||
| const size_t kMaxSize = 63; | ||
| // length atmost 63 chars | ||
| if (unit.size() > kMaxSize) | ||
| { | ||
| return false; | ||
| } | ||
| // all should be ascii chars. | ||
| return !std::any_of(unit.begin(), unit.end(), | ||
| [](char c) { return static_cast<unsigned char>(c) > 127; }); | ||
| # endif | ||
| } | ||
|
|
||
| bool InstrumentMetaDataValidator::ValidateDescription(nostd::string_view /*description*/) const | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace metrics | ||
| } // namespace sdk | ||
| OPENTELEMETRY_END_NAMESPACE | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
| # include "opentelemetry/sdk/metrics/state/observable_registry.h" | ||
| # include "opentelemetry/sdk/metrics/state/sync_metric_storage.h" | ||
|
|
||
| # include "opentelemetry/sdk/common/global_log_handler.h" | ||
| # include "opentelemetry/sdk/metrics/sync_instruments.h" | ||
| # include "opentelemetry/sdk_config.h" | ||
|
|
||
|
|
@@ -39,6 +40,14 @@ nostd::unique_ptr<metrics::Counter<uint64_t>> Meter::CreateUInt64Counter( | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateUInt64Counter - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return nostd::unique_ptr<metrics::Counter<uint64_t>>( | ||
| new metrics::NoopCounter<uint64_t>(name, description, unit)); | ||
|
Member
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. The calling instrumented application will not notice the error if returning a noop counter. Not crashing now with a noop is not helping. How about returning a nullptr, forcing the calling application to do something about it ?
Member
Author
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. Yes, good point. I too thought about it, but also felt that making critical application crash for some issue in telemetry configuration is not a good idea. We can also be more explicit in error message stating that measurements won't be recorded. This is also inline with the general error handling guidelines -
Member
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. Thanks for the details. Ok with noop then. |
||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kCounter, InstrumentValueType::kLong}; | ||
|
|
@@ -52,6 +61,14 @@ nostd::unique_ptr<metrics::Counter<double>> Meter::CreateDoubleCounter( | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateDoubleCounter - failed. Invalid parameters." | ||
|
Contributor
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. nit: probably use macro
Member
Author
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. yes, probably we can modify |
||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return nostd::unique_ptr<metrics::Counter<double>>( | ||
| new metrics::NoopCounter<double>(name, description, unit)); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kCounter, | ||
|
|
@@ -66,6 +83,13 @@ nostd::shared_ptr<opentelemetry::metrics::ObservableInstrument> Meter::CreateInt | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateInt64ObservableCounter - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return GetNoopObservableInsrument(); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kObservableCounter, | ||
|
|
@@ -80,6 +104,13 @@ Meter::CreateDoubleObservableCounter(nostd::string_view name, | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateDoubleObservableCounter - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return GetNoopObservableInsrument(); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kObservableCounter, | ||
|
|
@@ -94,6 +125,14 @@ nostd::unique_ptr<metrics::Histogram<uint64_t>> Meter::CreateUInt64Histogram( | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateUInt64Histogram - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return nostd::unique_ptr<metrics::Histogram<uint64_t>>( | ||
| new metrics::NoopHistogram<uint64_t>(name, description, unit)); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kHistogram, | ||
|
|
@@ -108,6 +147,14 @@ nostd::unique_ptr<metrics::Histogram<double>> Meter::CreateDoubleHistogram( | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateDoubleHistogram - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return nostd::unique_ptr<metrics::Histogram<double>>( | ||
| new metrics::NoopHistogram<double>(name, description, unit)); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kHistogram, | ||
|
|
@@ -122,6 +169,13 @@ nostd::shared_ptr<opentelemetry::metrics::ObservableInstrument> Meter::CreateInt | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateInt64ObservableGauge - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return GetNoopObservableInsrument(); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kObservableGauge, | ||
|
|
@@ -136,6 +190,13 @@ nostd::shared_ptr<opentelemetry::metrics::ObservableInstrument> Meter::CreateDou | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateDoubleObservableGauge - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return GetNoopObservableInsrument(); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kObservableGauge, | ||
|
|
@@ -150,6 +211,14 @@ nostd::unique_ptr<metrics::UpDownCounter<int64_t>> Meter::CreateInt64UpDownCount | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateInt64UpDownCounter - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return nostd::unique_ptr<metrics::UpDownCounter<int64_t>>( | ||
| new metrics::NoopUpDownCounter<int64_t>(name, description, unit)); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kUpDownCounter, | ||
|
|
@@ -164,6 +233,14 @@ nostd::unique_ptr<metrics::UpDownCounter<double>> Meter::CreateDoubleUpDownCount | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR("Meter::CreateDoubleUpDownCounter - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit | ||
| << ". Measurements won't be recorded."); | ||
| return nostd::unique_ptr<metrics::UpDownCounter<double>>( | ||
| new metrics::NoopUpDownCounter<double>(name, description, unit)); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kUpDownCounter, | ||
|
|
@@ -178,6 +255,13 @@ Meter::CreateInt64ObservableUpDownCounter(nostd::string_view name, | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR( | ||
| "Meter::CreateInt64ObservableUpDownCounter - failed. Invalid parameters -" | ||
| << name << " " << description << " " << unit << ". Measurements won't be recorded."); | ||
| return GetNoopObservableInsrument(); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kObservableUpDownCounter, | ||
|
|
@@ -192,6 +276,13 @@ Meter::CreateDoubleObservableUpDownCounter(nostd::string_view name, | |
| nostd::string_view description, | ||
| nostd::string_view unit) noexcept | ||
| { | ||
| if (!ValidateInstrument(name, description, unit)) | ||
| { | ||
| OTEL_INTERNAL_LOG_ERROR( | ||
| "Meter::CreateDoubleObservableUpDownCounter - failed. Invalid parameters." | ||
| << name << " " << description << " " << unit << ". Measurements won't be recorded."); | ||
| return GetNoopObservableInsrument(); | ||
| } | ||
| InstrumentDescriptor instrument_descriptor = { | ||
| std::string{name.data(), name.size()}, std::string{description.data(), description.size()}, | ||
| std::string{unit.data(), unit.size()}, InstrumentType::kObservableUpDownCounter, | ||
|
|
||
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.
nit: GNUC_MINOR >= 8?
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.
The regex support is partially implemented for gcc 4.8 and gcc 4.9 only. So the existing condition looks good to me.
Uh oh!
There was an error while loading. Please reload this page.
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.
But yeah, even GNUC_MINOR >= 8 should work fine. But let it be explicit. This was already existing in predicate.h, I just moved it here at common place :)