couchbase 3.7.0-x86_64-linux → 3.8.1-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/lib/active_support/cache/couchbase_store.rb +6 -6
  4. data/lib/couchbase/3.2/libcouchbase.so +0 -0
  5. data/lib/couchbase/3.3/libcouchbase.so +0 -0
  6. data/lib/couchbase/3.4/libcouchbase.so +0 -0
  7. data/lib/couchbase/{3.1 → 4.0}/libcouchbase.so +0 -0
  8. data/lib/couchbase/authenticator.rb +14 -0
  9. data/lib/couchbase/binary_collection.rb +37 -22
  10. data/lib/couchbase/bucket.rb +46 -31
  11. data/lib/couchbase/cluster.rb +146 -61
  12. data/lib/couchbase/collection.rb +257 -186
  13. data/lib/couchbase/datastructures/couchbase_list.rb +82 -50
  14. data/lib/couchbase/datastructures/couchbase_map.rb +87 -50
  15. data/lib/couchbase/datastructures/couchbase_queue.rb +65 -38
  16. data/lib/couchbase/datastructures/couchbase_set.rb +58 -41
  17. data/lib/couchbase/deprecations.rb +1 -1
  18. data/lib/couchbase/diagnostics.rb +8 -8
  19. data/lib/couchbase/errors.rb +7 -1
  20. data/lib/couchbase/json_transcoder.rb +1 -1
  21. data/lib/couchbase/libcouchbase.rb +1 -1
  22. data/lib/couchbase/management/analytics_index_manager.rb +90 -59
  23. data/lib/couchbase/management/bucket_manager.rb +73 -45
  24. data/lib/couchbase/management/collection_manager.rb +86 -43
  25. data/lib/couchbase/management/collection_query_index_manager.rb +56 -33
  26. data/lib/couchbase/management/query_index_manager.rb +88 -36
  27. data/lib/couchbase/management/scope_search_index_manager.rb +119 -52
  28. data/lib/couchbase/management/search_index_manager.rb +401 -178
  29. data/lib/couchbase/management/user_manager.rb +343 -174
  30. data/lib/couchbase/management/view_index_manager.rb +166 -73
  31. data/lib/couchbase/metrics/logging_meter.rb +108 -0
  32. data/lib/couchbase/metrics/logging_value_recorder.rb +50 -0
  33. data/lib/couchbase/metrics/meter.rb +27 -0
  34. data/lib/couchbase/metrics/noop_meter.rb +30 -0
  35. data/lib/couchbase/metrics/noop_value_recorder.rb +27 -0
  36. data/lib/couchbase/metrics/value_recorder.rb +25 -0
  37. data/lib/couchbase/options.rb +71 -5
  38. data/lib/couchbase/protostellar/client.rb +0 -2
  39. data/lib/couchbase/protostellar/cluster.rb +7 -0
  40. data/lib/couchbase/protostellar/generated/admin/analytics/v1/analytics_pb.rb +54 -0
  41. data/lib/couchbase/protostellar/generated/admin/analytics/v1/analytics_services_pb.rb +51 -0
  42. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_pb.rb +5 -24
  43. data/lib/couchbase/protostellar/generated/admin/bucket/v1/bucket_services_pb.rb +16 -0
  44. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_pb.rb +5 -24
  45. data/lib/couchbase/protostellar/generated/admin/collection/v1/collection_services_pb.rb +16 -0
  46. data/lib/couchbase/protostellar/generated/admin/query/v1/query_pb.rb +5 -24
  47. data/lib/couchbase/protostellar/generated/admin/query/v1/query_services_pb.rb +18 -0
  48. data/lib/couchbase/protostellar/generated/admin/search/v1/search_pb.rb +2 -23
  49. data/lib/couchbase/protostellar/generated/admin/search/v1/search_services_pb.rb +23 -0
  50. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_pb.rb +4 -25
  51. data/lib/couchbase/protostellar/generated/analytics/v1/analytics_services_pb.rb +10 -0
  52. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_pb.rb +6 -25
  53. data/lib/couchbase/protostellar/generated/internal/hooks/v1/hooks_services_pb.rb +18 -0
  54. data/lib/couchbase/protostellar/generated/internal/xdcr/v1/xdcr_pb.rb +46 -0
  55. data/lib/couchbase/protostellar/generated/internal/xdcr/v1/xdcr_services_pb.rb +56 -0
  56. data/lib/couchbase/protostellar/generated/kv/v1/kv_pb.rb +3 -26
  57. data/lib/couchbase/protostellar/generated/kv/v1/kv_services_pb.rb +47 -0
  58. data/lib/couchbase/protostellar/generated/query/v1/query_pb.rb +4 -26
  59. data/lib/couchbase/protostellar/generated/query/v1/query_services_pb.rb +10 -0
  60. data/lib/couchbase/protostellar/generated/routing/v2/routing_pb.rb +26 -0
  61. data/lib/couchbase/protostellar/generated/routing/v2/routing_services_pb.rb +43 -0
  62. data/lib/couchbase/protostellar/generated/search/v1/search_pb.rb +5 -26
  63. data/lib/couchbase/protostellar/generated/search/v1/search_services_pb.rb +11 -0
  64. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_pb.rb +2 -23
  65. data/lib/couchbase/protostellar/generated/transactions/v1/transactions_services_pb.rb +30 -0
  66. data/lib/couchbase/protostellar/generated/view/v1/view_pb.rb +2 -23
  67. data/lib/couchbase/protostellar/generated/view/v1/view_services_pb.rb +9 -0
  68. data/lib/couchbase/protostellar/request_generator/admin/collection.rb +4 -2
  69. data/lib/couchbase/protostellar/request_generator/admin/query.rb +2 -0
  70. data/lib/couchbase/protostellar/request_generator/kv.rb +1 -1
  71. data/lib/couchbase/protostellar/scope.rb +4 -0
  72. data/lib/couchbase/scope.rb +62 -48
  73. data/lib/couchbase/search_options.rb +18 -18
  74. data/lib/couchbase/tracing/noop_span.rb +29 -0
  75. data/lib/couchbase/tracing/noop_tracer.rb +29 -0
  76. data/lib/couchbase/tracing/request_span.rb +34 -0
  77. data/lib/couchbase/tracing/request_tracer.rb +28 -0
  78. data/lib/couchbase/tracing/threshold_logging_span.rb +112 -0
  79. data/lib/couchbase/tracing/threshold_logging_tracer.rb +231 -0
  80. data/lib/couchbase/utils/hdr_histogram.rb +55 -0
  81. data/lib/couchbase/utils/observability.rb +263 -0
  82. data/lib/couchbase/utils/observability_constants.rb +200 -0
  83. data/lib/couchbase/utils/stdlib_logger_adapter.rb +1 -3
  84. data/lib/couchbase/version.rb +1 -1
  85. data/lib/couchbase.rb +2 -2
  86. metadata +43 -10
  87. data/lib/couchbase/protostellar/generated/routing/v1/routing_pb.rb +0 -52
  88. data/lib/couchbase/protostellar/generated/routing/v1/routing_services_pb.rb +0 -30
