From 6099f79307adc8f66b4ef0ae0692a18551b11bf1 Mon Sep 17 00:00:00 2001 From: Josh Westbrook Date: Wed, 8 Jan 2025 14:16:01 -0600 Subject: [PATCH 1/4] feat: Gauge metrics exporter encoding (#1780) * feat: Gauge metrics exporter encoding * fix: combine observable_gauge and gauge * fix: rubocop --- .../exporter/otlp/metrics/metrics_exporter.rb | 5 ++-- .../otlp/metrics/metrics_exporter_test.rb | 23 +++++++++++++++++++ exporter/otlp-metrics/test/test_helper.rb | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb index 36705bbf7d..d2beac6d53 100644 --- a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb +++ b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/metrics_exporter.rb @@ -214,18 +214,17 @@ def encode(metrics_data) end # metrics_pb has following type of data: :gauge, :sum, :histogram, :exponential_histogram, :summary - # current metric sdk only implements instrument: :counter -> :sum, :histogram -> :histogram + # current metric sdk only implements instrument: :counter -> :sum, :histogram -> :histogram, :gauge -> :gauge # # metrics [MetricData] def as_otlp_metrics(metrics) case metrics.instrument_kind - when :observable_gauge + when :observable_gauge, :gauge Opentelemetry::Proto::Metrics::V1::Metric.new( name: metrics.name, description: metrics.description, unit: metrics.unit, gauge: Opentelemetry::Proto::Metrics::V1::Gauge.new( - aggregation_temporality: as_otlp_aggregation_temporality(metrics.aggregation_temporality), data_points: metrics.data_points.map do |ndp| number_data_point(ndp) end diff --git a/exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics/metrics_exporter_test.rb b/exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics/metrics_exporter_test.rb index 6076a80a20..020d0e9a8d 100644 --- a/exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics/metrics_exporter_test.rb +++ b/exporter/otlp-metrics/test/opentelemetry/exporter/otlp/metrics/metrics_exporter_test.rb @@ -576,11 +576,16 @@ stub_request(:post, 'http://localhost:4318/v1/metrics').to_return(status: 200) meter_provider.add_metric_reader(exporter) meter = meter_provider.meter('test') + counter = meter.create_counter('test_counter', unit: 'smidgen', description: 'a small amount of something') counter.add(5, attributes: { 'foo' => 'bar' }) histogram = meter.create_histogram('test_histogram', unit: 'smidgen', description: 'a small amount of something') histogram.record(10, attributes: { 'oof' => 'rab' }) + + gauge = meter.create_gauge('test_gauge', unit: 'smidgen', description: 'a small amount of something') + gauge.record(15, attributes: { 'baz' => 'qux' }) + exporter.pull meter_provider.shutdown @@ -644,6 +649,24 @@ ], aggregation_temporality: Opentelemetry::Proto::Metrics::V1::AggregationTemporality::AGGREGATION_TEMPORALITY_DELTA ) + ), + Opentelemetry::Proto::Metrics::V1::Metric.new( + name: 'test_gauge', + description: 'a small amount of something', + unit: 'smidgen', + gauge: Opentelemetry::Proto::Metrics::V1::Gauge.new( + data_points: [ + Opentelemetry::Proto::Metrics::V1::NumberDataPoint.new( + attributes: [ + Opentelemetry::Proto::Common::V1::KeyValue.new(key: 'baz', value: Opentelemetry::Proto::Common::V1::AnyValue.new(string_value: 'qux')) + ], + as_int: 15, + start_time_unix_nano: 1_699_593_427_329_946_585, + time_unix_nano: 1_699_593_427_329_946_586, + exemplars: nil + ) + ] + ) ) ] ) diff --git a/exporter/otlp-metrics/test/test_helper.rb b/exporter/otlp-metrics/test/test_helper.rb index 9fc4466458..4d3e4df6d9 100644 --- a/exporter/otlp-metrics/test/test_helper.rb +++ b/exporter/otlp-metrics/test/test_helper.rb @@ -26,6 +26,7 @@ def collect(start_time, end_time, data_points) OpenTelemetry::SDK::Metrics::Aggregation::Sum.prepend(MockSum) OpenTelemetry::SDK::Metrics::Aggregation::ExplicitBucketHistogram.prepend(MockSum) +OpenTelemetry::SDK::Metrics::Aggregation::LastValue.prepend(MockSum) def create_metrics_data(name: '', description: '', unit: '', instrument_kind: :counter, resource: nil, instrumentation_scope: OpenTelemetry::SDK::InstrumentationScope.new('', 'v0.0.1'), From 1c6004d76b985fb6ad03e30c934036c622e9ae51 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:32:34 -0500 Subject: [PATCH 2/4] docs: use link-inspector (#1790) Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> --- .github/workflows/ci-markdown-link.yml | 13 ++++++++----- .markdown-link-check.json | 10 ---------- 2 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 .markdown-link-check.json diff --git a/.github/workflows/ci-markdown-link.yml b/.github/workflows/ci-markdown-link.yml index 7b42be0c1e..626a8fce42 100644 --- a/.github/workflows/ci-markdown-link.yml +++ b/.github/workflows/ci-markdown-link.yml @@ -2,6 +2,8 @@ name: Markdown Link Check on: pull_request: + paths: + - '**/*.md' jobs: markdown-link-check: @@ -9,9 +11,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: "Markdown Link Check" - uses: gaurav-nelson/github-action-markdown-link-check@v1 + # equivalent cli: linkspector check + - name: Run linkspector + uses: umbrelladocs/action-linkspector@v1 with: - config-file: '.markdown-link-check.json' - use-quiet-mode: 'yes' - use-verbose-mode: 'yes' + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-pr-review + fail_on_error: true diff --git a/.markdown-link-check.json b/.markdown-link-check.json deleted file mode 100644 index 12284d673f..0000000000 --- a/.markdown-link-check.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "ignorePatterns": [ - { - "pattern": "^http://localhost" - } - ], - "timeout": "5s", - "retryOn429": true, - "aliveStatusCodes": [200, 206, 429] -} From a24500c251a2c472d6a200261a81b4d6e59800f6 Mon Sep 17 00:00:00 2001 From: Xuan <112967240+xuan-cao-swi@users.noreply.github.com> Date: Wed, 8 Jan 2025 17:12:06 -0500 Subject: [PATCH 3/4] docs: add documentation for Metrics API instruments (#1720) * docs: add documentation for Metrics API instruments * Update metrics_api/lib/opentelemetry/metrics/meter.rb Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> * Update metrics_api/lib/opentelemetry/metrics/meter.rb Co-authored-by: Hannah Ramadan <76922290+hannahramadan@users.noreply.github.com> * Update metrics_api/lib/opentelemetry/metrics/meter.rb * Update metrics_api/lib/opentelemetry/metrics/meter.rb --------- Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> Co-authored-by: Hannah Ramadan <76922290+hannahramadan@users.noreply.github.com> --- .../lib/opentelemetry/metrics/meter.rb | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/metrics_api/lib/opentelemetry/metrics/meter.rb b/metrics_api/lib/opentelemetry/metrics/meter.rb index 7bfc1e498a..7b7b524cdf 100644 --- a/metrics_api/lib/opentelemetry/metrics/meter.rb +++ b/metrics_api/lib/opentelemetry/metrics/meter.rb @@ -30,10 +30,38 @@ def initialize @instrument_registry = {} end + # {https://opentelemetry.io/docs/specs/otel/metrics/api/#counter Counter} is a synchronous Instrument which supports non-negative increments. + # + # With this api call: + # + # exception_counter = meter.create_counter("exceptions", + # description: "number of exceptions caught", + # unit: 's') + # + # @param name [String] the name of the counter + # @param unit [optional String] an optional string provided by user. + # @param description [optional String] an optional free-form text provided by user. + # + # @return [nil] after creation of counter, it will be stored in instrument_registry def create_counter(name, unit: nil, description: nil) create_instrument(:counter, name, unit, description, nil) { COUNTER } end + # Histogram is a synchronous Instrument which can be used to report arbitrary values that are likely + # to be statistically meaningful. It is intended for statistics such as histograms, + # summaries, and percentiles. + # + # With this api call: + # + # http_server_duration = meter.create_histogram("http.server.duration", + # description: "measures the duration of the inbound HTTP request", + # unit: "s") + # + # @param name [String] the name of the histogram + # @param unit [optional String] an optional string provided by user. + # @param description [optional String] an optional free-form text provided by user. + # + # @return [nil] after creation of histogram, it will be stored in instrument_registry def create_histogram(name, unit: nil, description: nil) create_instrument(:histogram, name, unit, description, nil) { HISTOGRAM } end @@ -56,18 +84,87 @@ def create_gauge(name, unit: nil, description: nil) create_instrument(:gauge, name, unit, description, nil) { GAUGE } end + # UpDownCounter is a synchronous Instrument which supports increments and decrements. + # + # With this api call: + # + # items_counter = meter.create_up_down_counter("store.inventory", + # description: "the number of the items available", + # unit: "s") + # + # @param name [String] the name of the up_down_counter + # @param unit [optional String] an optional string provided by user. + # @param description [optional String] an optional free-form text provided by user. + # + # @return [nil] after creation of up_down_counter, it will be stored in instrument_registry def create_up_down_counter(name, unit: nil, description: nil) create_instrument(:up_down_counter, name, unit, description, nil) { UP_DOWN_COUNTER } end + # ObservableCounter is an asynchronous Instrument which reports monotonically + # increasing value(s) when the instrument is being observed. + # + # With this api call: + # + # pf_callback = -> { # collect metrics here } + # meter.create_observable_counter("PF", + # pf_callback, + # description: "process page faults", + # unit: 'ms') + # + # + # @param name [String] the name of the observable_counter + # @param callback [Proc] the callback function that used to collect metrics + # @param unit [optional String] an optional string provided by user. + # @param description [optional String] an optional free-form text provided by user. + # + # @return [nil] after creation of observable_counter, it will be stored in instrument_registry def create_observable_counter(name, callback:, unit: nil, description: nil) create_instrument(:observable_counter, name, unit, description, callback) { OBSERVABLE_COUNTER } end + # ObservableGauge is an asynchronous Instrument which reports non-additive value(s) + # (e.g. the room temperature - it makes no sense to report the temperature value + # from multiple rooms and sum them up) when the instrument is being observed. + # + # With this api call: + # + # pf_callback = -> { # collect metrics here } + # meter.create_observable_counter("cpu.frequency", + # pf_callback, + # description: "the real-time CPU clock speed", + # unit: 'ms') + # + # + # @param name [String] the name of the observable_gauge + # @param callback [Proc] the callback function that used to collect metrics + # @param unit [optional String] an optional string provided by user. + # @param description [optional String] an optional free-form text provided by user. + # + # @return [nil] after creation of observable_gauge, it will be stored in instrument_registry def create_observable_gauge(name, callback:, unit: nil, description: nil) create_instrument(:observable_gauge, name, unit, description, callback) { OBSERVABLE_GAUGE } end + # ObservableUpDownCounter is an asynchronous Instrument which reports additive value(s) + # (e.g. the process heap size - it makes sense to report the heap size from multiple processes + # and sum them up, so we get the total heap usage) when the instrument is being observed. + # + # With this api call: + # + # pf_callback = -> { # collect metrics here } + # meter.create_observable_up_down_counter("process.workingset", + # pf_callback, + # description: "process working set", + # unit: 'KB') + # + # + # @param name [String] the name of the observable_up_down_counter + # @param callback [Proc] the callback function that used to collect metrics + # @param unit [optional String] an optional string provided by user. + # @param description [optional String] an optional free-form text provided by user. + # + # @return [nil] after creation of observable_up_down_counter, it will be stored in instrument_registry def create_observable_up_down_counter(name, callback:, unit: nil, description: nil) create_instrument(:observable_up_down_counter, name, unit, description, callback) { OBSERVABLE_UP_DOWN_COUNTER } end From baeda39731d70f3f18ac8693168039fb8a1d2c8c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Jan 2025 16:15:40 -0800 Subject: [PATCH 4/4] release: Release 3 gems (#1791) * release: Release 3 gems * opentelemetry-exporter-otlp-metrics 0.3.0 (was 0.2.1) * opentelemetry-metrics-api 0.2.0 (was 0.1.1) * opentelemetry-metrics-sdk 0.5.0 (was 0.4.1) * Apply suggestions from code review * chore: Increase minimum dependencies To make sure Gauge is accessible across all gems, raise the min version for metrics API and SDK to latest versions --------- Co-authored-by: Daniel Azuma Co-authored-by: Kayla Reopelle <87386821+kaylareopelle@users.noreply.github.com> Co-authored-by: Kayla Reopelle --- exporter/otlp-metrics/CHANGELOG.md | 4 ++++ .../lib/opentelemetry/exporter/otlp/metrics/version.rb | 2 +- .../otlp-metrics/opentelemetry-exporter-otlp-metrics.gemspec | 4 ++-- metrics_api/CHANGELOG.md | 5 +++++ metrics_api/lib/opentelemetry/metrics/version.rb | 2 +- metrics_sdk/CHANGELOG.md | 4 ++++ metrics_sdk/lib/opentelemetry/sdk/metrics/version.rb | 2 +- metrics_sdk/opentelemetry-metrics-sdk.gemspec | 2 +- 8 files changed, 19 insertions(+), 6 deletions(-) diff --git a/exporter/otlp-metrics/CHANGELOG.md b/exporter/otlp-metrics/CHANGELOG.md index 2151e8eaa9..6a274b08a2 100644 --- a/exporter/otlp-metrics/CHANGELOG.md +++ b/exporter/otlp-metrics/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-exporter-otlp-metrics +### v0.3.0 / 2025-01-08 + +* ADDED: Gauge metrics exporter encoding + ### v0.2.1 / 2024-12-04 * FIXED: Handle float value in NumberDataPoint diff --git a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/version.rb b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/version.rb index 4dd459fd6d..7640052da0 100644 --- a/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/version.rb +++ b/exporter/otlp-metrics/lib/opentelemetry/exporter/otlp/metrics/version.rb @@ -9,7 +9,7 @@ module Exporter module OTLP module Metrics ## Current OpenTelemetry OTLP exporter version - VERSION = '0.2.1' + VERSION = '0.3.0' end end end diff --git a/exporter/otlp-metrics/opentelemetry-exporter-otlp-metrics.gemspec b/exporter/otlp-metrics/opentelemetry-exporter-otlp-metrics.gemspec index 0729f3e377..bbcd01844a 100644 --- a/exporter/otlp-metrics/opentelemetry-exporter-otlp-metrics.gemspec +++ b/exporter/otlp-metrics/opentelemetry-exporter-otlp-metrics.gemspec @@ -29,8 +29,8 @@ Gem::Specification.new do |spec| spec.add_dependency 'google-protobuf', '>= 3.18', '< 5.0' spec.add_dependency 'opentelemetry-api', '~> 1.1' spec.add_dependency 'opentelemetry-common', '~> 0.20' - spec.add_dependency 'opentelemetry-metrics-api', '~> 0.1' - spec.add_dependency 'opentelemetry-metrics-sdk', '~> 0.2' + spec.add_dependency 'opentelemetry-metrics-api', '~> 0.2' + spec.add_dependency 'opentelemetry-metrics-sdk', '~> 0.5' spec.add_dependency 'opentelemetry-sdk', '~> 1.2' spec.add_dependency 'opentelemetry-semantic_conventions' diff --git a/metrics_api/CHANGELOG.md b/metrics_api/CHANGELOG.md index afbcca5eac..bb73745fa5 100644 --- a/metrics_api/CHANGELOG.md +++ b/metrics_api/CHANGELOG.md @@ -1,5 +1,10 @@ # Release History: opentelemetry-metrics-api +### v0.2.0 / 2025-01-08 + +* ADDED: Add synchronous gauge +* DOCS: Add documentation for Metrics API instruments + ### v0.1.1 / 2024-10-22 * FIXED: Refactor instrument validation diff --git a/metrics_api/lib/opentelemetry/metrics/version.rb b/metrics_api/lib/opentelemetry/metrics/version.rb index ab557fc819..fc9c43e1ef 100644 --- a/metrics_api/lib/opentelemetry/metrics/version.rb +++ b/metrics_api/lib/opentelemetry/metrics/version.rb @@ -7,6 +7,6 @@ module OpenTelemetry module Metrics ## Current OpenTelemetry metrics version - VERSION = '0.1.1' + VERSION = '0.2.0' end end diff --git a/metrics_sdk/CHANGELOG.md b/metrics_sdk/CHANGELOG.md index 57e69fb906..a442524c00 100644 --- a/metrics_sdk/CHANGELOG.md +++ b/metrics_sdk/CHANGELOG.md @@ -1,5 +1,9 @@ # Release History: opentelemetry-metrics-sdk +### v0.5.0 / 2025-01-08 + +* ADDED: Add synchronous gauge + ### v0.4.1 / 2024-12-04 * FIXED: Handle float value in NumberDataPoint diff --git a/metrics_sdk/lib/opentelemetry/sdk/metrics/version.rb b/metrics_sdk/lib/opentelemetry/sdk/metrics/version.rb index c33a284e94..440bfed4d7 100644 --- a/metrics_sdk/lib/opentelemetry/sdk/metrics/version.rb +++ b/metrics_sdk/lib/opentelemetry/sdk/metrics/version.rb @@ -8,7 +8,7 @@ module OpenTelemetry module SDK module Metrics # Current OpenTelemetry metrics sdk version - VERSION = '0.4.1' + VERSION = '0.5.0' end end end diff --git a/metrics_sdk/opentelemetry-metrics-sdk.gemspec b/metrics_sdk/opentelemetry-metrics-sdk.gemspec index 1919305ac5..3de7a61519 100644 --- a/metrics_sdk/opentelemetry-metrics-sdk.gemspec +++ b/metrics_sdk/opentelemetry-metrics-sdk.gemspec @@ -26,7 +26,7 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 3.0' spec.add_dependency 'opentelemetry-api', '~> 1.1' - spec.add_dependency 'opentelemetry-metrics-api', '~> 0.1.1' + spec.add_dependency 'opentelemetry-metrics-api', '~> 0.2' spec.add_dependency 'opentelemetry-sdk', '~> 1.2' spec.add_development_dependency 'benchmark-ipsa', '~> 0.2.0'