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