@@ -29,10 +29,11 @@ module Couchbase
29
29
  # @param [Couchbase::Backend] backend
30
30
  # @param [String] bucket_name name of the bucket
31
31
  # @param [String] scope_name name of the scope
32
- def initialize(backend, bucket_name, scope_name)
32
+ def initialize(backend, bucket_name, scope_name, observability)
33
33
  @backend = backend
34
34
  @bucket_name = bucket_name
35
35
  @name = scope_name
36
+ @observability = observability
36
37
  end
37
38
 
38
39
  # Opens the default collection for this scope
@@ -41,7 +42,7 @@ module Couchbase
41
42
  #
42
43
  # @return [Collection]
43
44
  def collection(collection_name)
44
- Collection.new(@backend, @bucket_name, @name, collection_name)
45
+ Collection.new(@backend, @bucket_name, @name, collection_name, @observability)
45
46
  end
46
47
 
47
48
  # Performs a query against the query (N1QL) services.
@@ -60,30 +61,34 @@ module Couchbase
60
61
  #
61
62
  # @return [QueryResult]
62
63
  def query(statement, options = Options::Query::DEFAULT)
63
- resp = @backend.document_query(statement, options.to_backend(scope_name: @name, bucket_name: @bucket_name))
64
+ @observability.record_operation(Observability::OP_QUERY, options.parent_span, self, :query) do |obs_handler|
65
+ obs_handler.add_query_statement(statement, options)
64
66
 
