Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OTLP GRPC CPP Exporter Does Not Compile #880

Closed
techxpert99 opened this issue Jun 29, 2021 · 7 comments · Fixed by #883
Closed

OTLP GRPC CPP Exporter Does Not Compile #880

techxpert99 opened this issue Jun 29, 2021 · 7 comments · Fixed by #883
Assignees
Labels
bug Something isn't working

Comments

@techxpert99
Copy link

techxpert99 commented Jun 29, 2021

Describe your environment

Running Manjaro Linux 21.0.7 Ornara (x86-64, Kernel: Linux 5.10.42-1-MANJARO), in a VirtualBox VM
Compiler(s) Used to build:
g++ (GCC) 11.1.0
gcc (GCC) 11.1.0
clang 12.0.0

Steps to reproduce

(1) Clone the Repo: git clone --recursive https://www.github.com/open-telemetry/opentelemetery-cpp.git

(2) Build and Install the API, SDK with CMake & Make along with third-party the relevant third-party libs ( opentelemetry-proto, nlohmann-json, ...) and ext libs (http, ...)

(3) The compilation should succeed and produce a superset of the following libs (that I have in /usr/local/lib):
libhttp_client_curl.a,libopentelemetry_common.a; libopentelemetry_exporter_otlp_grpc.a; libopentelemetry_otlp_recordable.a; libopentelemetry_proto.a; libopentelemetry_resources.a; libopentelemetry_trace.a; libopentelemetry_version.a

(4) Along with that install external dependencies- protobuf, grpc, absl

(5) Have a Demo.cpp file with the following code:

#include "opentelemetry/trace/provider.h"

#include "opentelemetry/sdk/trace/simple_processor.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"

#include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h"

#include <iostream>

using namespace opentelemetry;

nostd::shared_ptr<trace::Tracer> tracer;

void setup(){
	exporter::otlp::OtlpGrpcExporterOptions options;
	auto exporter = std::unique_ptr<sdk::trace::SpanExporter>( new exporter::otlp::OtlpGrpcExporter( options));
	auto processor = std::unique_ptr<sdk::trace::SpanProcessor>( new sdk::trace::SimpleSpanProcessor( std::move( exporter)));
	auto provider = nostd::shared_ptr<trace::TracerProvider>( new sdk::trace::TracerProvider( std::move( processor)));
	tracer = provider->GetTracer("otel-demo-cpp-oge2c2zb-tracer","0.1");
}

int fib(int n){
	int ans=-1;
	auto span = tracer->StartSpan("fib-function");
	auto scope = tracer->WithActiveSpan(span);
	if(n<0) span->AddEvent("Negative Input");
	else if(n == 0) ans = 0;
	else if(n == 1) ans = 1;
	else ans = fib(n-2) + fib(n-1);
	span->SetAttribute("answer",ans);
	span->End();
	return ans;
}

int main(int arc, char **argv){
	
	setup();
	int n;
	std::cout << "Input number: ";
	std::cin >> n;
	std::cout << "Output: " << fib(n) << std::endl;
	return 0;
}

(6) Have a CMakeLists.txt file with the following Code:

project (otel_demo_cpp_dtrace_oge2c2cb)

add_executable(demo Demo.cpp)

target_link_libraries(demo pthread opentelemetry_trace opentelemetry_common opentelemetry_exporter_otlp_grpc opentelemetry_otlp_recordable opentelemetry_proto opentelemetry_resources protobuf grpc++)

(7) Have a OtelConCol.yaml file to configure the collector to export to Zipkin:

receivers:
  otlp:
    protocols:
      grpc:
      
processors:
  batch:

exporters:
  zipkin:
    endpoint:
      "http://localhost:9411/api/v2/spans"

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [zipkin]

(8) A docker image: openzipkin/zipkin

(9) Compile in a build directory using cmake .. && make

(8) If successfully compiled, execute using ./demo after running otelconcol --config OtelConCol.yaml and docker run -dp 9411:9411 openzipkin/zipkin [Here otelconcol is the binary of the opentelemetry contrib collector for amd64 architecture]

What is the expected behavior?

Expected it to compile. After compilation, expect it to run and export data to collector, and from there to zipkin

What is the actual behavior?

Does not compile using any compiler gcc/g++/clang

Additional context

After analyzing the output of "make", it seems that the bug is because of the redefinition of some of the code of absl lib in the namespace nostd::absl. For instance, the struct identity is redefined. The macro #ifndef OTABSL_BASE_INTERNAL_IDENTITY_H_ , and #idnef ABSL_BASE_INTERNAL_IDENTITY_H_ do not match, and the struct is redefined because of that.

