Skip to content

Commit 57f03e9

Browse files
committed
WIP: OpenTelemetry integration refactoring
1 parent 0d2750b commit 57f03e9

File tree

18 files changed

+403
-238
lines changed

18 files changed

+403
-238
lines changed

.github/workflows/columnar.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Install build environment
2020
run: |
2121
sudo apt-get update -y
22-
sudo apt-get install -y libssl-dev cmake gcc g++ curl gdb
22+
sudo apt-get install -y libssl-dev cmake gcc g++ curl gdb libcurl4-openssl-dev libprotobuf-dev libgrpc-dev gdb
2323
- uses: actions/checkout@v4
2424
with:
2525
submodules: recursive

.github/workflows/linters.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
- name: Install dependencies
3939
run: |
4040
sudo apt-get update -y
41-
sudo apt-get install -y libssl-dev cmake curl wget gnupg2
41+
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 libcurl4-openssl-dev libprotobuf-dev libgrpc-dev gdb
4242
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
4343
sudo bash -c "echo 'deb https://apt.llvm.org/noble/ llvm-toolchain-noble main' >> /etc/apt/sources.list"
4444
sudo apt-get update -y
@@ -65,7 +65,7 @@ jobs:
6565
- name: Install dependencies
6666
run: |
6767
sudo apt-get update -y
68-
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 clang clang-tools cppcheck
68+
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 clang clang-tools cppcheck libcurl4-openssl-dev libprotobuf-dev libgrpc-dev gdb
6969
- name: Run cppcheck
7070
run: ./bin/check-cppcheck
7171

@@ -78,6 +78,6 @@ jobs:
7878
- name: Install dependencies
7979
run: |
8080
sudo apt-get update -y
81-
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 clang clang-tools clang-tidy
81+
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 clang clang-tools clang-tidy libcurl4-openssl-dev libprotobuf-dev libgrpc-dev gdb
8282
- name: Run cppcheck
8383
run: ./bin/check-clang-tidy

.github/workflows/sanitizers.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ jobs:
4040
- name: Install dependencies
4141
run: |
4242
sudo apt-get update -y
43-
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 gdb clang clang-tools valgrind
43+
sudo apt-get install -y libssl-dev cmake curl wget gnupg2 libcurl4-openssl-dev libprotobuf-dev libgrpc-dev gdb clang clang-tools valgrind
4444
- uses: actions/checkout@v4
4545
with:
4646
submodules: recursive

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
- name: Install build environment
4242
run: |
4343
sudo apt-get update -y
44-
sudo apt-get install -y libssl-dev cmake gcc g++ curl gdb
44+
sudo apt-get install -y libssl-dev cmake gcc g++ curl libcurl4-openssl-dev libprotobuf-dev libgrpc-dev gdb
4545
- uses: actions/checkout@v4
4646
with:
4747
submodules: recursive

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ set(couchbase_cxx_client_FILES
404404
core/search_query_options.cxx
405405
core/seed_config.cxx
406406
core/topology/configuration.cxx
407+
core/tracing/otel_tracer.cxx
407408
core/tracing/threshold_logging_tracer.cxx
408409
core/tracing/tracer_wrapper.cxx
409410
core/transactions/active_transaction_record.cxx
@@ -531,6 +532,7 @@ foreach(TARGET ${couchbase_cxx_client_LIBRARIES})
531532
snappy
532533
jsonsl
533534
couchbase_backtrace
535+
opentelemetry_api
534536
hdr_histogram_static)
535537

536538
if(WIN32)

cmake/ThirdPartyDependencies.cmake

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,30 @@ if(NOT TARGET spdlog::spdlog)
4040
"SPDLOG_FMT_EXTERNAL OFF")
4141
endif()
4242

43+
if(NOT TARGET opentelemetry_api)
44+
# https://github.com/open-telemetry/opentelemetry-cpp/releases
45+
cpmaddpackage(
46+
NAME
47+
opentelemetry_api
48+
VERSION
49+
1.20.0
50+
GITHUB_REPOSITORY
51+
"open-telemetry/opentelemetry-cpp"
52+
EXCLUDE_FROM_ALL ON
53+
OPTIONS
54+
"OPENTELEMETRY_INSTALL OFF"
55+
"WITH_STL ON"
56+
"WITH_ABSEIL OFF"
57+
"WITH_OTLP_HTTP ON"
58+
"WITH_OTLP_GRPC OFF"
59+
"WITH_BENCHMARK OFF"
60+
"BUILD_TESTING OFF"
61+
"BUILD_SHARED_LIBS OFF"
62+
"CMAKE_C_VISIBILITY_PRESET hidden"
63+
"CMAKE_CXX_VISIBILITY_PRESET hidden"
64+
"CMAKE_POSITION_INDEPENDENT_CODE ON")
65+
endif()
66+
4367
if(NOT TARGET Microsoft.GSL::GSL)
4468
# https://github.com/microsoft/GSL/releases
4569
cpmaddpackage(

core/meta/version.cxx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <llhttp.h>
3232
#include <openssl/crypto.h>
3333
#include <openssl/x509.h>
34+
#include <opentelemetry/version.h>
3435
#include <snappy-stubs-public.h>
3536
#include <spdlog/fmt/bundled/core.h>
3637
#include <spdlog/version.h>
@@ -168,6 +169,7 @@ sdk_build_info() -> std::map<std::string, std::string>
168169
#if defined(__GLIBC__)
169170
info["libc"] = fmt::format("glibc {}.{}", __GLIBC__, __GLIBC_MINOR__);
170171
#endif
172+
info["opentelemetry_api"] = OPENTELEMETRY_VERSION;
171173

172174
return info;
173175
}

