xref: /openbmc/pldm/common/flight_recorder.hpp (revision 14107a10)
1 #pragma once
2 
3 #include <common/utils.hpp>
4 #include <phosphor-logging/lg2.hpp>
5 
6 #include <fstream>
7 #include <iomanip>
8 #include <iostream>
9 #include <vector>
10 
11 PHOSPHOR_LOG2_USING;
12 
13 namespace pldm
14 {
15 namespace flightrecorder
16 {
17 using ReqOrResponse = bool;
18 using FlightRecorderData = std::vector<uint8_t>;
19 using FlightRecorderTimeStamp = std::string;
20 using FlightRecorderRecord =
21     std::tuple<FlightRecorderTimeStamp, ReqOrResponse, FlightRecorderData>;
22 using FlightRecorderCassette = std::vector<FlightRecorderRecord>;
23 static constexpr auto flightRecorderDumpPath = "/tmp/pldm_flight_recorder";
24 
25 /** @class FlightRecorder
26  *
27  *  The class for implementing the PLDM flight recorder logic. This class
28  *  handles the insertion of the data into the recorder and also provides
29  *  API's to dump the flight recorder into a file.
30  */
31 
32 class FlightRecorder
33 {
34   private:
35     FlightRecorder() : index(0)
36     {
37         flightRecorderPolicy = FLIGHT_RECORDER_MAX_ENTRIES ? true : false;
38         if (flightRecorderPolicy)
39         {
40             tapeRecorder = FlightRecorderCassette(FLIGHT_RECORDER_MAX_ENTRIES);
41         }
42     }
43 
44   protected:
45     int index;
46     FlightRecorderCassette tapeRecorder;
47     bool flightRecorderPolicy;
48 
49   public:
50     FlightRecorder(const FlightRecorder&) = delete;
51     FlightRecorder(FlightRecorder&&) = delete;
52     FlightRecorder& operator=(const FlightRecorder&) = delete;
53     FlightRecorder& operator=(FlightRecorder&&) = delete;
54     ~FlightRecorder() = default;
55 
56     static FlightRecorder& GetInstance()
57     {
58         static FlightRecorder flightRecorder;
59         return flightRecorder;
60     }
61 
62     /** @brief Add records to the flightRecorder
63      *
64      *  @param[in] buffer  - The request/response byte buffer
65      *  @param[in] isRequest - bool that captures if it is a request message or
66      *                         a response message
67      *
68      *  @return void
69      */
70     void saveRecord(const FlightRecorderData& buffer, ReqOrResponse isRequest)
71     {
72         // if the flight recorder policy is enabled, then only insert the
73         // messages into the flight recorder, if not this function will be just
74         // a no-op
75         if (flightRecorderPolicy)
76         {
77             int currentIndex = index++;
78             tapeRecorder[currentIndex] = std::make_tuple(
79                 pldm::utils::getCurrentSystemTime(), isRequest, buffer);
80             index = (currentIndex == FLIGHT_RECORDER_MAX_ENTRIES - 1) ? 0
81                                                                       : index;
82         }
83     }
84 
85     /** @brief play flight recorder
86      *
87      *  @return void
88      */
89 
90     void playRecorder()
91     {
92         if (flightRecorderPolicy)
93         {
94             std::ofstream recorderOutputFile(flightRecorderDumpPath);
95             info("Dumping the flight recorder into : {DUMP_PATH}", "DUMP_PATH",
96                  flightRecorderDumpPath);
97             for (const auto& message : tapeRecorder)
98             {
99                 recorderOutputFile << std::get<FlightRecorderTimeStamp>(message)
100                                    << " : ";
101                 if (std::get<ReqOrResponse>(message))
102                 {
103                     recorderOutputFile << "Tx : \n";
104                 }
105                 else
106                 {
107                     recorderOutputFile << "Rx : \n";
108                 }
109                 for (const auto& word : std::get<FlightRecorderData>(message))
110                 {
111                     recorderOutputFile << std::setfill('0') << std::setw(2)
112                                        << std::hex << (unsigned)word << " ";
113                 }
114                 recorderOutputFile << std::endl;
115             }
116             recorderOutputFile.close();
117         }
118         else
119         {
120             error("Fight recorder policy is disabled");
121         }
122     }
123 };
124 
125 } // namespace flightrecorder
126 } // namespace pldm
127