1 /** 2 * Copyright © 2021 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include "flight_recorder.hpp" 17 18 #include <phosphor-logging/log.hpp> 19 20 #include <algorithm> 21 #include <ctime> 22 #include <format> 23 #include <iomanip> 24 #include <sstream> 25 #include <vector> 26 27 constexpr auto maxEntriesPerID = 40; 28 29 namespace phosphor::fan::control::json 30 { 31 using json = nlohmann::json; 32 33 FlightRecorder& FlightRecorder::instance() 34 { 35 static FlightRecorder fr; 36 return fr; 37 } 38 39 void FlightRecorder::log(const std::string& id, const std::string& message) 40 { 41 uint64_t ts = std::chrono::duration_cast<std::chrono::microseconds>( 42 std::chrono::system_clock::now().time_since_epoch()) 43 .count(); 44 45 auto& entry = _entries[id]; 46 entry.emplace_back(ts, message); 47 if (entry.size() > maxEntriesPerID) 48 { 49 entry.pop_front(); 50 } 51 } 52 53 void FlightRecorder::dump(json& data) 54 { 55 using namespace std::chrono; 56 using Timepoint = time_point<system_clock, microseconds>; 57 58 size_t idSize = 0; 59 std::vector<std::tuple<Timepoint, std::string, std::string>> output; 60 61 for (const auto& [id, messages] : _entries) 62 { 63 for (const auto& [ts, msg] : messages) 64 { 65 idSize = std::max(idSize, id.size()); 66 Timepoint tp{microseconds{ts}}; 67 output.emplace_back(tp, id, msg); 68 } 69 } 70 71 std::sort(output.begin(), output.end(), 72 [](const auto& left, const auto& right) { 73 return std::get<Timepoint>(left) < std::get<Timepoint>(right); 74 }); 75 76 auto formatTime = [](const Timepoint& tp) { 77 std::stringstream ss; 78 std::time_t tt = system_clock::to_time_t(tp); 79 uint64_t us = 80 duration_cast<microseconds>(tp.time_since_epoch()).count(); 81 82 // e.g. Oct 04 16:43:45.923555 83 ss << std::put_time(std::localtime(&tt), "%b %d %H:%M:%S."); 84 ss << std::setfill('0') << std::setw(6) << std::to_string(us % 1000000); 85 return ss.str(); 86 }; 87 88 auto& fr = data["flight_recorder"]; 89 std::stringstream ss; 90 91 for (const auto& [ts, id, msg] : output) 92 { 93 ss << formatTime(ts) << ": " << std::setw(idSize) << id << ": " << msg; 94 fr.push_back(ss.str()); 95 ss.str(""); 96 } 97 } 98 99 } // namespace phosphor::fan::control::json 100