diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9f0aea79af..ee3cca52f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,8 +141,8 @@ on each other), the owner should try to get people aligned by: split it up. If none of the above worked and the PR has been stuck for more than 2 weeks, the -owner should bring it to the [OpenTelemetry C++ SIG -meeting](https://zoom.us/j/8203130519). The meeting passcode is _77777_. +owner should bring it to the OpenTelemetry C++ SIG meeting. See +[README.md](README.md#contributing) for the meeting link. ## Useful Resources diff --git a/README.md b/README.md index 890021c589..743032d17d 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ contributors' availability. Check the [OpenTelemetry community calendar](https://calendar.google.com/calendar/embed?src=google.com_b79e3e90j7bbsa2n2p5an5lf60%40group.calendar.google.com) for specific dates. -Meetings take place via [Zoom video conference](https://zoom.us/j/8203130519). +Meetings take place via [Zoom video conference](https://zoom.us/j/6729396170). The passcode is _77777_. Meeting notes are available as a public [Google diff --git a/api/include/opentelemetry/baggage/propagation/baggage_propagator.h b/api/include/opentelemetry/baggage/propagation/baggage_propagator.h index 74db10ea59..aa669dd1d9 100644 --- a/api/include/opentelemetry/baggage/propagation/baggage_propagator.h +++ b/api/include/opentelemetry/baggage/propagation/baggage_propagator.h @@ -46,6 +46,11 @@ class BaggagePropagator : public context::propagation::TextMapPropagator auto baggage = Baggage::FromHeader(baggage_str); return SetBaggage(context, baggage); } + + bool Fields(nostd::function_ref callback) const noexcept override + { + return callback(kBaggageHeader); + } }; } // namespace propagation } // namespace baggage diff --git a/api/include/opentelemetry/context/propagation/composite_propagator.h b/api/include/opentelemetry/context/propagation/composite_propagator.h index 52c05ae56f..85ad97b0fc 100644 --- a/api/include/opentelemetry/context/propagation/composite_propagator.h +++ b/api/include/opentelemetry/context/propagation/composite_propagator.h @@ -67,6 +67,21 @@ class CompositePropagator : public TextMapPropagator return propagators_.size() ? tmp_context : context; } + /** + * Invoke callback with fields set to carrier by `inject` method for all the + * configured propagators + * Returns true if all invocation return true + */ + bool Fields(nostd::function_ref callback) const noexcept override + { + bool status = true; + for (auto &p : propagators_) + { + status = status && p->Fields(callback); + } + return status; + } + private: std::vector> propagators_; }; diff --git a/api/include/opentelemetry/context/propagation/noop_propagator.h b/api/include/opentelemetry/context/propagation/noop_propagator.h index ece0229ae8..7c5edc5f8a 100644 --- a/api/include/opentelemetry/context/propagation/noop_propagator.h +++ b/api/include/opentelemetry/context/propagation/noop_propagator.h @@ -27,6 +27,11 @@ class NoOpPropagator : public TextMapPropagator /** Noop inject function does nothing */ void Inject(TextMapCarrier & /*carrier*/, const context::Context &context) noexcept override {} + + bool Fields(nostd::function_ref callback) const noexcept override + { + return true; + } }; } // namespace propagation } // namespace context diff --git a/api/include/opentelemetry/context/propagation/text_map_propagator.h b/api/include/opentelemetry/context/propagation/text_map_propagator.h index efa2686441..7efdc4919d 100644 --- a/api/include/opentelemetry/context/propagation/text_map_propagator.h +++ b/api/include/opentelemetry/context/propagation/text_map_propagator.h @@ -18,11 +18,19 @@ namespace propagation class TextMapCarrier { public: - /*returns the value associated with the passed key.*/ + // returns the value associated with the passed key. virtual nostd::string_view Get(nostd::string_view key) const noexcept = 0; - /*stores the key-value pair.*/ + // stores the key-value pair. virtual void Set(nostd::string_view key, nostd::string_view value) noexcept = 0; + + /* list of all the keys in the carrier. + By default, it returns true without invoking callback */ + virtual bool Keys(nostd::function_ref callback) const noexcept + { + return true; + } + virtual ~TextMapCarrier() = default; }; // The TextMapPropagator class provides an interface that enables extracting and injecting @@ -40,6 +48,11 @@ class TextMapPropagator // Sets the context for carrier with self defined rules. virtual void Inject(TextMapCarrier &carrier, const context::Context &context) noexcept = 0; + + // Gets the fields set in the carrier by the `inject` method + virtual bool Fields(nostd::function_ref callback) const noexcept = 0; + + virtual ~TextMapPropagator() = default; }; } // namespace propagation } // namespace context diff --git a/api/include/opentelemetry/context/runtime_context.h b/api/include/opentelemetry/context/runtime_context.h index 400b3de544..afefa93e7d 100644 --- a/api/include/opentelemetry/context/runtime_context.h +++ b/api/include/opentelemetry/context/runtime_context.h @@ -169,7 +169,7 @@ inline Token::~Token() } // The ThreadLocalContextStorage class is a derived class from -// RuntimeContextStorage and provides a wrapper for propogating context through +// RuntimeContextStorage and provides a wrapper for propagating context through // cpp thread locally. This file must be included to use the RuntimeContext // class if another implementation has not been registered. class ThreadLocalContextStorage : public RuntimeContextStorage diff --git a/api/include/opentelemetry/trace/noop.h b/api/include/opentelemetry/trace/noop.h index ad7f05273a..76c0fe0749 100644 --- a/api/include/opentelemetry/trace/noop.h +++ b/api/include/opentelemetry/trace/noop.h @@ -29,7 +29,12 @@ class NoopSpan final : public Span { public: explicit NoopSpan(const std::shared_ptr &tracer) noexcept - : tracer_{tracer}, span_context_{SpanContext::GetInvalid()} + : tracer_{tracer}, span_context_{new SpanContext(false, false)} + {} + + explicit NoopSpan(const std::shared_ptr &tracer, + nostd::unique_ptr span_context) noexcept + : tracer_{tracer}, span_context_{std::move(span_context)} {} void SetAttribute(nostd::string_view /*key*/, @@ -55,11 +60,11 @@ class NoopSpan final : public Span bool IsRecording() const noexcept override { return false; } - SpanContext GetContext() const noexcept override { return span_context_; } + SpanContext GetContext() const noexcept override { return *span_context_.get(); } private: std::shared_ptr tracer_; - SpanContext span_context_; + nostd::unique_ptr span_context_; }; /** diff --git a/api/include/opentelemetry/trace/propagation/b3_propagator.h b/api/include/opentelemetry/trace/propagation/b3_propagator.h index 9aac90f03e..f9485bd619 100644 --- a/api/include/opentelemetry/trace/propagation/b3_propagator.h +++ b/api/include/opentelemetry/trace/propagation/b3_propagator.h @@ -150,6 +150,11 @@ class B3Propagator : public B3PropagatorExtractor carrier.Set(kB3CombinedHeader, nostd::string_view(trace_identity, sizeof(trace_identity))); } + + bool Fields(nostd::function_ref callback) const noexcept override + { + return callback(kB3CombinedHeader); + } }; class B3PropagatorMultiHeader : public B3PropagatorExtractor @@ -173,6 +178,11 @@ class B3PropagatorMultiHeader : public B3PropagatorExtractor carrier.Set(kB3SpanIdHeader, nostd::string_view(span_id, sizeof(span_id))); carrier.Set(kB3SampledHeader, nostd::string_view(trace_flags + 1, 1)); } + + bool Fields(nostd::function_ref callback) const noexcept override + { + return callback(kB3TraceIdHeader) && callback(kB3SpanIdHeader) && callback(kB3SampledHeader); + } }; } // namespace propagation diff --git a/api/include/opentelemetry/trace/propagation/http_trace_context.h b/api/include/opentelemetry/trace/propagation/http_trace_context.h index 5bee19c9b7..41c6b1e61d 100644 --- a/api/include/opentelemetry/trace/propagation/http_trace_context.h +++ b/api/include/opentelemetry/trace/propagation/http_trace_context.h @@ -160,6 +160,11 @@ class HttpTraceContext : public opentelemetry::context::propagation::TextMapProp return ExtractContextFromTraceHeaders(trace_parent, trace_state); } + + bool Fields(nostd::function_ref callback) const noexcept override + { + return (callback(kTraceParent) && callback(kTraceState)); + } }; } // namespace propagation } // namespace trace diff --git a/api/include/opentelemetry/trace/propagation/jaeger.h b/api/include/opentelemetry/trace/propagation/jaeger.h index f1a842bdeb..6203752b91 100644 --- a/api/include/opentelemetry/trace/propagation/jaeger.h +++ b/api/include/opentelemetry/trace/propagation/jaeger.h @@ -15,7 +15,7 @@ namespace trace namespace propagation { -static const nostd::string_view kTraceHeader = "uber-trace-id"; +static const nostd::string_view kJaegerTraceHeader = "uber-trace-id"; class JaegerPropagator : public context::propagation::TextMapPropagator { @@ -45,7 +45,7 @@ class JaegerPropagator : public context::propagation::TextMapPropagator trace_identity[trace_id_length + span_id_length + 4] = '0'; trace_identity[trace_id_length + span_id_length + 5] = span_context.IsSampled() ? '1' : '0'; - carrier.Set(kTraceHeader, nostd::string_view(trace_identity, sizeof(trace_identity))); + carrier.Set(kJaegerTraceHeader, nostd::string_view(trace_identity, sizeof(trace_identity))); } context::Context Extract(const context::propagation::TextMapCarrier &carrier, @@ -56,6 +56,11 @@ class JaegerPropagator : public context::propagation::TextMapPropagator return SetSpan(context, sp); } + bool Fields(nostd::function_ref callback) const noexcept override + { + return callback(kJaegerTraceHeader); + } + private: static constexpr uint8_t kIsSampled = 0x01; @@ -67,7 +72,7 @@ class JaegerPropagator : public context::propagation::TextMapPropagator static SpanContext ExtractImpl(const context::propagation::TextMapCarrier &carrier) { - nostd::string_view trace_identity = carrier.Get(kTraceHeader); + nostd::string_view trace_identity = carrier.Get(kJaegerTraceHeader); const size_t trace_field_count = 4; nostd::string_view trace_fields[trace_field_count]; diff --git a/api/test/baggage/propagation/baggage_propagator_test.cc b/api/test/baggage/propagation/baggage_propagator_test.cc index 25f340bd3a..ad54c841ae 100644 --- a/api/test/baggage/propagation/baggage_propagator_test.cc +++ b/api/test/baggage/propagation/baggage_propagator_test.cc @@ -67,5 +67,13 @@ TEST(BaggagePropagatorTest, ExtractAndInjectBaggage) BaggageCarrierTest carrier2; format.Inject(carrier2, ctx2); EXPECT_EQ(carrier2.headers_[kBaggageHeader.data()], baggage.second); + + std::vector fields; + format.Fields([&fields](nostd::string_view field) { + fields.push_back(field.data()); + return true; + }); + EXPECT_EQ(fields.size(), 1); + EXPECT_EQ(fields[0], kBaggageHeader.data()); } } diff --git a/api/test/context/propagation/composite_propagator_test.cc b/api/test/context/propagation/composite_propagator_test.cc index 5168cec989..d516fe17d2 100644 --- a/api/test/context/propagation/composite_propagator_test.cc +++ b/api/test/context/propagation/composite_propagator_test.cc @@ -111,4 +111,14 @@ TEST_F(CompositePropagatorTest, Inject) EXPECT_EQ(carrier.headers_["traceparent"], "00-0102030405060708090a0b0c0d0e0f10-0102030405060708-01"); EXPECT_EQ(carrier.headers_["b3"], "0102030405060708090a0b0c0d0e0f10-0102030405060708-1"); + + std::vector fields; + composite_propagator_->Fields([&fields](nostd::string_view field) { + fields.push_back(field.data()); + return true; + }); + EXPECT_EQ(fields.size(), 3); + EXPECT_EQ(fields[0], opentelemetry::trace::propagation::kTraceParent); + EXPECT_EQ(fields[1], opentelemetry::trace::propagation::kTraceState); + EXPECT_EQ(fields[2], opentelemetry::trace::propagation::kB3CombinedHeader); } diff --git a/api/test/trace/noop_test.cc b/api/test/trace/noop_test.cc index 5414a5c726..b17faf64d4 100644 --- a/api/test/trace/noop_test.cc +++ b/api/test/trace/noop_test.cc @@ -10,14 +10,13 @@ #include -using opentelemetry::common::SystemTimestamp; -using opentelemetry::trace::NoopTracer; -using opentelemetry::trace::SpanContext; -using opentelemetry::trace::Tracer; +namespace trace_api = opentelemetry::trace; +namespace nonstd = opentelemetry::nostd; +namespace common = opentelemetry::common; TEST(NoopTest, UseNoopTracers) { - std::shared_ptr tracer{new NoopTracer{}}; + std::shared_ptr tracer{new trace_api::NoopTracer{}}; auto s1 = tracer->StartSpan("abc"); std::map attributes1; @@ -41,7 +40,7 @@ TEST(NoopTest, UseNoopTracers) s1->UpdateName("test_name"); - SystemTimestamp t1; + common::SystemTimestamp t1; s1->AddEvent("test_time_stamp", t1); s1->GetContext(); @@ -49,12 +48,34 @@ TEST(NoopTest, UseNoopTracers) TEST(NoopTest, StartSpan) { - std::shared_ptr tracer{new NoopTracer{}}; + std::shared_ptr tracer{new trace_api::NoopTracer{}}; - std::map attrs = {{"a", "3"}}; - std::vector>> links = { - {SpanContext(false, false), attrs}}; + std::map attrs = {{"a", "3"}}; + std::vector>> links = { + {trace_api::SpanContext(false, false), attrs}}; auto s1 = tracer->StartSpan("abc", attrs, links); - auto s2 = tracer->StartSpan("efg", {{"a", 3}}, {{SpanContext(false, false), {{"b", 4}}}}); + auto s2 = + tracer->StartSpan("efg", {{"a", 3}}, {{trace_api::SpanContext(false, false), {{"b", 4}}}}); +} + +TEST(NoopTest, CreateSpanValidSpanContext) +{ + // Create valid spancontext for NoopSpan + + constexpr uint8_t buf_span[] = {1, 2, 3, 4, 5, 6, 7, 8}; + constexpr uint8_t buf_trace[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + auto trace_id = trace_api::TraceId{buf_trace}; + auto span_id = trace_api::SpanId{buf_span}; + auto span_context = nonstd::unique_ptr( + new trace_api::SpanContext{trace_id, span_id, trace_api::TraceFlags{true}, false}); + std::shared_ptr tracer{new trace_api::NoopTracer{}}; + auto s1 = + nonstd::shared_ptr(new trace_api::NoopSpan(tracer, std::move(span_context))); + auto stored_span_context = s1->GetContext(); + EXPECT_EQ(stored_span_context.span_id(), span_id); + EXPECT_EQ(stored_span_context.trace_id(), trace_id); + + s1->AddEvent("even1"); // noop + s1->End(); // noop } diff --git a/api/test/trace/propagation/http_text_format_test.cc b/api/test/trace/propagation/http_text_format_test.cc index a775c3a9ac..497d716bb9 100644 --- a/api/test/trace/propagation/http_text_format_test.cc +++ b/api/test/trace/propagation/http_text_format_test.cc @@ -198,4 +198,13 @@ TEST(GlobalPropagator, SetAndGet) EXPECT_TRUE(carrier.headers_.count("traceparent") > 0); EXPECT_TRUE(carrier.headers_.count("tracestate") > 0); EXPECT_EQ(carrier.headers_["tracestate"], trace_state_value); + + std::vector fields; + propagator->Fields([&fields](nostd::string_view field) { + fields.push_back(field.data()); + return true; + }); + EXPECT_EQ(fields.size(), 2); + EXPECT_EQ(fields[0], opentelemetry::trace::propagation::kTraceParent); + EXPECT_EQ(fields[1], opentelemetry::trace::propagation::kTraceState); } diff --git a/api/test/trace/propagation/jaeger_propagation_test.cc b/api/test/trace/propagation/jaeger_propagation_test.cc index 85a126e663..a0e0ade270 100644 --- a/api/test/trace/propagation/jaeger_propagation_test.cc +++ b/api/test/trace/propagation/jaeger_propagation_test.cc @@ -147,6 +147,14 @@ TEST(JaegerPropagatorTest, InjectsContext) format.Inject(carrier, context::RuntimeContext::GetCurrent()); EXPECT_EQ(carrier.headers_["uber-trace-id"], "0102030405060708090a0b0c0d0e0f10:0102030405060708:0:01"); + + std::vector fields; + format.Fields([&fields](nostd::string_view field) { + fields.push_back(field.data()); + return true; + }); + EXPECT_EQ(fields.size(), 1); + EXPECT_EQ(fields[0], opentelemetry::trace::propagation::kJaegerTraceHeader); } TEST(JaegerPropagatorTest, DoNotInjectInvalidContext) diff --git a/bazel/curl.BUILD b/bazel/curl.BUILD index 58c71748d4..2c668b895c 100644 --- a/bazel/curl.BUILD +++ b/bazel/curl.BUILD @@ -6,13 +6,17 @@ package(features = ["no_copts_tokenization"]) config_setting( name = "windows", - values = {"cpu": "x64_windows"}, + constraint_values = [ + "@bazel_tools//platforms:windows", + ], visibility = ["//visibility:private"], ) config_setting( name = "osx", - values = {"cpu": "darwin"}, + constraint_values = [ + "@bazel_tools//platforms:osx", + ], visibility = ["//visibility:private"], ) @@ -27,11 +31,26 @@ cc_library( ]), copts = CURL_COPTS + [ "-DOS=\"os\"", - "-DCURL_EXTERN_SYMBOL=__attribute__((__visibility__(\"default\")))", ], + defines = ["CURL_STATICLIB"], includes = [ "include/", "lib/", ], + linkopts = select({ + "//:windows": [ + "-DEFAULTLIB:ws2_32.lib", + "-DEFAULTLIB:advapi32.lib", + "-DEFAULTLIB:crypt32.lib", + "-DEFAULTLIB:Normaliz.lib", + ], + "//:osx": [ + "-framework SystemConfiguration", + "-lpthread", + ], + "//conditions:default": [ + "-lpthread", + ], + }), visibility = ["//visibility:public"], -) \ No newline at end of file +) diff --git a/docs/public/GettingStarted.rst b/docs/public/GettingStarted.rst index abff4d6d13..c50a143d0a 100644 --- a/docs/public/GettingStarted.rst +++ b/docs/public/GettingStarted.rst @@ -42,9 +42,9 @@ Mark a span as active auto scope = tracer->WithActiveSpan(span); -This marks a span as active and returns a ``Scope`` object bound to the -lifetime of the span. When the ``Scope`` object is destroyed, the -related span is ended. +This marks a span as active and returns a ``Scope`` object. The scope object +controls how long a span is active. The span remains active for the lifetime +of the scope object. The concept of an active span is important, as any span that is created without explicitly specifying a parent is parented to the currently diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 9ea0a544fb..782f20d18e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,6 +2,9 @@ if(WITH_OTLP_GRPC OR WITH_OTLP_HTTP) add_subdirectory(otlp) add_subdirectory(grpc) endif() +if(WITH_ETW) + add_subdirectory(etw_threads) +endif() if(WITH_JAEGER) add_subdirectory(jaeger) endif() diff --git a/examples/etw_threads/CMakeLists.txt b/examples/etw_threads/CMakeLists.txt new file mode 100644 index 0000000000..fd6ac76443 --- /dev/null +++ b/examples/etw_threads/CMakeLists.txt @@ -0,0 +1,6 @@ +project(etw_threadpool) + +add_executable(etw_threadpool main.cc) + +target_link_libraries(etw_threadpool ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_api opentelemetry_exporter_etw) diff --git a/examples/etw_threads/README.md b/examples/etw_threads/README.md new file mode 100644 index 0000000000..a004a9f55b --- /dev/null +++ b/examples/etw_threads/README.md @@ -0,0 +1,32 @@ +# ETW Exporter multithreaded context propagation example + +## Preface + +This example shows how to pass context from main dispatcher thread to worker threads. +While this example is convenient to run in Visual Studio with ETW exporter, the same +logic should apply to any other exporter. Only the initial portion that obtains ETW +Tracer is unique to ETW, the rest can be reused. + +## How to debug events in Visual Studio 2019 or newer + +Specify your component instrumentation name, which should match the destination ETW +Provider Name or GUID. Example uses "OpenTelemetry-ETW-TLD" for the instrument / +instrumentation name. + +In Visual Studio IDE: + +- navigate to `View -> Other Windows -> Diagnostic Events...` +- click `Configure...` gear on top. +- specify `OpenTelemetry-ETW-TLD` in the list of providers to monitor. +- run example. +- `Diagnostic Events` view shows you the event flow in realtime. + +## Explanation of the code flow + +`main` function acts as a dispatcher to manage thread pool called `pool`. `beep_bop` +span is started in the `main`. Then in a loop up to `kMaxThreads` get started +concurrently. Each thread executing `beep` function with a parent scope of `main`. +`beep` subsequently calls into `bop` function, with a parent scope of `beep` span. +Entire execution of all threads is grouped under the main span called `beep_bop`. +At the end of execution, the `main` function joins all pending threads and ends +the main span. diff --git a/examples/etw_threads/main.cc b/examples/etw_threads/main.cc new file mode 100644 index 0000000000..d25883d1d1 --- /dev/null +++ b/examples/etw_threads/main.cc @@ -0,0 +1,154 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// Include common Trace Provider API and processor +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer_provider.h" +#include "opentelemetry/trace/provider.h" + +#include "opentelemetry/exporters/etw/etw_tracer_exporter.h" + +#include +#include + +#include +#ifndef LOG_DEBUG +# include + +/** + * @brief Thread-safe logger routine. + * @param format + * @param args + * @return + */ +static inline int log_vprintf(const char *format, va_list args) +{ + static std::mutex cout_mutex; + std::lock_guard lk(cout_mutex); + return vprintf(format, args); +}; + +/** + * @brief Thread-safe logger routine. + * @param format + * @param + * @return + */ +static inline int log_printf(const char *format, ...) +{ + int result; + va_list ap; + va_start(ap, format); + result = log_vprintf(format, ap); + va_end(ap); + return result; +}; + +// Debug macros +# define LOG_DEBUG(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_TRACE(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_INFO(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_WARN(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +# define LOG_ERROR(fmt_, ...) log_printf(" " fmt_ "\n", ##__VA_ARGS__) +#endif + +using namespace OPENTELEMETRY_NAMESPACE; + +using namespace opentelemetry::exporter::etw; + +// Specify destination ETW Provider Name or GUID. +// +// In Visual Studio: +// - View -> Other Windows -> Diagnostic Events... +// - Click Configure (gear on top). +// - Specify "OpenTelemetry-ETW-TLD" in the list of providers. +// +// Event view shows event flow in realtime. +const char *kGlobalProviderName = "OpenTelemetry-ETW-TLD"; + +std::string providerName = kGlobalProviderName; + +// One provider can be used to associate with different destinations. +exporter::etw::TracerProvider provider; + +// Code below is generic and may be reused with any other TracerProvider. +// In ETW provider case - instrumentation name must match destination +// ETW provider name. +nostd::shared_ptr tracer = provider.GetTracer(providerName, "1.0"); + +// Obtain numeric thread id +static inline uint64_t gettid() +{ + std::stringstream ss; + ss << std::this_thread::get_id(); + uint64_t id = std::stoull(ss.str()); + return id; +} + +// bop gets called by beep. +void bop() +{ + LOG_TRACE("bop worker tid=%u", gettid()); + auto span = tracer->StartSpan("bop"); + span->AddEvent("BopEvent", {{"tid", gettid()}}); + span->SetAttribute("attrib", 2); + span->End(); +} + +// beep gets called in its own thread. +// It is running in a thread pool, invoked via lambda by dispatcher. +void beep() +{ + LOG_TRACE("beep worker tid=%u", gettid()); + auto span = tracer->StartSpan("beep"); + span->AddEvent("BeepEvent", {{"tid", gettid()}}); + span->SetAttribute("attrib", 1); + { + auto bopScope = tracer->WithActiveSpan(span); + bop(); + } + span->End(); +} + +// Max number of threads to spawn +constexpr int kMaxThreads = 10; + +int main(int arc, char **argv) +{ + std::thread pool[kMaxThreads]; + + // Main dispatcher span: parent of all child thread spans. + auto mainSpan = tracer->StartSpan("beep_bop"); + mainSpan->SetAttribute("attrib", 0); + + // Start several threads to perform beep-bop actions. + LOG_TRACE("beep-boop dispatcher tid=%u", gettid()); + for (auto i = 0; i < kMaxThreads; i++) + { + pool[i] = std::thread([&]() { + // This code runs in its own worker thread. + auto beepScope = tracer->WithActiveSpan(mainSpan); + // call beep -> bop + beep(); + }); + }; + + // Join all worker threads in the pool + for (auto &th : pool) + { + try + { + if (th.joinable()) + th.join(); + } + catch (...) + { + // thread might have been gracefully terminated already + } + } + + // End span + mainSpan->End(); + + return 0; +} diff --git a/examples/http/BUILD b/examples/http/BUILD index 6f0618fd85..90624c1cb3 100644 --- a/examples/http/BUILD +++ b/examples/http/BUILD @@ -4,9 +4,7 @@ cc_binary( "client.cc", "tracer_common.h", ], - # TODO: Move copts/linkopts for static CURL usage into shared bzl file. copts = [ - "-DCURL_STATICLIB", "-DWITH_CURL", ], linkopts = select({ diff --git a/examples/otlp/README.md b/examples/otlp/README.md index 03325cd681..cd85a392a1 100644 --- a/examples/otlp/README.md +++ b/examples/otlp/README.md @@ -49,3 +49,18 @@ default. This can be changed with first argument from command-line, for example: Once you have the Collector running, see [CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and running the example. + +## Additional notes regarding Abseil library + +gRPC internally uses a different version of Abseil than OpenTelemetry C++ SDK. + +One option to optimize your code is to build the SDK with system-provided +Abseil library. If you are using CMake, then `-DWITH_ABSEIL=ON` may be passed +during the build of SDK to reuse the same Abseil library as gRPC. + +If you do not want to pursue the above option, and in case if you run into +conflict between Abseil library and OpenTelemetry C++ `absl::variant` +implementation, please include either `grpcpp/grpcpp.h` or +`opentelemetry/exporters/otlp/otlp_grpc_exporter.h` BEFORE any other API +headers. This approach efficiently avoids the conflict between the two different +versions of Abseil. diff --git a/examples/otlp/grpc_main.cc b/examples/otlp/grpc_main.cc index 7df891ad0a..7789457909 100644 --- a/examples/otlp/grpc_main.cc +++ b/examples/otlp/grpc_main.cc @@ -1,6 +1,9 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +// Make sure to include GRPC exporter first because otherwise Abseil may create +// ambiguity with `nostd::variant`. See issue: +// https://github.com/open-telemetry/opentelemetry-cpp/issues/880 #include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h" #include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/tracer_provider.h" diff --git a/exporters/elasticsearch/BUILD b/exporters/elasticsearch/BUILD index dd6547d511..29e9262b59 100644 --- a/exporters/elasticsearch/BUILD +++ b/exporters/elasticsearch/BUILD @@ -9,9 +9,6 @@ cc_library( "include/opentelemetry/exporters/elasticsearch/es_log_exporter.h", "include/opentelemetry/exporters/elasticsearch/es_log_recordable.h", ], - copts = [ - "-DCURL_STATICLIB", - ], linkopts = select({ "//bazel:windows": [ "-DEFAULTLIB:advapi32.lib", diff --git a/exporters/etw/test/etw_tracer_test.cc b/exporters/etw/test/etw_tracer_test.cc index 45d49356c8..400099bbe7 100644 --- a/exporters/etw/test/etw_tracer_test.cc +++ b/exporters/etw/test/etw_tracer_test.cc @@ -14,6 +14,8 @@ using namespace OPENTELEMETRY_NAMESPACE; using namespace opentelemetry::exporter::etw; +const char *kGlobalProviderName = "OpenTelemetry-ETW-TLD"; + std::string getTemporaryValue() { return std::string("Value from Temporary std::string"); @@ -43,11 +45,10 @@ TEST(ETWTracer, TracerCheck) // Windows Defender Firewall API - GP {0EFF663F-8B6E-4E6D-8182-087A8EAA29CB} // Windows Defender Firewall Driver {D5E09122-D0B2-4235-ADC1-C89FAAAF1069} - std::string providerName = "OpenTelemetry-ETW-TLD"; // supply unique instrumentation name here + std::string providerName = kGlobalProviderName; // supply unique instrumentation name here exporter::etw::TracerProvider tp; - // TODO: this code should fallback to MsgPack if TLD is not available - auto tracer = tp.GetTracer(providerName, "TLD"); + auto tracer = tp.GetTracer(providerName); // Span attributes Properties attribs = @@ -117,7 +118,7 @@ TEST(ETWTracer, TracerCheck) /* { "Timestamp": "2021-03-19T21:04:38.411193-07:00", - "ProviderName": "OpenTelemetry-ETW-Provider", + "ProviderName": "OpenTelemetry-ETW-TLD", "Id": 13, "Message": null, "ProcessId": 15120, @@ -131,7 +132,7 @@ TEST(ETWTracer, TracerCheck) */ TEST(ETWTracer, TracerCheckMinDecoration) { - std::string providerName = "OpenTelemetry-ETW-TLD"; + std::string providerName = kGlobalProviderName; exporter::etw::TracerProvider tp ({ {"enableTraceId", false}, @@ -141,7 +142,7 @@ TEST(ETWTracer, TracerCheckMinDecoration) {"enableRelatedActivityId", false}, {"enableAutoParent", false} }); - auto tracer = tp.GetTracer(providerName, "TLD"); + auto tracer = tp.GetTracer(providerName); { auto aSpan = tracer->StartSpan("A.min"); auto aScope = tracer->WithActiveSpan(aSpan); @@ -166,7 +167,7 @@ TEST(ETWTracer, TracerCheckMinDecoration) /* { "Timestamp": "2021-03-19T21:04:38.4120274-07:00", - "ProviderName": "OpenTelemetry-ETW-Provider", + "ProviderName": "OpenTelemetry-ETW-TLD", "Id": 21, "Message": null, "ProcessId": 15120, @@ -183,7 +184,7 @@ TEST(ETWTracer, TracerCheckMinDecoration) */ TEST(ETWTracer, TracerCheckMaxDecoration) { - std::string providerName = "OpenTelemetry-ETW-TLD"; + std::string providerName = kGlobalProviderName; exporter::etw::TracerProvider tp ({ {"enableTraceId", true}, @@ -192,7 +193,7 @@ TEST(ETWTracer, TracerCheckMaxDecoration) {"enableRelatedActivityId", true}, {"enableAutoParent", true} }); - auto tracer = tp.GetTracer(providerName, "TLD" ); + auto tracer = tp.GetTracer(providerName); { auto aSpan = tracer->StartSpan("A.max"); auto aScope = tracer->WithActiveSpan(aSpan); @@ -222,7 +223,7 @@ TEST(ETWTracer, TracerCheckMsgPack) {"enableRelatedActivityId", true}, {"enableAutoParent", true} }); - auto tracer = tp.GetTracer(providerName, "MsgPack" ); + auto tracer = tp.GetTracer(providerName); { auto aSpan = tracer->StartSpan("A.max"); auto aScope = tracer->WithActiveSpan(aSpan); @@ -249,6 +250,136 @@ TEST(ETWTracer, TracerCheckMsgPack) tracer->CloseWithMicroseconds(0); } +/** + * @brief Global Tracer singleton may be placed in .h header and + * shared across different compilation units. All would get the + * same object. + * + * @return Single global tracer instance. +*/ +static OPENTELEMETRY_NAMESPACE::trace::TracerProvider& GetGlobalTracerProvider() +{ + static exporter::etw::TracerProvider tp + ({ + {"enableTraceId", true}, + {"enableSpanId", true}, + {"enableActivityId", true}, + {"enableRelatedActivityId", true}, + {"enableAutoParent", true} + }); + return tp; +} + +static OPENTELEMETRY_NAMESPACE::trace::Tracer& GetGlobalTracer() +{ + static auto tracer = GetGlobalTracerProvider().GetTracer(kGlobalProviderName); + return (*tracer.get()); +} + +TEST(ETWTracer, GlobalSingletonTracer) +{ + // Obtain a global tracer using C++11 magic static. + auto& globalTracer = GetGlobalTracer(); + auto s1 = globalTracer.StartSpan("Span1"); + auto traceId1 = s1->GetContext().trace_id(); + s1->End(); +/* === Span 1 - "TraceId": "182a64258fb1864ca4e1a542eecbd9bf" +{ + "Timestamp": "2021-05-10T11:45:27.028827-07:00", + "ProviderName": "OpenTelemetry-ETW-TLD", + "Id": 5, + "Message": null, + "ProcessId": 23712, + "Level": "Always", + "Keywords": "0x0000000000000000", + "EventName": "Span", + "ActivityID": "6ed94703-6b0a-4e76-0000-000000000000", + "RelatedActivityID": null, + "Payload": { + "Duration": 0, + "Kind": 1, + "Name": "Span1", + "SpanId": "0347d96e0a6b764e", + "StartTime": "2021-05-10T18:45:27.028000Z", + "StatusCode": 0, + "StatusMessage": "", + "Success": "True", + "TraceId": "182a64258fb1864ca4e1a542eecbd9bf", + "_name": "Span" + } +} +*/ + + // Obtain a different tracer withs its own trace-id. + auto localTracer = GetGlobalTracerProvider().GetTracer(kGlobalProviderName); + auto s2 = localTracer->StartSpan("Span2"); + auto traceId2 = s2->GetContext().trace_id(); + s2->End(); +/* === Span 2 - "TraceId": "334bf9a1eed98d40a873a606295a9368" +{ + "Timestamp": "2021-05-10T11:45:27.0289654-07:00", + "ProviderName": "OpenTelemetry-ETW-TLD", + "Id": 5, + "Message": null, + "ProcessId": 23712, + "Level": "Always", + "Keywords": "0x0000000000000000", + "EventName": "Span", + "ActivityID": "3b7b2ecb-2e84-4903-0000-000000000000", + "RelatedActivityID": null, + "Payload": { + "Duration": 0, + "Kind": 1, + "Name": "Span2", + "SpanId": "cb2e7b3b842e0349", + "StartTime": "2021-05-10T18:45:27.028000Z", + "StatusCode": 0, + "StatusMessage": "", + "Success": "True", + "TraceId": "334bf9a1eed98d40a873a606295a9368", + "_name": "Span" + } +} +*/ + + // Obtain the same global tracer with the same trace-id as before. + auto& globalTracer2 = GetGlobalTracer(); + auto s3 = globalTracer2.StartSpan("Span3"); + auto traceId3 = s3->GetContext().trace_id(); + s3->End(); +/* === Span 3 - "TraceId": "182a64258fb1864ca4e1a542eecbd9bf" +{ + "Timestamp": "2021-05-10T11:45:27.0290936-07:00", + "ProviderName": "OpenTelemetry-ETW-TLD", + "Id": 5, + "Message": null, + "ProcessId": 23712, + "Level": "Always", + "Keywords": "0x0000000000000000", + "EventName": "Span", + "ActivityID": "0a970247-ba0e-4d4b-0000-000000000000", + "RelatedActivityID": null, + "Payload": { + "Duration": 1, + "Kind": 1, + "Name": "Span3", + "SpanId": "4702970a0eba4b4d", + "StartTime": "2021-05-10T18:45:27.028000Z", + "StatusCode": 0, + "StatusMessage": "", + "Success": "True", + "TraceId": "182a64258fb1864ca4e1a542eecbd9bf", + "_name": "Span" + } +} +*/ + EXPECT_NE(traceId1, traceId2); + EXPECT_EQ(traceId1, traceId3); + + localTracer->CloseWithMicroseconds(0); + globalTracer.CloseWithMicroseconds(0); +} + /* clang-format on */ #endif diff --git a/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h b/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h index 9f7cd2e5e4..bd827f7669 100644 --- a/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h +++ b/exporters/jaeger/include/opentelemetry/exporters/jaeger/recordable.h @@ -29,13 +29,13 @@ namespace jaeger # if defined(__clang__) || \ (defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5)) -inline uint64_t bswap_64(uint64_t host_int) +inline uint64_t otel_bswap_64(uint64_t host_int) { return __builtin_bswap64(host_int); } # elif defined(_MSC_VER) -inline uint64_t bswap_64(uint64_t host_int) +inline uint64_t otel_bswap_64(uint64_t host_int) { return _byteswap_uint64(host_int); } diff --git a/exporters/jaeger/src/recordable.cc b/exporters/jaeger/src/recordable.cc index 8480dad9a7..38370ba8a2 100644 --- a/exporters/jaeger/src/recordable.cc +++ b/exporters/jaeger/src/recordable.cc @@ -48,13 +48,13 @@ void Recordable::SetIdentity(const trace::SpanContext &span_context, // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/sdk_exporters/jaeger.md#ids #if JAEGER_IS_LITTLE_ENDIAN == 1 span_->__set_traceIdHigh( - bswap_64(*(reinterpret_cast(span_context.trace_id().Id().data())))); + otel_bswap_64(*(reinterpret_cast(span_context.trace_id().Id().data())))); span_->__set_traceIdLow( - bswap_64(*(reinterpret_cast(span_context.trace_id().Id().data()) + 1))); + otel_bswap_64(*(reinterpret_cast(span_context.trace_id().Id().data()) + 1))); span_->__set_spanId( - bswap_64(*(reinterpret_cast(span_context.span_id().Id().data())))); + otel_bswap_64(*(reinterpret_cast(span_context.span_id().Id().data())))); span_->__set_parentSpanId( - bswap_64(*(reinterpret_cast(parent_span_id.Id().data())))); + otel_bswap_64(*(reinterpret_cast(parent_span_id.Id().data())))); #else span_->__set_traceIdLow( *(reinterpret_cast(span_context.trace_id().Id().data()))); diff --git a/exporters/jaeger/test/jaeger_recordable_test.cc b/exporters/jaeger/test/jaeger_recordable_test.cc index 58de4eb0a2..e3ef6b07bf 100644 --- a/exporters/jaeger/test/jaeger_recordable_test.cc +++ b/exporters/jaeger/test/jaeger_recordable_test.cc @@ -43,10 +43,10 @@ TEST(JaegerSpanRecordable, SetIdentity) std::unique_ptr span{rec.Span()}; #if JAEGER_IS_LITTLE_ENDIAN == 1 - EXPECT_EQ(span->traceIdLow, opentelemetry::exporter::jaeger::bswap_64(trace_id_val[1])); - EXPECT_EQ(span->traceIdHigh, opentelemetry::exporter::jaeger::bswap_64(trace_id_val[0])); - EXPECT_EQ(span->spanId, opentelemetry::exporter::jaeger::bswap_64(span_id_val)); - EXPECT_EQ(span->parentSpanId, opentelemetry::exporter::jaeger::bswap_64(parent_span_id_val)); + EXPECT_EQ(span->traceIdLow, opentelemetry::exporter::jaeger::otel_bswap_64(trace_id_val[1])); + EXPECT_EQ(span->traceIdHigh, opentelemetry::exporter::jaeger::otel_bswap_64(trace_id_val[0])); + EXPECT_EQ(span->spanId, opentelemetry::exporter::jaeger::otel_bswap_64(span_id_val)); + EXPECT_EQ(span->parentSpanId, opentelemetry::exporter::jaeger::otel_bswap_64(parent_span_id_val)); #else EXPECT_EQ(span->traceIdLow, trace_id_val[0]); EXPECT_EQ(span->traceIdHigh, trace_id_val[1]); @@ -163,7 +163,7 @@ TEST(JaegerSpanRecordable, SetInstrumentationLibrary) std::string library_name = "opentelemetry-cpp"; std::string library_version = "0.1.0"; - auto instrumentation_library = InstrumentationLibrary::create(library_name, library_version); + auto instrumentation_library = InstrumentationLibrary::Create(library_name, library_version); rec.SetInstrumentationLibrary(*instrumentation_library); @@ -177,4 +177,4 @@ TEST(JaegerSpanRecordable, SetInstrumentationLibrary) EXPECT_EQ(tags[1].key, "otel.library.version"); EXPECT_EQ(tags[1].vType, thrift::TagType::STRING); EXPECT_EQ(tags[1].vStr, library_version); -} \ No newline at end of file +} diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 3af587b4a8..1ca788af58 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -33,8 +33,10 @@ if(WITH_OTLP_HTTP) set_target_properties(opentelemetry_exporter_otlp_http PROPERTIES EXPORT_NAME otlp_http_exporter) - target_link_libraries(opentelemetry_exporter_otlp_http - PUBLIC opentelemetry_otlp_recordable http_client_curl) + target_link_libraries( + opentelemetry_exporter_otlp_http + PUBLIC opentelemetry_otlp_recordable http_client_curl + nlohmann_json::nlohmann_json) list(APPEND OPENTELEMETRY_OTLP_TARGETS opentelemetry_exporter_otlp_http) endif() diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable.h b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable.h index b5b73e36d8..a2e9c83ae3 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/otlp_recordable.h @@ -25,6 +25,8 @@ class OtlpRecordable final : public sdk::trace::Recordable /** Dynamically converts the resource of this span into a proto. */ proto::resource::v1::Resource ProtoResource() const noexcept; + proto::common::v1::InstrumentationLibrary GetProtoInstrumentationLibrary() const noexcept; + void SetIdentity(const opentelemetry::trace::SpanContext &span_context, opentelemetry::trace::SpanId parent_span_id) noexcept override; @@ -57,6 +59,8 @@ class OtlpRecordable final : public sdk::trace::Recordable private: proto::trace::v1::Span span_; const opentelemetry::sdk::resource::Resource *resource_ = nullptr; + const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary + *instrumentation_library_ = nullptr; }; } // namespace otlp } // namespace exporter diff --git a/exporters/otlp/src/otlp_grpc_exporter.cc b/exporters/otlp/src/otlp_grpc_exporter.cc index e0aaa0a0ab..42c0b5d300 100644 --- a/exporters/otlp/src/otlp_grpc_exporter.cc +++ b/exporters/otlp/src/otlp_grpc_exporter.cc @@ -31,7 +31,8 @@ void PopulateRequest(const nostd::span> for (auto &recordable : spans) { auto rec = std::unique_ptr(static_cast(recordable.release())); - *instrumentation_lib->add_spans() = std::move(rec->span()); + *instrumentation_lib->add_spans() = std::move(rec->span()); + *instrumentation_lib->mutable_instrumentation_library() = rec->GetProtoInstrumentationLibrary(); if (!has_resource) { diff --git a/exporters/otlp/src/otlp_recordable.cc b/exporters/otlp/src/otlp_recordable.cc index 53e92d8d76..a17419df7e 100644 --- a/exporters/otlp/src/otlp_recordable.cc +++ b/exporters/otlp/src/otlp_recordable.cc @@ -138,9 +138,9 @@ void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute, { // Assert size of variant to ensure that this method gets updated if the variant // definition changes - static_assert(nostd::variant_size::value == - kOwnedAttributeValueSize + 1, - "AttributeValue contains unknown type"); + static_assert( + nostd::variant_size::value == kOwnedAttributeValueSize, + "OwnedAttributeValue contains unknown type"); attribute->set_key(key.data(), key.size()); @@ -237,6 +237,18 @@ proto::resource::v1::Resource OtlpRecordable::ProtoResource() const noexcept return proto; } +proto::common::v1::InstrumentationLibrary OtlpRecordable::GetProtoInstrumentationLibrary() + const noexcept +{ + proto::common::v1::InstrumentationLibrary instrumentation_library; + if (instrumentation_library_) + { + instrumentation_library.set_name(instrumentation_library_->GetName()); + instrumentation_library.set_version(instrumentation_library_->GetVersion()); + } + return instrumentation_library; +} + void OtlpRecordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept { resource_ = &resource; @@ -271,12 +283,11 @@ void OtlpRecordable::AddLink(const opentelemetry::trace::SpanContext &span_conte trace::TraceId::kSize); link->set_span_id(reinterpret_cast(span_context.span_id().Id().data()), trace::SpanId::kSize); + link->set_trace_state(span_context.trace_state()->ToHeader()); attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { PopulateAttribute(link->add_attributes(), key, value); return true; }); - - // TODO: Populate trace_state when it is supported by SpanContext } void OtlpRecordable::SetStatus(trace::StatusCode code, nostd::string_view description) noexcept @@ -347,7 +358,7 @@ void OtlpRecordable::SetInstrumentationLibrary( const opentelemetry::sdk::instrumentationlibrary::InstrumentationLibrary &instrumentation_library) noexcept { - // TODO: add instrumentation library to OTLP exporter. + instrumentation_library_ = &instrumentation_library; } } // namespace otlp diff --git a/exporters/otlp/test/otlp_recordable_test.cc b/exporters/otlp/test/otlp_recordable_test.cc index f6e0858a8a..9d34cd26a4 100644 --- a/exporters/otlp/test/otlp_recordable_test.cc +++ b/exporters/otlp/test/otlp_recordable_test.cc @@ -53,6 +53,16 @@ TEST(OtlpRecordable, SetSpanKind) opentelemetry::proto::trace::v1::Span_SpanKind::Span_SpanKind_SPAN_KIND_SERVER); } +TEST(OtlpRecordable, SetInstrumentationLibrary) +{ + OtlpRecordable rec; + auto inst_lib = opentelemetry::sdk::trace::InstrumentationLibrary::Create("test", "v1"); + rec.SetInstrumentationLibrary(*inst_lib); + auto proto_instr_libr = rec.GetProtoInstrumentationLibrary(); + EXPECT_EQ(proto_instr_libr.name(), inst_lib->GetName()); + EXPECT_EQ(proto_instr_libr.version(), inst_lib->GetVersion()); +} + TEST(OtlpRecordable, SetStartTime) { OtlpRecordable rec; @@ -141,11 +151,16 @@ TEST(OtlpRecordable, AddLink) auto trace_id = rec.span().trace_id(); auto span_id = rec.span().span_id(); - rec.AddLink(trace::SpanContext(false, false), + trace::TraceFlags flags; + std::string trace_state_header = "k1=v1,k2=v2"; + auto ts = trace::TraceState::FromHeader(trace_state_header); + + rec.AddLink(trace::SpanContext(trace::TraceId(), trace::SpanId(), flags, false, ts), common::KeyValueIterableView>(attributes)); EXPECT_EQ(rec.span().trace_id(), trace_id); EXPECT_EQ(rec.span().span_id(), span_id); + EXPECT_EQ(rec.span().links(0).trace_state(), trace_state_header); for (int i = 0; i < kNumAttributes; i++) { EXPECT_EQ(rec.span().links(0).attributes(i).key(), keys[i]); diff --git a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h index a69eaf9caf..cb244867d7 100644 --- a/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h +++ b/exporters/zipkin/include/opentelemetry/exporters/zipkin/zipkin_exporter.h @@ -17,11 +17,11 @@ namespace exporter namespace zipkin { -const char *kZipkinEndpointDefault = "http://localhost:9411/api/v2/spans"; - -static const std::string GetDefaultZipkinEndpoint() +inline const std::string GetDefaultZipkinEndpoint() { const char *otel_exporter_zipkin_endpoint_env = "OTEL_EXPORTER_ZIPKIN_ENDPOINT"; + const char *kZipkinEndpointDefault = "http://localhost:9411/api/v2/spans"; + #if defined(_MSC_VER) // avoid calling std::getenv which is deprecated in MSVC. size_t required_size = 0; diff --git a/exporters/zipkin/src/recordable.cc b/exporters/zipkin/src/recordable.cc index bbdc85c548..07d9b09c9d 100644 --- a/exporters/zipkin/src/recordable.cc +++ b/exporters/zipkin/src/recordable.cc @@ -225,7 +225,7 @@ void Recordable::SetStartTime(opentelemetry::common::SystemTimestamp start_time) void Recordable::SetDuration(std::chrono::nanoseconds duration) noexcept { - span_["duration"] = duration.count(); + span_["duration"] = std::chrono::duration_cast(duration).count(); } void Recordable::SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept diff --git a/exporters/zipkin/test/zipkin_recordable_test.cc b/exporters/zipkin/test/zipkin_recordable_test.cc index 51ba1024b6..9b51c46c29 100644 --- a/exporters/zipkin/test/zipkin_recordable_test.cc +++ b/exporters/zipkin/test/zipkin_recordable_test.cc @@ -12,8 +12,6 @@ #include "opentelemetry/common/timestamp.h" #include "opentelemetry/exporters/zipkin/recordable.h" -#include - #include namespace trace = opentelemetry::trace; @@ -69,16 +67,16 @@ TEST(ZipkinSpanRecordable, SetStartTime) TEST(ZipkinSpanRecordable, SetDuration) { - json j_span = {{"duration", 10}, {"timestamp", 0}}; + std::chrono::nanoseconds durationNS(1000000000); // in ns + std::chrono::microseconds durationMS = + std::chrono::duration_cast(durationNS); // in ms + json j_span = {{"duration", durationMS.count()}, {"timestamp", 0}}; opentelemetry::exporter::zipkin::Recordable rec; // Start time is 0 opentelemetry::common::SystemTimestamp start_timestamp; - std::chrono::nanoseconds duration(10); - uint64_t unix_end = duration.count(); - rec.SetStartTime(start_timestamp); - rec.SetDuration(duration); + rec.SetDuration(durationNS); EXPECT_EQ(rec.span(), j_span); } @@ -92,7 +90,7 @@ TEST(ZipkinSpanRecordable, SetInstrumentationLibrary) {"tags", {{"otel.library.name", library_name}, {"otel.library.version", library_version}}}}; opentelemetry::exporter::zipkin::Recordable rec; - rec.SetInstrumentationLibrary(*InstrumentationLibrary::create(library_name, library_version)); + rec.SetInstrumentationLibrary(*InstrumentationLibrary::Create(library_name, library_version)); EXPECT_EQ(rec.span(), j_span); } diff --git a/ext/src/http/client/curl/BUILD b/ext/src/http/client/curl/BUILD index 6d484d3770..33ab814b91 100644 --- a/ext/src/http/client/curl/BUILD +++ b/ext/src/http/client/curl/BUILD @@ -6,9 +6,7 @@ cc_library( "http_client_curl.cc", "http_client_factory_curl.cc", ], - # TODO: Move copts/linkopts for static CURL usage into shared bzl file. copts = [ - "-DCURL_STATICLIB", "-DWITH_CURL", ], include_prefix = "src/http/client/curl", diff --git a/ext/test/w3c_tracecontext_test/BUILD b/ext/test/w3c_tracecontext_test/BUILD index 19407e6b91..e52c943fe3 100644 --- a/ext/test/w3c_tracecontext_test/BUILD +++ b/ext/test/w3c_tracecontext_test/BUILD @@ -3,10 +3,6 @@ cc_binary( srcs = [ "main.cc", ], - # TODO: Move copts/linkopts for static CURL usage into shared bzl file. - copts = [ - "-DCURL_STATICLIB", - ], linkopts = select({ "//bazel:windows": [ "-DEFAULTLIB:advapi32.lib", diff --git a/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h b/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h index 20d62eba16..e4f7f78ef1 100644 --- a/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h +++ b/sdk/include/opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h @@ -25,7 +25,7 @@ class InstrumentationLibrary * @param version version of the instrumentation library. * @returns the newly created InstrumentationLibrary. */ - static nostd::unique_ptr create(nostd::string_view name, + static nostd::unique_ptr Create(nostd::string_view name, nostd::string_view version = "") { return nostd::unique_ptr( diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index 4b6c1de796..6aeb19fa57 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -29,7 +29,7 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th /** Construct a new Tracer with the given context pipeline. */ explicit Tracer(std::shared_ptr context, std::unique_ptr instrumentation_library = - InstrumentationLibrary::create("")) noexcept; + InstrumentationLibrary::Create("")) noexcept; nostd::shared_ptr StartSpan( nostd::string_view name, diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 149684bc8e..c84d847bd9 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -46,25 +46,27 @@ nostd::shared_ptr Tracer::StartSpan( auto sampling_result = context_->GetSampler().ShouldSample(parent_context, trace_id, name, options.kind, attributes, links); + auto trace_flags = sampling_result.decision == Decision::DROP + ? trace_api::TraceFlags{} + : trace_api::TraceFlags{trace_api::TraceFlags::kIsSampled}; + + auto span_context = std::unique_ptr(new trace_api::SpanContext( + trace_id, span_id, trace_flags, false, + sampling_result.trace_state ? sampling_result.trace_state + : is_parent_span_valid ? parent_context.trace_state() + : trace_api::TraceState::GetDefault())); if (sampling_result.decision == Decision::DROP) { - // Don't allocate a no-op span for every DROP decision, but use a static - // singleton for this case. - static nostd::shared_ptr noop_span( - new trace_api::NoopSpan{this->shared_from_this()}); + // create no-op span with valid span-context. + auto noop_span = nostd::shared_ptr{ + new (std::nothrow) trace_api::NoopSpan(this->shared_from_this(), std::move(span_context))}; return noop_span; } else { - auto span_context = std::unique_ptr(new trace_api::SpanContext( - trace_id, span_id, trace_api::TraceFlags{trace_api::TraceFlags::kIsSampled}, false, - sampling_result.trace_state ? sampling_result.trace_state - : is_parent_span_valid ? parent_context.trace_state() - : trace_api::TraceState::GetDefault())); - auto span = nostd::shared_ptr{ new (std::nothrow) Span{this->shared_from_this(), name, attributes, links, options, parent_context, std::move(span_context)}}; diff --git a/sdk/src/trace/tracer_provider.cc b/sdk/src/trace/tracer_provider.cc index 13b41d73b6..ed6853be67 100644 --- a/sdk/src/trace/tracer_provider.cc +++ b/sdk/src/trace/tracer_provider.cc @@ -55,7 +55,7 @@ nostd::shared_ptr TracerProvider::GetTracer( } } - auto lib = InstrumentationLibrary::create(library_name, library_version); + auto lib = InstrumentationLibrary::Create(library_name, library_version); tracers_.push_back(std::shared_ptr( new sdk::trace::Tracer(context_, std::move(lib)))); return nostd::shared_ptr{tracers_.back()}; diff --git a/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc b/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc index d21f113580..b6ac69df1f 100644 --- a/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc +++ b/sdk/test/instrumentationlibrary/instrumentationlibrary_test.cc @@ -16,7 +16,7 @@ TEST(InstrumentationLibrary, CreateInstrumentationLibrary) std::string library_name = "opentelemetry-cpp"; std::string library_version = "0.1.0"; - auto instrumentation_library = InstrumentationLibrary::create(library_name, library_version); + auto instrumentation_library = InstrumentationLibrary::Create(library_name, library_version); EXPECT_EQ(instrumentation_library->GetName(), library_name); EXPECT_EQ(instrumentation_library->GetVersion(), library_version); diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 0c5cc397d8..2e9dd73413 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -165,8 +165,14 @@ TEST(Tracer, StartSpanSampleOff) auto tracer_off = initTracer(std::move(exporter), new AlwaysOffSampler()); // This span will not be recorded. - tracer_off->StartSpan("span 2")->End(); + auto span = tracer_off->StartSpan("span 2"); + // Always generate a valid span-context (span-id) + auto context = span->GetContext(); + EXPECT_TRUE(context.IsValid()); + EXPECT_FALSE(context.IsSampled()); + + span->End(); // The span doesn't write any span data because the sampling decision is alway // DROP. ASSERT_EQ(0, span_data->GetSpans().size()); diff --git a/tools/build-benchmark.cmd b/tools/build-benchmark.cmd index 39b9f180d9..379cb1313a 100644 --- a/tools/build-benchmark.cmd +++ b/tools/build-benchmark.cmd @@ -1,5 +1,5 @@ @echo off -set VS_TOOLS_VERSION=vs2019 +set BUILDTOOLS_VERSION=vs2019 set CMAKE_GEN="Visual Studio 16 2019" echo Building Google Benchmark (test only dependency)... @setlocal ENABLEEXTENSIONS diff --git a/tools/build-clang-12.cmd b/tools/build-clang-12.cmd new file mode 100644 index 0000000000..a41c5bb6c1 --- /dev/null +++ b/tools/build-clang-12.cmd @@ -0,0 +1,7 @@ +@echo off +pushd %~dp0 +set "PATH=%ProgramFiles%\LLVM-12\bin;%PATH%" +set BUILDTOOLS_VERSION=clang-12 +set CMAKE_GEN=Ninja +call build.cmd %* +popd diff --git a/tools/build-clang.cmd b/tools/build-clang.cmd new file mode 100644 index 0000000000..c160fd661b --- /dev/null +++ b/tools/build-clang.cmd @@ -0,0 +1,7 @@ +@echo off +pushd %~dp0 +set "PATH=%ProgramFiles%\LLVM\bin;%PATH%" +set BUILDTOOLS_VERSION=clang +set CMAKE_GEN=Ninja +call build.cmd %* +popd diff --git a/tools/build-vs2015.cmd b/tools/build-vs2015.cmd index 30bb41c3c9..ed230d1559 100644 --- a/tools/build-vs2015.cmd +++ b/tools/build-vs2015.cmd @@ -1,11 +1,33 @@ REM Build with Visual Studio 2015 -set "VS_TOOLS_VERSION=vs2015" -set ARCH=Win64 +set "PATH=%ProgramFiles(x86)%\MSBuild\14.0\Bin;%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\bin;%PATH%" + +REM ### Note that vcpkg built with 2019/2017 can't be used with 2015! +REM ### Consider to specify custom VCPKG_ROOT for 2015 as follows: +REM +REM set VCPKG_ROOT=C:\vcpkg.2015 +REM + +set BUILDTOOLS_VERSION=vs2015 +set ARCH=x64 if NOT "%1"=="" ( set ARCH=%1 ) -set "CMAKE_GEN=Visual Studio 14 2015 %ARCH%" +set "CMAKE_GEN=Ninja" +set "VCPKG_VISUAL_STUDIO_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio 14.0" + +REM Building with Windows SDK 8.1 +set "PATH=%ProgramFiles(x86)%\Windows Kits\8.1\bin\%ARCH%;%PATH%" +set WINSDK_VERSION=8.1 +set CMAKE_SYSTEM_VERSION=8.1 +set VCPKG_PLATFORM_TOOLSET=v140 + +REM ### Replace above Windows SDK 8.1 by Windows 10 SDK if necessary. +REM ### Resulting binaries may not be compatible with Windows 8 +REM +REM set WINSDK_VERSION=10.0.19041.0 +REM set "PATH=%ProgramFiles(x86)%\Windows Kits\10\bin\10.0.19041.0\%ARCH%\;%PATH%" +REM + cd %~dp0 call setup-buildtools.cmd -REM TODO: currently we cannot build without Abseil variant for Visual Studio 2015 -call build.cmd -DWITH_ABSEIL:BOOL=ON +call build.cmd -DMSVC_TOOLSET_VERSION=140 diff --git a/tools/build-vs2017.cmd b/tools/build-vs2017.cmd index de84593123..3a95d9b110 100644 --- a/tools/build-vs2017.cmd +++ b/tools/build-vs2017.cmd @@ -1,10 +1,17 @@ REM Build with Visual Studio 2017 -set "VS_TOOLS_VERSION=vs2017" -set ARCH=Win64 +set "BUILDTOOLS_VERSION=vs2017" +set ARCH=x64 if NOT "%1"=="" ( set ARCH=%1 ) -set "CMAKE_GEN=Visual Studio 15 2017 %ARCH%" + +REM ### Uncomment below to use Visual Studio MSBuild solution. +REM ### Ninja generator produces much faster builds. But it is +REM ### easier to debug MSBuild solution in vs2017 IDE : +REM +REM set "CMAKE_GEN=Visual Studio 15 2017" +REM + cd %~dp0 call setup-buildtools.cmd call build.cmd diff --git a/tools/build-vs2019.cmd b/tools/build-vs2019.cmd index b4a39938a3..2fd6dbc59e 100644 --- a/tools/build-vs2019.cmd +++ b/tools/build-vs2019.cmd @@ -1,15 +1,13 @@ REM Build with Visual Studio 2017 -set "VS_TOOLS_VERSION=vs2019" -set ARCH=Win64 +set "BUILDTOOLS_VERSION=vs2019" +set ARCH=x64 if NOT "%1"=="" ( set ARCH=%1 ) -if "%ARCH%"=="Win64" ( +if "%ARCH%"=="x64" ( REM Parameter needed for CMake Visual Studio 2019 generator set CMAKE_ARCH=x64 ) - -set "CMAKE_GEN=Visual Studio 16 2019" cd %~dp0 call setup-buildtools.cmd call build.cmd diff --git a/tools/build.cmd b/tools/build.cmd index 14da784661..7558f4efff 100644 --- a/tools/build.cmd +++ b/tools/build.cmd @@ -1,6 +1,6 @@ @echo off REM ########################################################################################## -REM # Build SDK with Visual Studio + CMake + MSBUild or Ninja. # +REM # Build SDK with (msvc or clang) + CMake + (MSBuild or Ninja). # REM # # REM # CMake arguments may be passed as parameters to this script. # REM # If Visual Studio is not installed, then this script falls back to LLVM-CLang, # @@ -10,7 +10,7 @@ REM ############################################################################ REM # # REM # Options passed as environment variables: # REM # # -REM # VS_TOOLS_VERSION - specify visual studio version. See `vcvars.cmd` for details. # +REM # BUILDTOOLS_VERSION - specify build tools version. See `vcvars.cmd` for details. # REM # CMAKE_GEN - specify CMake generator. # REM # VCPKG_ROOT - path to vcpkg root # REM # ARCH - architecture to build for (default: x64) # @@ -20,36 +20,43 @@ set "PATH=%PATH%;%ProgramFiles%\CMake\bin" pushd %~dp0 setlocal enableextensions setlocal enabledelayedexpansion -if not defined VS_TOOLS_VERSION ( - set VS_TOOLS_VERSION=vs2019 +if not defined BUILDTOOLS_VERSION ( + set BUILDTOOLS_VERSION=vs2019 ) REM ########################################################################################## REM Set up CMake generator. Use Ninja if available. REM ########################################################################################## -if not defined CMAKE_GEN ( - set CMAKE_GEN=Visual Studio 16 2019 - for /f "tokens=*" %%F in ('where ninja') do ( - set NINJA=%%F - ) - if defined VCPKG_ROOT ( - if not defined NINJA ( - for /f "tokens=*" %%F in ('where /R %VCPKG_ROOT%\vcpkg\downloads\tools ninja') do ( - set NINJA=%%F - ) - popd - ) - ) +for /f "tokens=*" %%F in ('where ninja') do ( + set NINJA=%%F +) + +if defined VCPKG_ROOT ( if not defined NINJA ( - for /f "tokens=*" %%F in ('where /R %CD%\vcpkg\downloads\tools ninja') do ( + for /f "tokens=*" %%F in ('where /R %VCPKG_ROOT%\vcpkg\downloads\tools ninja') do ( set NINJA=%%F ) + popd ) - if defined NINJA ( - echo Using ninja at !NINJA! +) + +if not defined NINJA ( + for /f "tokens=*" %%F in ('where /R %CD%\vcpkg\downloads\tools ninja') do ( + set NINJA=%%F + ) +) + +if defined NINJA ( + echo Found ninja: !NINJA! + if not defined CMAKE_GEN ( set CMAKE_GEN=Ninja ) ) + +if not defined CMAKE_GEN ( + set CMAKE_GEN=Visual Studio 16 2019 +) + set "ROOT=%~dp0\.." if not defined ARCH ( set ARCH=x64 @@ -80,23 +87,18 @@ REM The following two configurations are built below: REM - nostd - build with OpenTelemetry C++ Template library REM - stl - build with Standard Template Library REM ########################################################################################## -REM Build with nostd implementation. Supported VS_TOOLS_VERSION: -REM - vs2015 (C++11) -REM - vs2017 (C++14) -REM - vs2019 (C++20) +REM Build with nostd implementation. REM ########################################################################################## set CONFIG=-DWITH_STL:BOOL=OFF %* -set "OUTDIR=%ROOT%\out\%VS_TOOLS_VERSION%\nostd" +set "OUTDIR=%ROOT%\out\%BUILDTOOLS_VERSION%\nostd" call :build_config REM ########################################################################################## -REM Build with STL implementation (only for vs2017+). Supported VS_TOOLS_VERSION: -REM - vs2017 (C++14) -REM - vs2019 (C++20) - optimal config with all OpenTelemetry API classes using STL only. +REM Build with STL implementation. This option does not yield benefits for vs2015 build. REM ########################################################################################## -if "%VS_TOOLS_VERSION%" neq "vs2015" ( +if "%BUILDTOOLS_VERSION%" neq "vs2015" ( set CONFIG=-DWITH_STL:BOOL=ON %* - set "OUTDIR=%ROOT%\out\%VS_TOOLS_VERSION%\stl" + set "OUTDIR=%ROOT%\out\%BUILDTOOLS_VERSION%\stl" call :build_config ) @@ -110,18 +112,36 @@ REM TODO: consider rmdir for clean builds if not exist "%OUTDIR%" mkdir "%OUTDIR%" cd "%OUTDIR%" -if "!VS_TOOLS_VERSION!" == "vs2019" ( - REM Prefer ninja if available - if "!CMAKE_GEN!" == "Ninja" ( - call :build_config_ninja - exit /b - ) - REM Only latest vs2019 generator supports and requires -A parameter +REM Prefer ninja if available +if "!CMAKE_GEN!" == "Ninja" ( + call :build_config_ninja + exit /b +) + +if "!BUILDTOOLS_VERSION!" == "vs2015" ( cmake -G "!CMAKE_GEN!" -A !ARCH! -DCMAKE_TOOLCHAIN_FILE="!VCPKG_CMAKE!" !CONFIG! "!ROOT!" -) else ( - REM Old vs2017 generator does not support -A parameter - cmake -G "!CMAKE_GEN!" -DCMAKE_TOOLCHAIN_FILE="!VCPKG_CMAKE!" !CONFIG! "!ROOT!" + call :build_msbuild + exit /b ) + +if "!BUILDTOOLS_VERSION!" == "vs2017" ( + cmake -G "!CMAKE_GEN!" -A !ARCH! -DCMAKE_TOOLCHAIN_FILE="!VCPKG_CMAKE!" !CONFIG! "!ROOT!" + call :build_msbuild + exit /b +) + +if "!BUILDTOOLS_VERSION!" == "vs2019" ( + cmake -G "!CMAKE_GEN!" -A !ARCH! -DCMAKE_TOOLCHAIN_FILE="!VCPKG_CMAKE!" !CONFIG! "!ROOT!" + call :build_msbuild + exit /b +) + +REM ########################################################################################## +REM Exotic CMake generators, like MSYS and MinGW MAY work, but untested +REM ########################################################################################## +cmake -G "!CMAKE_GEN!" -DCMAKE_TOOLCHAIN_FILE="!VCPKG_CMAKE!" !CONFIG! "!ROOT!" + +:build_msbuild set "SOLUTION=%OUTDIR%\opentelemetry-cpp.sln" msbuild "%SOLUTION%" /p:Configuration=Release /p:VcpkgEnabled=true exit /b diff --git a/tools/ports/benchmark/portfile.cmake b/tools/ports/benchmark/portfile.cmake index dba57ab53d..fdb988c538 100644 --- a/tools/ports/benchmark/portfile.cmake +++ b/tools/ports/benchmark/portfile.cmake @@ -1,11 +1,7 @@ if (VCPKG_PLATFORM_TOOLSET STREQUAL "v140") - # set(CMAKE_C_COMPILER_WORKS 1) - # set(CMAKE_CXX_COMPILER_WORKS 1) set(CMAKE_C_COMPILER cl.exe) set(CMAKE_CXX_COMPILER cl.exe) set(MSVC_TOOLSET_VERSION 140) - # set(VCPKG_VISUAL_STUDIO_PATH "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0") - # set(VCPKG_PLATFORM_TOOLSET v140) else() # Make sure vs2019 compiled binaries are compat with vs2017 set(VCPKG_CXX_FLAGS "/Zc:__cplusplus /d2FH4-") diff --git a/tools/setup-buildtools.cmd b/tools/setup-buildtools.cmd index fd31eb21fd..956c8ddfe4 100644 --- a/tools/setup-buildtools.cmd +++ b/tools/setup-buildtools.cmd @@ -1,8 +1,12 @@ @echo off setlocal enableextensions setlocal enabledelayedexpansion -set "PATH=%ProgramFiles%\CMake\bin;%~dp0;%~dp0vcpkg;%ProgramData%\chocolatey\bin;%PATH%" -if "%VCPKG_ROOT%" NEQ "" set "PATH=%VCPKG_ROOT%;%PATH%" +set "PATH=%ProgramFiles%\CMake\bin;%~dp0;%ProgramData%\chocolatey\bin;%PATH%" +if defined VCPKG_ROOT ( + set "PATH=%VCPKG_ROOT%;%PATH%" +) else ( + set "PATH=%~dp0vcpkg;%PATH%" +) pushd %~dp0 net session >nul 2>&1 @@ -22,11 +26,13 @@ if %errorLevel% == 0 ( echo Running without Administrative privilege... ) -REM Print current Visual Studio installations detected -where /Q vswhere -if %ERRORLEVEL% == 0 ( - echo Visual Studio installations detected: - vswhere -property installationPath +if not defined BUILDTOOLS_VERSION ( + REM Print current Visual Studio installations detected + where /Q vswhere + if %ERRORLEVEL% == 0 ( + echo Visual Studio installations detected: + vswhere -property installationPath + ) ) REM This script allows to pass architecture in ARCH env var diff --git a/tools/vcvars.cmd b/tools/vcvars.cmd index 69308778a7..94f5cca95a 100644 --- a/tools/vcvars.cmd +++ b/tools/vcvars.cmd @@ -1,7 +1,7 @@ @echo off REM +-------------------------------------------------------------------+ -REM | Autodetect and set up the build environment for Visual Studio. | -REM | Visual Studio version may be specified as 1st argument. | +REM | Autodetect and set up the build environment. | +REM | Build Tools version may be specified as 1st argument. | REM +-------------------------------------------------------------------+ REM | Description | Argument value | REM +-----------------------------------------+-------------------------+ @@ -18,6 +18,12 @@ REM | Visual Studio 2017 Community | vs2017_community | REM | Visual Studio 2017 Build Tools (no IDE) | vs2017_buildtools | REM | | | REM | Visual Studio 2015 Build Tools (no IDE) | vs2015 | +REM | | | +REM | LLVM Clang (any version) | clang | +REM | LLVM Clang 9 | clang-9 | +REM | LLVM Clang 10 | clang-10 | +REM | LLVM Clang 11 | clang-11 | +REM | LLVM Clang 11 | clang-12 | REM +-----------------------------------------+-------------------------+ set "VSCMD_START_DIR=%CD%" @@ -29,8 +35,8 @@ if "%1" neq "" ( goto %1 ) -if defined VS_TOOLS_VERSION ( - goto %VS_TOOLS_VERSION% +if defined BUILDTOOLS_VERSION ( + goto %BUILDTOOLS_VERSION% ) :vs2019 @@ -100,10 +106,10 @@ if exist %TOOLS_VS2017% ( ) :vs2015 -set TOOLS_VS2015="%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\bin\vcvarsall.bat" +set TOOLS_VS2015="%ProgramFiles(x86)%\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" if exist %TOOLS_VS2015% ( echo Building with vs2015 BuildTools... - call %TOOLS_VS2015% %ARCH% + call %TOOLS_VS2015% %ARCH% %WINSDK_VERSION% set "VCPKG_VISUAL_STUDIO_PATH=%ProgramFiles(x86)%\Microsoft Visual Studio 14.0" set VCPKG_PLATFORM_TOOLSET=v140 goto tools_configured @@ -115,4 +121,38 @@ REM is not set up by checking TOOLS_VS_NOTFOUND set TOOLS_VS_NOTFOUND=1 exit /b 0 +REM +-------------------------------------------------------------------+ +REM | There is no auto-detection of LLVM Clang version. | +REM | LLVM Clang of any version is installed in the same directory | +REM | at %ProgramFiles%\LLVM\bin . Developers choose their own custom | +REM | layout for installing multiple clang toolchains side-by-side. | +REM | | +REM | Example layout (merely a guideline, layout could differ): | +REM | | +REM | %ProgramFiles%\LLVM-9\bin | +REM | %ProgramFiles%\LLVM-10\bin | +REM | %ProgramFiles%\LLVM-11\bin | +REM | %ProgramFiles%\LLVM-12\bin | +REM +-------------------------------------------------------------------+ +REM +REM ## Example 1: use clang-10 located in LLVM-10 directory: +REM set BUILDTOOLS_VERSION=clang-10 +REM set "PATH=%ProgramFiles%\LLVM-10\bin;%PATH%" +REM tools\build.cmd +REM +REM ## Example 2: use whatever clang located in LLVM directory: +REM set BUILDTOOLS_VERSION=clang +REM set "PATH=%ProgramFiles%\LLVM\bin;%PATH%" +REM tools\build.cmd +REM +REM BUILDTOOLS_VERSION determines the output directory location. +REM Store build artifacts produced by different toolchains - +REM side-by-side, each in its own separate output directory. +REM +:clang +:clang-9 +:clang-10 +:clang-11 +:clang-12 + :tools_configured