65
- Cluster::QueryResult.new do |res|
66
- res.meta_data = Cluster::QueryMetaData.new do |meta|
67
- meta.status = resp[:meta][:status]
68
- meta.request_id = resp[:meta][:request_id]
69
- meta.client_context_id = resp[:meta][:client_context_id]
70
- meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
71
- meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
72
- meta.metrics = Cluster::QueryMetrics.new do |metrics|
73
- if resp[:meta][:metrics]
74
- metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
75
- metrics.execution_time = resp[:meta][:metrics][:execution_time]
76
- metrics.sort_count = resp[:meta][:metrics][:sort_count]
77
- metrics.result_count = resp[:meta][:metrics][:result_count]
78
- metrics.result_size = resp[:meta][:metrics][:result_size]
79
- metrics.mutation_count = resp[:meta][:metrics][:mutation_count]
80
- metrics.error_count = resp[:meta][:metrics][:error_count]
81
- metrics.warning_count = resp[:meta][:metrics][:warning_count]
67
+ resp = @backend.document_query(statement, options.to_backend(scope_name: @name, bucket_name: @bucket_name), obs_handler)
68
+
69
+ Cluster::QueryResult.new do |res|
70
+ res.meta_data = Cluster::QueryMetaData.new do |meta|
71
+ meta.status = resp[:meta][:status]
72
+ meta.request_id = resp[:meta][:request_id]
73
+ meta.client_context_id = resp[:meta][:client_context_id]
74
+ meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
75
+ meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
76
+ meta.metrics = Cluster::QueryMetrics.new do |metrics|
77
+ if resp[:meta][:metrics]
78
+ metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
79
+ metrics.execution_time = resp[:meta][:metrics][:execution_time]
80
+ metrics.sort_count = resp[:meta][:metrics][:sort_count]
81
+ metrics.result_count = resp[:meta][:metrics][:result_count]
82
+ metrics.result_size = resp[:meta][:metrics][:result_size]
83
+ metrics.mutation_count = resp[:meta][:metrics][:mutation_count]
84
+ metrics.error_count = resp[:meta][:metrics][:error_count]
85
+ metrics.warning_count = resp[:meta][:metrics][:warning_count]
86
+ end
82
87
  end
