Skip to content

Commit 0827267

Browse files
authored
RCBC-524: OpenTelemetry integration (#216)
1 parent 691a27b commit 0827267

27 files changed

+835
-48
lines changed

.github/workflows/tests.yml

Lines changed: 109 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ jobs:
2020
runs-on: ubuntu-22.04
2121
outputs:
2222
gem_version: ${{ steps.build_gem.outputs.gem_version }}
23+
otel_gem_version: ${{ steps.build_otel_gem.outputs.otel_gem_version }}
2324
steps:
2425
- uses: actions/checkout@v4
2526
with:
@@ -30,15 +31,22 @@ jobs:
3031
with:
3132
ruby-version: 3.3
3233
bundler-cache: true
33-
- name: Build
34+
- name: Build couchbase gem
3435
id: build_gem
3536
run: |
3637
COMMITS_SINCE_LAST_TAG=$(git describe --tags --always --long | awk -F '-' '{print $2}')
3738
ruby bin/jenkins/patch-version.rb ${COMMITS_SINCE_LAST_TAG}
3839
GEM_VERSION=$(ruby -r ./lib/couchbase/version.rb -e "puts Couchbase::VERSION[:sdk]")
3940
echo "gem_version=${GEM_VERSION}" >> "$GITHUB_OUTPUT"
4041
bundle exec rake build
41-
- name: RDoc
42+
- name: Build couchbase-opentelemetry gem
43+
id: build_otel_gem
44+
run: |
45+
cd couchbase-opentelemetry
46+
OTEL_GEM_VERSION=$(ruby -r ./lib/couchbase/opentelemetry/version.rb -e "puts Couchbase::OpenTelemetry::VERSION")
47+
echo "otel_gem_version=${OTEL_GEM_VERSION}" >> "$GITHUB_OUTPUT"
48+
bundle exec rake build
49+
- name: Generate documentation for the couchbase gem
4250
run: |
4351
cat > patch-readme.rb <<EOF
4452
require_relative "./lib/couchbase/version.rb"
@@ -50,36 +58,69 @@ jobs:
5058
File.write("README.md", new_content)
5159
EOF
5260
ruby patch-readme.rb
53-
bundle exec yard doc --hide-api private --output-dir docs/couchbase-ruby-client-${{ steps.build_gem.outputs.gem_version }} lib --main README.md
54-
- uses: actions/upload-artifact@v4
61+
bundle exec rake doc
62+
- name: Generate documentation for the couchbase-opentelemetry gem
63+
run: |
64+
cd couchbase-opentelemetry
65+
cat > patch-readme.rb <<EOF
66+
require_relative "./lib/couchbase/opentelemetry/version.rb"
67+
gemfile = <<EOS.strip
68+
gem "couchbase-opentelemetry", "#{Couchbase::OpenTelemetry::VERSION}"
69+
EOS
70+
old_content = File.read("README.md")
71+
new_content = old_content.gsub(/(gem "couchbase-opentelemetry", ").*?"/, gemfile)
72+
File.write("README.md", new_content)
73+
EOF
74+
ruby patch-readme.rb
75+
bundle exec rake doc
76+
- name: Upload artifact - couchbase gem
77+
uses: actions/upload-artifact@v4
5578
with:
5679
name: couchbase-${{ steps.build_gem.outputs.gem_version }}
5780
path: |
5881
pkg/*.gem
59-
- uses: actions/upload-artifact@v4
82+
- name: Upload artifact - couchbase-opentelemetry gem
83+
uses: actions/upload-artifact@v4
84+
with:
85+
name: couchbase-opentelemetry-${{ steps.build_otel_gem.outputs.otel_gem_version }}
86+
path: |
87+
couchbase-opentelemetry/pkg/*.gem
88+
- name: Upload artifact - scripts
89+
uses: actions/upload-artifact@v4
6090
with:
6191
retention-days: 1
6292
name: scripts-${{ steps.build_gem.outputs.gem_version }}
6393
path: |
64-
Gemfile
6594
Rakefile
95+
couchbase*.gemspec
96+
lib/couchbase/**/version.rb
97+
Gemfile
6698
bin/**/*
67-
couchbase.gemspec
68-
lib/couchbase/version.rb
6999
task/**/*
70-
- uses: actions/upload-artifact@v4
100+
couchbase-opentelemetry/Rakefile
101+
couchbase-opentelemetry/couchbase-opentelemetry*.gemspec
102+
couchbase-opentelemetry/lib/couchbase/opentelemetry/version.rb
103+
- name: Upload artifact - tests and test data
104+
uses: actions/upload-artifact@v4
71105
with:
72106
retention-days: 1
73107
name: tests-${{ steps.build_gem.outputs.gem_version }}
74108
path: |
75109
test/**/*
76110
test_data/**/*
77-
- uses: actions/upload-artifact@v4
111+
- name: Upload artifact - couchbase gem docs
112+
uses: actions/upload-artifact@v4
78113
with:
79114
name: docs-${{ steps.build_gem.outputs.gem_version }}
80115
path: |
81-
docs/**/*
82-
116+
doc/**/*
117+
- name: Upload artifact - couchbase-opentelemetry gem docs
118+
uses: actions/upload-artifact@v4
119+
with:
120+
name: otel-docs-${{ steps.build_otel_gem.outputs.otel_gem_version }}
121+
path: |
122+
couchbase-opentelemetry/doc/**/*
123+
83124
build_alpine_x86_64:
84125
# FIXME(SA): add aarch64 for Alpine Linux
85126
# Right now github does not allow to execute JS-based actions (like
@@ -131,6 +172,10 @@ jobs:
131172
with:
132173
path: pkg
133174
name: couchbase-${{ needs.source.outputs.gem_version }}
175+
- uses: actions/download-artifact@v4
176+
with:
177+
path: pkg
178+
name: couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}
134179
- name: Build gem
135180
env:
136181
SUPPORTED_RUBY_VERSIONS: "3.2 3.3 3.4 4.0"
@@ -457,6 +502,9 @@ jobs:
457502
- uses: actions/download-artifact@v4
458503
with:
459504
name: couchbase-${{ needs.source.outputs.gem_version }}-x86_64-linux
505+
- uses: actions/download-artifact@v4
506+
with:
507+
name: couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}
460508
- uses: actions/download-artifact@v4
461509
with:
462510
name: scripts-${{ needs.source.outputs.gem_version }}
@@ -468,12 +516,17 @@ jobs:
468516
ruby-version: ${{ matrix.ruby }}
469517
- name: Install
470518
run: |
471-
COUCHBASE_GEM_PATH=$(realpath couchbase-*.gem)
472-
UNPACKED_GEM_PATH=$(gem unpack ${COUCHBASE_GEM_PATH} | grep "Unpacked gem" | cut -d "'" -f 2)
473-
gem unpack --spec --target ${UNPACKED_GEM_PATH} ${COUCHBASE_GEM_PATH}
474-
ruby -i.bak -pe "gsub(/gemspec/, 'gem \"couchbase\", path: \"${UNPACKED_GEM_PATH}\"')" Gemfile
519+
COUCHBASE_GEM_PATH=$(realpath couchbase-${{ needs.source.outputs.gem_version }}-*.gem)
520+
COUCHBASE_OPENTELEMETRY_GEM_PATH=$(realpath couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}.gem)
521+
mkdir -p local-gem-repo/gems
522+
mv ${COUCHBASE_GEM_PATH} local-gem-repo/gems
523+
mv ${COUCHBASE_OPENTELEMETRY_GEM_PATH} local-gem-repo/gems
524+
GEM_REPO_PATH=$(realpath local-gem-repo)
525+
gem generate_index --directory local-gem-repo
526+
ruby -i.bak -pe "gsub(/gemspec$/, 'gem \"couchbase\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
527+
ruby -i.bak -pe "gsub(/gemspec path: \"couchbase-opentelemetry\"$/, 'gem \"couchbase-opentelemetry\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
475528
bundle install
476-
bundle exec ruby -r bundler/setup -r couchbase -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO'
529+
bundle exec ruby -r bundler/setup -r couchbase -r couchbase/opentelemetry -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO, {otel: Couchbase::OpenTelemetry::VERSION}'
477530
- name: Test
478531
env:
479532
CB_CAVES_LOGS_DIR: caves-logs
@@ -518,6 +571,9 @@ jobs:
518571
- uses: actions/download-artifact@v4
519572
with:
520573
name: couchbase-${{ needs.source.outputs.gem_version }}-arm64-darwin
574+
- uses: actions/download-artifact@v4
575+
with:
576+
name: couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}
521577
- uses: actions/download-artifact@v4
522578
with:
523579
name: scripts-${{ needs.source.outputs.gem_version }}
@@ -530,14 +586,17 @@ jobs:
530586
- name: Install
531587
run: |
532588
set -xe
533-
COUCHBASE_GEM_PATH=$(realpath couchbase-*.gem)
534-
UNPACKED_GEM_PATH=$(gem unpack ${COUCHBASE_GEM_PATH} | grep "Unpacked gem" | cut -d "'" -f 2)
535-
gem unpack --spec --target ${UNPACKED_GEM_PATH} ${COUCHBASE_GEM_PATH}
536-
ruby -i.bak -pe "gsub(/gemspec/, 'gem \"couchbase\", path: \"${UNPACKED_GEM_PATH}\"')" Gemfile
537-
find .
538-
ls -ld ${UNPACKED_GEM_PATH}
589+
COUCHBASE_GEM_PATH=$(realpath couchbase-${{ needs.source.outputs.gem_version }}-*.gem)
590+
COUCHBASE_OPENTELEMETRY_GEM_PATH=$(realpath couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}.gem)
591+
mkdir -p local-gem-repo/gems
592+
mv ${COUCHBASE_GEM_PATH} local-gem-repo/gems
593+
mv ${COUCHBASE_OPENTELEMETRY_GEM_PATH} local-gem-repo/gems
594+
GEM_REPO_PATH=$(realpath local-gem-repo)
595+
gem generate_index --directory local-gem-repo
596+
ruby -i.bak -pe "gsub(/gemspec$/, 'gem \"couchbase\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
597+
ruby -i.bak -pe "gsub(/gemspec path: \"couchbase-opentelemetry\"$/, 'gem \"couchbase-opentelemetry\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
539598
bundle install
540-
bundle exec ruby -r bundler/setup -r couchbase -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO'
599+
bundle exec ruby -r bundler/setup -r couchbase -r couchbase/opentelemetry -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO, {otel: Couchbase::OpenTelemetry::VERSION}'
541600
- name: Test
542601
env:
543602
CB_CAVES_LOGS_DIR: caves-logs
@@ -591,6 +650,9 @@ jobs:
591650
- uses: actions/download-artifact@v4
592651
with:
593652
name: couchbase-${{ needs.source.outputs.gem_version }}-x86_64-darwin
653+
- uses: actions/download-artifact@v4
654+
with:
655+
name: couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}
594656
- uses: actions/download-artifact@v4
595657
with:
596658
name: scripts-${{ needs.source.outputs.gem_version }}
@@ -602,12 +664,17 @@ jobs:
602664
ruby-version: ${{ matrix.ruby }}
603665
- name: Install
604666
run: |
605-
COUCHBASE_GEM_PATH=$(realpath couchbase-*.gem)
606-
UNPACKED_GEM_PATH=$(gem unpack ${COUCHBASE_GEM_PATH} | grep "Unpacked gem" | cut -d "'" -f 2)
607-
gem unpack --spec --target ${UNPACKED_GEM_PATH} ${COUCHBASE_GEM_PATH}
608-
ruby -i.bak -pe "gsub(/gemspec/, 'gem \"couchbase\", path: \"${UNPACKED_GEM_PATH}\"')" Gemfile
667+
COUCHBASE_GEM_PATH=$(realpath couchbase-${{ needs.source.outputs.gem_version }}-*.gem)
668+
COUCHBASE_OPENTELEMETRY_GEM_PATH=$(realpath couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}.gem)
669+
mkdir -p local-gem-repo/gems
670+
mv ${COUCHBASE_GEM_PATH} local-gem-repo/gems
671+
mv ${COUCHBASE_OPENTELEMETRY_GEM_PATH} local-gem-repo/gems
672+
GEM_REPO_PATH=$(realpath local-gem-repo)
673+
gem generate_index --directory local-gem-repo
674+
ruby -i.bak -pe "gsub(/gemspec$/, 'gem \"couchbase\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
675+
ruby -i.bak -pe "gsub(/gemspec path: \"couchbase-opentelemetry\"$/, 'gem \"couchbase-opentelemetry\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
609676
bundle install
610-
bundle exec ruby -r bundler/setup -r couchbase -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO'
677+
bundle exec ruby -r bundler/setup -r couchbase -r couchbase/opentelemetry -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO, {otel: Couchbase::OpenTelemetry::VERSION}'
611678
- name: Test
612679
env:
613680
CB_CAVES_LOGS_DIR: caves-logs
@@ -696,6 +763,9 @@ jobs:
696763
- uses: actions/download-artifact@v4
697764
with:
698765
name: couchbase-${{ needs.source.outputs.gem_version }}-x86_64-linux
766+
- uses: actions/download-artifact@v4
767+
with:
768+
name: couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}
699769
- uses: actions/download-artifact@v4
700770
with:
701771
name: scripts-${{ needs.source.outputs.gem_version }}
@@ -707,12 +777,17 @@ jobs:
707777
ruby-version: 3.3
708778
- name: Install
709779
run: |
710-
COUCHBASE_GEM_PATH=$(realpath couchbase-*.gem)
711-
UNPACKED_GEM_PATH=$(gem unpack ${COUCHBASE_GEM_PATH} | grep "Unpacked gem" | cut -d "'" -f 2)
712-
gem unpack --spec --target ${UNPACKED_GEM_PATH} ${COUCHBASE_GEM_PATH}
713-
ruby -i.bak -pe "gsub(/gemspec/, 'gem \"couchbase\", path: \"${UNPACKED_GEM_PATH}\"')" Gemfile
780+
COUCHBASE_GEM_PATH=$(realpath couchbase-${{ needs.source.outputs.gem_version }}-*.gem)
781+
COUCHBASE_OPENTELEMETRY_GEM_PATH=$(realpath couchbase-opentelemetry-${{ needs.source.outputs.otel_gem_version }}.gem)
782+
mkdir -p local-gem-repo/gems
783+
mv ${COUCHBASE_GEM_PATH} local-gem-repo/gems
784+
mv ${COUCHBASE_OPENTELEMETRY_GEM_PATH} local-gem-repo/gems
785+
GEM_REPO_PATH=$(realpath local-gem-repo)
786+
gem generate_index --directory local-gem-repo
787+
ruby -i.bak -pe "gsub(/gemspec$/, 'gem \"couchbase\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
788+
ruby -i.bak -pe "gsub(/gemspec path: \"couchbase-opentelemetry\"$/, 'gem \"couchbase-opentelemetry\", source: \"file://${GEM_REPO_PATH}\"')" Gemfile
714789
bundle install
715-
bundle exec ruby -r bundler/setup -r couchbase -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO'
790+
bundle exec ruby -r bundler/setup -r couchbase -r couchbase/opentelemetry -e 'pp Couchbase::VERSION, Couchbase::BUILD_INFO, {otel: Couchbase::OpenTelemetry::VERSION}'
716791
- name: Test
717792
env:
718793
TEST_SERVER_VERSION: ${{ matrix.server }}

