Skip to content

04. Component 2: OtelTraceSink (Span Exporter & Attributes)

Overview & Purpose

OtelTraceSink maps ns-3 packet events (TracePacketTx, TracePacketRx, TracePacketDrop) to OpenTelemetry spans. It is implemented as an ns3::Object registered with TypeId under group "otlp".


Detailed API Specification

Header: ns3/otlp-trace-sink.h
Base Class: ns3::Object
Namespace: ns3

Class Declaration

namespace ns3 {

class OtelTraceSink : public Object
{
public:
    static TypeId GetTypeId();

    OtelTraceSink();
    ~OtelTraceSink() override = default;

    /**
     * \brief Fetch active tracer from global Provider and cache m_tracer.
     */
    void InitTracer();

    /**
     * \brief Trace a packet transmission event.
     * \param packet The ns-3 packet being transmitted.
     * \param nodeId ID of the transmitting node.
     */
    void TracePacketTx(Ptr<const Packet> packet, uint32_t nodeId);

    /**
     * \brief Trace a packet reception event.
     * \param packet The ns-3 packet being received.
     * \param nodeId ID of the receiving node.
     */
    void TracePacketRx(Ptr<const Packet> packet, uint32_t nodeId);

    /**
     * \brief Trace a packet drop event.
     * \param packet The ns-3 packet being dropped.
     * \param nodeId ID of the node dropping the packet.
     * \param reason String explanation for the drop.
     */
    void TracePacketDrop(Ptr<const Packet> packet, uint32_t nodeId, const std::string& reason);

private:
    opentelemetry::nostd::shared_ptr<opentelemetry::trace::Tracer> m_tracer;
};

} // namespace ns3

Attribute Mapping Dictionary

Each span emitted by OtelTraceSink contains standard key-value attributes:

Attribute Name Data Type Description Example Value
ns3.node_id int64_t ID of the active node emitting event 0, 1, 2
ns3.packet_uid int64_t Unique ns-3 Packet UID 425fd63
ns3.packet_size int64_t Total size of packet in bytes 1024
event.type string Event category TX_START, RX_OK, DROP
ns3.drop_reason string Reason for drop (only on drop spans) PHY_DROP, WIFI_PHY_1

Implementation Code (model/otlp-trace-sink.cc)

// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Arun Santhosh R A <arunsanthosh.rashok@gmail.com>

#include "otlp-trace-sink.h"
#include "otlp-clock-provider.h"

#include "ns3/log.h"
#include <opentelemetry/trace/provider.h>

namespace ns3
{

NS_LOG_COMPONENT_DEFINE("OtelTraceSink");
NS_OBJECT_ENSURE_REGISTERED(OtelTraceSink);

TypeId
OtelTraceSink::GetTypeId()
{
    static TypeId tid = TypeId("ns3::OtelTraceSink")
                            .SetParent<Object>()
                            .SetGroupName("otlp")
                            .AddConstructor<OtelTraceSink>();
    return tid;
}

OtelTraceSink::OtelTraceSink() : m_tracer(nullptr)
{
}

void
OtelTraceSink::InitTracer()
{
    auto provider = opentelemetry::trace::Provider::GetTracerProvider();
    m_tracer = provider->GetTracer("ns3-otlp-tracer", "1.0.0");
    NS_LOG_INFO("OtelTraceSink: tracer initialised");
}

void
OtelTraceSink::TracePacketTx(Ptr<const Packet> packet, uint32_t nodeId)
{
    if (!m_tracer || !packet) return;

    opentelemetry::trace::StartSpanOptions options;
    options.start_system_time = OtelClock::GetNow();

    auto span = m_tracer->StartSpan("packet_tx",
                                    {{"ns3.node_id", static_cast<int64_t>(nodeId)},
                                     {"ns3.packet_uid", static_cast<int64_t>(packet->GetUid())},
                                     {"ns3.packet_size", static_cast<int64_t>(packet->GetSize())},
                                     {"event.type", "TX_START"}},
                                    options);
    span->End();
}

void
OtelTraceSink::TracePacketRx(Ptr<const Packet> packet, uint32_t nodeId)
{
    if (!m_tracer || !packet) return;

    opentelemetry::trace::StartSpanOptions options;
    options.start_system_time = OtelClock::GetNow();

    auto span = m_tracer->StartSpan("packet_rx",
                                    {{"ns3.node_id", static_cast<int64_t>(nodeId)},
                                     {"ns3.packet_uid", static_cast<int64_t>(packet->GetUid())},
                                     {"ns3.packet_size", static_cast<int64_t>(packet->GetSize())},
                                     {"event.type", "RX_OK"}},
                                    options);
    span->End();
}

void
OtelTraceSink::TracePacketDrop(Ptr<const Packet> packet, uint32_t nodeId, const std::string& reason)
{
    if (!m_tracer || !packet) return;

    opentelemetry::trace::StartSpanOptions options;
    options.start_system_time = OtelClock::GetNow();

    auto span = m_tracer->StartSpan("packet_drop",
                                    {{"ns3.node_id", static_cast<int64_t>(nodeId)},
                                     {"ns3.packet_uid", static_cast<int64_t>(packet->GetUid())},
                                     {"ns3.packet_size", static_cast<int64_t>(packet->GetSize())},
                                     {"ns3.drop_reason", reason},
                                     {"event.type", "DROP"}},
                                    options);
    span->SetStatus(opentelemetry::trace::StatusCode::kError, reason);
    span->End();
}

} // namespace ns3