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 <fmt/format.h> 19 20 #include <phosphor-logging/log.hpp> 21 22 #include <algorithm> 23 #include <ctime> 24 #include <iomanip> 25 #include <sstream> 26 #include <vector> 27 28 constexpr auto maxEntriesPerID = 20; 29 30 namespace phosphor::fan::control::json 31 { 32 using json = nlohmann::json; 33 34 FlightRecorder& FlightRecorder::instance() 35 { 36 static FlightRecorder fr; 37 return fr; 38 } 39 40 void FlightRecorder::log(const std::string& id, const std::string& message) 41 { 42 uint64_t ts = std::chrono::duration_cast<std::chrono::microseconds>( 43 std::chrono::system_clock::now().time_since_epoch()) 44 .count(); 45 46 auto& entry = _entries[id]; 47 entry.emplace_back(ts, message); 48 if (entry.size() > maxEntriesPerID) 49 { 50 entry.pop_front(); 51 } 52 } 53 54 void FlightRecorder::dump(json& data) 55 { 56 using namespace std::chrono; 57 using Timepoint = time_point<system_clock, microseconds>; 58 59 size_t idSize = 0; 60 std::vector<std::tuple<Timepoint, std::string, std::string>> output; 61 62 for (const auto& [id, messages] : _entries) 63 { 64 for (const auto& [ts, msg] : messages) 65 { 66 idSize = std::max(idSize, id.size()); 67 Timepoint tp{microseconds{ts}}; 68 output.emplace_back(tp, id, msg); 69 } 70 } 71 72 std::sort(output.begin(), output.end(), 73 [](const auto& left, const auto& right) { 74 return std::get<Timepoint>(left) < std::get<Timepoint>(right); 75 }); 76 77 auto formatTime = [](const Timepoint& tp) { 78 std::stringstream ss; 79 std::time_t tt = system_clock::to_time_t(tp); 80 uint64_t us = 81 duration_cast<microseconds>(tp.time_since_epoch()).count(); 82 83 // e.g. Oct 04 16:43:45.923555 84 ss << std::put_time(std::localtime(&tt), "%b %d %H:%M:%S."); 85 ss << std::setfill('0') << std::setw(6) << std::to_string(us % 1000000); 86 return ss.str(); 87 }; 88 89 auto& fr = data["flight_recorder"]; 90 std::stringstream ss; 91 92 for (const auto& [ts, id, msg] : output) 93 { 94 ss << formatTime(ts) << ": " << std::setw(idSize) << id << ": " << msg; 95 fr.push_back(ss.str()); 96 ss.str(""); 97 } 98 } 99 100 } // namespace phosphor::fan::control::json 101