.gitignore

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
.byebug_history
99
/.rakeTasks
1010
/.ruby-version
11-
/.yardoc
11+
/**/.yardoc
1212
/_yardoc/
1313
/cmake-build-*/
1414
/build*
1515
/coverage/
16-
/doc/
16+
/**/doc/
1717
/ext/cache/
18-
/pkg/
18+
/**/pkg/
1919
/test/reports/
2020
/tmp/
2121
/logs/

.yardopts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
--no-progress --output-dir doc/couchbase-ruby-client-master lib - README.md
22
--tag couchbase.stability:"Stability"
33
--transitive-tag couchbase.stability
4+
--hide-api private

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ source "https://rubygems.org"
1818
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
1919

2020
gemspec
21+
gemspec path: "couchbase-opentelemetry"
2122

2223
gem "rake"
2324

@@ -35,6 +36,8 @@ group :development do
3536
gem "minitest", "< 6.0"
3637
gem "minitest-reporters"
3738
gem "mutex_m"
39+
gem "opentelemetry-metrics-sdk"
40+
gem "opentelemetry-sdk"
3841
gem "rack"
3942
gem "reek"
4043
gem "rubocop", require: false

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Please attach version information to the ticket/post. To obtain this information
1818

1919
## Installation
2020

21-
The library has been tested with MRI 3.1, 3.2, 3.3 and 3.4. Supported platforms are Linux and MacOS.
21+
The library has been tested with MRI 3.2, 3.3, 3.4 and 4.0. Supported platforms are Linux and MacOS.
2222