88
+ meta.warnings = resp[:warnings].map { |warn| Cluster::QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
83
89
  end
84
- meta.warnings = resp[:warnings].map { |warn| Cluster::QueryWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
90
+ res.instance_variable_set(:@rows, resp[:rows])
85
91
  end
86
- res.instance_variable_set(:@rows, resp[:rows])
87
92
  end
88
93
  end
89
94
 
@@ -100,30 +105,34 @@ module Couchbase
100
105
  #
101
106
  # @return [AnalyticsResult]
102
107
  def analytics_query(statement, options = Options::Analytics::DEFAULT)
103
- resp = @backend.document_analytics(statement, options.to_backend(scope_name: @name, bucket_name: @bucket_name))
108
+ @observability.record_operation(Observability::OP_ANALYTICS_QUERY, options.parent_span, self, :analytics) do |obs_handler|
109
+ obs_handler.add_query_statement(statement, options)
110
+
111
+ resp = @backend.document_analytics(statement, options.to_backend(scope_name: @name, bucket_name: @bucket_name))
104
112
 
105
- Cluster::AnalyticsResult.new do |res|
106
- res.transcoder = options.transcoder
107
- res.meta_data = Cluster::AnalyticsMetaData.new do |meta|
108
- meta.status = resp[:meta][:status]
109
- meta.request_id = resp[:meta][:request_id]
110
- meta.client_context_id = resp[:meta][:client_context_id]
111
- meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
112
- meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
113
- meta.metrics = Cluster::AnalyticsMetrics.new do |metrics|
114
- if resp[:meta][:metrics]
115
- metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
116
- metrics.execution_time = resp[:meta][:metrics][:execution_time]
117
- metrics.result_count = resp[:meta][:metrics][:result_count]
118
- metrics.result_size = resp[:meta][:metrics][:result_size]
119
- metrics.error_count = resp[:meta][:metrics][:error_count]
120
- metrics.warning_count = resp[:meta][:metrics][:warning_count]
121
- metrics.processed_objects = resp[:meta][:metrics][:processed_objects]
113
+ Cluster::AnalyticsResult.new do |res|
114
+ res.transcoder = options.transcoder
115
+ res.meta_data = Cluster::AnalyticsMetaData.new do |meta|
116
+ meta.status = resp[:meta][:status]
117
+ meta.request_id = resp[:meta][:request_id]
118
+ meta.client_context_id = resp[:meta][:client_context_id]
119
+ meta.signature = JSON.parse(resp[:meta][:signature]) if resp[:meta][:signature]
120
+ meta.profile = JSON.parse(resp[:meta][:profile]) if resp[:meta][:profile]
121
+ meta.metrics = Cluster::AnalyticsMetrics.new do |metrics|
122
+ if resp[:meta][:metrics]
123
+ metrics.elapsed_time = resp[:meta][:metrics][:elapsed_time]
124
+ metrics.execution_time = resp[:meta][:metrics][:execution_time]
125
+ metrics.result_count = resp[:meta][:metrics][:result_count]
126
+ metrics.result_size = resp[:meta][:metrics][:result_size]
127
+ metrics.error_count = resp[:meta][:metrics][:error_count]
128
+ metrics.warning_count = resp[:meta][:metrics][:warning_count]
129
+ metrics.processed_objects = resp[:meta][:metrics][:processed_objects]
130
+ end
122
131
  end
132
+ res[:warnings] = resp[:warnings].map { |warn| Cluster::AnalyticsWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
123
133
  end
124
- res[:warnings] = resp[:warnings].map { |warn| Cluster::AnalyticsWarning.new(warn[:code], warn[:message]) } if resp[:warnings]
134
+ res.instance_variable_set(:@rows, resp[:rows])
125
135
  end
126
- res.instance_variable_set(:@rows, resp[:rows])
127
136
  end
128
137
  end
129
138
 
@@ -145,8 +154,10 @@ module Couchbase
145
154
  #
146
155
  # @return [SearchResult]
147
156
  def search_query(index_name, query, options = Options::Search::DEFAULT)
148
- resp = @backend.document_search(@bucket_name, @name, index_name, JSON.generate(query), {}, options.to_backend)
149
- convert_search_result(resp, options)
157
+ @observability.record_operation(Observability::OP_SEARCH_QUERY, options.parent_span, self, :search) do |obs_handler|
158
+ resp = @backend.document_search(@bucket_name, @name, index_name, JSON.generate(query), {}, options.to_backend, obs_handler)
159
+ convert_search_result(resp, options)
160
+ end
150
161
  end
151
162
 
152
163
  # Performs a request against the Full Text Search (FTS) service.
@@ -157,14 +168,17 @@ module Couchbase
157
168
  #
158
169
  # @return [SearchResult]
159
170
  def search(index_name, search_request, options = Options::Search::DEFAULT)
160
- encoded_query, encoded_req = search_request.to_backend
161
- resp = @backend.document_search(@bucket_name, @name, index_name, encoded_query, encoded_req, options.to_backend(show_request: false))
162
- convert_search_result(resp, options)
171
+ @observability.record_operation(Observability::OP_SEARCH_QUERY, options.parent_span, self, :search) do |obs_handler|
172
+ encoded_query, encoded_req = search_request.to_backend
173
+ resp = @backend.document_search(@bucket_name, @name, index_name, encoded_query, encoded_req,
174
+ options.to_backend(show_request: false), obs_handler)
175
+ convert_search_result(resp, options)
176
+ end
163
177
  end
164
178
 
165
179
  # @return [Management::ScopeSearchIndexManager]
166
180
  def search_indexes
167
- Management::ScopeSearchIndexManager.new(@backend, @bucket_name, @name)
181
+ Management::ScopeSearchIndexManager.new(@backend, @bucket_name, @name, @observability)
168
182
  end
169
183
 
170
184
  private
@@ -84,8 +84,8 @@ module Couchbase
84
84
  end
85
85
 
86
86
  # @return [String]
87
- def to_json(*args)
88
- to_h.to_json(*args)
87
+ def to_json(*)
88
+ to_h.to_json(*)
89
89
  end
90
90
 
91
91
  # Prepare {MatchQuery} body
@@ -1128,8 +1128,8 @@ module Couchbase
1128
1128
  end
1129
1129
 
1130
1130
  # @api private
1131
- def to_json(*args)
1132
- to_h.to_json(*args)
1131
+ def to_json(*)
1132
+ to_h.to_json(*)
1133
1133
  end
1134
1134
  end
1135
1135
 
@@ -1173,8 +1173,8 @@ module Couchbase
1173
1173
  end
1174
1174
 
1175
1175
  # @api private
1176
- def to_json(*args)
1177
- {by: :score, desc: desc}.to_json(*args)
1176
+ def to_json(*)
1177
+ {by: :score, desc: desc}.to_json(*)
1178
1178
  end
1179
1179
  end
1180
1180
 
@@ -1189,8 +1189,8 @@ module Couchbase
1189
1189
  end
1190
1190
 
1191
1191
  # @api private
1192
- def to_json(*args)
1193
- {by: :id, desc: desc}.to_json(*args)
1192
+ def to_json(*)
1193
+ {by: :id, desc: desc}.to_json(*)
1194
1194
  end
1195
1195
  end
1196
1196
 
@@ -1219,8 +1219,8 @@ module Couchbase
1219
1219
  end
1220
1220
 
1221
1221
  # @api private
1222
- def to_json(*args)
1223
- {by: :field, field: field, desc: desc, type: type, missing: missing, mode: mode}.to_json(*args)
1222
+ def to_json(*)
1223
+ {by: :field, field: field, desc: desc, type: type, missing: missing, mode: mode}.to_json(*)
1224
1224
  end
1225
1225
  end
1226
1226
 
@@ -1253,8 +1253,8 @@ module Couchbase
1253
1253
  end
1254
1254
 
1255
1255
  # @api private
1256
- def to_json(*args)
1257
- {by: :geo_distance, field: field, desc: desc, location: [longitude, latitude], unit: unit}.to_json(*args)
1256
+ def to_json(*)
1257
+ {by: :geo_distance, field: field, desc: desc, location: [longitude, latitude], unit: unit}.to_json(*)
1258
1258
  end
1259
1259
  end
1260
1260
  end
@@ -1292,8 +1292,8 @@ module Couchbase
1292
1292
  end
1293
1293
 
1294
1294
  # @api private
1295
- def to_json(*args)
1296
- {field: field, size: size}.to_json(*args)
1295
+ def to_json(*)
1296
+ {field: field, size: size}.to_json(*)
1297
1297
  end
1298
1298
  end
1299
1299
 
@@ -1319,8 +1319,8 @@ module Couchbase
1319
1319
  end
1320
1320
 
1321
1321
  # @api private
1322
- def to_json(*args)
1323
- {field: field, size: size, numeric_ranges: @ranges}.to_json(*args)
1322
+ def to_json(*)
1323
+ {field: field, size: size, numeric_ranges: @ranges}.to_json(*)
1324
1324
  end
1325
1325
  end
1326
1326
 
@@ -1351,8 +1351,8 @@ module Couchbase
1351
1351
  end
1352
1352
 
1353
1353
  # @api private
1354
- def to_json(*args)
1355
- {field: field, size: size, date_ranges: @ranges}.to_json(*args)
1354
+ def to_json(*)
1355
+ {field: field, size: size, date_ranges: @ranges}.to_json(*)
1356
1356
  end
1357
1357
  end
1358
1358
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2025-Present Couchbase, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require_relative 'request_span'
18
+
19
+ module Couchbase
20
+ module Tracing
21
+ class NoopSpan < RequestSpan
22
+ def set_attribute(*); end
23
+
24
+ def status=(*); end
25
+
26
+ def finish(*); end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2025-Present Couchbase, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require_relative 'noop_span'
18
+
19
+ module Couchbase
20
+ module Tracing
21
+ class NoopTracer < RequestTracer
22
+ def request_span(*)
23
+ SPAN_INSTANCE
24
+ end
25
+
26
+ SPAN_INSTANCE = NoopSpan.new.freeze
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2025-Present Couchbase, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Couchbase
18
+ module Tracing
19
+ # @!macro volatile
20
+ class RequestSpan
21
+ def set_attribute(key, value)
22
+ raise NotImplementedError, "The RequestSpan does not implement #set_attribute"
23
+ end
24
+
25
+ def status=(status_code)
26
+ raise NotImplementedError, "The RequestSpan does not implement #status="
27
+ end
28
+
29
+ def finish(end_timestamp: nil)
30
+ raise NotImplementedError, "The RequestSpan does not implement #finish"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2025-Present Couchbase, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ module Couchbase
18
+ module Tracing
19
+ # @!macro volatile
20
+ class RequestTracer
21
+ def request_span(name, parent: nil, start_timestamp: nil)
22
+ raise NotImplementedError, "The tracer does not implement #request_span"
23
+ end
24
+
25
+ def close; end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2025-Present Couchbase, Inc.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+ require 'couchbase/tracing/request_span'
18
+ require 'couchbase/utils/observability_constants'
19
+
20
+ module Couchbase
21
+ module Tracing
22
+ class ThresholdLoggingSpan < RequestSpan
23
+ attr_accessor :name
24
+ attr_accessor :should_report
25
+ attr_accessor :service
26
+ attr_accessor :encode_duration_us
27
+ attr_accessor :last_dispatch_duration_us
28
+ attr_accessor :total_dispatch_duration_us
29
+ attr_accessor :last_server_duration_us
30
+ attr_accessor :total_server_duration_us
31
+ attr_accessor :last_local_id
32
+ attr_accessor :operation_id
33
+ attr_accessor :last_peer_address
34
+ attr_accessor :last_peer_port
35
+
36
+ def initialize(name, start_timestamp: nil, parent: nil, tracer: nil)
37
+ super()
38
+ @name = name
39
+ @parent = parent
40
+ @tracer = tracer
41
+
42
+ @start_timestamp = if start_timestamp.nil?
43
+ Time.now
44
+ else
45
+ start_timestamp
46
+ end
47
+ end
48
+
49
+ def set_attribute(key, value)
50
+ case key
51
+ when Observability::ATTR_OPERATION_ID
52
+ @operation_id = value
53
+ when Observability::ATTR_LOCAL_ID
54
+ @last_local_id = value
55
+ when Observability::ATTR_PEER_ADDRESS
56
+ @last_peer_address = value
57
+ when Observability::ATTR_PEER_PORT
58
+ @last_peer_port = value
59
+ when Observability::ATTR_SERVICE
60
+ @service = value
61
+ when Observability::ATTR_SERVER_DURATION
62
+ @last_server_duration_us = value
63
+ end
64
+ end
65
+
66
+ def status=(*); end
67
+
68
+ def finish(end_timestamp: nil)
69
+ duration_us = (((end_timestamp || Time.now) - @start_timestamp) * 1_000_000).round
70
+ case name
71
+ when Observability::STEP_REQUEST_ENCODING
72
+ return if @parent.nil?
73
+
74
+ @parent.should_report = true
75
+ @parent.encode_duration_us = duration_us
76
+ when Observability::STEP_DISPATCH_TO_SERVER
77
+ return if @parent.nil?
78
+
79
+ @parent.should_report = true
80
+ @parent.last_dispatch_duration_us = duration_us
81
+ @parent.total_dispatch_duration_us = 0 if @parent.total_dispatch_duration_us.nil?
82
+ @parent.total_dispatch_duration_us += duration_us
83
+ unless @last_server_duration_us.nil?
84
+ @parent.last_server_duration_us = @last_server_duration_us
85
+ @parent.total_server_duration_us = 0 if @parent.total_server_duration_us.nil?
86
+ @parent.total_server_duration_us += @last_server_duration_us
87
+ end
88
+ @parent.last_local_id = @last_local_id
89
+ @parent.operation_id = @operation_id
90
+ @parent.last_peer_address = @last_peer_address
91
+ @parent.last_peer_port = @last_peer_port
92
+ else
93
+ @should_report ||= @parent.nil?
94
+ return unless @should_report && !@service.nil?
95
+
96
+ @tracer.record_operation(@service, ThresholdLoggingTracer::Item.new(
97
+ total_duration_us: duration_us,
98
+ encode_duration_us: @encode_duration_us,
99
+ last_dispatch_duration_us: @last_dispatch_duration_us,
100
+ total_dispatch_duration_us: @total_dispatch_duration_us,
101
+ last_server_duration_us: @last_server_duration_us,
102
+ total_server_duration_us: @total_server_duration_us,
103
+ operation_name: @name,
104
+ last_local_id: @last_local_id,
105
+ operation_id: @operation_id,
106
+ last_remote_socket: "#{@last_peer_address}:#{@last_peer_port}",
107
+ ))
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end