diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d8db91364..3674c360d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -193,6 +193,38 @@ jobs: run: | (cd ./functional/otlp; ./run_test.sh) + cmake_clang_maintainer_abiv2_test: + name: CMake clang 14 (maintainer mode, abiv2) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: setup + env: + CC: /usr/bin/clang-14 + CXX: /usr/bin/clang++-14 + PROTOBUF_VERSION: 21.12 + run: | + sudo -E ./ci/setup_cmake.sh + sudo -E ./ci/setup_ci_environment.sh + sudo -E ./ci/install_protobuf.sh + - name: run cmake clang (maintainer mode, abiv2) + env: + CC: /usr/bin/clang-14 + CXX: /usr/bin/clang++-14 + run: | + ./ci/do_ci.sh cmake.maintainer.abiv2.test + - name: generate test cert + env: + CFSSL_VERSION: 1.6.3 + run: | + sudo -E ./tools/setup-cfssl.sh + (cd ./functional/cert; ./generate_cert.sh) + - name: run func test + run: | + (cd ./functional/otlp; ./run_test.sh) + cmake_msvc_maintainer_test: name: CMake msvc (maintainer mode) runs-on: windows-latest @@ -316,6 +348,42 @@ jobs: CXX: /usr/bin/g++-4.8 run: ./ci/do_ci.sh cmake.legacy.exporter.otprotocol.test + cmake_test_cxx14_gcc: + name: CMake C++14 test(GCC) + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: setup + env: + CMAKE_VERSION: 3.20.6 + run: | + sudo -E ./ci/setup_ci_environment.sh + sudo -E ./ci/setup_cmake.sh + - name: run tests (enable stl) + env: + CXX_STANDARD: '14' + run: ./ci/do_ci.sh cmake.c++14.stl.test + + cmake_test_cxx17_gcc: + name: CMake C++17 test(GCC) + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v4 + with: + submodules: 'recursive' + - name: setup + env: + CMAKE_VERSION: 3.20.6 + run: | + sudo -E ./ci/setup_ci_environment.sh + sudo -E ./ci/setup_cmake.sh + - name: run tests (enable stl) + env: + CXX_STANDARD: '17' + run: ./ci/do_ci.sh cmake.c++17.stl.test + cmake_test_cxx20_gcc: name: CMake C++20 test(GCC) runs-on: ubuntu-20.04 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7901a35732..a884208922 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,41 @@ Increment the: [#2324](https://github.com/open-telemetry/opentelemetry-cpp/pull/2326) * [EXPORTER] Replace colons with underscores when converting to Prometheus label [#2324](https://github.com/open-telemetry/opentelemetry-cpp/pull/2330) +* [API] Add InstrumentationScope attributes in MeterProvider::GetMeter() + [#2224](https://github.com/open-telemetry/opentelemetry-cpp/pull/2224) + +Important changes: + +* [API] Add InstrumentationScope attributes in MeterProvider::GetMeter() + [#2224](https://github.com/open-telemetry/opentelemetry-cpp/pull/2224) + * MeterProvider::GetMeter() now accepts InstrumentationScope attributes. + * Because this is an `ABI` breaking change, the fix is only available + with the `CMake` option `WITH_ABI_VERSION_2=ON`. + * When building with `CMake` option `WITH_ABI_VERSION_1=ON` (by default) + the `ABI` is unchanged, and the fix is not available. + +Breaking changes: + +* [BUILD] Need fine-grained HAVE_CPP_STDLIB + [#2304](https://github.com/open-telemetry/opentelemetry-cpp/pull/2304) + * In `CMAKE`, the boolean option `WITH_STL` as changed to an option + that accepts the values `OFF`, `ON`, `CXX11`, `CXX14`, `CXX17`, + `CXX20` and `CXX23`. + * Applications makefiles that did not set WITH_STL need to use + `WITH_STL=OFF` instead (this is the default). + * Applications makefiles that did set WITH_STL need to use + `WITH_STL=ON` instead, or may choose to pick a specific value. + * In the `API` header files, the preprocessor symbol `HAVE_CPP_STDLIB` + is no longer used. + * Applications that did set `HAVE_CPP_STDLIB` before, need to set + `OPENTELEMETRY_STL_VERSION=` instead, to build with a + specific STL version (2011, 2014, 2017, 2020, 2023). + * The opentelemetry-cpp makefile no longer sets + CMAKE_CXX_STANDARD by itself. + Instead, the CMAKE_CXX_STANDARD and/or compiler options -stdc++ used + by the caller are honored. + * Applications that set neither CMAKE_CXX_STANDARD nor -stdc++ + options may need to provide a C++ standard in their makefiles. ## [1.11.0] 2023-08-21 diff --git a/CMakeLists.txt b/CMakeLists.txt index 64cf88ea5b..dddca04a70 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,7 +154,10 @@ message(STATUS "OPENTELEMETRY_VERSION=${OPENTELEMETRY_VERSION}") option(WITH_NO_DEPRECATED_CODE "Do not include deprecated code" OFF) -option(WITH_STL "Whether to use Standard Library for C++ latest features" OFF) +set(WITH_STL + "OFF" + CACHE STRING "Which version of the Standard Library for C++ to use") + option(WITH_GSL "Whether to use Guidelines Support Library for C++ latest features" OFF) @@ -169,22 +172,7 @@ option(OPENTELEMETRY_INSTALL "Whether to install opentelemetry targets" include("${PROJECT_SOURCE_DIR}/cmake/tools.cmake") -if(NOT DEFINED CMAKE_CXX_STANDARD) - if(WITH_STL) - # Require at least C++17. C++20 is needed to avoid gsl::span - if(CMAKE_VERSION VERSION_GREATER 3.11.999) - # Ask for 20, may get anything below - set(CMAKE_CXX_STANDARD 20) - else() - # Ask for 17, may get anything below - set(CMAKE_CXX_STANDARD 17) - endif() - else() - set(CMAKE_CXX_STANDARD 11) - endif() -endif() - -if(WITH_STL) +if(NOT WITH_STL STREQUAL "OFF") # These definitions are needed for test projects that do not link against # opentelemetry-api library directly. We ensure that variant implementation # (absl::variant or std::variant) in variant unit test code is consistent with diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index f5f1fbf897..dd1eda3c78 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -51,11 +51,36 @@ if(WITH_ABSEIL) "absl_bits" "absl_city") endif() -if(WITH_STL) - message("Building with standard library types...") - target_compile_definitions(opentelemetry_api INTERFACE HAVE_CPP_STDLIB) +if(WITH_STL STREQUAL "OFF") + message(STATUS "Building WITH_STL=OFF") +elseif(WITH_STL STREQUAL "CXX11") + message(STATUS "Building WITH_STL=CXX11") + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_STL_VERSION=2011) +elseif(WITH_STL STREQUAL "CXX14") + message(STATUS "Building WITH_STL=CXX14") + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_STL_VERSION=2014) +elseif(WITH_STL STREQUAL "CXX17") + message(STATUS "Building WITH_STL=CXX17") + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_STL_VERSION=2017) +elseif(WITH_STL STREQUAL "CXX20") + message(STATUS "Building WITH_STL=CXX20") + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_STL_VERSION=2020) +elseif(WITH_STL STREQUAL "CXX23") + message(STATUS "Building WITH_STL=CXX23") + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_STL_VERSION=2023) +elseif(WITH_STL STREQUAL "ON") + message(STATUS "Building WITH_STL=ON") + # "ON" corresponds to "CXX23" at this time. + target_compile_definitions(opentelemetry_api + INTERFACE OPENTELEMETRY_STL_VERSION=2023) else() - message("Building with nostd types...") + message( + FATAL_ERROR "WITH_STL must be ON, OFF, CXX11, CXX14, CXX17, CXX20 or CXX23") endif() if(WITH_GSL) diff --git a/api/include/opentelemetry/metrics/meter_provider.h b/api/include/opentelemetry/metrics/meter_provider.h index e0b0285ef4..152e543d36 100644 --- a/api/include/opentelemetry/metrics/meter_provider.h +++ b/api/include/opentelemetry/metrics/meter_provider.h @@ -3,8 +3,11 @@ #pragma once +#include "opentelemetry/common/key_value_iterable.h" +#include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/type_traits.h" #include "opentelemetry/version.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -20,19 +23,113 @@ class MeterProvider { public: virtual ~MeterProvider() = default; + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + + /** + * Gets or creates a named Meter instance (ABI). + * + * @since ABI_VERSION 2 + * + * @param[in] name Meter instrumentation scope + * @param[in] version Instrumentation scope version + * @param[in] schema_url Instrumentation scope schema URL + * @param[in] attributes Instrumentation scope attributes (optional, may be nullptr) + */ + virtual nostd::shared_ptr GetMeter( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const common::KeyValueIterable *attributes) noexcept = 0; + + /** + * Gets or creates a named Meter instance (API helper). + * + * @since ABI_VERSION 2 + * + * @param[in] name Meter instrumentation scope + * @param[in] version Instrumentation scope version, optional + * @param[in] schema_url Instrumentation scope schema URL, optional + */ + nostd::shared_ptr GetMeter(nostd::string_view name, + nostd::string_view version = "", + nostd::string_view schema_url = "") + { + return GetMeter(name, version, schema_url, nullptr); + } + + /** + * Gets or creates a named Meter instance (API helper). + * + * @since ABI_VERSION 2 + * + * @param[in] name Meter instrumentation scope + * @param[in] version Instrumentation scope version + * @param[in] schema_url Instrumentation scope schema URL + * @param[in] attributes Instrumentation scope attributes + */ + nostd::shared_ptr GetMeter( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + std::initializer_list> attributes) + { + /* Build a container from std::initializer_list. */ + nostd::span> attributes_span{ + attributes.begin(), attributes.end()}; + + /* Build a view on the container. */ + common::KeyValueIterableView< + nostd::span>> + iterable_attributes{attributes_span}; + + /* Add attributes using the view. */ + return GetMeter(name, version, schema_url, &iterable_attributes); + } + + /** + * Gets or creates a named Meter instance (API helper). + * + * @since ABI_VERSION 2 + * + * @param[in] name Meter instrumentation scope + * @param[in] version Instrumentation scope version + * @param[in] schema_url Instrumentation scope schema URL + * @param[in] attributes Instrumentation scope attributes container + */ + template ::value> * = nullptr> + nostd::shared_ptr GetMeter(nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const T &attributes) + { + /* Build a view on the container. */ + common::KeyValueIterableView iterable_attributes(attributes); + + /* Add attributes using the view. */ + return GetMeter(name, version, schema_url, &iterable_attributes); + } + +#else /** - * Gets or creates a named Meter instance. + * Gets or creates a named Meter instance (ABI) * - * Optionally a version can be passed to create a named and versioned Meter - * instance. + * @since ABI_VERSION 1 + * + * @param[in] name Meter instrumentation scope + * @param[in] version Instrumentation scope version, optional + * @param[in] schema_url Instrumentation scope schema URL, optional */ - virtual nostd::shared_ptr GetMeter(nostd::string_view library_name, - nostd::string_view library_version = "", - nostd::string_view schema_url = "") noexcept = 0; + virtual nostd::shared_ptr GetMeter(nostd::string_view name, + nostd::string_view version = "", + nostd::string_view schema_url = "") noexcept = 0; +#endif + #ifdef ENABLE_REMOVE_METER_PREVIEW - virtual void RemoveMeter(nostd::string_view library_name, - nostd::string_view library_version = "", - nostd::string_view schema_url = "") noexcept = 0; + virtual void RemoveMeter(nostd::string_view name, + nostd::string_view version = "", + nostd::string_view schema_url = "") noexcept = 0; #endif }; } // namespace metrics diff --git a/api/include/opentelemetry/metrics/noop.h b/api/include/opentelemetry/metrics/noop.h index c5802f3dd3..edbbe2c100 100644 --- a/api/include/opentelemetry/metrics/noop.h +++ b/api/include/opentelemetry/metrics/noop.h @@ -196,12 +196,23 @@ class NoopMeterProvider final : public MeterProvider public: NoopMeterProvider() : meter_{nostd::shared_ptr(new NoopMeter)} {} - nostd::shared_ptr GetMeter(nostd::string_view /* library_name */, - nostd::string_view /* library_version */, +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + nostd::shared_ptr GetMeter( + nostd::string_view /* name */, + nostd::string_view /* version */, + nostd::string_view /* schema_url */, + const common::KeyValueIterable * /* attributes */) noexcept override + { + return meter_; + } +#else + nostd::shared_ptr GetMeter(nostd::string_view /* name */, + nostd::string_view /* version */, nostd::string_view /* schema_url */) noexcept override { return meter_; } +#endif #ifdef ENABLE_REMOVE_METER_PREVIEW void RemoveMeter(nostd::string_view /* name */, diff --git a/api/include/opentelemetry/nostd/shared_ptr.h b/api/include/opentelemetry/nostd/shared_ptr.h index 4f7dd86bb4..0222352030 100644 --- a/api/include/opentelemetry/nostd/shared_ptr.h +++ b/api/include/opentelemetry/nostd/shared_ptr.h @@ -2,9 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#ifdef HAVE_CPP_STDLIB -# include "opentelemetry/std/shared_ptr.h" -#else + +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2011 +# include "opentelemetry/std/shared_ptr.h" +# define OPENTELEMETRY_HAVE_STD_SHARED_PTR +# endif +#endif + +#if !defined(OPENTELEMETRY_HAVE_STD_SHARED_PTR) # include # include # include @@ -201,4 +207,4 @@ inline bool operator!=(std::nullptr_t, const shared_ptr &rhs) noexcept } } // namespace nostd OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_HAVE_STD_SHARED_PTR */ diff --git a/api/include/opentelemetry/nostd/span.h b/api/include/opentelemetry/nostd/span.h index 3022a913d9..da0f385cf0 100644 --- a/api/include/opentelemetry/nostd/span.h +++ b/api/include/opentelemetry/nostd/span.h @@ -4,32 +4,34 @@ #pragma once // Try to use either `std::span` or `gsl::span` -#ifdef HAVE_CPP_STDLIB -# include -# include -# include -# include +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2020 +# include +# include +# include +# include /** * @brief Clang 14.0.0 with libc++ do not support implicitly construct a span * for a range. We just use our fallback version. * */ -# if !defined(OPENTELEMETRY_OPTION_USE_STD_SPAN) && defined(_LIBCPP_VERSION) -# if _LIBCPP_VERSION <= 14000 -# define OPENTELEMETRY_OPTION_USE_STD_SPAN 0 +# if !defined(OPENTELEMETRY_OPTION_USE_STD_SPAN) && defined(_LIBCPP_VERSION) +# if _LIBCPP_VERSION <= 14000 +# define OPENTELEMETRY_OPTION_USE_STD_SPAN 0 +# endif # endif -# endif -# ifndef OPENTELEMETRY_OPTION_USE_STD_SPAN -# define OPENTELEMETRY_OPTION_USE_STD_SPAN 1 -# endif -# if OPENTELEMETRY_OPTION_USE_STD_SPAN -# include "opentelemetry/std/span.h" -# endif -#endif +# ifndef OPENTELEMETRY_OPTION_USE_STD_SPAN +# define OPENTELEMETRY_OPTION_USE_STD_SPAN 1 +# endif +# if OPENTELEMETRY_OPTION_USE_STD_SPAN +# include "opentelemetry/std/span.h" +# endif +# endif /* OPENTELEMETRY_STL_VERSION >= 2020 */ +#endif /* OPENTELEMETRY_STL_VERSION */ // Fallback to `nostd::span` if necessary -#if !defined(HAVE_SPAN) +#if !defined(OPENTELEMETRY_HAVE_SPAN) # include # include # include diff --git a/api/include/opentelemetry/nostd/string_view.h b/api/include/opentelemetry/nostd/string_view.h index 4f065effa0..9f9fb42180 100644 --- a/api/include/opentelemetry/nostd/string_view.h +++ b/api/include/opentelemetry/nostd/string_view.h @@ -3,9 +3,14 @@ #pragma once -#ifdef HAVE_CPP_STDLIB -# include "opentelemetry/std/string_view.h" -#else +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2017 +# include "opentelemetry/std/string_view.h" +# define OPENTELEMETRY_HAVE_STD_STRING_VIEW +# endif +#endif + +#if !defined(OPENTELEMETRY_HAVE_STD_STRING_VIEW) # include # include # include @@ -216,4 +221,4 @@ struct hash } }; } // namespace std -#endif +#endif /* OPENTELEMETRY_HAVE_STD_STRING_VIEW */ diff --git a/api/include/opentelemetry/nostd/type_traits.h b/api/include/opentelemetry/nostd/type_traits.h index 3d212ea3e2..46d11c89cb 100644 --- a/api/include/opentelemetry/nostd/type_traits.h +++ b/api/include/opentelemetry/nostd/type_traits.h @@ -3,9 +3,14 @@ #pragma once -#ifdef HAVE_CPP_STDLIB -# include "opentelemetry/std/type_traits.h" -#else +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2011 +# include "opentelemetry/std/type_traits.h" +# define OPENTELEMETRY_HAVE_STD_TYPE_TRAITS +# endif +#endif + +#if !defined(OPENTELEMETRY_HAVE_STD_TYPE_TRAITS) # include # include @@ -154,4 +159,4 @@ struct is_trivially_move_assignable # endif } // namespace nostd OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_HAVE_STD_TYPE_TRAITS */ diff --git a/api/include/opentelemetry/nostd/unique_ptr.h b/api/include/opentelemetry/nostd/unique_ptr.h index a97111b9d0..f864eb4f04 100644 --- a/api/include/opentelemetry/nostd/unique_ptr.h +++ b/api/include/opentelemetry/nostd/unique_ptr.h @@ -3,9 +3,14 @@ #pragma once -#ifdef HAVE_CPP_STDLIB -# include "opentelemetry/std/unique_ptr.h" -#else +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2011 +# include "opentelemetry/std/unique_ptr.h" +# define OPENTELEMETRY_HAVE_STD_UNIQUE_PTR +# endif +#endif + +#if !defined(OPENTELEMETRY_HAVE_STD_UNIQUE_PTR) # include # include # include @@ -172,4 +177,4 @@ bool operator!=(std::nullptr_t, const unique_ptr &rhs) noexcept } } // namespace nostd OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_HAVE_STD_UNIQUE_PTR */ diff --git a/api/include/opentelemetry/nostd/utility.h b/api/include/opentelemetry/nostd/utility.h index bb350594ad..e7ad2d77f0 100644 --- a/api/include/opentelemetry/nostd/utility.h +++ b/api/include/opentelemetry/nostd/utility.h @@ -3,10 +3,14 @@ #pragma once -#ifdef HAVE_CPP_STDLIB -# include "opentelemetry/std/utility.h" -#else +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2014 +# include "opentelemetry/std/utility.h" +# define OPENTELEMETRY_HAVE_STD_UTILITY +# endif +#endif +#if !defined(OPENTELEMETRY_HAVE_STD_UTILITY) # include # include # include @@ -153,4 +157,4 @@ struct in_place_type_t }; } // namespace nostd OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_HAVE_STD_UTILITY */ diff --git a/api/include/opentelemetry/nostd/variant.h b/api/include/opentelemetry/nostd/variant.h index b6b2326998..d0b2d96001 100644 --- a/api/include/opentelemetry/nostd/variant.h +++ b/api/include/opentelemetry/nostd/variant.h @@ -5,9 +5,14 @@ #include "opentelemetry/version.h" -#ifdef HAVE_CPP_STDLIB -# include "opentelemetry/std/variant.h" -#else +#if defined(OPENTELEMETRY_STL_VERSION) +# if OPENTELEMETRY_STL_VERSION >= 2017 +# include "opentelemetry/std/variant.h" +# define OPENTELEMETRY_HAVE_STD_VARIANT +# endif +#endif + +#if !defined(OPENTELEMETRY_HAVE_STD_VARIANT) # ifndef HAVE_ABSEIL // We use a LOCAL snapshot of Abseil that is known to compile with Visual Studio 2015. @@ -73,4 +78,4 @@ using absl::visit; } // namespace nostd OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_HAVE_STD_VARIANT */ diff --git a/api/include/opentelemetry/std/span.h b/api/include/opentelemetry/std/span.h index 5fdff57fd5..2a3dc12a84 100644 --- a/api/include/opentelemetry/std/span.h +++ b/api/include/opentelemetry/std/span.h @@ -12,18 +12,18 @@ # if __has_include() // Check for __cpp_{feature} # include # if defined(__cpp_lib_span) && __cplusplus > 201703L -# define HAVE_SPAN +# define OPENTELEMETRY_HAVE_SPAN # endif # endif -# if !defined(HAVE_SPAN) +# if !defined(OPENTELEMETRY_HAVE_SPAN) # // Check for Visual Studio span # if defined(_MSVC_LANG) && _HAS_CXX20 -# define HAVE_SPAN +# define OPENTELEMETRY_HAVE_SPAN # endif # // Check for other compiler span implementation # if !defined(_MSVC_LANG) && __has_include() && __cplusplus > 201703L // This works as long as compiler standard is set to C++20 -# define HAVE_SPAN +# define OPENTELEMETRY_HAVE_SPAN # endif # endif # if !__has_include() @@ -31,7 +31,7 @@ # endif #endif -#if !defined(HAVE_SPAN) +#if !defined(OPENTELEMETRY_HAVE_SPAN) # if defined(HAVE_GSL) # include // Guidelines Support Library provides an implementation of std::span @@ -44,12 +44,12 @@ template using span = gsl::span; } // namespace nostd OPENTELEMETRY_END_NAMESPACE -# define HAVE_SPAN +# define OPENTELEMETRY_HAVE_SPAN # else // No `gsl::span`, no `std::span`, fallback to `nostd::span` # endif -#else // HAVE_SPAN +#else // OPENTELEMETRY_HAVE_SPAN // Using std::span (https://wg21.link/P0122R7) from Standard Library available in C++20 : // - GCC libstdc++ 10+ // - Clang libc++ 7 @@ -66,4 +66,4 @@ template using span = std::span; } // namespace nostd OPENTELEMETRY_END_NAMESPACE -#endif // of HAVE_SPAN +#endif // if OPENTELEMETRY_HAVE_SPAN diff --git a/api/test/nostd/span_test.cc b/api/test/nostd/span_test.cc index 98e825142d..5c13ee590e 100644 --- a/api/test/nostd/span_test.cc +++ b/api/test/nostd/span_test.cc @@ -60,11 +60,6 @@ TEST(SpanTest, PointerCountConstruction) span s2{array.data(), array.size()}; EXPECT_EQ(s2.data(), array.data()); EXPECT_EQ(s2.size(), array.size()); - -#ifndef HAVE_CPP_STDLIB - /* This test is not supposed to fail with STL. Why is this invalid construct? */ - EXPECT_DEATH((span{array.data(), array.size()}), ".*"); -#endif } TEST(SpanTest, RangeConstruction) @@ -78,11 +73,6 @@ TEST(SpanTest, RangeConstruction) span s2{std::begin(array), std::end(array)}; EXPECT_EQ(s2.data(), array); EXPECT_EQ(s2.size(), 3); - -#ifndef HAVE_CPP_STDLIB - /* This test is not supposed to fail with STL. Why is this invalid construct? */ - EXPECT_DEATH((span{std::begin(array), std::end(array)}), ".*"); -#endif } TEST(SpanTest, ArrayConstruction) @@ -122,11 +112,6 @@ TEST(SpanTest, ContainerConstruction) EXPECT_EQ(s2.data(), v.data()); EXPECT_EQ(s2.size(), v.size()); -#ifndef HAVE_CPP_STDLIB - /* This test is not supposed to fail with STL. Why is this invalid construct? */ - EXPECT_DEATH((span{v.data(), 3}), ".*"); -#endif - EXPECT_FALSE((std::is_constructible, std::vector>::value)); EXPECT_FALSE((std::is_constructible, std::list>::value)); } diff --git a/api/test/nostd/string_view_test.cc b/api/test/nostd/string_view_test.cc index fc580debc1..52c72ea4d8 100644 --- a/api/test/nostd/string_view_test.cc +++ b/api/test/nostd/string_view_test.cc @@ -71,7 +71,7 @@ TEST(StringViewTest, SubstrPortion) TEST(StringViewTest, SubstrOutOfRange) { string_view s = "abc123"; -#if __EXCEPTIONS || defined(HAVE_CPP_STDLIB) +#if __EXCEPTIONS || ((defined(OPENTELEMETRY_STL_VERSION) && (OPENTELEMETRY_STL_VERSION >= 2020))) EXPECT_THROW(s.substr(10), std::out_of_range); #else EXPECT_DEATH({ s.substr(10); }, ""); diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 6452faa451..948a62b9dd 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -174,6 +174,31 @@ elif [[ "$1" == "cmake.maintainer.cpp11.async.test" ]]; then make -k -j $(nproc) make test exit 0 +elif [[ "$1" == "cmake.maintainer.abiv2.test" ]]; then + cd "${BUILD_DIR}" + rm -rf * + cmake ${CMAKE_OPTIONS[@]} \ + -DWITH_OTLP_HTTP=ON \ + -DWITH_OTLP_HTTP_SSL_PREVIEW=ON \ + -DWITH_OTLP_HTTP_SSL_TLS_PREVIEW=ON \ + -DWITH_REMOVE_METER_PREVIEW=ON \ + -DWITH_PROMETHEUS=ON \ + -DWITH_EXAMPLES=ON \ + -DWITH_EXAMPLES_HTTP=ON \ + -DWITH_ZIPKIN=ON \ + -DBUILD_W3CTRACECONTEXT_TEST=ON \ + -DWITH_ELASTICSEARCH=ON \ + -DWITH_METRICS_EXEMPLAR_PREVIEW=ON \ + -DWITH_ASYNC_EXPORT_PREVIEW=OFF \ + -DOTELCPP_MAINTAINER_MODE=ON \ + -DWITH_NO_DEPRECATED_CODE=ON \ + -DWITH_ABI_VERSION_1=OFF \ + -DWITH_ABI_VERSION_2=ON \ + ${IWYU} \ + "${SRC_DIR}" + eval "$MAKE_COMMAND" + make test + exit 0 elif [[ "$1" == "cmake.with_async_export.test" ]]; then cd "${BUILD_DIR}" rm -rf * @@ -221,6 +246,32 @@ elif [[ "$1" == "cmake.c++20.test" ]]; then eval "$MAKE_COMMAND" make test exit 0 +elif [[ "$1" == "cmake.c++14.stl.test" ]]; then + cd "${BUILD_DIR}" + rm -rf * + cmake ${CMAKE_OPTIONS[@]} \ + -DWITH_METRICS_EXEMPLAR_PREVIEW=ON \ + -DCMAKE_CXX_FLAGS="-Werror $CXXFLAGS" \ + -DWITH_ASYNC_EXPORT_PREVIEW=ON \ + -DWITH_STL=CXX14 \ + ${IWYU} \ + "${SRC_DIR}" + eval "$MAKE_COMMAND" + make test + exit 0 +elif [[ "$1" == "cmake.c++17.stl.test" ]]; then + cd "${BUILD_DIR}" + rm -rf * + cmake ${CMAKE_OPTIONS[@]} \ + -DWITH_METRICS_EXEMPLAR_PREVIEW=ON \ + -DCMAKE_CXX_FLAGS="-Werror $CXXFLAGS" \ + -DWITH_ASYNC_EXPORT_PREVIEW=ON \ + -DWITH_STL=CXX17 \ + ${IWYU} \ + "${SRC_DIR}" + eval "$MAKE_COMMAND" + make test + exit 0 elif [[ "$1" == "cmake.c++20.stl.test" ]]; then cd "${BUILD_DIR}" rm -rf * diff --git a/docs/building-with-stdlib.md b/docs/building-with-stdlib.md index a90a14a6ed..d9c73073da 100644 --- a/docs/building-with-stdlib.md +++ b/docs/building-with-stdlib.md @@ -138,14 +138,22 @@ Visual Studio provides 1st class debug experience for the standard library. Supported build flavors: * `nostd` - OpenTelemetry backport of classes for C++11. Not using standard lib. -* `stdlib` - Standard Library. Full native experience with C++20 compiler. - C++17 works but with additional dependencies, e.g. either MS-GSL or Abseil for +* `stdlib` - Standard Library. + Native experience with C++11/C++14/C++17/C++20/C++23 compiler. + Depending on the stdlib level in effect, + C++ features are used from the standard library, + completed with `nostd` replacement implementations. + C++17 and below works but with additional dependencies, + e.g. either MS-GSL or Abseil for `std::span` implementation (`gsl::span` or `absl::Span`). * `absl` - TODO: this should allow using Abseil C++ library only (no MS-GSL). Currently only `nostd` and `stdlib` configurations are implemented in CMake build. `absl` is reserved for future use. Build systems other than CMake need to -`#define HAVE_CPP_STDLIB` to enable the Standard Library classes. +`#define OPENTELEMETRY_STL_VERSION=` to enable the Standard Library classes. + +Valid values for `OPENTELEMETRY_STL_VERSION` are `2011`, `2014`, `2017`, `2020` and +`2023`. ### Build matrix diff --git a/docs/dependencies.md b/docs/dependencies.md index 62fbefc297..d0dc09c54f 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -24,8 +24,9 @@ Both these dependencies are listed here: [SDK](/sdk): - Uses Standard C++ library for latest features (std::string_view, std::variant, std::span, std::shared_ptr, std::unique_ptr) with C++14/17/20 - compiler if `WITH_STL` cmake option is enabled or `HAVE_CPP_STDLIB` macro is - defined. License: `GNU General Public License` + compiler if cmake option `WITH_STL` is enabled + or macro `OPENTELEMETRY_STL_VERSION` is defined. + License: `GNU General Public License` - For C++11/14/17 compilers, fallback to gsl::span if [GSL C++ library](https://github.com/microsoft/GSL) is installed. License: `MIT License` diff --git a/exporters/etw/README.md b/exporters/etw/README.md index 29dc3de430..3339223fa6 100644 --- a/exporters/etw/README.md +++ b/exporters/etw/README.md @@ -121,7 +121,7 @@ compiled: | Name | Description | |---------------------|------------------------------------------------------------------------------------------------------------------------| -| HAVE_CPP_STDLIB | Use STL classes for API surface. This option requires at least C++17. C++20 is recommended. Some customers may benefit from STL library provided with the compiler instead of using custom OpenTelemetry `nostd::` implementation due to security and performance considerations. | +| OPENTELEMETRY_STL_VERSION | Use STL classes for API surface. C++20 is recommended. Some customers may benefit from STL library provided with the compiler instead of using custom OpenTelemetry `nostd::` implementation due to security and performance considerations. | | HAVE_GSL | Use [Microsoft GSL](https://github.com/microsoft/GSL) for `gsl::span` implementation. Library must be in include path. Microsoft GSL claims to be the most feature-complete implementation of `std::span`. It may be used instead of `nostd::span` implementation in projects that statically link OpenTelemetry SDK. | | HAVE_TLD | Use ETW/TraceLogging Dynamic protocol. This is the default implementation compatible with existing C# "listeners" / "decoders" of ETW events. This option requires an additional optional Microsoft MIT-licensed `TraceLoggingDynamic.h` header. | diff --git a/exporters/otlp/test/otlp_grpc_exporter_test.cc b/exporters/otlp/test/otlp_grpc_exporter_test.cc index 3298e5390d..3be2bcc653 100644 --- a/exporters/otlp/test/otlp_grpc_exporter_test.cc +++ b/exporters/otlp/test/otlp_grpc_exporter_test.cc @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#ifndef HAVE_CPP_STDLIB +#ifndef OPENTELEMETRY_STL_VERSION // Unfortunately as of 04/27/2021 the fix is NOT in the vcpkg snapshot of Google Test. // Remove above `#ifdef` once the GMock fix for C++20 is in the mainline. // @@ -284,4 +284,4 @@ TEST_F(OtlpGrpcExporterTestPeer, ConfigUnknownInsecureFromEnv) } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_STL_VERSION */ diff --git a/exporters/otlp/test/otlp_http_exporter_test.cc b/exporters/otlp/test/otlp_http_exporter_test.cc index 2ac698b0de..42258d2b45 100644 --- a/exporters/otlp/test/otlp_http_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_exporter_test.cc @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#ifndef HAVE_CPP_STDLIB +#ifndef OPENTELEMETRY_STL_VERSION # include # include @@ -612,4 +612,4 @@ TEST_F(OtlpHttpExporterTestPeer, ConfigFromTracesEnv) } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_STL_VERSION */ diff --git a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc index 4dc3b5829d..df89ca17fa 100644 --- a/exporters/otlp/test/otlp_http_log_record_exporter_test.cc +++ b/exporters/otlp/test/otlp_http_log_record_exporter_test.cc @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#ifndef HAVE_CPP_STDLIB +#ifndef OPENTELEMETRY_STL_VERSION # include # include @@ -740,4 +740,4 @@ TEST_F(OtlpHttpLogRecordExporterTestPeer, DefaultEndpoint) } // namespace otlp } // namespace exporter OPENTELEMETRY_END_NAMESPACE -#endif +#endif /* OPENTELEMETRY_STL_VERSION */ diff --git a/exporters/zipkin/test/zipkin_exporter_test.cc b/exporters/zipkin/test/zipkin_exporter_test.cc index fab19efb65..870ff427e9 100644 --- a/exporters/zipkin/test/zipkin_exporter_test.cc +++ b/exporters/zipkin/test/zipkin_exporter_test.cc @@ -1,7 +1,7 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#ifndef HAVE_CPP_STDLIB +#ifndef OPENTELEMETRY_STL_VERSION # include "opentelemetry/exporters/zipkin/zipkin_exporter.h" # include "opentelemetry/ext/http/client/curl/http_client_curl.h" @@ -246,4 +246,4 @@ TEST_F(ZipkinExporterTestPeer, ConfigFromEnv) } // namespace zipkin } // namespace exporter OPENTELEMETRY_END_NAMESPACE -#endif // HAVE_CPP_STDLIB +#endif /* OPENTELEMETRY_STL_VERSION */ diff --git a/ext/test/http/CMakeLists.txt b/ext/test/http/CMakeLists.txt index 3ce72b3b83..328f78638b 100644 --- a/ext/test/http/CMakeLists.txt +++ b/ext/test/http/CMakeLists.txt @@ -25,7 +25,7 @@ endif() set(URL_PARSER_FILENAME url_parser_test) add_executable(${URL_PARSER_FILENAME} ${URL_PARSER_FILENAME}.cc) target_link_libraries(${URL_PARSER_FILENAME} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT}) + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_api) gtest_add_tests( TARGET ${URL_PARSER_FILENAME} TEST_PREFIX ext.http.urlparser. diff --git a/sdk/include/opentelemetry/sdk/common/attribute_utils.h b/sdk/include/opentelemetry/sdk/common/attribute_utils.h index c8afd657e2..e21649b695 100644 --- a/sdk/include/opentelemetry/sdk/common/attribute_utils.h +++ b/sdk/include/opentelemetry/sdk/common/attribute_utils.h @@ -105,10 +105,10 @@ struct AttributeConverter class AttributeMap : public std::unordered_map { public: - // Contruct empty attribute map + // Construct empty attribute map AttributeMap() : std::unordered_map() {} - // Contruct attribute map and populate with attributes + // Construct attribute map and populate with attributes AttributeMap(const opentelemetry::common::KeyValueIterable &attributes) : AttributeMap() { attributes.ForEachKeyValue( @@ -118,6 +118,19 @@ class AttributeMap : public std::unordered_map }); } + // Construct attribute map and populate with optional attributes + AttributeMap(const opentelemetry::common::KeyValueIterable *attributes) : AttributeMap() + { + if (attributes != nullptr) + { + attributes->ForEachKeyValue( + [&](nostd::string_view key, opentelemetry::common::AttributeValue value) noexcept { + SetAttribute(key, value); + return true; + }); + } + } + // Construct map from initializer list by applying `SetAttribute` transform for every attribute AttributeMap( std::initializer_list> diff --git a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h index c74c37f8a4..00f9a35ac2 100644 --- a/sdk/include/opentelemetry/sdk/metrics/meter_provider.h +++ b/sdk/include/opentelemetry/sdk/metrics/meter_provider.h @@ -48,10 +48,23 @@ class MeterProvider final : public opentelemetry::metrics::MeterProvider */ explicit MeterProvider(std::unique_ptr context) noexcept; + /* + Make sure GetMeter() helpers from the API are seen in overload resolution. + */ + using opentelemetry::metrics::MeterProvider::GetMeter; + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + nostd::shared_ptr GetMeter( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const opentelemetry::common::KeyValueIterable *attributes) noexcept override; +#else nostd::shared_ptr GetMeter( nostd::string_view name, nostd::string_view version = "", nostd::string_view schema_url = "") noexcept override; +#endif #ifdef ENABLE_REMOVE_METER_PREVIEW void RemoveMeter(nostd::string_view name, diff --git a/sdk/src/metrics/meter_provider.cc b/sdk/src/metrics/meter_provider.cc index 84ab58c4cf..23ddbc75cf 100644 --- a/sdk/src/metrics/meter_provider.cc +++ b/sdk/src/metrics/meter_provider.cc @@ -32,11 +32,23 @@ MeterProvider::MeterProvider(std::unique_ptr views, OTEL_INTERNAL_LOG_DEBUG("[MeterProvider] MeterProvider created."); } +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 +nostd::shared_ptr MeterProvider::GetMeter( + nostd::string_view name, + nostd::string_view version, + nostd::string_view schema_url, + const opentelemetry::common::KeyValueIterable *attributes) noexcept +#else nostd::shared_ptr MeterProvider::GetMeter( nostd::string_view name, nostd::string_view version, nostd::string_view schema_url) noexcept +#endif { +#if OPENTELEMETRY_ABI_VERSION_NO < 2 + const opentelemetry::common::KeyValueIterable *attributes = nullptr; +#endif + if (name.data() == nullptr || name == "") { OTEL_INTERNAL_LOG_WARN("[MeterProvider::GetMeter] Library name is empty."); @@ -53,8 +65,12 @@ nostd::shared_ptr MeterProvider::GetMeter( return nostd::shared_ptr{meter}; } } - auto lib = instrumentationscope::InstrumentationScope::Create(name, version, schema_url); - auto meter = std::shared_ptr(new Meter(context_, std::move(lib))); + + instrumentationscope::InstrumentationScopeAttributes attrs_map(attributes); + auto scope = + instrumentationscope::InstrumentationScope::Create(name, version, schema_url, attrs_map); + + auto meter = std::shared_ptr(new Meter(context_, std::move(scope))); context_->AddMeter(meter); return nostd::shared_ptr{meter}; } diff --git a/sdk/test/metrics/meter_provider_sdk_test.cc b/sdk/test/metrics/meter_provider_sdk_test.cc index a1ca8de330..1844f113d2 100644 --- a/sdk/test/metrics/meter_provider_sdk_test.cc +++ b/sdk/test/metrics/meter_provider_sdk_test.cc @@ -59,6 +59,138 @@ TEST(MeterProvider, GetMeter) mp1.Shutdown(); } +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 +TEST(MeterProvider, GetMeterAbiv2) +{ + MeterProvider mp; + + auto m1 = mp.GetMeter("name1", "version1", "url1"); + ASSERT_NE(nullptr, m1); + + auto m2 = mp.GetMeter("name2", "version2", "url2", nullptr); + ASSERT_NE(nullptr, m2); + + auto m3 = mp.GetMeter("name3", "version3", "url3", {{"accept_single_attr", true}}); + ASSERT_NE(nullptr, m3); + { + auto meter = static_cast(m3.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 1); + auto attr = attrs.find("accept_single_attr"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), true); + } + + std::pair attr4 = { + "accept_single_attr", true}; + auto m4 = mp.GetMeter("name4", "version4", "url4", {attr4}); + ASSERT_NE(nullptr, m4); + { + auto meter = static_cast(m4.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 1); + auto attr = attrs.find("accept_single_attr"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), true); + } + + auto m5 = mp.GetMeter("name5", "version5", "url5", {{"foo", "1"}, {"bar", "2"}}); + ASSERT_NE(nullptr, m5); + { + auto meter = static_cast(m5.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 2); + auto attr = attrs.find("bar"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), "2"); + } + + std::initializer_list< + std::pair> + attrs6 = {{"foo", "1"}, {"bar", 42}}; + + auto m6 = mp.GetMeter("name6", "version6", "url6", attrs6); + ASSERT_NE(nullptr, m6); + { + auto meter = static_cast(m6.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 2); + auto attr = attrs.find("bar"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), 42); + } + + typedef std::pair KV; + + std::initializer_list attrs7 = {{"foo", 3.14}, {"bar", "2"}}; + auto m7 = mp.GetMeter("name7", "version7", "url7", attrs7); + ASSERT_NE(nullptr, m7); + { + auto meter = static_cast(m7.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 2); + auto attr = attrs.find("foo"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), 3.14); + } + + auto m8 = mp.GetMeter("name8", "version8", "url8", + {{"a", "string"}, + {"b", false}, + {"c", 314159}, + {"d", (unsigned int)314159}, + {"e", (int32_t)-20}, + {"f", (uint32_t)20}, + {"g", (int64_t)-20}, + {"h", (uint64_t)20}, + {"i", 3.1}, + {"j", "string"}}); + ASSERT_NE(nullptr, m8); + { + auto meter = static_cast(m8.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 10); + auto attr = attrs.find("e"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), -20); + } + + std::map attr9{ + {"a", "string"}, {"b", false}, {"c", 314159}, {"d", (unsigned int)314159}, + {"e", (int32_t)-20}, {"f", (uint32_t)20}, {"g", (int64_t)-20}, {"h", (uint64_t)20}, + {"i", 3.1}, {"j", "string"}}; + + auto m9 = mp.GetMeter("name9", "version9", "url9", attr9); + ASSERT_NE(nullptr, m9); + { + auto meter = static_cast(m9.get()); + auto scope = meter->GetInstrumentationScope(); + auto attrs = scope->GetAttributes(); + ASSERT_EQ(attrs.size(), 10); + auto attr = attrs.find("h"); + ASSERT_FALSE(attr == attrs.end()); + ASSERT_TRUE(opentelemetry::nostd::holds_alternative(attr->second)); + EXPECT_EQ(opentelemetry::nostd::get(attr->second), 20); + } + + // cleanup properly without crash + mp.ForceFlush(); + mp.Shutdown(); +} +#endif /* OPENTELEMETRY_ABI_VERSION_NO >= 2 */ + #ifdef ENABLE_REMOVE_METER_PREVIEW TEST(MeterProvider, RemoveMeter) {