core/metrics/otel_meter.cxx

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2+
/*
3+
* Copyright 2021 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+
18+
#pragma once
19+
20+
#include "otel_meter.hxx"
21+
22+
#include <couchbase/metrics/meter.hxx>
23+
24+
#include <opentelemetry/metrics/meter_provider.h>
25+
#include <opentelemetry/metrics/provider.h>
26+
27+
#include <algorithm>
28+
#include <iostream>
29+
#include <thread>
30+
#include <utility>
31+
32+
namespace couchbase::core::metrics
33+
{
34+
namespace
35+
{
36+
class otel_sync_histogram
37+
{
38+
public:
39+
otel_sync_histogram(
40+
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<std::uint64_t>>
41+
histogram_counter)
42+
: histogram_counter_(histogram_counter)
43+
{
44+
}
45+
46+
void record(std::uint64_t value,
47+
const opentelemetry::common::KeyValueIterable& tags,
48+
opentelemetry::context::Context& ctx)
49+
{
50+
histogram_counter_->Record(value, tags, ctx);
51+
}
52+
53+
private:
54+
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<std::uint64_t>>
55+
histogram_counter_;
56+
std::mutex mutex_;
57+
};
58+
59+
class otel_value_recorder : public couchbase::metrics::value_recorder
60+
{
61+
public:
62+
explicit otel_value_recorder(
63+
nostd::shared_ptr<metrics_api::Histogram<std::uint64_t>> histogram_counter,
64+
const std::map<std::string, std::string>& tags)
65+
: histogram_counter_(histogram_counter)
66+
, tags_(tags)
67+
{
68+
}
69+
void record_value(std::int64_t value) override
70+
{
71+
value = std::max<int64_t>(value, 0);
72+
auto uvalue = static_cast<std::uint64_t>(value);
73+
histogram_counter_->Record(
74+
uvalue, opentelemetry::common::KeyValueIterableView<decltype(tags_)>{ tags_ }, context_);
75+
}
76+
77+
auto tags() -> const std::map<std::string, std::string>
78+
{
79+
return tags_;
80+
}
81+
82+
auto histogram_counter()
83+
-> opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<std::uint64_t>>
84+
{
85+
return histogram_counter_;
86+
}
87+
88+
private:
89+
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Histogram<std::uint64_t>>
90+
histogram_counter_;
91+
const std::map<std::string, std::string> tags_;
92+
opentelemetry::context::Context context_{};
93+
std::mutex mutex_;
94+
};
95+
} // namespace
96+
97+
class otel_meter_impl
98+
{
99+
friend otel_meter;
100+
101+
public:
102+
explicit otel_meter_impl(opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Meter> meter)
103+
: meter_(meter)
104+
{
105+
}
106+
107+
private:
108+
opentelemetry::nostd::shared_ptr<opentelemetry::metrics::Meter> meter_;
109+
std::mutex mutex_;
110+
std::multimap<std::string, std::shared_ptr<otel_value_recorder>> recorders_;
111+
};
112+
113+
auto
114+
otel_meter::get_value_recorder(const std::string& name,
115+
const std::map<std::string, std::string>& tags)
116+
-> std::shared_ptr<couchbase::metrics::value_recorder>
117+
{
118+
// first look up the histogram, in case we already have it...
119+
std::scoped_lock<std::mutex> lock(mutex_);
120+
auto it = recorders_.equal_range(name);
121+
if (it.first == it.second) {
122+
// this name isn't associated with any histogram, so make one and return it.
123+
// Note we'd like to make one with more buckets than default, given the range of
124+
// response times we'd like to display (queries vs kv for instance), but otel
125+
// api doesn't seem to allow this.
126+
return recorders_
127+
.insert({ name,
128+
std::make_shared<otel_value_recorder>(meter_->CreateUInt64Histogram(name, "", "us"),
129+
tags) })
130+
->second;
131+
}
132+
// so it is already, lets see if we already have one with those tags, or need
133+
// to make a new one (using the histogram we already have).
134+
for (auto itr = it.first; itr != it.second; itr++) {
135+
if (tags == itr->second->tags()) {
136+
return itr->second;
137+
}
138+
}
139+
// if you are here, we need to add one with these tags and the histogram associated with the
140+
// name.
141+
return recorders_
142+
.insert(
143+
{ name, std::make_shared<otel_value_recorder>(it.first->second->histogram_counter(), tags) })
144+
->second;
145+
}
146+
} // namespace couchbase::core::metrics

core/metrics/otel_meter.hxx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2+
/*
3+
* Copyright 2021 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+
18+
#pragma once
19+
20+
#include <couchbase/metrics/meter.hxx>
21+
22+
namespace couchbase::core::metrics
23+
{
24+
25+
class otel_meter_impl;
26+
27+
class otel_meter : public couchbase::metrics::meter
28+
{
29+
public:
30+
auto get_value_recorder(const std::string& name, const std::map<std::string, std::string>& tags)
31+
-> std::shared_ptr<couchbase::metrics::value_recorder> override;
32+
33+
private:
34+
std::unique_ptr<otel_meter_impl> impl_;
35+
};
36+
} // namespace couchbase::core::metrics

core/tracing/noop_tracer.hxx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class noop_span : public couchbase::tracing::request_span
3939
/* do nothing */
4040
}
4141

42-
auto uses_tags() const -> bool override
42+
[[nodiscard]] auto uses_tags() const -> bool override
4343
{
4444
return false;
4545
}

0 commit comments

Comments
 (0)