Skip to content
Open
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
39 changes: 21 additions & 18 deletions include/bm/bm_sim/event_logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
*/

//! @file event_logger.h
//! @brief Structured event logger for BMv2. Enables machine-readable packet trace collection
//! (e.g., via JSON or Protobuf), not just console logs.

#ifndef BM_BM_SIM_EVENT_LOGGER_H_
#define BM_BM_SIM_EVENT_LOGGER_H_
Expand All @@ -37,10 +39,7 @@ namespace bm {

class Packet;

// Forward declarations of P4 object classes. This is ugly, but:
// 1) I don't have to worry about circular dependencies
// 2) If I decide to switch from id to name for msgs, I won't have to modify the
// EventLogger interface
// Forward declarations for P4 object classes, to avoid circular dependencies
class Parser;
class Deparser;
class MatchTableAbstract;
Expand All @@ -53,26 +52,22 @@ class Pipeline;

using entry_handle_t = uint32_t;

//! Signals significant packet event by publishing a message on a
//! transport. This is meant to be used with the nanomsg PUB/SUB transport.
//! Other processes can subscribe to the channel to monitor the activity of the
//! switch (e.g. for logging). So far, we are mostly using this for the
//! end-to-end testing of target switch implementations. Note that depending on
//! the transport, some messages can be lost (the nanomsg PUB/SUB transport does
//! not guarantee delivery to all subscribers, and message drops will happen if
//! a subscriber is slower than the producer).
//! @class EventLogger
//! @brief Publishes structured event messages representing significant packet processing events.
//!
//! Most messages are generated by the bmv2 code, but the target is for now
//! responsible of generated "packet in" and "packet out" messages (when a
//! packet is received / transmitted). Obviously, this is optional and you do
//! not have to do it if you are not interested in using the event logger.
//! This logger is intended as the canonical source for structured, machine-parsable event logs
//! (e.g., for automated packet tracing or test analysis). It is designed to support multiple
//! output formats (text, JSON, Protobuf, etc.) and transports (e.g., nanomsg PUB/SUB).
//!
//! Most messages are generated by bmv2 code, but packet_in/packet_out events may be logged by the target.
//! The event logger should be extended, not bypassed, for all future packet trace capabilities.
class EventLogger {
public:
explicit EventLogger(std::unique_ptr<TransportIface> transport,
device_id_t device_id = 0)
: transport_instance(std::move(transport)), device_id(device_id) { }

// we need the ingress / egress ports, but they are part of the Packet
// Ingress/egress ports are part of the Packet
//! Signal that a packet was received by the switch
void packet_in(const Packet &packet);
//! Signal that a packet was transmitted by the switch
Expand Down Expand Up @@ -102,6 +97,14 @@ class EventLogger {

void config_change();

//! Future extension: support multiple output formats (text, JSON, Protobuf).
//! Implementations should override this to produce machine-readable traces.
virtual void set_output_format(const std::string &format) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this change. Why not turn EventLogger into an interface class?
Or maybe something a bit more fancy if we want all implementations to use a TransportInterface?

If all implementations will use TransportInterface, it feels like we could define an EventSerializerIface interface class, and then have EventLogger take both an EventSerializerIface implementation and a TransportIface implementation as parameters.

I am open to alternatives, but I don't think the set_output_format approach is the right one.

// Example: "protobuf", "json", "text"
// Default: no-op. Extend in subclass or implementation.
(void)format;
}

static EventLogger *get() {
static EventLogger event_logger(TransportIface::make_dummy());
return &event_logger;
Expand All @@ -113,7 +116,7 @@ class EventLogger {
get()->device_id = device_id;
}

private:
protected:
std::unique_ptr<TransportIface> transport_instance{nullptr};
device_id_t device_id{};
};
Expand Down
Loading