lib/Recorder.h (282 lines of code) (raw):
#pragma once
extern "C" {
#include "sai.h"
}
#include "swss/table.h"
#include "sairedis.h"
#include "meta/SaiInterface.h"
#include <string>
#include <fstream>
#include <vector>
#define SAI_REDIS_RECORDER_DECLARE_RECORD_REMOVE(X,ot) \
void recordRemove( \
_In_ const sai_ ## ot ## _t* ot);
#define SAI_REDIS_RECORDER_DECLARE_RECORD_CREATE(X,ot) \
void recordCreate( \
_In_ const sai_ ## ot ## _t* ot, \
_In_ uint32_t attr_count, \
_In_ const sai_attribute_t *attr_list);
#define SAI_REDIS_RECORDER_DECLARE_RECORD_SET(X,ot) \
void recordSet( \
_In_ const sai_ ## ot ## _t* ot, \
_In_ const sai_attribute_t *attr);
#define SAI_REDIS_RECORDER_DECLARE_RECORD_GET(X,ot) \
void recordGet( \
_In_ const sai_ ## ot ## _t* ot, \
_In_ uint32_t attr_count, \
_In_ const sai_attribute_t *attr_list);
namespace sairedis
{
class Recorder
{
public:
Recorder();
virtual ~Recorder();
public: // SAI API
// Ideally we would have each record api here with exact the same
// attributes as SAI apis, but since we use serialize methods for
// attributes and the same format is used in recorder and in REDIS
// database in message queue, it make sense to reuse those
// serialized values to not double serialize the same attributes.
// generic create, remove, set, get
// generic bulk apis
//
// sai_flush_fdb_entries
// sai_remove_all_neighbor_entries
// sai_clear_port_all_stats
//
// sai_api_query
// sai_log_set
// sai_api_initialize
// sai_api_uninitialize
// sai_dbg_generate_dump
// sai_object_type_get_availability
// sai_get_maximum_attribute_count
// sai_get_object_key
// sai_get_object_count
// sai_query_attribute_capability
// sai_query_attribute_enum_values_capability
// sai_bulk_get_attribute
// sai_tam_telemetry_get_data
public: // SAI quad API
/**
* @brief Record generic Create API.
*
* NOTE: recordCreate should log (object_type, switch_id,
* attr_count, attr_list) which we want to create new object id.
* We omit object id since we assume that object id was already
* allocated/generated by syncd, but this approach will not work in
* asynchronous mode, so we are allocating new object id before
* calling SAI create API by using VirtualObjectIdManager. That's
* why record interface here is different than SAI interface.
*
* Also currently in sai player response for create is not expected.
*/
void recordGenericCreate(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId, // already allocated
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list);
// TODO to be private
void recordGenericCreate(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
/**
* @brief Record generic Create API response.
*
* @param status Returned status from SAI implementation.
* @param objectId Newly allocated object ID if call to create succeeded.
*/
void recordGenericCreateResponse(
_In_ sai_status_t status,
_In_ sai_object_id_t objectId);
void recordGenericCreateResponse(
_In_ sai_status_t status);
void recordGenericRemove(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId);
// TODO to be private
void recordGenericRemove(
_In_ const std::string& key);
void recordGenericRemoveResponse(
_In_ sai_status_t status);
void recordGenericSet(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId,
_In_ const sai_attribute_t *attr);
// TODO to be private
void recordGenericSet(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordGenericSetResponse(
_In_ sai_status_t status);
void recordGenericGet(
_In_ sai_object_type_t objectType,
_In_ sai_object_id_t objectId,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list);
// TODO to be private
void recordGenericGet(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordGenericGetResponse(
_In_ sai_status_t status,
_In_ sai_object_type_t objectType,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list);
// TODO to be private
void recordGenericGetResponse(
_In_ sai_status_t status,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordGenericResponse(
_In_ sai_status_t status);
public: // create ENTRY
SAIREDIS_DECLARE_EVERY_ENTRY(SAI_REDIS_RECORDER_DECLARE_RECORD_CREATE);
public: // remove ENTRY
SAIREDIS_DECLARE_EVERY_ENTRY(SAI_REDIS_RECORDER_DECLARE_RECORD_REMOVE);
public: // set ENTRY
SAIREDIS_DECLARE_EVERY_ENTRY(SAI_REDIS_RECORDER_DECLARE_RECORD_SET);
public: // get ENTRY
SAIREDIS_DECLARE_EVERY_ENTRY(SAI_REDIS_RECORDER_DECLARE_RECORD_GET);
public: // SAI stats API
void recordGenericCounterPolling(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordGenericGetStats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids);
// TODO to private
void recordGenericGetStats(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordGenericGetStatsResponse(
_In_ sai_status_t status,
_In_ uint32_t count,
_In_ const uint64_t *counters);
void recordGenericClearStats(
_In_ sai_object_type_t object_type,
_In_ sai_object_id_t object_id,
_In_ uint32_t number_of_counters,
_In_ const sai_stat_id_t *counter_ids);
// TODO to private
void recordGenericClearStats(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordGenericClearStatsResponse(
_In_ sai_status_t status);
public: // SAI bulk API
void recordBulkGenericCreate(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordBulkGenericCreateResponse(
_In_ sai_status_t status,
_In_ uint32_t objectCount,
_In_ const sai_status_t *objectStatuses);
void recordBulkGenericRemove(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordBulkGenericRemoveResponse(
_In_ sai_status_t status,
_In_ uint32_t objectCount,
_In_ const sai_status_t *objectStatuses);
void recordBulkGenericSet(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordBulkGenericSetResponse(
_In_ sai_status_t status,
_In_ uint32_t objectCount,
_In_ const sai_status_t *objectStatuses);
void recordBulkGenericResponse(
_In_ sai_status_t status,
_In_ uint32_t objectCount,
_In_ const sai_status_t *objectStatuses);
void recordBulkGenericGet(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordBulkGenericGetResponse(
_In_ sai_status_t status,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
public: // SAI query interface API
void recordFlushFdbEntries(
_In_ sai_object_id_t switchId,
_In_ uint32_t attrCount,
_In_ const sai_attribute_t *attrList);
// TODO move to private
void recordFlushFdbEntries(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordFlushFdbEntriesResponse(
_In_ sai_status_t status);
public: // SAI global interface API
void recordObjectTypeGetAvailability(
_In_ sai_object_id_t switchId,
_In_ sai_object_type_t objectType,
_In_ uint32_t attrCount,
_In_ const sai_attribute_t *attrList);
void recordObjectTypeGetAvailabilityResponse(
_In_ sai_status_t status,
_In_ const uint64_t *count);
void recordQueryAttributeCapability(
_In_ sai_object_id_t switch_id,
_In_ sai_object_type_t object_type,
_In_ sai_attr_id_t attr_id,
_Out_ sai_attr_capability_t *capability);
void recordQueryAttributeCapabilityResponse(
_In_ sai_status_t status,
_In_ sai_object_type_t objectType,
_In_ sai_attr_id_t attrId,
_In_ const sai_attr_capability_t* capability);
void recordQueryAttributeEnumValuesCapability(
_In_ sai_object_id_t switch_id,
_In_ sai_object_type_t object_type,
_In_ sai_attr_id_t attr_id,
_Inout_ sai_s32_list_t *enum_values_capability);
void recordQueryAttributeEnumValuesCapabilityResponse(
_In_ sai_status_t status,
_In_ sai_object_type_t objectType,
_In_ sai_attr_id_t attrId,
_In_ const sai_s32_list_t* enumValuesCapability);
void recordQueryStatsCapability(
_In_ sai_object_id_t switch_id,
_In_ sai_object_type_t object_type,
_Inout_ sai_stat_capability_list_t* stats_capability);
void recordQueryStatsCapabilityResponse(
_In_ sai_status_t status,
_In_ sai_object_type_t objectType,
_In_ const sai_stat_capability_list_t *stats_capability);
// TODO move to private
void recordQueryAttributeCapability(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordQueryAttributeCapabilityResponse(
_In_ sai_status_t status,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordQueryAttributeEnumValuesCapability(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordQueryAttributeEnumValuesCapabilityResponse(
_In_ sai_status_t status,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordObjectTypeGetAvailability(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordObjectTypeGetAvailabilityResponse(
_In_ sai_status_t status,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordQueryStatsCapability(
_In_ const std::string& key,
_In_ const std::vector<swss::FieldValueTuple>& arguments);
void recordQueryStatsCapabilityResponse(
_In_ sai_status_t status,
_In_ const std::string& arguments);
public: // SAI notifications
void recordNotification(
_In_ const std::string &name,
_In_ const std::string &serializedNotification,
_In_ const std::vector<swss::FieldValueTuple> &values);
public: // sairedis/syncd internal API
void recordNotifySyncd(
_In_ sai_object_id_t switchId,
_In_ sai_redis_notify_syncd_t redisNotifySyncd);
void recordNotifySyncd(
_In_ const std::string& key);
void recordNotifySyncdResponse(
_In_ sai_status_t status);
public: // Recorder API
void enableRecording(
_In_ bool enabled);
bool setRecordingOutputDirectory(
_In_ const sai_attribute_t &attr);
bool setRecordingFilename(
_In_ const sai_attribute_t &attr);
void requestLogRotate();
void recordComment(
_In_ const std::string& comment);
public: // static helper functions
static std::string getTimestamp();
void recordStats(
_In_ bool enable);
private: // recording helpers
void recordCreate(
_In_ sai_object_type_t objectType,
_In_ const std::string& serializedObjectId,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list);
void recordRemove(
_In_ sai_object_type_t objectType,
_In_ const std::string& serializedObjectId);
void recordSet(
_In_ sai_object_type_t objectType,
_In_ const std::string& serializedObjectId,
_In_ const sai_attribute_t *attr);
void recordGet(
_In_ sai_object_type_t object_type,
_In_ const std::string &serializedObjectId,
_In_ uint32_t attr_count,
_In_ const sai_attribute_t *attr_list);
private:
void recordingFileReopen();
void startRecording();
void stopRecording();
void recordLine(
_In_ const std::string& line);
private:
bool m_performLogRotate;
bool m_enabled;
bool m_recordStats;
std::string m_recordingOutputDirectory;
std::string m_recordingFileName;
std::string m_recordingFile;
std::ofstream m_ofstream;
std::mutex m_mutex;
};
}