Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions exe/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "motis/data.h"
#include "motis/import.h"
#include "motis/logging.h"
#include "motis/otel_tracer.h"
#include "motis/server.h"

#include "./flags.h"
Expand Down Expand Up @@ -137,6 +138,11 @@ int main(int ac, char** av) {
(return_value = set_log_level(std::move(log_lvl)))) {
break;
}

if (c.use_otlp()) {
init_opentelemetry(*c.otlp_, motis_version);
}

return_value = server(data{data_path, c}, c, motis_version);
} catch (std::exception const& e) {
std::cerr << "unable to start server: " << e.what() << "\n";
Expand Down Expand Up @@ -293,6 +299,7 @@ int main(int ac, char** av) {
break;
}

cleanup_opentelemetry_tracer();
google::protobuf::ShutdownProtobufLibrary();
return return_value;
}
16 changes: 16 additions & 0 deletions include/motis/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct config {
bool has_elevators() const;
bool has_rt_feeds() const;
bool use_street_routing() const;
bool use_otlp() const;

bool operator==(config const&) const = default;

Expand Down Expand Up @@ -258,6 +259,21 @@ struct config {
limits get_limits() const { return limits_.value_or(limits{}); }
std::optional<limits> limits_{};

struct otlp {
bool operator==(otlp const&) const = default;
struct http {
bool operator==(http const&) const = default;
std::string url_{"http://localhost:4318"};
std::string content_type_{"json"};
bool use_json_name_{false};
};
std::optional<http> http_{};

unsigned timeout_{10U};
headers_t headers_{};
};
std::optional<otlp> otlp_{};

struct logging {
bool operator==(logging const&) const = default;
std::optional<std::string> log_level_{};
Expand Down
6 changes: 6 additions & 0 deletions include/motis/ctx_data.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
#pragma once

#include <vector>

#include "opentelemetry/context/context.h"

#include "ctx/op_id.h"
#include "ctx/operation.h"

namespace motis {

struct ctx_data {
void transition(ctx::transition, ctx::op_id, ctx::op_id) {}

std::vector<opentelemetry::context::Context> otel_context_stack_;
};

} // namespace motis
68 changes: 68 additions & 0 deletions include/motis/otel_runtime_context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

#include <memory>

#include "utl/helpers/algorithm.h"

#include "opentelemetry/context/context.h"
#include "opentelemetry/context/runtime_context.h"

#include "ctx/operation.h"

#include "motis/ctx_data.h"

namespace motis {

struct otel_runtime_context_storage
: public opentelemetry::context::RuntimeContextStorage {
opentelemetry::context::Context GetCurrent() noexcept override {
auto const op = ctx::current_op<ctx_data>();

if (op == nullptr) {
return default_storage_->GetCurrent();
}

// How to get stack of contexts from op (operation<ctx_data>*)
auto& stack = op->data_.otel_context_stack_;
return stack.empty() ? opentelemetry::context::Context{} : stack.back();
}

opentelemetry::nostd::unique_ptr<opentelemetry::context::Token> Attach(
opentelemetry::context::Context const& context) noexcept override {
auto const op = ctx::current_op<ctx_data>();

if (op == nullptr) {
return default_storage_->Attach(context);
}

op->data_.otel_context_stack_.push_back(context);
return CreateToken(context);
}

bool Detach(opentelemetry::context::Token& token) noexcept override {
auto const op = ctx::current_op<ctx_data>();

if (op == nullptr) {
return default_storage_->Detach(token);
}

auto& stack = op->data_.otel_context_stack_;

if (utl::find(stack, token) == stack.end()) {
return false;
}

while (!(token == stack.back())) {
stack.pop_back();
}
stack.pop_back();
return true;
}

private:
std::unique_ptr<opentelemetry::context::ThreadLocalContextStorage>
default_storage_{std::make_unique<
opentelemetry::context::ThreadLocalContextStorage>()};
};

} // namespace motis
21 changes: 21 additions & 0 deletions include/motis/otel_tracer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "opentelemetry/trace/provider.h"
#include "opentelemetry/trace/span.h"
#include "opentelemetry/trace/tracer.h"

#include "motis/config.h"

namespace motis {

void init_opentelemetry(config::otlp const&, std::string_view const);

void cleanup_opentelemetry_tracer();

inline opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer>
get_otel_tracer() {
return opentelemetry::trace::Provider::GetTracerProvider()->GetTracer(
"motis");
}

} // namespace motis
4 changes: 4 additions & 0 deletions src/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,8 @@ bool config::use_street_routing() const {
street_routing_);
}

bool config::use_otlp() const {
return otlp_.has_value() && otlp_->http_.has_value();
}

} // namespace motis
94 changes: 94 additions & 0 deletions src/otel_tracer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include "motis/otel_tracer.h"

#include <chrono>
#include <memory>
#include <utility>

#include "utl/verify.h"

#include "opentelemetry/context/propagation/global_propagator.h"
#include "opentelemetry/context/runtime_context.h"
#include "opentelemetry/exporters/otlp/otlp_http.h"
#include "opentelemetry/exporters/otlp/otlp_http_exporter_factory.h"
#include "opentelemetry/sdk/resource/resource.h"
#include "opentelemetry/sdk/trace/samplers/always_on_factory.h"
#include "opentelemetry/sdk/trace/simple_processor_factory.h"
#include "opentelemetry/sdk/trace/tracer_provider.h"
#include "opentelemetry/sdk/trace/tracer_provider_factory.h"
#include "opentelemetry/trace/propagation/http_trace_context.h"

#include "motis/otel_runtime_context.h"

namespace motis {

static std::shared_ptr<opentelemetry::sdk::trace::TracerProvider> provider_;

void init_opentelemetry_tracer(
opentelemetry::sdk::resource::Resource const& resource,
config::otlp const& c) {

auto const& http_opts = c.http_.value();
auto opts = opentelemetry::exporter::otlp::OtlpHttpExporterOptions{};
opts.url = http_opts.url_;
if (http_opts.content_type_ == "json") {
opts.content_type =
opentelemetry::exporter::otlp::HttpRequestContentType::kJson;
} else if (http_opts.content_type_ == "binary") {
opts.content_type =
opentelemetry::exporter::otlp::HttpRequestContentType::kBinary;
} else {
utl::fail("Invalid OTLP content type {}", http_opts.content_type_);
}
opts.use_json_name = http_opts.use_json_name_;
opts.timeout = std::chrono::seconds(c.timeout_);
for (auto [key, value] : c.headers_) {
opts.http_headers.insert({key, value});
}

auto exporter =
opentelemetry::exporter::otlp::OtlpHttpExporterFactory::Create(opts);

auto processor =
opentelemetry::sdk::trace::SimpleSpanProcessorFactory::Create(
std::move(exporter));

auto sampler = opentelemetry::sdk::trace::AlwaysOnSamplerFactory::Create();

auto provider =
std::shared_ptr{opentelemetry::sdk::trace::TracerProviderFactory::Create(
std::move(processor), resource, std::move(sampler))};
opentelemetry::trace::Provider::SetTracerProvider(provider);
provider_ = provider;
}

void init_opentelemetry(config::otlp const& c,
std::string_view const motis_version) {
auto resource_attributes = opentelemetry::sdk::resource::ResourceAttributes{
{"service.name", "motis"}, {"service.version", motis_version}};
auto resource =
opentelemetry::sdk::resource::Resource::Create(resource_attributes);

opentelemetry::context::RuntimeContext::SetRuntimeContextStorage(
std::make_shared<otel_runtime_context_storage>());

if (c.http_.has_value()) {
init_opentelemetry_tracer(resource, c);
}

opentelemetry::context::propagation::GlobalTextMapPropagator::
SetGlobalPropagator(
std::make_shared<
opentelemetry::trace::propagation::HttpTraceContext>());
}

void cleanup_opentelemetry_tracer() {
if (provider_) {
provider_->ForceFlush();
provider_.reset();
}

auto const none = std::shared_ptr<opentelemetry::trace::NoopTracerProvider>();
opentelemetry::trace::Provider::SetTracerProvider(none);
}

} // namespace motis
3 changes: 2 additions & 1 deletion tools/ubsan-suppress.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
src:*/LuaJIT/*
src:*/libressl/*
src:*/libressl/*
src:*/curl/*
Loading