couchbase 4.4.6 → 4.5.1

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 (143) hide show
  1. package/deps/couchbase-cxx-cache/mozilla-ca-bundle.crt +79 -165
  2. package/deps/couchbase-cxx-cache/mozilla-ca-bundle.sha256 +1 -1
  3. package/deps/couchbase-cxx-client/CMakeLists.txt +14 -3
  4. package/deps/couchbase-cxx-client/README.md +2 -2
  5. package/deps/couchbase-cxx-client/cmake/Profiler.cmake +15 -0
  6. package/deps/couchbase-cxx-client/core/app_telemetry_address.cxx +55 -0
  7. package/deps/couchbase-cxx-client/core/app_telemetry_address.hxx +39 -0
  8. package/deps/couchbase-cxx-client/core/app_telemetry_meter.cxx +791 -0
  9. package/deps/couchbase-cxx-client/core/app_telemetry_meter.hxx +200 -0
  10. package/deps/couchbase-cxx-client/core/app_telemetry_reporter.cxx +895 -0
  11. package/deps/couchbase-cxx-client/core/app_telemetry_reporter.hxx +59 -0
  12. package/deps/couchbase-cxx-client/core/bucket.cxx +77 -35
  13. package/deps/couchbase-cxx-client/core/bucket.hxx +17 -10
  14. package/deps/couchbase-cxx-client/core/cluster.cxx +56 -17
  15. package/deps/couchbase-cxx-client/core/cluster_credentials.cxx +27 -0
  16. package/deps/couchbase-cxx-client/core/cluster_credentials.hxx +36 -0
  17. package/deps/couchbase-cxx-client/core/cluster_options.hxx +13 -0
  18. package/deps/couchbase-cxx-client/core/collections_component.cxx +7 -5
  19. package/deps/couchbase-cxx-client/core/http_component.cxx +6 -0
  20. package/deps/couchbase-cxx-client/core/impl/bucket_manager.cxx +2 -0
  21. package/deps/couchbase-cxx-client/core/impl/cluster.cxx +10 -0
  22. package/deps/couchbase-cxx-client/core/impl/collection.cxx +2 -0
  23. package/deps/couchbase-cxx-client/core/impl/error.cxx +22 -6
  24. package/deps/couchbase-cxx-client/core/impl/error.hxx +1 -1
  25. package/deps/couchbase-cxx-client/core/impl/logger.cxx +51 -0
  26. package/deps/couchbase-cxx-client/core/impl/replica_utils.cxx +1 -1
  27. package/deps/couchbase-cxx-client/core/impl/transaction_get_multi_replicas_from_preferred_server_group_spec.cxx +32 -0
  28. package/deps/couchbase-cxx-client/core/impl/transaction_get_multi_spec.cxx +30 -0
  29. package/deps/couchbase-cxx-client/core/impl/transaction_op_error_category.cxx +2 -0
  30. package/deps/couchbase-cxx-client/core/io/config_tracker.cxx +6 -6
  31. package/deps/couchbase-cxx-client/core/io/http_command.hxx +35 -11
  32. package/deps/couchbase-cxx-client/core/io/http_session.cxx +10 -0
  33. package/deps/couchbase-cxx-client/core/io/http_session.hxx +4 -0
  34. package/deps/couchbase-cxx-client/core/io/http_session_manager.hxx +87 -35
  35. package/deps/couchbase-cxx-client/core/io/mcbp_command.hxx +41 -2
  36. package/deps/couchbase-cxx-client/core/io/mcbp_session.cxx +52 -19
  37. package/deps/couchbase-cxx-client/core/io/mcbp_session.hxx +3 -0
  38. package/deps/couchbase-cxx-client/core/logger/logger.cxx +46 -0
  39. package/deps/couchbase-cxx-client/core/logger/logger.hxx +41 -1
  40. package/deps/couchbase-cxx-client/core/management/bucket_settings.hxx +1 -0
  41. package/deps/couchbase-cxx-client/core/management/bucket_settings_json.hxx +4 -0
  42. package/deps/couchbase-cxx-client/core/meta/features.hxx +32 -0
  43. package/deps/couchbase-cxx-client/core/operations/document_analytics.cxx +9 -9
  44. package/deps/couchbase-cxx-client/core/operations/document_get_all_replicas.hxx +10 -2
  45. package/deps/couchbase-cxx-client/core/operations/document_lookup_in.cxx +4 -0
  46. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_all_replicas.hxx +14 -2
  47. package/deps/couchbase-cxx-client/core/operations/document_lookup_in_any_replica.hxx +4 -0
  48. package/deps/couchbase-cxx-client/core/operations/document_mutate_in.cxx +4 -0
  49. package/deps/couchbase-cxx-client/core/operations/document_mutate_in.hxx +1 -0
  50. package/deps/couchbase-cxx-client/core/operations/document_query.cxx +12 -10
  51. package/deps/couchbase-cxx-client/core/operations/http_noop.cxx +1 -0
  52. package/deps/couchbase-cxx-client/core/operations/management/bucket_create.cxx +3 -0
  53. package/deps/couchbase-cxx-client/core/operations/management/bucket_update.cxx +3 -0
  54. package/deps/couchbase-cxx-client/core/operations/management/search_index_get_all.cxx +3 -2
  55. package/deps/couchbase-cxx-client/core/origin.cxx +25 -5
  56. package/deps/couchbase-cxx-client/core/origin.hxx +18 -24
  57. package/deps/couchbase-cxx-client/core/platform/random.cc +6 -3
  58. package/deps/couchbase-cxx-client/core/platform/random.h +2 -2
  59. package/deps/couchbase-cxx-client/core/protocol/cmd_mutate_in.hxx +9 -0
  60. package/deps/couchbase-cxx-client/core/timeout_defaults.hxx +4 -0
  61. package/deps/couchbase-cxx-client/core/topology/configuration.cxx +10 -13
  62. package/deps/couchbase-cxx-client/core/topology/configuration.hxx +14 -15
  63. package/deps/couchbase-cxx-client/core/topology/configuration_json.hxx +6 -0
  64. package/deps/couchbase-cxx-client/core/transactions/async_attempt_context.hxx +22 -2
  65. package/deps/couchbase-cxx-client/core/transactions/attempt_context.hxx +25 -7
  66. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.cxx +723 -245
  67. package/deps/couchbase-cxx-client/core/transactions/attempt_context_impl.hxx +91 -12
  68. package/deps/couchbase-cxx-client/core/transactions/exceptions.cxx +5 -0
  69. package/deps/couchbase-cxx-client/core/transactions/exceptions.hxx +20 -0
  70. package/deps/couchbase-cxx-client/core/transactions/exceptions_fmt.hxx +3 -0
  71. package/deps/couchbase-cxx-client/core/transactions/forward_compat.cxx +71 -6
  72. package/deps/couchbase-cxx-client/core/transactions/forward_compat.hxx +45 -59
  73. package/deps/couchbase-cxx-client/core/transactions/get_multi_orchestrator.cxx +616 -0
  74. package/deps/couchbase-cxx-client/core/transactions/get_multi_orchestrator.hxx +61 -0
  75. package/deps/couchbase-cxx-client/core/transactions/internal/doc_record.cxx +8 -0
  76. package/deps/couchbase-cxx-client/core/transactions/internal/doc_record.hxx +16 -5
  77. package/deps/couchbase-cxx-client/core/transactions/internal/exceptions_internal.hxx +12 -0
  78. package/deps/couchbase-cxx-client/core/transactions/internal/transaction_context.hxx +13 -0
  79. package/deps/couchbase-cxx-client/core/transactions/internal/transaction_fields.hxx +1 -0
  80. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.cxx +277 -96
  81. package/deps/couchbase-cxx-client/core/transactions/staged_mutation.hxx +28 -76
  82. package/deps/couchbase-cxx-client/core/transactions/transaction_context.cxx +33 -0
  83. package/deps/couchbase-cxx-client/core/transactions/transaction_get_multi_mode.hxx +28 -0
  84. package/deps/couchbase-cxx-client/core/transactions/transaction_get_multi_replicas_from_preferred_server_group_mode.hxx +27 -0
  85. package/deps/couchbase-cxx-client/core/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +72 -0
  86. package/deps/couchbase-cxx-client/core/transactions/transaction_get_multi_result.hxx +67 -0
  87. package/deps/couchbase-cxx-client/core/transactions/transaction_links.hxx +10 -0
  88. package/deps/couchbase-cxx-client/core/transactions/transactions.cxx +8 -3
  89. package/deps/couchbase-cxx-client/core/utils/connection_string.cxx +7 -0
  90. package/deps/couchbase-cxx-client/core/utils/connection_string.hxx +1 -0
  91. package/deps/couchbase-cxx-client/core/utils/url_codec.cxx +26 -0
  92. package/deps/couchbase-cxx-client/core/utils/url_codec.hxx +11 -0
  93. package/deps/couchbase-cxx-client/core/websocket_codec.cxx +647 -0
  94. package/deps/couchbase-cxx-client/core/websocket_codec.hxx +77 -0
  95. package/deps/couchbase-cxx-client/couchbase/analytics_options.hxx +70 -6
  96. package/deps/couchbase-cxx-client/couchbase/application_telemetry_options.hxx +124 -0
  97. package/deps/couchbase-cxx-client/couchbase/behavior_options.hxx +9 -0
  98. package/deps/couchbase-cxx-client/couchbase/cluster_options.hxx +17 -0
  99. package/deps/couchbase-cxx-client/couchbase/error_codes.hxx +1 -0
  100. package/deps/couchbase-cxx-client/couchbase/logger.hxx +16 -0
  101. package/deps/couchbase-cxx-client/couchbase/management/bucket_settings.hxx +1 -0
  102. package/deps/couchbase-cxx-client/couchbase/query_options.hxx +70 -6
  103. package/deps/couchbase-cxx-client/couchbase/transactions/async_attempt_context.hxx +29 -5
  104. package/deps/couchbase-cxx-client/couchbase/transactions/attempt_context.hxx +24 -7
  105. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_mode.hxx +47 -0
  106. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_options.hxx +44 -0
  107. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_mode.hxx +46 -0
  108. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_options.hxx +48 -0
  109. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_result.hxx +112 -0
  110. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_replicas_from_preferred_server_group_spec.hxx +47 -0
  111. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_result.hxx +105 -0
  112. package/deps/couchbase-cxx-client/couchbase/transactions/transaction_get_multi_spec.hxx +45 -0
  113. package/dist/analyticsindexmanager.d.ts +1 -0
  114. package/dist/binarycollection.d.ts +1 -0
  115. package/dist/binding.d.ts +82 -38
  116. package/dist/binding.js +14 -7
  117. package/dist/bindingutilities.d.ts +16 -4
  118. package/dist/bindingutilities.js +233 -31
  119. package/dist/cluster.d.ts +39 -0
  120. package/dist/cluster.js +21 -3
  121. package/dist/collection.d.ts +20 -1
  122. package/dist/collection.js +13 -0
  123. package/dist/errorcontexts.d.ts +24 -0
  124. package/dist/errorcontexts.js +12 -6
  125. package/dist/generaltypes.d.ts +16 -0
  126. package/dist/generaltypes.js +18 -1
  127. package/dist/httpexecutor.d.ts +1 -2
  128. package/dist/httpexecutor.js +0 -9
  129. package/dist/streamablepromises.d.ts +25 -7
  130. package/dist/streamablepromises.js +32 -7
  131. package/dist/transactions.d.ts +239 -1
  132. package/dist/transactions.js +316 -2
  133. package/dist/transcoders.d.ts +1 -0
  134. package/dist/utilities.d.ts +1 -0
  135. package/package.json +24 -24
  136. package/src/connection.cpp +34 -4
  137. package/src/constants.cpp +124 -0
  138. package/src/jstocbpp_autogen.hpp +22 -8
  139. package/src/jstocbpp_transactions.hpp +76 -2
  140. package/src/transaction.cpp +101 -0
  141. package/src/transaction.hpp +5 -0
  142. package/tools/gen-bindings-js.js +2 -1
  143. package/tools/gen-bindings-json.py +28 -3
