113270967SMatt Spinler /**
213270967SMatt Spinler * Copyright © 2021 IBM Corporation
313270967SMatt Spinler *
413270967SMatt Spinler * Licensed under the Apache License, Version 2.0 (the "License");
513270967SMatt Spinler * you may not use this file except in compliance with the License.
613270967SMatt Spinler * You may obtain a copy of the License at
713270967SMatt Spinler *
813270967SMatt Spinler * http://www.apache.org/licenses/LICENSE-2.0
913270967SMatt Spinler *
1013270967SMatt Spinler * Unless required by applicable law or agreed to in writing, software
1113270967SMatt Spinler * distributed under the License is distributed on an "AS IS" BASIS,
1213270967SMatt Spinler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313270967SMatt Spinler * See the License for the specific language governing permissions and
1413270967SMatt Spinler * limitations under the License.
1513270967SMatt Spinler */
1613270967SMatt Spinler #include "flight_recorder.hpp"
1713270967SMatt Spinler
1813270967SMatt Spinler #include <phosphor-logging/log.hpp>
1913270967SMatt Spinler
2013270967SMatt Spinler #include <algorithm>
2113270967SMatt Spinler #include <ctime>
22*fbf4703fSPatrick Williams #include <format>
2313270967SMatt Spinler #include <iomanip>
247787def0SMatt Spinler #include <sstream>
2513270967SMatt Spinler #include <vector>
2613270967SMatt Spinler
274907daceSMatt Spinler constexpr auto maxEntriesPerID = 40;
2813270967SMatt Spinler
2913270967SMatt Spinler namespace phosphor::fan::control::json
3013270967SMatt Spinler {
317787def0SMatt Spinler using json = nlohmann::json;
3213270967SMatt Spinler
instance()3313270967SMatt Spinler FlightRecorder& FlightRecorder::instance()
3413270967SMatt Spinler {
3513270967SMatt Spinler static FlightRecorder fr;
3613270967SMatt Spinler return fr;
3713270967SMatt Spinler }
3813270967SMatt Spinler
log(const std::string & id,const std::string & message)3913270967SMatt Spinler void FlightRecorder::log(const std::string& id, const std::string& message)
4013270967SMatt Spinler {
4113270967SMatt Spinler uint64_t ts = std::chrono::duration_cast<std::chrono::microseconds>(
4213270967SMatt Spinler std::chrono::system_clock::now().time_since_epoch())
4313270967SMatt Spinler .count();
4413270967SMatt Spinler
4513270967SMatt Spinler auto& entry = _entries[id];
4613270967SMatt Spinler entry.emplace_back(ts, message);
4713270967SMatt Spinler if (entry.size() > maxEntriesPerID)
4813270967SMatt Spinler {
4913270967SMatt Spinler entry.pop_front();
5013270967SMatt Spinler }
5113270967SMatt Spinler }
5213270967SMatt Spinler
dump(json & data)537787def0SMatt Spinler void FlightRecorder::dump(json& data)
5413270967SMatt Spinler {
5513270967SMatt Spinler using namespace std::chrono;
5613270967SMatt Spinler using Timepoint = time_point<system_clock, microseconds>;
5713270967SMatt Spinler
5813270967SMatt Spinler size_t idSize = 0;
5913270967SMatt Spinler std::vector<std::tuple<Timepoint, std::string, std::string>> output;
6013270967SMatt Spinler
6113270967SMatt Spinler for (const auto& [id, messages] : _entries)
6213270967SMatt Spinler {
6313270967SMatt Spinler for (const auto& [ts, msg] : messages)
6413270967SMatt Spinler {
6513270967SMatt Spinler idSize = std::max(idSize, id.size());
6613270967SMatt Spinler Timepoint tp{microseconds{ts}};
6713270967SMatt Spinler output.emplace_back(tp, id, msg);
6813270967SMatt Spinler }
6913270967SMatt Spinler }
7013270967SMatt Spinler
7113270967SMatt Spinler std::sort(output.begin(), output.end(),
7213270967SMatt Spinler [](const auto& left, const auto& right) {
7313270967SMatt Spinler return std::get<Timepoint>(left) < std::get<Timepoint>(right);
7413270967SMatt Spinler });
7513270967SMatt Spinler
7613270967SMatt Spinler auto formatTime = [](const Timepoint& tp) {
7713270967SMatt Spinler std::stringstream ss;
7813270967SMatt Spinler std::time_t tt = system_clock::to_time_t(tp);
7913270967SMatt Spinler uint64_t us =
8013270967SMatt Spinler duration_cast<microseconds>(tp.time_since_epoch()).count();
8113270967SMatt Spinler
8213270967SMatt Spinler // e.g. Oct 04 16:43:45.923555
8313270967SMatt Spinler ss << std::put_time(std::localtime(&tt), "%b %d %H:%M:%S.");
8413270967SMatt Spinler ss << std::setfill('0') << std::setw(6) << std::to_string(us % 1000000);
8513270967SMatt Spinler return ss.str();
8613270967SMatt Spinler };
8713270967SMatt Spinler
887787def0SMatt Spinler auto& fr = data["flight_recorder"];
897787def0SMatt Spinler std::stringstream ss;
907787def0SMatt Spinler
9113270967SMatt Spinler for (const auto& [ts, id, msg] : output)
9213270967SMatt Spinler {
937787def0SMatt Spinler ss << formatTime(ts) << ": " << std::setw(idSize) << id << ": " << msg;
947787def0SMatt Spinler fr.push_back(ss.str());
957787def0SMatt Spinler ss.str("");
9613270967SMatt Spinler }
9713270967SMatt Spinler }
9813270967SMatt Spinler
9913270967SMatt Spinler } // namespace phosphor::fan::control::json
100