2323
Add this line to your application's Gemfile:
2424

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
inherit_from: ../.rubocop.yml

couchbase-opentelemetry/.yardopts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
--no-progress --output-dir doc/couchbase-ruby-client-master lib - README.md
2+
--tag couchbase.stability:"Stability"
3+
--transitive-tag couchbase.stability
4+
--hide-api private

couchbase-opentelemetry/README.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Couchbase Ruby Client OpenTelemetry Integration
2+
3+
## Installation
4+
5+
The library has been tested with MRI 3.2, 3.3, 3.4 and 4.0. Supported platforms are Linux and MacOS.
6+
7+
Add this line to your application's Gemfile:
8+
9+
```ruby
10+
gem "couchbase-opentelemetry", "0.1.0"
11+
```
12+
13+
And then execute:
14+
15+
$ bundle install
16+
17+
Or install it yourself as:
18+
19+
$ gem install couchbase-opentelemetry
20+
21+
## Usage
22+
23+
Here is an example on how to set up Tracing and Metrics with OpenTelemetry:
24+
25+
```ruby
26+
require "couchbase"
27+
require "couchbase/opentelemetry"
28+
29+
require "opentelemetry-sdk"
30+
require "opentelemetry-metrics-sdk"
31+
32+
# Initialize a tracer provider
33+
tracer_provider = OpenTelemetry::SDK::Trace::TracerProvider.new
34+
tracer_provider.add_span_processor(
35+
OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
36+
OpenTelemetry::Exporter::OTLP::Exporter.new(endpoint: "https://<hostname>:<port>/v1/traces")
37+
)
38+
)
39+
40+
# Initialize the Couchbase OpenTelemetry Request Tracer
41+
tracer = Couchbase::OpenTelemetry::RequestTracer.new(tracer_provider)
42+
43+
# Initialize a meter provider
44+
meter_provider = OpenTelemetry::SDK::Metrics::MeterProvider.new
45+
meter_provider.add_metric_reader(
46+
OpenTelemetry::SDK::Metrics::Export::PeriodicMetricReader.new(
47+
exporter: OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter.new(
48+
endpoint: "https://<hostname>:<port>/v1/metrics"
49+
)
50+
)
51+
)
52+
53+
# Initialize the Couchbase OpenTelemetry Meter
54+
meter = Couchbase::OpenTelemetry::Meter.new(meter_provider)
55+
56+
# Configure tracer and meter in cluster options
57+
options = Couchbase::Options::Cluster.new(
58+
authenticator: Couchbase::PasswordAuthenticator.new("Administrator", "password")
59+
tracer: tracer,
60+
meter: meter
61+
)
62+
63+
# Initialize cluster instance
64+
cluster = Cluster.connect("couchbase://127.0.0.1", options)
65+
```
66+
67+
## License
68+
69+
The gem is available as open source under the terms of the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
70+
71+
Copyright 2025-Present Couchbase, Inc.
72+
73+
Licensed under the Apache License, Version 2.0 (the "License");
74+
you may not use this file except in compliance with the License.
75+
You may obtain a copy of the License at
76+
77+
http://www.apache.org/licenses/LICENSE-2.0
78+
79+
Unless required by applicable law or agreed to in writing, software
80+
distributed under the License is distributed on an "AS IS" BASIS,
81+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
82+
See the License for the specific language governing permissions and
83+
limitations under the License.

0 commit comments

Comments
 (0)