diff --git a/exporters/memory/BUILD b/exporters/memory/BUILD index a3ab2d1532..c839044316 100644 --- a/exporters/memory/BUILD +++ b/exporters/memory/BUILD @@ -8,6 +8,7 @@ cc_library( strip_include_prefix = "include", deps = [ "//api", + "//sdk/src/resource", "//sdk/src/trace", ], ) diff --git a/exporters/memory/CMakeLists.txt b/exporters/memory/CMakeLists.txt index 870e932730..20d963a9df 100644 --- a/exporters/memory/CMakeLists.txt +++ b/exporters/memory/CMakeLists.txt @@ -30,11 +30,12 @@ if(BUILD_TESTING) target_link_libraries( in_memory_span_data_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_in_memory) + opentelemetry_exporter_in_memory opentelemetry_resources) target_link_libraries( in_memory_span_exporter_test ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_exporter_in_memory) + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_exporter_in_memory + opentelemetry_resources) gtest_add_tests( TARGET in_memory_span_data_test diff --git a/exporters/otlp/BUILD b/exporters/otlp/BUILD index 1124adf341..8eae69449c 100644 --- a/exporters/otlp/BUILD +++ b/exporters/otlp/BUILD @@ -28,6 +28,7 @@ cc_library( ], strip_include_prefix = "include", deps = [ + "//sdk/src/resource", "//sdk/src/trace", "@com_github_opentelemetry_proto//:trace_proto_cc", ], diff --git a/exporters/otlp/CMakeLists.txt b/exporters/otlp/CMakeLists.txt index 0529436ac6..526a824da6 100644 --- a/exporters/otlp/CMakeLists.txt +++ b/exporters/otlp/CMakeLists.txt @@ -4,8 +4,9 @@ add_library(opentelemetry_exporter_otprotocol src/recordable.cc set_target_properties(opentelemetry_exporter_otprotocol PROPERTIES EXPORT_NAME otlp_exporter) -target_link_libraries(opentelemetry_exporter_otprotocol - PUBLIC opentelemetry_trace opentelemetry_proto) +target_link_libraries( + opentelemetry_exporter_otprotocol + PUBLIC opentelemetry_trace opentelemetry_resources opentelemetry_proto) install( TARGETS opentelemetry_exporter_otprotocol diff --git a/exporters/otlp/include/opentelemetry/exporters/otlp/recordable.h b/exporters/otlp/include/opentelemetry/exporters/otlp/recordable.h index b58e1ae6e1..53fc5f4d55 100644 --- a/exporters/otlp/include/opentelemetry/exporters/otlp/recordable.h +++ b/exporters/otlp/include/opentelemetry/exporters/otlp/recordable.h @@ -1,7 +1,7 @@ #pragma once #include "opentelemetry/exporters/otlp/protobuf_include_prefix.h" - +#include "opentelemetry/proto/resource/v1/resource.pb.h" #include "opentelemetry/proto/trace/v1/trace.pb.h" #include "opentelemetry/exporters/otlp/protobuf_include_suffix.h" @@ -19,6 +19,9 @@ class Recordable final : public sdk::trace::Recordable public: const proto::trace::v1::Span &span() const noexcept { return span_; } + /** Dynamically converts the resource of this span into a proto. */ + proto::resource::v1::Resource ProtoResource() const noexcept; + void SetIdentity(const opentelemetry::trace::SpanContext &span_context, opentelemetry::trace::SpanId parent_span_id) noexcept override; @@ -38,6 +41,8 @@ class Recordable final : public sdk::trace::Recordable void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override; + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override; + void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override; void SetDuration(std::chrono::nanoseconds duration) noexcept override; @@ -48,6 +53,7 @@ class Recordable final : public sdk::trace::Recordable private: proto::trace::v1::Span span_; + const opentelemetry::sdk::resource::Resource *resource_; }; } // namespace otlp } // namespace exporter diff --git a/exporters/otlp/src/otlp_exporter.cc b/exporters/otlp/src/otlp_exporter.cc index 20433c2393..74e1a71bd4 100644 --- a/exporters/otlp/src/otlp_exporter.cc +++ b/exporters/otlp/src/otlp_exporter.cc @@ -23,10 +23,12 @@ void PopulateRequest(const nostd::span> { auto resource_span = request->add_resource_spans(); auto instrumentation_lib = resource_span->add_instrumentation_library_spans(); + bool has_resource = false; for (auto &recordable : spans) { auto rec = std::unique_ptr(static_cast(recordable.release())); + // TODO - Handle Resource *instrumentation_lib->add_spans() = std::move(rec->span()); } } diff --git a/exporters/otlp/src/recordable.cc b/exporters/otlp/src/recordable.cc index ccec6eaf17..a973bad994 100644 --- a/exporters/otlp/src/recordable.cc +++ b/exporters/otlp/src/recordable.cc @@ -9,7 +9,8 @@ namespace otlp // // See `attribute_value.h` for details. // -const int kAttributeValueSize = 15; +const int kAttributeValueSize = 15; +const int kOwnedAttributeValueSize = 15; void Recordable::SetIdentity(const opentelemetry::trace::SpanContext &span_context, opentelemetry::trace::SpanId parent_span_id) noexcept @@ -123,6 +124,116 @@ void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute, } } +/** Maps from C++ attribute into OTLP proto attribute. */ +void PopulateAttribute(opentelemetry::proto::common::v1::KeyValue *attribute, + nostd::string_view key, + const sdk::common::OwnedAttributeValue &value) +{ + // Assert size of variant to ensure that this method gets updated if the variant + // definition changes + static_assert( + nostd::variant_size::value == kOwnedAttributeValueSize, + "AttributeValue contains unknown type"); + + attribute->set_key(key.data(), key.size()); + + if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_bool_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_int_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_double_value(nostd::get(value)); + } + else if (nostd::holds_alternative(value)) + { + attribute->mutable_value()->set_string_value(nostd::get(value)); + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_bool_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_int_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_double_value(val); + } + } + else if (nostd::holds_alternative>(value)) + { + for (const auto &val : nostd::get>(value)) + { + attribute->mutable_value()->mutable_array_value()->add_values()->set_string_value(val); + } + } +} + +proto::resource::v1::Resource Recordable::ProtoResource() const noexcept +{ + proto::resource::v1::Resource proto; + if (resource_) + { + for (const auto &kv : resource_->GetAttributes()) + { + PopulateAttribute(proto.add_attributes(), kv.first, kv.second); + } + } + return proto; +} + +void Recordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept +{ + resource_ = &resource; +}; + void Recordable::SetAttribute(nostd::string_view key, const opentelemetry::common::AttributeValue &value) noexcept { diff --git a/exporters/zipkin/CMakeLists.txt b/exporters/zipkin/CMakeLists.txt index 5d4fe8ddbd..50c3103533 100644 --- a/exporters/zipkin/CMakeLists.txt +++ b/exporters/zipkin/CMakeLists.txt @@ -38,7 +38,8 @@ if(BUILD_TESTING) target_link_libraries( zipkin_recordable_test ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} - opentelemetry_exporter_zipkin_trace http_client_curl) + opentelemetry_exporter_zipkin_trace opentelemetry_resources + http_client_curl) gtest_add_tests( TARGET zipkin_recordable_test diff --git a/exporters/zipkin/include/opentelemetry/exporters/zipkin/recordable.h b/exporters/zipkin/include/opentelemetry/exporters/zipkin/recordable.h index f597a45400..edfc85686c 100644 --- a/exporters/zipkin/include/opentelemetry/exporters/zipkin/recordable.h +++ b/exporters/zipkin/include/opentelemetry/exporters/zipkin/recordable.h @@ -38,6 +38,8 @@ class Recordable final : public sdk::trace::Recordable public: const ZipkinSpan &span() const noexcept { return span_; } + const std::string &GetServiceName() const noexcept { return service_name_; } + void SetIdentity(const opentelemetry::trace::SpanContext &span_context, opentelemetry::trace::SpanId parent_span_id) noexcept override; @@ -57,7 +59,9 @@ class Recordable final : public sdk::trace::Recordable void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override; - virtual void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override; + void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override; + + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override; void SetDuration(std::chrono::nanoseconds duration) noexcept override; @@ -67,6 +71,7 @@ class Recordable final : public sdk::trace::Recordable private: ZipkinSpan span_; + std::string service_name_; }; } // namespace zipkin } // namespace exporter diff --git a/exporters/zipkin/src/recordable.cc b/exporters/zipkin/src/recordable.cc index a6722f225f..6999bb21e3 100644 --- a/exporters/zipkin/src/recordable.cc +++ b/exporters/zipkin/src/recordable.cc @@ -213,6 +213,16 @@ void Recordable::SetName(nostd::string_view name) noexcept span_["name"] = name.data(); } +void Recordable::SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept +{ + // only service.name attribute is supported by specs as of now. + auto attributes = resource.GetAttributes(); + if (attributes.find("service.name") != attributes.end()) + { + service_name_ = nostd::get(attributes["service.name"]); + } +} + void Recordable::SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept { span_["timestamp"] = diff --git a/exporters/zipkin/src/zipkin_exporter.cc b/exporters/zipkin/src/zipkin_exporter.cc index 87bddb57bd..acef753ef7 100644 --- a/exporters/zipkin/src/zipkin_exporter.cc +++ b/exporters/zipkin/src/zipkin_exporter.cc @@ -62,6 +62,12 @@ sdk::common::ExportResult ZipkinExporter::Export( auto json_span = rec->span(); // add localEndPoint json_span["localEndpoint"] = local_end_point_; + // check service.name + auto service_name = rec->GetServiceName(); + if (service_name.size()) + { + json_span["localEndpoint"]["serviceName"] = service_name; + } json_spans.push_back(json_span); } } diff --git a/exporters/zipkin/test/zipkin_recordable_test.cc b/exporters/zipkin/test/zipkin_recordable_test.cc index a5eb1dc934..fc445bb15e 100644 --- a/exporters/zipkin/test/zipkin_recordable_test.cc +++ b/exporters/zipkin/test/zipkin_recordable_test.cc @@ -228,6 +228,15 @@ TEST(ZipkinSpanRecordable, SetArrayAtrribute) EXPECT_EQ(rec.span(), j_span); } +TEST(ZipkinSpanRecordable, SetResource) +{ + opentelemetry::exporter::zipkin::Recordable rec; + std::string service_name = "test"; + auto resource = opentelemetry::sdk::resource::Resource::Create({{"service.name", service_name}}); + rec.SetResource(resource); + EXPECT_EQ(rec.GetServiceName(), service_name); +} + /** * AttributeValue can contain different int types, such as int, int64_t, * unsigned int, and uint64_t. To avoid writing test cases for each, we can diff --git a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h index 009719f94b..e15fbc8703 100644 --- a/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h +++ b/ext/include/opentelemetry/ext/zpages/threadsafe_span_data.h @@ -160,6 +160,11 @@ class ThreadsafeSpanData final : public opentelemetry::sdk::trace::Recordable span_kind_ = span_kind; } + void SetResource(const opentelemetry::sdk::resource::Resource & /*resource*/) noexcept override + { + // Not Implemented + } + void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override { std::lock_guard lock(mutex_); diff --git a/sdk/include/opentelemetry/sdk/trace/multi_recordable.h b/sdk/include/opentelemetry/sdk/trace/multi_recordable.h index 925685a14f..be04566627 100644 --- a/sdk/include/opentelemetry/sdk/trace/multi_recordable.h +++ b/sdk/include/opentelemetry/sdk/trace/multi_recordable.h @@ -63,8 +63,8 @@ class MultiRecordable : public Recordable } } - virtual void SetAttribute(nostd::string_view key, - const opentelemetry::common::AttributeValue &value) noexcept override + void SetAttribute(nostd::string_view key, + const opentelemetry::common::AttributeValue &value) noexcept override { for (auto &recordable : recordables_) { @@ -72,9 +72,9 @@ class MultiRecordable : public Recordable } } - virtual void AddEvent(nostd::string_view name, - opentelemetry::common::SystemTimestamp timestamp, - const opentelemetry::common::KeyValueIterable &attributes) noexcept override + void AddEvent(nostd::string_view name, + opentelemetry::common::SystemTimestamp timestamp, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override { for (auto &recordable : recordables_) @@ -83,8 +83,8 @@ class MultiRecordable : public Recordable } } - virtual void AddLink(const opentelemetry::trace::SpanContext &span_context, - const opentelemetry::common::KeyValueIterable &attributes) noexcept override + void AddLink(const opentelemetry::trace::SpanContext &span_context, + const opentelemetry::common::KeyValueIterable &attributes) noexcept override { for (auto &recordable : recordables_) { @@ -92,8 +92,8 @@ class MultiRecordable : public Recordable } } - virtual void SetStatus(opentelemetry::trace::StatusCode code, - nostd::string_view description) noexcept override + void SetStatus(opentelemetry::trace::StatusCode code, + nostd::string_view description) noexcept override { for (auto &recordable : recordables_) { @@ -101,7 +101,7 @@ class MultiRecordable : public Recordable } } - virtual void SetName(nostd::string_view name) noexcept override + void SetName(nostd::string_view name) noexcept override { for (auto &recordable : recordables_) { @@ -109,7 +109,7 @@ class MultiRecordable : public Recordable } } - virtual void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override + void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override { for (auto &recordable : recordables_) { @@ -117,7 +117,15 @@ class MultiRecordable : public Recordable } } - virtual void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override + { + for (auto &recordable : recordables_) + { + recordable.second->SetResource(resource); + } + } + + void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override { for (auto &recordable : recordables_) { @@ -125,7 +133,7 @@ class MultiRecordable : public Recordable } } - virtual void SetDuration(std::chrono::nanoseconds duration) noexcept override + void SetDuration(std::chrono::nanoseconds duration) noexcept override { for (auto &recordable : recordables_) { diff --git a/sdk/include/opentelemetry/sdk/trace/recordable.h b/sdk/include/opentelemetry/sdk/trace/recordable.h index 3132c0d350..64492b665b 100644 --- a/sdk/include/opentelemetry/sdk/trace/recordable.h +++ b/sdk/include/opentelemetry/sdk/trace/recordable.h @@ -6,6 +6,7 @@ #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/empty_attributes.h" #include "opentelemetry/sdk/instrumentationlibrary/instrumentation_library.h" +#include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/trace/canonical_code.h" #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/span_context.h" @@ -118,6 +119,12 @@ class Recordable */ virtual void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept = 0; + /** + * Set Resource of the span + * @param Resource the resource to set + */ + virtual void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept = 0; + /** * Set the start time of the span. * @param start_time the start time to set diff --git a/sdk/include/opentelemetry/sdk/trace/span_data.h b/sdk/include/opentelemetry/sdk/trace/span_data.h index d92fb7a049..fafd6ce315 100644 --- a/sdk/include/opentelemetry/sdk/trace/span_data.h +++ b/sdk/include/opentelemetry/sdk/trace/span_data.h @@ -144,6 +144,13 @@ class SpanData final : public Recordable */ opentelemetry::nostd::string_view GetDescription() const noexcept { return status_desc_; } + /** + * Get the attributes associated with the resource + * @returns the attributes associated with the resource configured for TracerProvider + */ + + const opentelemetry::sdk::resource::Resource &GetResource() const noexcept { return *resource_; } + /** * Get the start time for this span * @return the start time for this span @@ -225,6 +232,11 @@ class SpanData final : public Recordable span_kind_ = span_kind; } + void SetResource(const opentelemetry::sdk::resource::Resource &resource) noexcept override + { + resource_ = &resource; + } + void SetStartTime(opentelemetry::common::SystemTimestamp start_time) noexcept override { start_time_ = start_time; @@ -250,6 +262,7 @@ class SpanData final : public Recordable std::vector events_; std::vector links_; opentelemetry::trace::SpanKind span_kind_{opentelemetry::trace::SpanKind::kInternal}; + const opentelemetry::sdk::resource::Resource *resource_; const InstrumentationLibrary *instrumentation_library_; }; } // namespace trace diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index 57a05d8ff5..ce1f60370f 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -50,6 +50,9 @@ class Tracer final : public trace_api::Tracer, public std::enable_shared_from_th return *instrumentation_library_; } + /** Returns the currently configured resource **/ + const opentelemetry::sdk::resource::Resource &GetResource() { return context_->GetResource(); } + // Note: Test only Sampler &GetSampler() { return context_->GetSampler(); } diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index 4ad453158f..395b3c3dd7 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -102,8 +102,7 @@ Span::Span(std::shared_ptr &&tracer, recordable_->SetSpanKind(options.kind); recordable_->SetStartTime(NowOr(options.start_system_time)); start_steady_time = NowOr(options.start_steady_time); - // recordable_->SetResource(tracer_->GetResoource()); TODO - // recordable_->SetResource(tracer_->GetInstrumentationLibrary()); TODO + recordable_->SetResource(tracer_->GetResource()); tracer_->GetProcessor().OnStart(*recordable_, parent_span_context); } diff --git a/sdk/test/trace/span_data_test.cc b/sdk/test/trace/span_data_test.cc index da4a31bd8e..2ae870b7ea 100644 --- a/sdk/test/trace/span_data_test.cc +++ b/sdk/test/trace/span_data_test.cc @@ -91,6 +91,16 @@ TEST(SpanData, EventAttributes) } } +TEST(SpanData, Resources) +{ + SpanData data; + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto input_attr = resource.GetAttributes(); + data.SetResource(resource); + auto output_attr = data.GetResource().GetAttributes(); + EXPECT_EQ(input_attr, output_attr); +} + TEST(SpanData, Links) { SpanData data;