@@ -0,0 +1,791 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2024-Present Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
6
+ * except in compliance with the License. You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software distributed under
11
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
12
+ * ANY KIND, either express or implied. See the License for the specific language governing
13
+ * permissions and limitations under the License.
14
+ */
15
+
16
+ #include "app_telemetry_meter.hxx"
17
+
18
+ #include "logger/logger.hxx"
19
+ #include "meta/version.hxx"
20
+ #include "topology/configuration.hxx"
21
+ #include "utils/json.hxx"
22
+
23
+ #include <spdlog/fmt/bin_to_hex.h>
24
+ #include <spdlog/fmt/bundled/core.h>
25
+ #include <tao/json/to_string.hpp>
26
+ #include <tao/json/value.hpp>
27
+
28
+ #include <array>
29
+ #include <atomic>
30
+ #include <chrono>
31
+ #include <map>
32
+ #include <mutex>
33
+ #include <utility>
34
+
35
+ namespace couchbase::core
36
+ {
37
+ struct node_labels {
38
+ std::string node;
39
+ std::optional<std::string> alt_node;
40
+ };
41
+
42
+ class app_telemetry_meter_impl
43
+ {
44
+ public:
45
+ app_telemetry_meter_impl() = default;
46
+ app_telemetry_meter_impl(app_telemetry_meter_impl&&) = delete;
47
+ app_telemetry_meter_impl(const app_telemetry_meter_impl&) = delete;
48
+ auto operator=(app_telemetry_meter_impl&&) -> app_telemetry_meter_impl& = delete;
49
+ auto operator=(const app_telemetry_meter_impl&) -> app_telemetry_meter_impl& = delete;
50
+ virtual ~app_telemetry_meter_impl() = default;
51
+
52
+ virtual auto enabled() -> bool = 0;
53
+ [[nodiscard]] virtual auto current_node_labels() const -> std::map<std::string, node_labels> = 0;
54
+ virtual void set_node_labels_cache(std::map<std::string, node_labels>) = 0;
55
+ virtual auto nothing_to_report() -> bool = 0;
56
+ virtual void update_config(const topology::configuration& config) = 0;
57
+ virtual auto value_recorder(const std::string& node_uuid, const std::string& bucket_name)
58
+ -> std::shared_ptr<app_telemetry_value_recorder> = 0;
59
+ virtual void generate_to(std::vector<std::byte>& output_buffer, const std::string& agent) = 0;
60
+ };
61
+
62
+ namespace detail
63
+ {
64
+ class byte_appender
65
+ {
66
+ public:
67
+ using iterator_category = std::output_iterator_tag;
68
+ using value_type = void;
69
+
70
+ explicit byte_appender(std::vector<std::byte>& output)
71
+ : buffer_{ output }
72
+ {
73
+ }
74
+
75
+ auto operator=(char ch) -> byte_appender&
76
+ {
77
+ buffer_.push_back(static_cast<std::byte>(ch));
78
+ return *this;
79
+ }
80
+
81
+ auto operator*() -> byte_appender&
82
+ {
83
+ return *this;
84
+ }
85
+
86
+ auto operator++() const -> byte_appender
87
+ {
88
+ return *this;
89
+ }
90
+
91
+ auto operator++(int) const -> byte_appender
92
+ {
93
+ return *this;
94
+ }
95
+
96
+ private:
97
+ std::vector<std::byte>& buffer_;
98
+ };
99
+ } // namespace detail
100
+ } // namespace couchbase::core
101
+
102
+ template<>
103
+ struct fmt::detail::is_output_iterator<couchbase::core::detail::byte_appender, char>
104
+ : std::true_type {
105
+ };
106
+
107
+ namespace couchbase::core
108
+ {
109
+ namespace
110
+ {
111
+ struct kv_non_durable_histogram {
112
+ const char* name;
113
+ std::atomic_uint64_t le_1ms{};
114
+ std::atomic_uint64_t le_10ms{};
115
+ std::atomic_uint64_t le_100ms{};
116
+ std::atomic_uint64_t le_500ms{};
117
+ std::atomic_uint64_t le_1s{};
118
+ std::atomic_uint64_t le_2_5s{};
119
+ std::atomic_uint64_t inf{};
120
+ std::atomic_uint64_t sum{};
121
+ std::atomic_uint64_t count{};
122
+
123
+ void generate_to(detail::byte_appender& output,
124
+ const std::string& node_uuid,
125
+ const node_labels& labels,
126
+ const std::string& bucket,
127
+ const std::string& agent)
128
+ {
129
+ if (count > 0) {
130
+ std::string lbuf{};
131
+ fmt::format_to(back_inserter(lbuf), "node_uuid=\"{}\"", node_uuid);
132
+ if (!labels.node.empty()) {
133
+ fmt::format_to(back_inserter(lbuf), ",node=\"{}\"", labels.node);
134
+ }
135
+ if (const auto& alt = labels.alt_node; alt && !alt->empty()) {
136
+ fmt::format_to(back_inserter(lbuf), ",alt_node=\"{}\"", alt.value());
137
+ }
138
+ if (!bucket.empty()) {
139
+ fmt::format_to(back_inserter(lbuf), ",bucket=\"{}\"", bucket);
140
+ }
141
+ fmt::format_to(back_inserter(lbuf), ",agent={}", agent);
142
+ fmt::format_to(output, "{}_bucket{{le=\"1\",{}}} {}\n", name, lbuf, le_1ms.load());
143
+ fmt::format_to(output, "{}_bucket{{le=\"10\",{}}} {}\n", name, lbuf, le_10ms.load());
144
+ fmt::format_to(output, "{}_bucket{{le=\"100\",{}}} {}\n", name, lbuf, le_100ms.load());
145
+ fmt::format_to(output, "{}_bucket{{le=\"500\",{}}} {}\n", name, lbuf, le_500ms.load());
146
+ fmt::format_to(output, "{}_bucket{{le=\"1000\",{}}} {}\n", name, lbuf, le_1s.load());
147
+ fmt::format_to(output, "{}_bucket{{le=\"2500\",{}}} {}\n", name, lbuf, le_2_5s.load());
148
+ fmt::format_to(output, "{}_bucket{{le=\"+Inf\",{}}} {}\n", name, lbuf, inf.load());
149
+ fmt::format_to(output, "{}_sum{{{}}} {}\n", name, lbuf, sum.load());
150
+ fmt::format_to(output, "{}_count{{{}}} {}\n", name, lbuf, count.load());
151
+ }
152
+ }
153
+ };
154
+
155
+ struct kv_durable_histogram {
156
+ const char* name;
157
+ std::atomic_uint64_t le_10ms{};
158
+ std::atomic_uint64_t le_100ms{};
159
+ std::atomic_uint64_t le_500ms{};
160
+ std::atomic_uint64_t le_1s{};
161
+ std::atomic_uint64_t le_2s{};
162
+ std::atomic_uint64_t le_10s{};
163
+ std::atomic_uint64_t inf{};
164
+ std::atomic_uint64_t sum{};
165
+ std::atomic_uint64_t count{};
166
+
167
+ void generate_to(detail::byte_appender& output,
168
+ const std::string& node_uuid,
169
+ const node_labels& labels,
170
+ const std::string& bucket,
171
+ const std::string& agent)
172
+ {
173
+ if (count > 0) {
174
+ std::string lbuf{};
175
+ fmt::format_to(back_inserter(lbuf), "node_uuid=\"{}\"", node_uuid);
176
+ if (!labels.node.empty()) {
177
+ fmt::format_to(back_inserter(lbuf), ",node=\"{}\"", labels.node);
178
+ }
179
+ if (const auto& alt = labels.alt_node; alt && !alt->empty()) {
180
+ fmt::format_to(back_inserter(lbuf), ",alt_node=\"{}\"", alt.value());
181
+ }
182
+ if (!bucket.empty()) {
183
+ fmt::format_to(back_inserter(lbuf), ",bucket=\"{}\"", bucket);
184
+ }
185
+ fmt::format_to(back_inserter(lbuf), ",agent={}", agent);
186
+ fmt::format_to(output, "{}_bucket{{le=\"10\",{}}} {}\n", name, lbuf, le_10ms.load());
187
+ fmt::format_to(output, "{}_bucket{{le=\"100\",{}}} {}\n", name, lbuf, le_100ms.load());
188
+ fmt::format_to(output, "{}_bucket{{le=\"500\",{}}} {}\n", name, lbuf, le_500ms.load());
189
+ fmt::format_to(output, "{}_bucket{{le=\"1000\",{}}} {}\n", name, lbuf, le_1s.load());
190
+ fmt::format_to(output, "{}_bucket{{le=\"2000\",{}}} {}\n", name, lbuf, le_2s.load());
191
+ fmt::format_to(output, "{}_bucket{{le=\"10000\",{}}} {}\n", name, lbuf, le_10s.load());
192
+ fmt::format_to(output, "{}_bucket{{le=\"+Inf\",{}}} {}\n", name, lbuf, inf.load());
193
+ fmt::format_to(output, "{}_sum{{{}}} {}\n", name, lbuf, sum.load());
194
+ fmt::format_to(output, "{}_count{{{}}} {}\n", name, lbuf, count.load());
195
+ }
196
+ }
197
+ };
198
+
199
+ struct http_histogram {
200
+ const char* name;
201
+ std::atomic_uint64_t le_100ms{};
202
+ std::atomic_uint64_t le_1s{};
203
+ std::atomic_uint64_t le_10s{};
204
+ std::atomic_uint64_t le_30s{};
205
+ std::atomic_uint64_t le_75s{};
206
+ std::atomic_uint64_t inf{};
207
+ std::atomic_uint64_t sum{};
208
+ std::atomic_uint64_t count{};
209
+
210
+ void generate_to(detail::byte_appender& output,
211
+ const std::string& node_uuid,
212
+ const node_labels& labels,
213
+ const std::string& bucket,
214
+ const std::string& agent)
215
+ {
216
+ if (count > 0) {
217
+ std::string lbuf{};
218
+ fmt::format_to(back_inserter(lbuf), "node_uuid=\"{}\"", node_uuid);
219
+ if (!labels.node.empty()) {
220
+ fmt::format_to(back_inserter(lbuf), ",node=\"{}\"", labels.node);
221
+ }
222
+ if (const auto& alt = labels.alt_node; alt && !alt->empty()) {
223
+ fmt::format_to(back_inserter(lbuf), ",alt_node=\"{}\"", alt.value());
224
+ }
225
+ if (!bucket.empty()) {
226
+ fmt::format_to(back_inserter(lbuf), ",bucket=\"{}\"", bucket);
227
+ }
228
+ fmt::format_to(back_inserter(lbuf), ",agent={}", agent);
229
+ fmt::format_to(output, "{}_bucket{{le=\"100\",{}}} {}\n", name, lbuf, le_100ms.load());
230
+ fmt::format_to(output, "{}_bucket{{le=\"1000\",{}}} {}\n", name, lbuf, le_1s.load());
231
+ fmt::format_to(output, "{}_bucket{{le=\"10000\",{}}} {}\n", name, lbuf, le_10s.load());
232
+ fmt::format_to(output, "{}_bucket{{le=\"30000\",{}}} {}\n", name, lbuf, le_30s.load());
233
+ fmt::format_to(output, "{}_bucket{{le=\"75000\",{}}} {}\n", name, lbuf, le_75s.load());
234
+ fmt::format_to(output, "{}_bucket{{le=\"+Inf\",{}}} {}\n", name, lbuf, inf.load());
235
+ fmt::format_to(output, "{}_sum{{{}}} {}\n", name, lbuf, sum.load() / 1000);
236
+ fmt::format_to(output, "{}_count{{{}}} {}\n", name, lbuf, count.load());
237
+ }
238
+ }
239
+ };
240
+
241
+ constexpr auto max_number_of_counters{ static_cast<std::size_t>(
242
+ app_telemetry_counter::number_of_elements) };
243
+
244
+ constexpr auto
245
+ is_valid_app_telemetry_counter(std::size_t name) -> bool
246
+ {
247
+ return name > static_cast<std::size_t>(app_telemetry_counter::unknown) &&
248
+ name < static_cast<std::size_t>(app_telemetry_counter::number_of_elements);
249
+ }
250
+
251
+ constexpr auto
252
+ app_telemetry_counter_name(std::size_t name) -> const char*
253
+ {
254
+ switch (static_cast<app_telemetry_counter>(name)) {
255
+
256
+ case app_telemetry_counter::kv_r_timedout:
257
+ return "sdk_kv_r_timedout";
258
+ case app_telemetry_counter::kv_r_canceled:
259
+ return "sdk_kv_r_canceled";
260
+ case app_telemetry_counter::kv_r_total:
261
+ return "sdk_kv_r_total";
262
+
263
+ case app_telemetry_counter::query_r_timedout:
264
+ return "sdk_query_r_timedout";
265
+ case app_telemetry_counter::query_r_canceled:
266
+ return "sdk_query_r_canceled";
267
+ case app_telemetry_counter::query_r_total:
268
+ return "sdk_query_r_total";
269
+
270
+ case app_telemetry_counter::search_r_timedout:
271
+ return "sdk_search_r_timedout";
272
+ case app_telemetry_counter::search_r_canceled:
273
+ return "sdk_search_r_canceled";
274
+ case app_telemetry_counter::search_r_total:
275
+ return "sdk_search_r_total";
276
+
277
+ case app_telemetry_counter::analytics_r_timedout:
278
+ return "sdk_analytics_r_timedout";
279
+ case app_telemetry_counter::analytics_r_canceled:
280
+ return "sdk_analytics_r_canceled";
281
+ case app_telemetry_counter::analytics_r_total:
282
+ return "sdk_analytics_r_total";
283
+
284
+ case app_telemetry_counter::management_r_timedout:
285
+ return "sdk_management_r_timedout";
286
+ case app_telemetry_counter::management_r_canceled:
287
+ return "sdk_management_r_canceled";
288
+ case app_telemetry_counter::management_r_total:
289
+ return "sdk_management_r_total";
290
+
291
+ case app_telemetry_counter::eventing_r_timedout:
292
+ return "sdk_eventing_r_timedout";
293
+ case app_telemetry_counter::eventing_r_canceled:
294
+ return "sdk_eventing_r_canceled";
295
+ case app_telemetry_counter::eventing_r_total:
296
+ return "sdk_eventing_r_total";
297
+
298
+ case app_telemetry_counter::unknown:
299
+ case app_telemetry_counter::number_of_elements:
300
+ break;
301
+ }
302
+ return "";
303
+ }
304
+
305
+ class null_app_telemetry_value_recorder : public app_telemetry_value_recorder
306
+ {
307
+ public:
308
+ void record_latency(app_telemetry_latency /* name */,
309
+ std::chrono::milliseconds /* interval */) override
310
+ {
311
+ /* do nothing */
312
+ }
313
+
314
+ void update_counter(app_telemetry_counter /* name */) override
315
+ {
316
+ /* do nothing */
317
+ }
318
+ };
319
+
320
+ class null_app_telemetry_meter_impl : public app_telemetry_meter_impl
321
+ {
322
+ private:
323
+ std::shared_ptr<null_app_telemetry_value_recorder> instance_{
324
+ std::make_shared<null_app_telemetry_value_recorder>()
325
+ };
326
+
327
+ public:
328
+ void update_config(const topology::configuration& /* config */) override
329
+ {
330
+ /* do nothing */
331
+ }
332
+
333
+ auto value_recorder(const std::string& /* node_uuid */, const std::string& /* bucket_name */)
334
+ -> std::shared_ptr<app_telemetry_value_recorder> override
335
+ {
336
+ return instance_;
337
+ }
338
+
339
+ auto enabled() -> bool override
340
+ {
341
+ return false;
342
+ }
343
+
344
+ auto nothing_to_report() -> bool override
345
+ {
346
+ return true;
347
+ }
348
+
349
+ void generate_to(std::vector<std::byte>& /* output_buffer */,
350
+ const std::string& /* agent */) override
351
+ {
352
+ /* do nothing */
353
+ }
354
+
355
+ [[nodiscard]] auto current_node_labels() const -> std::map<std::string, node_labels> override
356
+ {
357
+ return {};
358
+ }
359
+
360
+ void set_node_labels_cache(std::map<std::string, node_labels>) override
361
+ {
362
+ /* do nothing */
363
+ }
364
+ };
365
+
366
+ class default_app_telemetry_value_recorder : public app_telemetry_value_recorder
367
+ {
368
+ public:
369
+ default_app_telemetry_value_recorder(std::string node_uuid, std::string bucket_name)
370
+ : node_uuid_{ std::move(node_uuid) }
371
+ , bucket_name_{ std::move(bucket_name) }
372
+ {
373
+ }
374
+
375
+ void record_latency(app_telemetry_latency name, std::chrono::milliseconds interval) override
376
+ {
377
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-constant-array-index)
378
+ switch (name) {
379
+ case app_telemetry_latency::unknown:
380
+ case app_telemetry_latency::number_of_elements:
381
+ return;
382
+ case app_telemetry_latency::kv_retrieval:
383
+ ++kv_retrieval_.count;
384
+ kv_retrieval_.sum += static_cast<std::uint64_t>(interval.count());
385
+ if (interval <= std::chrono::milliseconds{ 1 }) {
386
+ ++kv_retrieval_.le_1ms;
387
+ }
388
+ if (interval <= std::chrono::milliseconds{ 10 }) {
389
+ ++kv_retrieval_.le_10ms;
390
+ }
391
+ if (interval <= std::chrono::milliseconds{ 100 }) {
392
+ ++kv_retrieval_.le_100ms;
393
+ }
394
+ if (interval <= std::chrono::milliseconds{ 500 }) {
395
+ ++kv_retrieval_.le_500ms;
396
+ }
397
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
398
+ ++kv_retrieval_.le_1s;
399
+ }
400
+ if (interval <= std::chrono::milliseconds{ 2500 }) {
401
+ ++kv_retrieval_.le_2_5s;
402
+ }
403
+ ++kv_retrieval_.inf;
404
+ break;
405
+
406
+ case app_telemetry_latency::kv_mutation_nondurable:
407
+ ++kv_mutation_nondurable_.count;
408
+ kv_mutation_nondurable_.sum += static_cast<std::uint64_t>(interval.count());
409
+ if (interval <= std::chrono::milliseconds{ 1 }) {
410
+ ++kv_mutation_nondurable_.le_1ms;
411
+ }
412
+ if (interval <= std::chrono::milliseconds{ 10 }) {
413
+ ++kv_mutation_nondurable_.le_10ms;
414
+ }
415
+ if (interval <= std::chrono::milliseconds{ 100 }) {
416
+ ++kv_mutation_nondurable_.le_100ms;
417
+ }
418
+ if (interval <= std::chrono::milliseconds{ 500 }) {
419
+ ++kv_mutation_nondurable_.le_500ms;
420
+ }
421
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
422
+ ++kv_mutation_nondurable_.le_1s;
423
+ }
424
+ if (interval <= std::chrono::milliseconds{ 2500 }) {
425
+ ++kv_mutation_nondurable_.le_2_5s;
426
+ }
427
+ ++kv_mutation_nondurable_.inf;
428
+ break;
429
+
430
+ case app_telemetry_latency::kv_mutation_durable:
431
+ ++kv_mutation_durable_.count;
432
+ kv_mutation_durable_.sum += static_cast<std::uint64_t>(interval.count());
433
+ if (interval <= std::chrono::milliseconds{ 10 }) {
434
+ ++kv_mutation_durable_.le_10ms;
435
+ }
436
+ if (interval <= std::chrono::milliseconds{ 100 }) {
437
+ ++kv_mutation_durable_.le_100ms;
438
+ }
439
+ if (interval <= std::chrono::milliseconds{ 500 }) {
440
+ ++kv_mutation_durable_.le_500ms;
441
+ }
442
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
443
+ ++kv_mutation_durable_.le_1s;
444
+ }
445
+ if (interval <= std::chrono::milliseconds{ 2000 }) {
446
+ ++kv_mutation_durable_.le_2s;
447
+ }
448
+ if (interval <= std::chrono::milliseconds{ 10000 }) {
449
+ ++kv_mutation_durable_.le_10s;
450
+ }
451
+ ++kv_mutation_durable_.inf;
452
+ break;
453
+
454
+ case app_telemetry_latency::query:
455
+ ++query_.count;
456
+ query_.sum += static_cast<std::uint64_t>(interval.count());
457
+ if (interval <= std::chrono::milliseconds{ 100 }) {
458
+ ++query_.le_100ms;
459
+ }
460
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
461
+ ++query_.le_1s;
462
+ }
463
+ if (interval <= std::chrono::milliseconds{ 10000 }) {
464
+ ++query_.le_10s;
465
+ }
466
+ if (interval <= std::chrono::milliseconds{ 30000 }) {
467
+ ++query_.le_30s;
468
+ }
469
+ if (interval <= std::chrono::milliseconds{ 75000 }) {
470
+ ++query_.le_75s;
471
+ }
472
+ ++query_.inf;
473
+ break;
474
+
475
+ case app_telemetry_latency::search:
476
+ ++search_.count;
477
+ search_.sum += static_cast<std::uint64_t>(interval.count());
478
+ if (interval <= std::chrono::milliseconds{ 100 }) {
479
+ ++search_.le_100ms;
480
+ }
481
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
482
+ ++search_.le_1s;
483
+ }
484
+ if (interval <= std::chrono::milliseconds{ 10000 }) {
485
+ ++search_.le_10s;
486
+ }
487
+ if (interval <= std::chrono::milliseconds{ 30000 }) {
488
+ ++search_.le_30s;
489
+ }
490
+ if (interval <= std::chrono::milliseconds{ 75000 }) {
491
+ ++search_.le_75s;
492
+ }
493
+ ++search_.inf;
494
+ break;
495
+
496
+ case app_telemetry_latency::analytics:
497
+ ++analytics_.count;
498
+ analytics_.sum += static_cast<std::uint64_t>(interval.count());
499
+ if (interval <= std::chrono::milliseconds{ 100 }) {
500
+ ++analytics_.le_100ms;
501
+ }
502
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
503
+ ++analytics_.le_1s;
504
+ }
505
+ if (interval <= std::chrono::milliseconds{ 10000 }) {
506
+ ++analytics_.le_10s;
507
+ }
508
+ if (interval <= std::chrono::milliseconds{ 30000 }) {
509
+ ++analytics_.le_30s;
510
+ }
511
+ if (interval <= std::chrono::milliseconds{ 75000 }) {
512
+ ++analytics_.le_75s;
513
+ }
514
+ ++analytics_.inf;
515
+ break;
516
+
517
+ case app_telemetry_latency::management:
518
+ ++management_.count;
519
+ management_.sum += static_cast<std::uint64_t>(interval.count());
520
+ if (interval <= std::chrono::milliseconds{ 100 }) {
521
+ ++management_.le_100ms;
522
+ }
523
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
524
+ ++management_.le_1s;
525
+ }
526
+ if (interval <= std::chrono::milliseconds{ 10000 }) {
527
+ ++management_.le_10s;
528
+ }
529
+ if (interval <= std::chrono::milliseconds{ 30000 }) {
530
+ ++management_.le_30s;
531
+ }
532
+ if (interval <= std::chrono::milliseconds{ 75000 }) {
533
+ ++management_.le_75s;
534
+ }
535
+ ++management_.inf;
536
+ break;
537
+
538
+ case app_telemetry_latency::eventing:
539
+ ++eventing_.count;
540
+ eventing_.sum += static_cast<std::uint64_t>(interval.count());
541
+ if (interval <= std::chrono::milliseconds{ 100 }) {
542
+ ++eventing_.le_100ms;
543
+ }
544
+ if (interval <= std::chrono::milliseconds{ 1000 }) {
545
+ ++eventing_.le_1s;
546
+ }
547
+ if (interval <= std::chrono::milliseconds{ 10000 }) {
548
+ ++eventing_.le_10s;
549
+ }
550
+ if (interval <= std::chrono::milliseconds{ 30000 }) {
551
+ ++eventing_.le_30s;
552
+ }
553
+ if (interval <= std::chrono::milliseconds{ 75000 }) {
554
+ ++eventing_.le_75s;
555
+ }
556
+ ++eventing_.inf;
557
+
558
+ break;
559
+ }
560
+ // NOLINTEND(cppcoreguidelines-pro-bounds-constant-array-index)
561
+ }
562
+
563
+ void update_counter(app_telemetry_counter name) override
564
+ {
565
+ switch (name) {
566
+ case app_telemetry_counter::unknown:
567
+ case app_telemetry_counter::number_of_elements:
568
+ return;
569
+ default:
570
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
571
+ ++counters_[static_cast<std::size_t>(name)];
572
+ break;
573
+ }
574
+ }
575
+
576
+ private:
577
+ friend class default_app_telemetry_meter_impl;
578
+
579
+ std::string node_uuid_;
580
+ std::string bucket_name_;
581
+ std::array<std::atomic_uint64_t, max_number_of_counters> counters_{};
582
+
583
+ kv_non_durable_histogram kv_retrieval_{ "sdk_kv_retrieval_duration_milliseconds" };
584
+ kv_non_durable_histogram kv_mutation_nondurable_{
585
+ "sdk_kv_mutation_nondurable_duration_milliseconds"
586
+ };
587
+ kv_durable_histogram kv_mutation_durable_{ "sdk_kv_mutation_durable_duration_milliseconds" };
588
+ http_histogram query_{ "sdk_query_duration_milliseconds" };
589
+ http_histogram search_{ "sdk_search_duration_milliseconds" };
590
+ http_histogram analytics_{ "sdk_analytics_duration_milliseconds" };
591
+ http_histogram management_{ "sdk_management_duration_milliseconds" };
592
+ http_histogram eventing_{ "sdk_eventing_duration_milliseconds" };
593
+ };
594
+
595
+ class default_app_telemetry_meter_impl : public app_telemetry_meter_impl
596
+ {
597
+ public:
598
+ auto value_recorder(const std::string& node_uuid, const std::string& bucket_name)
599
+ -> std::shared_ptr<app_telemetry_value_recorder> override
600
+ {
601
+ const std::lock_guard<std::mutex> lock(mutex_);
602
+
603
+ if (auto node = recorders_.find(node_uuid); node != recorders_.end()) {
604
+ if (auto bucket = node->second.find(bucket_name); bucket != node->second.end()) {
605
+ return bucket->second;
606
+ }
607
+ }
608
+ auto recorder = std::make_shared<default_app_telemetry_value_recorder>(node_uuid, bucket_name);
609
+ recorders_[node_uuid][bucket_name] = recorder;
610
+ return recorder;
611
+ }
612
+
613
+ void update_config(const topology::configuration& config) override
614
+ {
615
+ node_uuids_in_last_config_.clear();
616
+ for (const auto& node : config.nodes) {
617
+ std::optional<std::string> alt_node{};
618
+ if (auto it = node.alt.find("external"); it != node.alt.end()) {
619
+ if (!it->second.hostname.empty()) {
620
+ alt_node = it->second.hostname;
621
+ }
622
+ }
623
+ labels_cache_[node.node_uuid] = node_labels{
624
+ node.hostname,
625
+ alt_node,
626
+ };
627
+ node_uuids_in_last_config_.push_back(node.node_uuid);
628
+ }
629
+ }
630
+
631
+ auto enabled() -> bool override
632
+ {
633
+ return true;
634
+ }
635
+
636
+ auto nothing_to_report() -> bool override
637
+ {
638
+ const std::lock_guard<std::mutex> lock(mutex_);
639
+ return recorders_.empty();
640
+ }
641
+
642
+ [[nodiscard]] auto current_node_labels() const -> std::map<std::string, node_labels> override
643
+ {
644
+ std::map<std::string, node_labels> labels{};
645
+ for (const auto& node_uuid : node_uuids_in_last_config_) {
646
+ labels[node_uuid] = labels_cache_.at(node_uuid);
647
+ }
648
+ return labels;
649
+ }
650
+
651
+ void set_node_labels_cache(std::map<std::string, node_labels> labels) override
652
+ {
653
+ for (const auto& [node_uuid, _] : labels) {
654
+ node_uuids_in_last_config_.push_back(node_uuid);
655
+ }
656
+ labels_cache_ = std::move(labels);
657
+ }
658
+
659
+ void generate_to(std::vector<std::byte>& buffer, const std::string& agent) override
660
+ {
661
+ auto now = std::chrono::duration_cast<std::chrono::milliseconds>(
662
+ std::chrono::system_clock::now().time_since_epoch())
663
+ .count();
664
+ detail::byte_appender output{ buffer };
665
+ for (const auto& [node_uuid, buckets] : recorders_) {
666
+ auto labels = labels_cache_[node_uuid];
667
+ for (const auto& [bucket, recorder] : buckets) {
668
+
669
+ for (std::size_t i = 0; i < recorder->counters_.size(); ++i) {
670
+ if (is_valid_app_telemetry_counter(i)) {
671
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
672
+ std::uint64_t value = recorder->counters_[i];
673
+ if (value == 0) {
674
+ continue;
675
+ }
676
+
677
+ fmt::format_to(
678
+ output, "{}{{node_uuid=\"{}\"", app_telemetry_counter_name(i), node_uuid);
679
+ if (!labels.node.empty()) {
680
+ fmt::format_to(output, ",node=\"{}\"", labels.node);
681
+ }
682
+ if (const auto& alt = labels.alt_node; alt && !alt->empty()) {
683
+ fmt::format_to(output, ",alt_node=\"{}\"", alt.value());
684
+ }
685
+ if (!bucket.empty()) {
686
+ fmt::format_to(output, ",bucket=\"{}\"", bucket);
687
+ }
688
+ fmt::format_to(output, ",agent={}}} {} {}\n", agent, value, now);
689
+ }
690
+ }
691
+
692
+ recorder->kv_retrieval_.generate_to(output, node_uuid, labels, bucket, agent);
693
+ recorder->kv_mutation_nondurable_.generate_to(output, node_uuid, labels, bucket, agent);
694
+ recorder->kv_mutation_durable_.generate_to(output, node_uuid, labels, bucket, agent);
695
+ recorder->query_.generate_to(output, node_uuid, labels, bucket, agent);
696
+ recorder->search_.generate_to(output, node_uuid, labels, bucket, agent);
697
+ recorder->analytics_.generate_to(output, node_uuid, labels, bucket, agent);
698
+ recorder->management_.generate_to(output, node_uuid, labels, bucket, agent);
699
+ recorder->eventing_.generate_to(output, node_uuid, labels, bucket, agent);
700
+ }
701
+ }
702
+ }
703
+
704
+ private:
705
+ std::mutex mutex_{};
706
+ // node_uuid -> bucket_name -> recorders
707
+ std::map<std::string,
708
+ std::map<std::string, std::shared_ptr<default_app_telemetry_value_recorder>>>
709
+ recorders_{};
710
+ std::map<std::string, node_labels> labels_cache_{};
711
+ std::vector<std::string> node_uuids_in_last_config_{};
712
+ };
713
+
714
+ auto
715
+ generate_agent_string(const std::string& extra = {}) -> std::string
716
+ {
717
+ constexpr auto uuid{ "00000000-0000-0000-0000-000000000000" };
718
+ auto hello = meta::user_agent_for_mcbp(uuid, uuid, extra);
719
+ auto json = utils::json::parse(hello.data(), hello.size());
720
+ return utils::json::generate(json["a"]);
721
+ }
722
+
723
+ } // namespace
724
+
725
+ app_telemetry_meter::app_telemetry_meter()
726
+ : impl_{ std::make_unique<default_app_telemetry_meter_impl>() }
727
+ {
728
+ agent_ = generate_agent_string();
729
+ }
730
+
731
+ void
732
+ app_telemetry_meter::disable()
733
+ {
734
+ const std::scoped_lock lock{ impl_mutex_ };
735
+ if (!impl_->enabled()) {
736
+ return;
737
+ }
738
+ CB_LOG_DEBUG("Disable app telemetry meter. {}",
739
+ tao::json::to_string(tao::json::value{
740
+ { "nothing_to_report", impl_->nothing_to_report() },
741
+ }));
742
+ impl_ = std::make_unique<null_app_telemetry_meter_impl>();
743
+ }
744
+
745
+ void
746
+ app_telemetry_meter::enable()
747
+ {
748
+ const std::scoped_lock lock{ impl_mutex_ };
749
+ if (impl_->enabled()) {
750
+ return;
751
+ }
752
+ CB_LOG_DEBUG("Enable app telemetry meter.");
753
+ impl_ = std::make_unique<default_app_telemetry_meter_impl>();
754
+ }
755
+
756
+ void
757
+ app_telemetry_meter::update_agent(const std::string& extra)
758
+ {
759
+ agent_ = generate_agent_string(extra);
760
+ }
761
+
762
+ app_telemetry_meter::~app_telemetry_meter() = default;
763
+
764
+ void
765
+ app_telemetry_meter::update_config(const topology::configuration& config)
766
+ {
767
+ const std::shared_lock lock{ impl_mutex_ };
768
+ return impl_->update_config(config);
769
+ }
770
+
771
+ auto
772
+ app_telemetry_meter::value_recorder(const std::string& node_uuid, const std::string& bucket_name)
773
+ -> std::shared_ptr<app_telemetry_value_recorder>
774
+ {
775
+ const std::shared_lock lock{ impl_mutex_ };
776
+ return impl_->value_recorder(node_uuid, bucket_name);
777
+ }
778
+
779
+ void
780
+ app_telemetry_meter::generate_report(std::vector<std::byte>& output_buffer)
781
+ {
782
+ const std::scoped_lock lock{ impl_mutex_ };
783
+ if (impl_->nothing_to_report()) {
784
+ return;
785
+ }
786
+ const auto old_impl = std::move(impl_);
787
+ impl_ = std::make_unique<default_app_telemetry_meter_impl>();
788
+ impl_->set_node_labels_cache(old_impl->current_node_labels());
789
+ old_impl->generate_to(output_buffer, agent_);
790
+ }
791
+ } // namespace couchbase::core