0

I want to create an opentelemetry tracing configuration that writes the exporter logs to a file. For that, I used the OStreamSpanExporter class that takes a ref to a std::ostream object (by default, the ctor argument is std::cout). So here is what I did:

#include <fstream>

namespace trace_sdk = opentelemetry::sdk::trace;

std::ofstream file_handle(log_trace_output_file_.c_str());

auto exporter = std::unique_ptr<trace_sdk::SpanExporter>(new opentelemetry::exporter::trace::OStreamSpanExporter(file_handle));

auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(
      new trace_sdk::SimpleSpanProcessor(std::move(exporter)));

auto provider = nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
      new trace_sdk::TracerProvider(std::move(processor)));
// Set the global trace provider
opentelemetry::trace::Provider::SetTracerProvider(provider);

This compiles nicely. Before you ask, we checked that log_trace_output_file_.c_str() is not empty. However I encounter segmentation fault as soon as I start creating spans... Do you know what I might have been doing wrong here ? Thank you.

1 Answers1

0

Ok, I realised that because of the std::move when declaring the processor, we were giving away the ownership thus we were trying to access a stream that was nullptr... Here is what I ended up doing:

main.cpp

auto trace_provider = new TraceProvider(vm["trace-provider"].as<std::string>(), vm["trace-output-log-file"].as<std::string>());
trace_provider->InitTracer();

TraceProvider.hpp

class TraceProvider {
public:
  TraceProvider(std::string exporter_backend_str, std::string log_trace_output_file = std::string());
  ~TraceProvider();
  void InitTracer();

private:
  std::string exporter_backend_str_;
  std::string log_trace_output_file_;
  std::shared_ptr<std::ofstream> log_trace_output_file_handle_ = nullptr;
  void initSimpleTracer();
};

TraceProvider.cpp

TraceProvider::TraceProvider(std::string exporter_backend_str, std::string log_trace_output_file) {
  exporter_backend_str_ = exporter_backend_str;
  exporter_backend_ = string_to_trace_exporter(exporter_backend_str);
  log_trace_output_file_ = log_trace_output_file;
  if (exporter_backend_ == Exporter::SIMPLE) {
    try {
      if (log_trace_output_file_.compare("") != 0) {
        log_trace_output_file_handle_ = std::make_shared<std::ofstream>(std::ofstream(log_trace_output_file.c_str()));
      } else {
        throw std::runtime_error("You chose the Simple trace exporter but you specified an empty log file.");
      }
    } catch(std::exception const& e) {
      std::cout << "Exception: " << e.what() << "\n";
    }
  }
}

TraceProvider::~TraceProvider() {
  // If it exists, close the file stream and delete the ptr
  if (log_trace_output_file_handle_ != nullptr) {
    std::cout << "Closing tracing log file at: " << log_trace_output_file_ << std::endl;
    log_trace_output_file_handle_.get()->close();
    log_trace_output_file_handle_.reset();
    log_trace_output_file_handle_ = nullptr;
  }
}

void TraceProvider::InitTracer() {
  switch (exporter_backend_) {
  case Exporter::SIMPLE:
    initSimpleTracer();
    break;
  case Exporter::JAEGER:
    initJaegerTracer();
    break;
  default:
    std::stringstream err_msg_stream;
    err_msg_stream << "Invalid tracing backend: " << exporter_backend_str_
                   << "\n";
    throw po::validation_error(po::validation_error::invalid_option_value,
                               err_msg_stream.str());
  }
}

void TraceProvider::initSimpleTracer() {
  std::unique_ptr<trace_sdk::SpanExporter> exporter;
  if (log_trace_output_file_.compare("") != 0) 
    exporter = std::unique_ptr<trace_sdk::SpanExporter>(new opentelemetry::exporter::trace::OStreamSpanExporter(*log_trace_output_file_handle_.get()));
  } else {
    exporter = std::unique_ptr<trace_sdk::SpanExporter>(new opentelemetry::exporter::trace::OStreamSpanExporter);
  }
  auto processor = std::unique_ptr<trace_sdk::SpanProcessor>(
      new trace_sdk::SimpleSpanProcessor(std::move(exporter)));
  auto provider = nostd::shared_ptr<opentelemetry::trace::TracerProvider>(
      new trace_sdk::TracerProvider(std::move(processor), resources));
  // Set the global trace provider
  opentelemetry::trace::Provider::SetTracerProvider(provider);

  // Set global propagator
  context::propagation::GlobalTextMapPropagator::SetGlobalPropagator(
      nostd::shared_ptr<context::propagation::TextMapPropagator>(
          new opentelemetry::trace::propagation::HttpTraceContext()));
  std::cout << "Simple (log stream) exporter successfully initialized!"
            << std::endl;
}