-
Notifications
You must be signed in to change notification settings - Fork 440
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
Add Jaeger exporter #534
Add Jaeger exporter #534
Changes from 28 commits
7cd462f
62746e5
9fd15a4
2081396
fcb82b7
eacbe0b
5c09997
02b3bbd
a3a08ad
5d8140b
ca66fed
8a7fa9f
f7f6d79
64672ba
dbed4aa
4bde77a
0a64e80
6cbffcf
d09aa9b
fd3d26f
04581ee
0d74fac
f337341
e58b00b
843e2c6
accce34
05a7f42
adb49c4
b443819
8e6c3a1
9a980ad
aeadf81
e1b93df
3d9597d
d7c3498
2027eb9
ec6ee47
6d09836
c962561
3f2ef72
e38dec6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
cc_library( | ||
name = "foo_library", | ||
srcs = [ | ||
"foo_library/foo_library.cc", | ||
], | ||
hdrs = [ | ||
"foo_library/foo_library.h", | ||
], | ||
deps = [ | ||
"//api", | ||
], | ||
) | ||
|
||
# TODO: enable bazel build | ||
# cc_binary( | ||
# name = "example_jaeger", | ||
# srcs = [ | ||
# "main.cc", | ||
# ], | ||
# deps = [ | ||
# ":foo_library", | ||
# "//api", | ||
# "//exporters/jaeger:jaeger_exporter", | ||
# "//sdk/src/trace", | ||
# ], | ||
# ) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
include_directories(${CMAKE_SOURCE_DIR}/exporters/jaeger/include) | ||
|
||
add_library(jaeger_foo_library foo_library/foo_library.cc) | ||
target_link_libraries(jaeger_foo_library ${CMAKE_THREAD_LIBS_INIT} | ||
${CORE_RUNTIME_LIBS} opentelemetry_api) | ||
|
||
add_executable(example_jaeger main.cc) | ||
target_link_libraries( | ||
example_jaeger ${CMAKE_THREAD_LIBS_INIT} jaeger_foo_library | ||
opentelemetry_trace ${CORE_RUNTIME_LIBS} jaeger_trace_exporter) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Jaeger Exporter Example | ||
|
||
This is an example of how to use the Jaeger exporter. | ||
|
||
The application in `main.cc` initializes an `JaegerExporter` instance and uses it | ||
to register a tracer provider from the [OpenTelemetry | ||
SDK](https://github.com/open-telemetry/opentelemetry-cpp). The application then | ||
calls a `foo_library` which has been instrumented using the [OpenTelemetry | ||
API](https://github.com/open-telemetry/opentelemetry-cpp/tree/main/api). | ||
|
||
Resulting spans are exported to the Jaeger agent using the Jaeger exporter. | ||
|
||
Note that the Jaeger exporter connects to the agent at `localhost:6831` by | ||
default. | ||
|
||
Once you have the Collector running, see | ||
[CONTRIBUTING.md](../../CONTRIBUTING.md) for instructions on building and | ||
running the example. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#include "opentelemetry/trace/provider.h" | ||
|
||
namespace trace = opentelemetry::trace; | ||
namespace nostd = opentelemetry::nostd; | ||
|
||
namespace | ||
{ | ||
nostd::shared_ptr<trace::Tracer> get_tracer() | ||
{ | ||
auto provider = trace::Provider::GetTracerProvider(); | ||
return provider->GetTracer("foo_library"); | ||
} | ||
|
||
void f1() | ||
{ | ||
auto scoped_span = trace::Scope(get_tracer()->StartSpan("f1")); | ||
} | ||
|
||
void f2() | ||
{ | ||
auto scoped_span = trace::Scope(get_tracer()->StartSpan("f2")); | ||
|
||
f1(); | ||
f1(); | ||
} | ||
} // namespace | ||
|
||
void foo_library() | ||
{ | ||
auto scoped_span = trace::Scope(get_tracer()->StartSpan("library")); | ||
|
||
f2(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#pragma once | ||
|
||
void foo_library(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include "opentelemetry/exporters/jaeger/jaeger_exporter.h" | ||
#include "opentelemetry/sdk/trace/simple_processor.h" | ||
#include "opentelemetry/sdk/trace/tracer_provider.h" | ||
#include "opentelemetry/trace/provider.h" | ||
|
||
#include "foo_library/foo_library.h" | ||
|
||
namespace trace = opentelemetry::trace; | ||
namespace nostd = opentelemetry::nostd; | ||
namespace sdktrace = opentelemetry::sdk::trace; | ||
namespace jaeger = opentelemetry::exporter::jaeger; | ||
|
||
namespace | ||
{ | ||
opentelemetry::exporter::jaeger::JaegerExporterOptions opts; | ||
void InitTracer() | ||
{ | ||
// Create Jaeger exporter instance | ||
auto exporter = std::unique_ptr<sdktrace::SpanExporter>(new jaeger::JaegerExporter(opts)); | ||
auto processor = std::shared_ptr<sdktrace::SpanProcessor>( | ||
new sdktrace::SimpleSpanProcessor(std::move(exporter))); | ||
auto provider = nostd::shared_ptr<trace::TracerProvider>(new sdktrace::TracerProvider(processor)); | ||
// Set the global trace provider | ||
trace::Provider::SetTracerProvider(provider); | ||
} | ||
} // namespace | ||
|
||
int main(int argc, char *argv[]) | ||
{ | ||
if (argc == 2) | ||
{ | ||
opts.server_addr = argv[1]; | ||
} | ||
// Removing this line will leave the default noop TracerProvider in place. | ||
InitTracer(); | ||
|
||
foo_library(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -34,3 +34,7 @@ endif() | |
if(WITH_ETW) | ||
add_subdirectory(etw) | ||
endif() | ||
|
||
if(WITH_JAEGER) | ||
add_subdirectory(jaeger) | ||
endif() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
include_directories(include) | ||
include_directories(thrift-gen) | ||
|
||
find_package(Boost REQUIRED) | ||
ThomsonTan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
find_package(thrift REQUIRED) | ||
|
||
if(MSVC) | ||
add_definitions(-DNOMINMAX) | ||
endif() | ||
|
||
set(JAEGER_THRIFT_GENCPP_SOURCES | ||
thrift-gen/Agent.cpp thrift-gen/jaeger_types.cpp thrift-gen/Collector.cpp | ||
thrift-gen/zipkincore_types.cpp) | ||
|
||
set(JAEGER_EXPORTER_SOURCES | ||
src/jaeger_exporter.cc src/thrift_sender.cc src/udp_transport.cc | ||
src/recordable.cc src/TUDPTransport.cc) | ||
|
||
add_library(jaeger_trace_exporter ${JAEGER_EXPORTER_SOURCES} | ||
${JAEGER_THRIFT_GENCPP_SOURCES}) | ||
target_link_libraries(jaeger_trace_exporter PRIVATE thrift::thrift) | ||
|
||
if(BUILD_TESTING) | ||
add_executable(jaeger_recordable_test test/jaeger_recordable_test.cc) | ||
target_link_libraries(jaeger_recordable_test ${GTEST_BOTH_LIBRARIES} | ||
${CMAKE_THREAD_LIBS_INIT} jaeger_trace_exporter) | ||
|
||
gtest_add_tests( | ||
TARGET jaeger_recordable_test | ||
TEST_PREFIX exporter. | ||
TEST_LIST jaeger_recordable_test) | ||
endif() # BUILD_TESTING |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright 2021, OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#pragma once | ||
|
||
#include <opentelemetry/sdk/trace/exporter.h> | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace exporter | ||
{ | ||
namespace jaeger | ||
{ | ||
enum class TransportFormat | ||
{ | ||
kThriftUdp, | ||
kThriftUdpCompact, | ||
kThriftHttp, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps only the currently supported transports should be listed here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that works too. But as this list is expected to be stable, I just leave it there to make the header file stable (later extension should not need to update the header file, just update the |
||
kProtobufGrpc, | ||
}; | ||
|
||
class ThriftSender; | ||
|
||
/** | ||
* Struct to hold Jaeger exporter options. | ||
*/ | ||
struct JaegerExporterOptions | ||
{ | ||
// The endpoint to export to. | ||
std::string server_addr = "localhost"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps future proofing, but ff Thrift over HTTP is supported, perhaps rename it to endpoint and parse host, port from it? With HTTP it will be necessary to specify the full endpoint, e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I suggest we refactor the option in later PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 |
||
uint16_t server_port = 6831; | ||
TransportFormat transport_format = TransportFormat::kThriftUdpCompact; | ||
}; | ||
|
||
namespace trace_sdk = opentelemetry::sdk::trace; | ||
|
||
class JaegerExporter final : public trace_sdk::SpanExporter | ||
{ | ||
public: | ||
/** | ||
* Create a JaegerExporter using all default options. | ||
*/ | ||
JaegerExporter(); | ||
|
||
/** | ||
* Create a JaegerExporter using the given options. | ||
*/ | ||
explicit JaegerExporter(const JaegerExporterOptions &options); | ||
|
||
/** | ||
* Create a span recordable. | ||
* @return a new initialized Recordable object. | ||
*/ | ||
std::unique_ptr<trace_sdk::Recordable> MakeRecordable() noexcept override; | ||
|
||
/** | ||
* Export a batch of spans. | ||
* @param spans a span of unique pointers to span recordables. | ||
*/ | ||
trace_sdk::ExportResult Export( | ||
const nostd::span<std::unique_ptr<trace_sdk::Recordable>> &spans) noexcept override; | ||
|
||
/** | ||
* Shutdown the exporter. | ||
* @param timeout an option timeout, default to max. | ||
*/ | ||
bool Shutdown( | ||
std::chrono::microseconds timeout = std::chrono::microseconds::max()) noexcept override | ||
{ | ||
return true; | ||
} | ||
|
||
private: | ||
void InitializeEndpoint(); | ||
|
||
private: | ||
// The configuration options associated with this exporter. | ||
bool is_shutdown_ = false; | ||
JaegerExporterOptions options_; | ||
std::unique_ptr<ThriftSender> sender_; | ||
}; | ||
|
||
} // namespace jaeger | ||
} // namespace exporter | ||
OPENTELEMETRY_END_NAMESPACE |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright 2020, OpenTelemetry Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#pragma once | ||
|
||
#include <jaeger_types.h> | ||
#include <opentelemetry/sdk/trace/recordable.h> | ||
#include <opentelemetry/version.h> | ||
|
||
OPENTELEMETRY_BEGIN_NAMESPACE | ||
namespace exporter | ||
{ | ||
namespace jaeger | ||
{ | ||
|
||
using namespace jaegertracing; | ||
|
||
class Recordable final : public sdk::trace::Recordable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Not something which needs immediate attention, but probably we should have recordable names after transport types - eg There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agree. I logged the same comment for ETW exporter. I think we could create a task for the cleanup for all the exporters? I'll try the renaming anyway. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Created issue #735 for this. |
||
{ | ||
public: | ||
Recordable(); | ||
|
||
thrift::Span *Span() noexcept { return span_.release(); } | ||
std::vector<thrift::Tag> Tags() noexcept { return std::move(tags_); } | ||
|
||
void SetIds(trace::TraceId trace_id, | ||
trace::SpanId span_id, | ||
trace::SpanId parent_span_id) noexcept override; | ||
|
||
void SetAttribute(nostd::string_view key, | ||
const opentelemetry::common::AttributeValue &value) noexcept override; | ||
|
||
void AddEvent(nostd::string_view key, | ||
core::SystemTimestamp timestamp, | ||
const common::KeyValueIterable &attributes) noexcept override; | ||
|
||
void AddLink(const opentelemetry::trace::SpanContext &span_context, | ||
const common::KeyValueIterable &attributes) noexcept override; | ||
|
||
void SetStatus(trace::StatusCode code, nostd::string_view description) noexcept override; | ||
|
||
void SetName(nostd::string_view name) noexcept override; | ||
|
||
void SetStartTime(opentelemetry::core::SystemTimestamp start_time) noexcept override; | ||
|
||
void SetSpanKind(opentelemetry::trace::SpanKind span_kind) noexcept override; | ||
|
||
void SetDuration(std::chrono::nanoseconds duration) noexcept override; | ||
|
||
private: | ||
void AddTag(const std::string &key, const std::string &value); | ||
void AddTag(const std::string &key, bool value); | ||
void AddTag(const std::string &key, int64_t value); | ||
void AddTag(const std::string &key, double value); | ||
|
||
void PopulateAttribute(nostd::string_view key, | ||
const opentelemetry::common::AttributeValue &value); | ||
|
||
private: | ||
std::unique_ptr<thrift::Span> span_; | ||
std::vector<thrift::Tag> tags_; | ||
}; | ||
|
||
} // namespace jaeger | ||
} // namespace exporter | ||
OPENTELEMETRY_END_NAMESPACE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: anything I can do to help get this working?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @jsuereth I will send out another PR with bazel build script then will need your help to make sure it is installing thrift dependence in the right way.