1 #pragma once 2 3 #include "elog_block.hpp" 4 #include "elog_entry.hpp" 5 #include "xyz/openbmc_project/Collection/DeleteAll/server.hpp" 6 #include "xyz/openbmc_project/Logging/Create/server.hpp" 7 #include "xyz/openbmc_project/Logging/Entry/server.hpp" 8 #include "xyz/openbmc_project/Logging/Internal/Manager/server.hpp" 9 10 #include <list> 11 #include <phosphor-logging/log.hpp> 12 #include <sdbusplus/bus.hpp> 13 14 namespace phosphor 15 { 16 namespace logging 17 { 18 19 extern const std::map<std::string, std::vector<std::string>> g_errMetaMap; 20 extern const std::map<std::string, level> g_errLevelMap; 21 22 using CreateIface = sdbusplus::xyz::openbmc_project::Logging::server::Create; 23 using DeleteAllIface = 24 sdbusplus::xyz::openbmc_project::Collection::server::DeleteAll; 25 26 namespace details 27 { 28 template <typename... T> 29 using ServerObject = typename sdbusplus::server::object_t<T...>; 30 31 using ManagerIface = 32 sdbusplus::xyz::openbmc_project::Logging::Internal::server::Manager; 33 34 } // namespace details 35 36 constexpr size_t ffdcFormatPos = 0; 37 constexpr size_t ffdcSubtypePos = 1; 38 constexpr size_t ffdcVersionPos = 2; 39 constexpr size_t ffdcFDPos = 3; 40 41 using FFDCEntry = std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t, 42 sdbusplus::message::unix_fd>; 43 44 using FFDCEntries = std::vector<FFDCEntry>; 45 46 namespace internal 47 { 48 49 /** @class Manager 50 * @brief OpenBMC logging manager implementation. 51 * @details A concrete implementation for the 52 * xyz.openbmc_project.Logging.Internal.Manager DBus API. 53 */ 54 class Manager : public details::ServerObject<details::ManagerIface> 55 { 56 public: 57 Manager() = delete; 58 Manager(const Manager&) = delete; 59 Manager& operator=(const Manager&) = delete; 60 Manager(Manager&&) = delete; 61 Manager& operator=(Manager&&) = delete; 62 virtual ~Manager() = default; 63 64 /** @brief Constructor to put object onto bus at a dbus path. 65 * @param[in] bus - Bus to attach to. 66 * @param[in] path - Path to attach at. 67 */ 68 Manager(sdbusplus::bus_t& bus, const char* objPath) : 69 details::ServerObject<details::ManagerIface>(bus, objPath), busLog(bus), 70 entryId(0), fwVersion(readFWVersion()){}; 71 72 /* 73 * @fn commit() 74 * @brief sd_bus Commit method implementation callback. 75 * @details Create an error/event log based on transaction id and 76 * error message. 77 * @param[in] transactionId - Unique identifier of the journal entries 78 * to be committed. 79 * @param[in] errMsg - The error exception message associated with the 80 * error log to be committed. 81 */ 82 uint32_t commit(uint64_t transactionId, std::string errMsg) override; 83 84 /* 85 * @fn commit() 86 * @brief sd_bus CommitWithLvl method implementation callback. 87 * @details Create an error/event log based on transaction id and 88 * error message. 89 * @param[in] transactionId - Unique identifier of the journal entries 90 * to be committed. 91 * @param[in] errMsg - The error exception message associated with the 92 * error log to be committed. 93 * @param[in] errLvl - level of the error 94 */ 95 uint32_t commitWithLvl(uint64_t transactionId, std::string errMsg, 96 uint32_t errLvl) override; 97 98 /** @brief Erase specified entry d-bus object 99 * 100 * @param[in] entryId - unique identifier of the entry 101 */ 102 void erase(uint32_t entryId); 103 104 /** @brief Construct error d-bus objects from their persisted 105 * representations. 106 */ 107 void restore(); 108 109 /** @brief Erase all error log entries 110 * 111 */ 112 void eraseAll() 113 { 114 auto iter = entries.begin(); 115 while (iter != entries.end()) 116 { 117 auto e = iter->first; 118 ++iter; 119 erase(e); 120 } 121 entryId = 0; 122 } 123 124 /** @brief Returns the count of high severity errors 125 * 126 * @return int - count of real errors 127 */ 128 int getRealErrSize(); 129 130 /** @brief Returns the count of Info errors 131 * 132 * @return int - count of info errors 133 */ 134 int getInfoErrSize(); 135 136 /** @brief Returns the number of blocking errors 137 * 138 * @return int - count of blocking errors 139 */ 140 int getBlockingErrSize() 141 { 142 return blockingErrors.size(); 143 } 144 145 /** @brief Returns the number of property change callback objects 146 * 147 * @return int - count of property callback entries 148 */ 149 int getEntryCallbackSize() 150 { 151 return propChangedEntryCallback.size(); 152 } 153 154 /** 155 * @brief Returns the sdbusplus bus object 156 * 157 * @return sdbusplus::bus_t& 158 */ 159 sdbusplus::bus_t& getBus() 160 { 161 return busLog; 162 } 163 164 /** 165 * @brief Returns the ID of the last created entry 166 * 167 * @return uint32_t - The ID 168 */ 169 uint32_t lastEntryID() const 170 { 171 return entryId; 172 } 173 174 /** @brief Creates an event log 175 * 176 * This is an alternative to the _commit() API. It doesn't use 177 * the journal to look up event log metadata like _commit does. 178 * 179 * @param[in] errMsg - The error exception message associated with the 180 * error log to be committed. 181 * @param[in] severity - level of the error 182 * @param[in] additionalData - The AdditionalData property for the error 183 */ 184 void create( 185 const std::string& message, 186 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity, 187 const std::map<std::string, std::string>& additionalData); 188 189 /** @brief Creates an event log, and accepts FFDC files 190 * 191 * This is the same as create(), but also takes an FFDC argument. 192 * 193 * The FFDC argument is a vector of tuples that allows one to pass in file 194 * descriptors for files that contain FFDC (First Failure Data Capture). 195 * These will be passed to any event logging extensions. 196 * 197 * @param[in] errMsg - The error exception message associated with the 198 * error log to be committed. 199 * @param[in] severity - level of the error 200 * @param[in] additionalData - The AdditionalData property for the error 201 * @param[in] ffdc - A vector of FFDC file info 202 */ 203 void createWithFFDC( 204 const std::string& message, 205 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity, 206 const std::map<std::string, std::string>& additionalData, 207 const FFDCEntries& ffdc); 208 209 /** @brief Common wrapper for creating an Entry object 210 * 211 * @return true if quiesce on error setting is enabled, false otherwise 212 */ 213 bool isQuiesceOnErrorEnabled(); 214 215 /** @brief Create boot block association and quiesce host if running 216 * 217 * @param[in] entryId - The ID of the phosphor logging error 218 */ 219 void quiesceOnError(const uint32_t entryId); 220 221 /** @brief Check if inventory callout present in input entry 222 * 223 * @param[in] entry - The error to check for callouts 224 * 225 * @return true if inventory item in associations, false otherwise 226 */ 227 bool isCalloutPresent(const Entry& entry); 228 229 /** @brief Check (and remove) entry being erased from blocking errors 230 * 231 * @param[in] entryId - The entry that is being erased 232 */ 233 void checkAndRemoveBlockingError(uint32_t entryId); 234 235 /** @brief Persistent map of Entry dbus objects and their ID */ 236 std::map<uint32_t, std::unique_ptr<Entry>> entries; 237 238 private: 239 /* 240 * @fn _commit() 241 * @brief commit() helper 242 * @param[in] transactionId - Unique identifier of the journal entries 243 * to be committed. 244 * @param[in] errMsg - The error exception message associated with the 245 * error log to be committed. 246 * @param[in] errLvl - level of the error 247 */ 248 void _commit(uint64_t transactionId, std::string&& errMsg, 249 Entry::Level errLvl); 250 251 /** @brief Call metadata handler(s), if any. Handlers may create 252 * associations. 253 * @param[in] errorName - name of the error 254 * @param[in] additionalData - list of metadata (in key=value format) 255 * @param[out] objects - list of error's association objects 256 */ 257 void processMetadata(const std::string& errorName, 258 const std::vector<std::string>& additionalData, 259 AssociationList& objects) const; 260 261 /** @brief Synchronize unwritten journal messages to disk. 262 * @details This is the same implementation as the systemd command 263 * "journalctl --sync". 264 */ 265 void journalSync(); 266 267 /** @brief Reads the BMC code level 268 * 269 * @return std::string - the version string 270 */ 271 static std::string readFWVersion(); 272 273 /** @brief Call any create() functions provided by any extensions. 274 * This is called right after an event log is created to allow 275 * extensions to create their own log based on this one. 276 * 277 * @param[in] entry - the new event log entry 278 * @param[in] ffdc - A vector of FFDC file info 279 */ 280 void doExtensionLogCreate(const Entry& entry, const FFDCEntries& ffdc); 281 282 /** @brief Common wrapper for creating an Entry object 283 * 284 * @param[in] errMsg - The error exception message associated with the 285 * error log to be committed. 286 * @param[in] errLvl - level of the error 287 * @param[in] additionalData - The AdditionalData property for the error 288 * @param[in] ffdc - A vector of FFDC file info. Defaults to an empty 289 * vector. 290 */ 291 void createEntry(std::string errMsg, Entry::Level errLvl, 292 std::vector<std::string> additionalData, 293 const FFDCEntries& ffdc = FFDCEntries{}); 294 295 /** @brief Notified on entry property changes 296 * 297 * If an entry is blocking, this callback will be registered to monitor for 298 * the entry having it's Resolved field set to true. If it is then remove 299 * the blocking object. 300 * 301 * @param[in] msg - sdbusplus dbusmessage 302 */ 303 void onEntryResolve(sdbusplus::message_t& msg); 304 305 /** @brief Remove block objects for any resolved entries */ 306 void findAndRemoveResolvedBlocks(); 307 308 /** @brief Quiesce host if it is running 309 * 310 * This is called when the user has requested the system be quiesced 311 * if a log with a callout is created 312 */ 313 void checkAndQuiesceHost(); 314 315 /** @brief Persistent sdbusplus DBus bus connection. */ 316 sdbusplus::bus_t& busLog; 317 318 /** @brief List of error ids for high severity errors */ 319 std::list<uint32_t> realErrors; 320 321 /** @brief List of error ids for Info(and below) severity */ 322 std::list<uint32_t> infoErrors; 323 324 /** @brief Id of last error log entry */ 325 uint32_t entryId; 326 327 /** @brief The BMC firmware version */ 328 const std::string fwVersion; 329 330 /** @brief Array of blocking errors */ 331 std::vector<std::unique_ptr<Block>> blockingErrors; 332 333 /** @brief Map of entry id to call back object on properties changed */ 334 std::map<uint32_t, std::unique_ptr<sdbusplus::bus::match_t>> 335 propChangedEntryCallback; 336 }; 337 338 } // namespace internal 339 340 /** @class Manager 341 * @brief Implementation for deleting all error log entries and 342 * creating new logs. 343 * @details A concrete implementation for the 344 * xyz.openbmc_project.Collection.DeleteAll and 345 * xyz.openbmc_project.Logging.Create interfaces. 346 */ 347 class Manager : public details::ServerObject<DeleteAllIface, CreateIface> 348 { 349 public: 350 Manager() = delete; 351 Manager(const Manager&) = delete; 352 Manager& operator=(const Manager&) = delete; 353 Manager(Manager&&) = delete; 354 Manager& operator=(Manager&&) = delete; 355 virtual ~Manager() = default; 356 357 /** @brief Constructor to put object onto bus at a dbus path. 358 * Defer signal registration (pass true for deferSignal to the 359 * base class) until after the properties are set. 360 * @param[in] bus - Bus to attach to. 361 * @param[in] path - Path to attach at. 362 * @param[in] manager - Reference to internal manager object. 363 */ 364 Manager(sdbusplus::bus_t& bus, const std::string& path, 365 internal::Manager& manager) : 366 details::ServerObject<DeleteAllIface, CreateIface>( 367 bus, path.c_str(), 368 details::ServerObject<DeleteAllIface, 369 CreateIface>::action::defer_emit), 370 manager(manager){}; 371 372 /** @brief Delete all d-bus objects. 373 */ 374 void deleteAll() override 375 { 376 log<level::INFO>("Deleting all log entries"); 377 manager.eraseAll(); 378 } 379 380 /** @brief D-Bus method call implementation to create an event log. 381 * 382 * @param[in] errMsg - The error exception message associated with the 383 * error log to be committed. 384 * @param[in] severity - Level of the error 385 * @param[in] additionalData - The AdditionalData property for the error 386 */ 387 void create( 388 std::string message, 389 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity, 390 std::map<std::string, std::string> additionalData) override 391 { 392 manager.create(message, severity, additionalData); 393 } 394 395 /** @brief D-Bus method call implementation to create an event log with FFDC 396 * 397 * The same as create(), but takes an extra FFDC argument. 398 * 399 * @param[in] errMsg - The error exception message associated with the 400 * error log to be committed. 401 * @param[in] severity - Level of the error 402 * @param[in] additionalData - The AdditionalData property for the error 403 * @param[in] ffdc - A vector of FFDC file info 404 */ 405 void createWithFFDCFiles( 406 std::string message, 407 sdbusplus::xyz::openbmc_project::Logging::server::Entry::Level severity, 408 std::map<std::string, std::string> additionalData, 409 std::vector<std::tuple<CreateIface::FFDCFormat, uint8_t, uint8_t, 410 sdbusplus::message::unix_fd>> 411 ffdc) override 412 { 413 manager.createWithFFDC(message, severity, additionalData, ffdc); 414 } 415 416 private: 417 /** @brief This is a reference to manager object */ 418 internal::Manager& manager; 419 }; 420 421 } // namespace logging 422 } // namespace phosphor 423