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; }; }