Here is a filtered output of make:

[ghostbox build]# make 2> >( fgrep error )
Consolidate compiler generated dependencies of target demo
[ 50%] Building CXX object CMakeFiles/demo.dir/Demo.cpp.o
/usr/local/include/absl/base/internal/identity.h:26:8: error: redefinition of ‘struct absl::otel_v1::internal::identity<T>’

The complete output is as follows:

ghostbox build]# make
Consolidate compiler generated dependencies of target demo
[ 50%] Building CXX object CMakeFiles/demo.dir/Demo.cpp.o
In file included from /usr/local/include/absl/synchronization/mutex.h:66,
                 from /usr/include/grpcpp/impl/codegen/sync.h:35,
                 from /usr/include/grpcpp/impl/codegen/client_context.h:53,
                 from /usr/include/grpcpp/impl/codegen/call_op_set.h:32,
                 from /usr/include/grpcpp/impl/codegen/server_context.h:33,
                 from /usr/include/grpcpp/impl/codegen/async_stream.h:24,
                 from /usr/include/grpcpp/impl/codegen/async_generic_service.h:24,
                 from /usr/local/include/opentelemetry/proto/collector/trace/v1/trace_service.grpc.pb.h:26,
                 from /usr/local/include/opentelemetry/exporters/otlp/otlp_grpc_exporter.h:8,
                 from /home/ghost/Desktop/OTEL_DEMO/CPP/DTRACE_OGE2C2ZB/Demo.cpp:6:
/usr/local/include/absl/base/internal/identity.h:26:8: error: redefinition of ‘struct absl::otel_v1::internal::identity<T>’
   26 | struct identity {
      |        ^~~~~~~~
In file included from /usr/local/include/opentelemetry/nostd/absl/base/internal/inline_variable.h:20,
                 from /usr/local/include/opentelemetry/nostd/absl/utility/utility.h:49,
                 from /usr/local/include/opentelemetry/nostd/absl/types/variant.h:46,
                 from /usr/local/include/opentelemetry/nostd/variant.h:52,
                 from /usr/local/include/opentelemetry/common/attribute_value.h:10,
                 from /usr/local/include/opentelemetry/common/key_value_iterable.h:6,
                 from /usr/local/include/opentelemetry/common/key_value_iterable_view.h:10,
                 from /usr/local/include/opentelemetry/common/kv_properties.h:6,
                 from /usr/local/include/opentelemetry/baggage/baggage.h:8,
                 from /usr/local/include/opentelemetry/context/context_value.h:8,
                 from /usr/local/include/opentelemetry/context/context.h:7,
                 from /usr/local/include/opentelemetry/context/runtime_context.h:6,
                 from /usr/local/include/opentelemetry/trace/noop.h:10,
                 from /usr/local/include/opentelemetry/trace/provider.h:10,
                 from /home/ghost/Desktop/OTEL_DEMO/CPP/DTRACE_OGE2C2ZB/Demo.cpp:1:
/usr/local/include/opentelemetry/nostd/absl/base/internal/identity.h:26:8: note: previous definition of ‘struct absl::otel_v1::internal::identity<T>’
   26 | struct identity {
      |        ^~~~~~~~
make[2]: *** [CMakeFiles/demo.dir/build.make:76: CMakeFiles/demo.dir/Demo.cpp.o] Error 1
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/demo.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
@techxpert99 techxpert99 added the bug Something isn't working label Jun 29, 2021
@maxgolov
Copy link
Contributor

@techxpert99 - please try the following options:

  • rebuild the SDK by passing CMake flag -DWITH_ABSEIL=ON

or

  • move the include #include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h" to be the very first line in Demo.cpp

@techxpert99
Copy link
Author

@maxgolov Thank you. Any of the two options resolve the bug, and the export works as intended. I will be closing this issue now.

@maxgolov
Copy link
Contributor

maxgolov commented Jun 29, 2021

@lalitb @techxpert99 - I also wrote this example that works:

// Make sure to include GRPC headers first because otherwise Abseil may create
// ambiguity with `nostd::variant` if compiled with Visual Studio 2015. Other
// modern compilers are unaffected.
#include <grpcpp/grpcpp.h>

#include "opentelemetry/exporters/otlp/otlp_grpc_exporter.h"
#include "opentelemetry/trace/provider.h"

#include "opentelemetry/sdk/trace/simple_processor.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"

#include <iostream>

using namespace opentelemetry;

nostd::shared_ptr<trace::Tracer> tracer;

void setup()
{
  exporter::otlp::OtlpGrpcExporterOptions options;
  auto exporter =
      std::unique_ptr<sdk::trace::SpanExporter>(new exporter::otlp::OtlpGrpcExporter(options));
  auto processor = std::unique_ptr<sdk::trace::SpanProcessor>(
      new sdk::trace::SimpleSpanProcessor(std::move(exporter)));
  auto provider = nostd::shared_ptr<trace::TracerProvider>(
      new sdk::trace::TracerProvider(std::move(processor)));
  tracer = provider->GetTracer("otel-demo-cpp-oge2c2zb-tracer", "0.1");
}

int fib(int n)
{
  int ans    = -1;
  auto span  = tracer->StartSpan("fib-function");
  auto scope = tracer->WithActiveSpan(span);
  if (n < 0)
    span->AddEvent("Negative Input");
  else if (n == 0)
    ans = 0;
  else if (n == 1)
    ans = 1;
  else
    ans = fib(n - 2) + fib(n - 1);
  span->SetAttribute("answer", ans);
  span->End();
  return ans;
}

int main(int arc, char **argv)
{

  setup();
  int n;
  std::cout << "Input number: ";
  std::cin >> n;
  std::cout << "Output: " << fib(n) << std::endl;
  return 0;
}

I will think about how to fix it better. The issue is that we use internally a different version of Abseil library than gRPC uses. We shield this by adding our own Abseil into our own private namespace. Somehow it clashes with certain compilers, when gRPC's Abseil gets included after ours. However, if gRPC header is included BEFORE the rest of OpenTelemetry headers - everything works! I think it's some sort of a bug, where the two types are in different namespaces clearly. But compiler collapses them all into the same. Maybe it's due to one of the using namespace.

My CMakeLists.txt :

project(otlp_grpc_simple)

include_directories(
  ${CMAKE_BINARY_DIR}/generated/third_party/opentelemetry-proto)
include_directories(${CMAKE_SOURCE_DIR}/exporters/otlp/include)

if(WITH_OTLP_GRPC)
  add_executable(otlp_grpc_simple main.cc)
  target_link_libraries(
    otlp_grpc_simple
    ${CMAKE_THREAD_LIBS_INIT}
    opentelemetry_api
    opentelemetry_common
    opentelemetry_trace
    opentelemetry_exporter_otlp_grpc
    opentelemetry_otlp_recordable
    opentelemetry_proto
    opentelemetry_resources
    protobuf
    gRPC::grpc++)
endif()

I can add this example in our repo, because I believe a similar issue may pop up again. I will also consider a better fix. But I am not yet sure, maybe it's something we need to document... For now I consider you are unblocked! As there are at least two workarounds available to properly make it work.

@techxpert99
Copy link
Author

@maxgolov Yes fortunately! There is a similar issue with ZipkinExporter, because of a constant named kDefaultZipkinOptions.
I fixed that by including the implementation in my source instead of using static libs.
Also, it exports a field named "duration" in nanoseconds, where Zipkin expects microseconds ( and so the duration is displayed in seconds where it should have been milliseconds). I fixed the latter of the issues by dividing the duration.count() by 1000.
I think I should open a separate issue for that.
Once again, thank you Max!

@lalitb
Copy link
Member

lalitb commented Jun 29, 2021

There is a similar issue with ZipkinExporter, because of a constant named kDefaultZipkinOptions.
I fixed that by including the implementation in my source instead of using static libs.
Also, it exports a field named "duration" in nanoseconds, where Zipkin expects microseconds ( and so the duration is displayed in seconds where it should have been milliseconds). I fixed the latter of the issues by dividing the duration.count() by 1000.
I think I should open a separate issue for that.

@techxpert99 Both are valid issues, thanks for reporting. Please raise a bug for the same.

@lalitb
Copy link
Member

lalitb commented Jun 29, 2021

I will also consider a better fix. But I am not yet sure, maybe it's something we need to document... For now I consider you are unblocked! As there are at least two workarounds available to properly make it work.

Thanks @maxgolov for looking into this. I agree, we can document this in README.md for OTLP exporter, and gRPC example.

@lalitb
Copy link
Member

lalitb commented Jun 29, 2021

@techxpert99 Both are valid issues, thanks for reporting. Please raise a bug for the same.

Ok please ignore, has created an issue for the same : #881

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
3 participants