1 #include "log_id.hpp" 2 3 #include "paths.hpp" 4 5 #include <chrono> 6 #include <filesystem> 7 #include <fstream> 8 #include <phosphor-logging/log.hpp> 9 10 namespace openpower 11 { 12 namespace pels 13 { 14 15 namespace fs = std::filesystem; 16 using namespace phosphor::logging; 17 18 constexpr uint32_t startingLogID = 1; 19 constexpr uint32_t bmcLogIDPrefix = 0x50000000; 20 21 namespace detail 22 { 23 24 uint32_t addLogIDPrefix(uint32_t id) 25 { 26 // If redundant BMCs are ever a thing, may need a different prefix. 27 return (id & 0x00FFFFFF) | bmcLogIDPrefix; 28 } 29 30 uint32_t getTimeBasedLogID() 31 { 32 using namespace std::chrono; 33 34 // Use 3 bytes of the nanosecond count since the epoch. 35 uint32_t id = 36 duration_cast<nanoseconds>(system_clock::now().time_since_epoch()) 37 .count(); 38 39 return addLogIDPrefix(id); 40 } 41 42 } // namespace detail 43 44 uint32_t generatePELID() 45 { 46 // Note: there isn't a need to be thread safe. 47 48 static std::string idFilename; 49 if (idFilename.empty()) 50 { 51 idFilename = getPELIDFile(); 52 } 53 54 uint32_t id = 0; 55 56 if (!fs::exists(idFilename)) 57 { 58 auto path = fs::path(idFilename).parent_path(); 59 if (!fs::exists(path)) 60 { 61 fs::create_directories(path); 62 } 63 64 id = startingLogID; 65 } 66 else 67 { 68 std::ifstream idFile{idFilename}; 69 idFile >> id; 70 if (idFile.fail()) 71 { 72 // Just make up an ID 73 log<level::ERR>("Unable to read PEL ID File!"); 74 return detail::getTimeBasedLogID(); 75 } 76 } 77 78 // Wrapping shouldn't be a problem, but check anyway 79 if (id == 0x00FFFFFF) 80 { 81 id = startingLogID; 82 } 83 84 std::ofstream idFile{idFilename}; 85 idFile << (id + 1); 86 if (idFile.fail()) 87 { 88 // Just make up an ID so we don't reuse one next time 89 log<level::ERR>("Unable to write PEL ID File!"); 90 return detail::getTimeBasedLogID(); 91 } 92 93 return detail::addLogIDPrefix(id); 94 } 95 96 } // namespace pels 97 } // namespace openpower 98