otTrace.resource_spans.at(0).scope_spans.at(0).scope.attributes.push_back(hostnameAttr);
- {
- auto lockedPre = d_preActivationSpans.read_only_lock();
-
- for (auto const& preActivationTrace : *lockedPre) {
- otTrace.resource_spans.at(0).scope_spans.at(0).spans.push_back(
- {
- .trace_id = d_traceid,
- .span_id = preActivationTrace.span_id,
- .parent_span_id = preActivationTrace.parent_span_id,
- .name = preActivationTrace.name,
- .kind = pdns::trace::Span::SpanKind::SPAN_KIND_SERVER,
- .start_time_unix_nano = preActivationTrace.start_time_unix_nano,
- .end_time_unix_nano = preActivationTrace.end_time_unix_nano,
- });
-
- if (preActivationTrace.parent_span_id == pdns::trace::s_emptySpanID) {
- // This is the root span
- otTrace.resource_spans.at(0).scope_spans.at(0).spans.back().attributes.insert(
- otTrace.resource_spans.at(0).scope_spans.at(0).spans.back().attributes.cend(),
- d_rootSpanAttributes.begin(),
- d_rootSpanAttributes.end());
- }
- }
+ auto lockedSpans = d_spans.read_only_lock();
+ for (auto const& lockedSpan : *lockedSpans) {
+ otTrace.resource_spans.at(0).scope_spans.at(0).spans.push_back(
+ {
+ .trace_id = getTraceID(),
+ .span_id = lockedSpan.span_id,
+ .parent_span_id = lockedSpan.parent_span_id,
+ .name = lockedSpan.name,
+ .kind = pdns::trace::Span::SpanKind::SPAN_KIND_SERVER,
+ .start_time_unix_nano = lockedSpan.start_time_unix_nano,
+ .end_time_unix_nano = lockedSpan.end_time_unix_nano,
+ .attributes = lockedSpan.attributes,
+ });
}
- {
- auto lockedPost = d_postActivationSpans.read_only_lock();
- otTrace.resource_spans.at(0).scope_spans.at(0).spans.insert(
- otTrace.resource_spans.at(0).scope_spans.at(0).spans.end(),
- lockedPost->begin(),
- lockedPost->end());
- }
return otTrace;
#endif
}
return 0;
#else
auto spanID = pdns::trace::SpanID::getRandomSpanID();
- if (d_activated) {
- d_postActivationSpans.lock()->push_back({
- .trace_id = d_traceid,
- .span_id = spanID,
- .parent_span_id = parentSpanID,
- .name = name,
- .kind = pdns::trace::Span::SpanKind::SPAN_KIND_SERVER,
- .start_time_unix_nano = pdns::trace::timestamp(),
- });
- return spanID;
- }
-
- // We're not activated, so we are in pre-activation.
- d_preActivationSpans.lock()->push_back({
+ d_spans.lock()->push_back({
.name = name,
.span_id = spanID,
.parent_span_id = parentSpanID,
.start_time_unix_nano = pdns::trace::timestamp(),
.end_time_unix_nano = 0,
+ .attributes = {},
});
d_lastSpanID = spanID;
-
return spanID;
#endif
}
// always succesfull
return true;
#else
- if (!d_activated) {
- return false;
- }
d_attributes.push_back({key, value});
return true;
#endif
void Tracer::closeSpan([[maybe_unused]] const SpanID& spanID)
{
#ifndef DISABLE_PROTOBUF
- if (d_activated) {
- auto lockedPost = d_postActivationSpans.lock();
- auto spanIt = std::find_if(
- lockedPost->rbegin(),
- lockedPost->rend(),
- [spanID](const pdns::trace::Span& span) { return span.span_id == spanID; });
- if (spanIt != lockedPost->rend()) {
- if (spanIt->end_time_unix_nano == 0) {
- spanIt->end_time_unix_nano = pdns::trace::timestamp();
- }
- return;
- }
- }
-
- auto lockedPre = d_preActivationSpans.lock();
+ auto lockedSpans = d_spans.lock();
auto spanIt = std::find_if(
- lockedPre->rbegin(),
- lockedPre->rend(),
- [spanID](const preActivationSpanInfo& span) { return span.span_id == spanID; });
- if (spanIt != lockedPre->rend() && spanIt->end_time_unix_nano == 0) {
+ lockedSpans->rbegin(),
+ lockedSpans->rend(),
+ [spanID](const miniSpan& span) { return span.span_id == spanID; });
+ if (spanIt != lockedSpans->rend() && spanIt->end_time_unix_nano == 0) {
spanIt->end_time_unix_nano = pdns::trace::timestamp();
return;
}
void Tracer::setRootSpanAttribute([[maybe_unused]] const std::string& key, [[maybe_unused]] const AnyValue& value)
{
#ifndef DISABLE_PROTOBUF
- d_rootSpanAttributes.push_back({
- .key = key,
- .value = value,
- });
+ setSpanAttribute(getRootSpanID(), key, value);
#endif
}
void Tracer::setSpanAttribute([[maybe_unused]] const SpanID& spanid, [[maybe_unused]] const std::string& key, [[maybe_unused]] const AnyValue& value)
{
#ifndef DISABLE_PROTOBUF
- if (d_activated) {
- auto lockedPost = d_postActivationSpans.lock();
- if (auto iter = std::find_if(lockedPost->rbegin(),
- lockedPost->rend(),
- [spanid](const pdns::trace::Span& span) { return span.span_id == spanid; });
- iter != lockedPost->rend()) {
- iter->attributes.push_back({key, value});
- return;
- }
+ auto lockedSpans = d_spans.lock();
+ if (auto iter = std::find_if(lockedSpans->rbegin(),
+ lockedSpans->rend(),
+ [spanid](const auto& span) { return span.span_id == spanid; });
+ iter != lockedSpans->rend()) {
+ iter->attributes.push_back({key, value});
}
- // XXX: It is not possible to add attributes to d_preActivationTraces. Perhaps these should be converted on calling activate
#endif
}
#ifdef DISABLE_PROTOBUF
return 0;
#else
- if (auto spans = d_preActivationSpans.read_only_lock(); spans->size() != 0) {
+ if (auto spans = d_spans.read_only_lock(); !spans->empty()) {
auto iter = std::find_if(spans->cbegin(), spans->cend(), [](const auto& span) { return span.parent_span_id == pdns::trace::s_emptySpanID; });
if (iter != spans->cend()) {
return iter->span_id;
#ifdef DISABLE_PROTOBUF
return 0;
#else
- if (d_activated && d_postActivationSpans.read_only_lock()->size() != 0) {
- return d_postActivationSpans.read_only_lock()->back().span_id;
- }
- if (d_preActivationSpans.read_only_lock()->size() != 0) {
- return d_preActivationSpans.read_only_lock()->back().span_id;
+ if (auto lockedSpans = d_spans.read_only_lock(); !lockedSpans->empty()) {
+ return lockedSpans->back().span_id;
}
- return SpanID{};
+ return pdns::trace::s_emptySpanID;
#endif
}
#ifdef DISABLE_PROTOBUF
return 0;
#else
- if (d_activated && d_postActivationSpans.read_only_lock()->size() != 0) {
- auto lockedPost = d_postActivationSpans.read_only_lock();
- if (auto iter = std::find_if(lockedPost->rbegin(),
- lockedPost->rend(),
- [name](const pdns::trace::Span& span) { return span.name == name; });
- iter != lockedPost->rend()) {
- return iter->span_id;
- }
- }
-
- if (d_preActivationSpans.read_only_lock()->size() != 0) {
- auto lockedPre = d_preActivationSpans.read_only_lock();
- if (auto iter = std::find_if(lockedPre->rbegin(),
- lockedPre->rend(),
- [name](const preActivationSpanInfo& span) { return span.name == name; });
- iter != lockedPre->rend()) {
+ if (auto lockedSpans = d_spans.read_only_lock(); !lockedSpans->empty()) {
+ if (auto iter = std::find_if(lockedSpans->rbegin(),
+ lockedSpans->rend(),
+ [name](const miniSpan& span) { return span.name == name; });
+ iter != lockedSpans->rend()) {
return iter->span_id;
}
}
- return SpanID{};
+ return pdns::trace::s_emptySpanID;
#endif
}
#ifdef DISABLE_PROTOBUF
return 0;
#else
+ if (d_traceid == pdns::trace::s_emptyTraceID) {
+ d_traceid.makeRandom();
+ }
return d_traceid;
#endif
}
return std::shared_ptr<Tracer>(new Tracer);
}
- /**
- * @brief Activate the Tracer
- *
- * Once activated, all new events are stored as actual Spans
- */
- void activate()
- {
-#ifndef DISABLE_PROTOBUF
- d_activated = true;
- if (d_traceid == pdns::trace::s_emptyTraceID) {
- d_traceid.makeRandom();
- }
-#endif
- }
-
- /**
- * @brief Deactivate the tracer
- */
- void deactivate()
- {
-#ifndef DISABLE_PROTOBUF
- // Set deactivated, but don't delete any data.
- // The Tracer can be activated later
- d_activated = false;
-#endif
- }
-
/**
* @brief Add an attribute to the Trace
*
- * This only works when Tracer is active
- *
* @param key
* @param value
* @return true on success, false when attribute was not added
}
#endif
};
- Closer(const Closer&) = default;
+ Closer(const Closer&) = delete;
Closer& operator=(const Closer&) = default;
Closer& operator=(Closer&&) noexcept = default;
- Closer(Closer&&) = default;
+ Closer(Closer&&) = delete;
/**
* @brief Get the SpanID
#ifndef DISABLE_PROTOBUF
/**
- * @class preActivationSpanInfo
- * @brief Used before the Tracer is activated to store Span information
+ * @class miniSpan
+ * @brief Used to store Span information
*/
- struct preActivationSpanInfo
+ struct miniSpan
{
std::string name;
SpanID span_id;
SpanID parent_span_id;
uint64_t start_time_unix_nano;
uint64_t end_time_unix_nano;
+ std::vector<pdns::trace::KeyValue> attributes;
};
/**
- * @brief Stores all preActivationSpanInfos. It is used until d_activated is true
- */
- LockGuarded<std::vector<preActivationSpanInfo>> d_preActivationSpans;
- /**
- * @brief Stores all Spans. It is used when d_activated is true
+ * @brief Stores all miniSpans.
*/
- LockGuarded<std::vector<Span>> d_postActivationSpans;
+ LockGuarded<std::vector<miniSpan>> d_spans;
/**
* @brief All attributes related to this Trace (added to the ScopeSpan)
*/
std::vector<pdns::trace::KeyValue> d_attributes;
- /**
- * @brief All attributes related to the root span of this trace
- */
- std::vector<pdns::trace::KeyValue> d_rootSpanAttributes;
/**
* @brief The TraceID for this Tracer. It is stable for the lifetime of the Tracer
+ *
+ * it is mutable because it is set the first time it is accessed
*/
- TraceID d_traceid{};
+ mutable TraceID d_traceid{};
/**
* @brief The last SpanID that was added to this Tracer
*/
SpanID d_lastSpanID{};
- /**
- * @brief Whether or not we are storing full Spans or minimal Spans
- */
- bool d_activated{false};
#endif
};
} // namespace pdns::trace::dnsdist
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "protozero-trace.hh"
+#include <boost/test/unit_test_suite.hpp>
#ifndef DISABLE_PROTOBUF
#ifndef BOOST_TEST_DYN_LINK
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_NO_MAIN
BOOST_AUTO_TEST_SUITE(dnsdistopentelemetry_cc)
-BOOST_AUTO_TEST_CASE(getTraceID)
+BOOST_AUTO_TEST_CASE(TraceID)
{
- // Ensure we always have a TraceID after activation
+ // Ensure we always have a TraceID
auto tracer = pdns::trace::dnsdist::Tracer::getTracer();
- BOOST_CHECK_EQUAL(tracer->getTraceID(), TraceID{});
+ BOOST_CHECK_NE(tracer->getTraceID(), pdns::trace::s_emptyTraceID);
- // Ensure we have one *after* activation
- tracer->activate();
- auto traceid = tracer->getTraceID();
- BOOST_CHECK_NE(traceid, TraceID{});
-
- // Ensure we have the same one *after* deactivation
- tracer->deactivate();
- BOOST_CHECK_EQUAL(tracer->getTraceID(), traceid);
-
- // Ensure we have the same one *after* reactivation
- tracer->deactivate();
- BOOST_CHECK_EQUAL(tracer->getTraceID(), traceid);
+ // Ensure we have a trace ID, even if we don't call getTraceID
+ tracer = pdns::trace::dnsdist::Tracer::getTracer();
+ tracer->openSpan("bla");
+ auto data = tracer->getTracesData();
+ BOOST_CHECK_NE(data.resource_spans.at(0).scope_spans.at(0).spans.at(0).trace_id, pdns::trace::s_emptyTraceID);
}
BOOST_AUTO_TEST_CASE(getLastSpanID)
}
lastSpanID = tracer->getLastSpanID();
BOOST_CHECK_EQUAL(spanid, lastSpanID);
-
- tracer->activate();
- spanid = tracer->openSpan("post-activation-myevent").getSpanID();
- lastSpanID = tracer->getLastSpanID();
- BOOST_CHECK_EQUAL(spanid, lastSpanID);
-
- for (auto i = 0; i < 4; i++) {
- spanid = tracer->openSpan("post-activation-myevent" + std::to_string(i)).getSpanID();
- }
- lastSpanID = tracer->getLastSpanID();
- BOOST_CHECK_EQUAL(spanid, lastSpanID);
}
BOOST_AUTO_TEST_CASE(getLastSpanIDForName)
}
lastSpanID = tracer->getLastSpanIDForName(eventName);
BOOST_CHECK_EQUAL(spanid, lastSpanID);
- auto preactivationSpanID = spanid;
-
- tracer->activate();
- spanid = tracer->openSpan(eventName).getSpanID();
- lastSpanID = tracer->getLastSpanIDForName(eventName);
- BOOST_CHECK_EQUAL(spanid, lastSpanID);
-
- for (auto i = 0; i < 4; i++) {
- spanid = tracer->openSpan(eventName).getSpanID();
- }
- lastSpanID = tracer->getLastSpanIDForName(eventName);
- BOOST_CHECK_EQUAL(spanid, lastSpanID);
-
- tracer->deactivate();
- lastSpanID = tracer->getLastSpanIDForName(eventName);
- BOOST_CHECK_EQUAL(preactivationSpanID, lastSpanID);
-}
-
-BOOST_AUTO_TEST_CASE(activate)
-{
- auto tracer = pdns::trace::dnsdist::Tracer::getTracer();
-
- // We don't actually check the internal state, but we infer it from the order
- // of the output.
- auto preActivationSpanID = tracer->openSpan("pre-activation-event").getSpanID();
- tracer->activate();
- auto postActivationSpanID = tracer->openSpan("post-activation-event").getSpanID();
-
- // Ensure order is pre1, post1
- auto trace = tracer->getTracesData();
- BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 2);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, preActivationSpanID);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).span_id, postActivationSpanID);
-
- // Now deactivate and check if the order will be pre1, pre2, post1
- tracer->deactivate();
- auto preActivationSpanID2 = tracer->openSpan("pre-activation-event2").getSpanID();
-
- trace = tracer->getTracesData();
- BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 3);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, preActivationSpanID);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).span_id, preActivationSpanID2);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(2).span_id, postActivationSpanID);
}
BOOST_AUTO_TEST_CASE(Closer)
{
auto tracer = pdns::trace::dnsdist::Tracer::getTracer();
- auto prespanid = tracer->openSpan("foo").getSpanID();
- tracer->activate();
- auto postspanid = tracer->openSpan("bar").getSpanID();
+ auto spanid = tracer->openSpan("foo").getSpanID();
SpanID openeventSpanID;
SpanID openevent2SpanID;
{
- auto precloser = tracer->getCloser(prespanid);
- auto postcloser = tracer->getCloser(postspanid);
+ auto closer = tracer->getCloser(spanid);
auto openEventCloser = tracer->openSpan("openEvent");
openeventSpanID = openEventCloser.getSpanID();
// Closer is out of scope, so each event should have a closing time
auto trace = tracer->getTracesData();
- BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 4);
+ BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.size() == 3);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, prespanid);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).span_id, spanid);
BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).end_time_unix_nano, 0U);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).span_id, postspanid);
BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).end_time_unix_nano, 0U);
-
- BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(2).end_time_unix_nano, 0U);
- BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(3).end_time_unix_nano, 0U);
+ BOOST_CHECK_NE(trace.resource_spans.at(0).scope_spans.at(0).spans.at(1).end_time_unix_nano, 0U);
// Check the parent span_id for the second closer
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(3).span_id, openevent2SpanID);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(3).parent_span_id, openeventSpanID);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(2).span_id, openevent2SpanID);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(2).parent_span_id, openeventSpanID);
pdns::trace::dnsdist::Tracer::Closer emptyCloser;
BOOST_CHECK_EQUAL(emptyCloser.getSpanID(), SpanID{});
}
-BOOST_AUTO_TEST_CASE(attributes)
+BOOST_AUTO_TEST_CASE(traceAttributes)
{
auto tracer = pdns::trace::dnsdist::Tracer::getTracer();
tracer->setTraceAttribute("foo", AnyValue{"bar"});
- // Test that no attributes are added when the tracer is not activated
auto trace = tracer->getTracesData();
BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.size(), 1U);
BOOST_CHECK_EQUAL(trace.resource_spans.at(0).resource.attributes.at(0).key, "service.name");
// Check if we have a hostname
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.size(), 1U);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(0).key, "hostname");
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.size(), 2U);
- // Now activate and add 2 attributes
- tracer->activate();
- tracer->setTraceAttribute("foo", AnyValue{"bar"});
- tracer->setTraceAttribute("baz", AnyValue{256});
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(0).key, "foo");
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(0).value, AnyValue{"bar"});
- trace = tracer->getTracesData();
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(1).key, "hostname");
+}
- BOOST_ASSERT(trace.resource_spans.at(0).resource.attributes.size() == 1);
- // hostname plus the two we set
- BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.size() == 3);
+BOOST_AUTO_TEST_CASE(spanAttributes)
+{
+ auto tracer = pdns::trace::dnsdist::Tracer::getTracer();
+ auto closer = tracer->openSpan("myspan");
+ auto spanid = closer.getSpanID();
+ tracer->setSpanAttribute(spanid, "foo", AnyValue{42});
+ auto trace = tracer->getTracesData();
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(0).key, "foo");
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(0).value, AnyValue{"bar"});
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.size(), 1U);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.size(), 1U);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.at(0).key, "foo");
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.at(0).value, AnyValue{42});
+}
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(1).key, "baz");
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).scope.attributes.at(1).value, AnyValue{256});
+BOOST_AUTO_TEST_CASE(rootSpanAttributes)
+{
+ auto tracer = pdns::trace::dnsdist::Tracer::getTracer();
+ auto closer = tracer->openSpan("myspan");
+ auto spanid = closer.getSpanID();
+ tracer->openSpan("not root", spanid);
- // Add a span and some attributes
- auto spanid = tracer->openSpan("anEvent").getSpanID();
- tracer->setSpanAttribute(spanid, "spanattr", AnyValue{"exciting"});
+ tracer->setRootSpanAttribute("foobar", AnyValue{"baz"});
- trace = tracer->getTracesData();
+ auto trace = tracer->getTracesData();
- BOOST_ASSERT(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.size() == 1);
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.front().key, "spanattr");
- BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.front().value, AnyValue{"exciting"});
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.size(), 2U);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.size(), 1U);
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.at(0).key, "foobar");
+ BOOST_CHECK_EQUAL(trace.resource_spans.at(0).scope_spans.at(0).spans.at(0).attributes.at(0).value, AnyValue{"baz"});
}
BOOST_AUTO_TEST_CASE(getOTProtobuf)
auto data = tracer->getOTProtobuf();
BOOST_TEST(data.size() >= 100U);
- tracer->activate();
tracer->setTraceAttribute("foo", AnyValue{"bar"});
data = tracer->getOTProtobuf();
BOOST_TEST(data.size() >= 110U);