1# phosphor-logging 2 3The phosphor logging repository provides mechanisms for event and journal 4logging. 5 6## Table Of Contents 7 8- [Building](#to-build) 9- [Structured Logging](#structured-logging) 10- [Event Logs](#event-logs) 11- [Event Log Extensions](#event-log-extensions) 12- [Remote Logging](#remote-logging-via-rsyslog) 13- [Boot Fail on Hardware Errors](#boot-fail-on-hardware-errors) 14 15## To Build 16 17To build this package, do the following steps: 18 191. meson builddir 202. ninja -c builddir 21 22## Structured Logging 23 24phosphor-logging provides APIs to add program logging information to the 25systemd-journal and it is preferred that this logging data is formatted in a 26structured manner (using the facilities provided by the APIs). 27 28See [Structured Logging](./docs/structured-logging.md) for more details on this 29API. 30 31## Event Logs 32 33OpenBMC event logs are a collection of D-Bus interfaces owned by 34phosphor-log-manager that reside at `/xyz/openbmc_project/logging/entry/X`, 35where X starts at 1 and is incremented for each new log. 36 37The interfaces are: 38 39- [xyz.openbmc_project.Logging.Entry] 40 - The main event log interface. 41- [xyz.openbmc_project.Association.Definitions] 42 - Used for specifying inventory items as the cause of the event. 43 - For more information on associations, see the [associations 44 doc][associations-doc]. 45- [xyz.openbmc_project.Object.Delete] 46 - Provides a Delete method to delete the event. 47- [xyz.openbmc_project.Software.Version] 48 - Stores the code version that the error occurred on. 49 50On platforms that make use of these event logs, the intent is that they are the 51common event log representation that other types of event logs can be created 52from. For example, there is code to convert these into both Redfish and IPMI 53event logs, in addition to the event log extensions mentioned 54[below](#event-log-extensions). 55 56The logging daemon has the ability to add `callout` associations to an event log 57based on text in the AdditionalData property. A callout is a link to the 58inventory item(s) that were the cause of the event log. See [callout 59doc][callout-doc] for details. 60 61### Creating Event Logs In Code 62 63The preferred method for creating event logs is specified in the project-level 64[event log design][event-log-design]. Events are defined using YAML in the 65phosphor-dbus-interfaces repository, such as the 66[Logging.Cleared][logging-cleared] event, which will generate a C++ class for 67the event. Then a call to `lg2::commit` is made on a constructed event to add it 68to the event log. 69 70```cpp 71lg2::commit(sdbusplus::event::xyz::openbmc_project::Logging::Cleared( 72 "NUMBER_OF_LOGS", count)); 73``` 74 75The above function will return the object path of the created log entry. This 76log-entry can be resolved with the helper `lg2::resolve` fuction. 77 78```cpp 79lg2::resolve(logPath); 80``` 81 82### Event Log Filtering 83 84Vendors customizing phosphor-logging for their platforms may decide that they 85would like to prevent certain events from being added to the event log. This is 86especially true for informational / tracing events. The `lg2::commit` supports a 87compile-time event filtering mechanism that can accomplish this. 88 89The meson option `event-filter` can be used to specify a file containing 90filtering policy. When left unspecified, the [default 91policy][default-policy-json] of "allow all" is enabled. For both events and 92errors, a default policy of "allowed" or "blocked" can be specified and an 93additional set of events can be given for which the non-defaulted action should 94be taken. A JSON-Schema is available for the [policy 95JSON][filter-policy-schema]. 96 97[default-policy-json]: 98 https://github.com/openbmc/phosphor-logging/blob/master/tools/phosphor-logging/default-eventfilter.json 99[filter-policy-schema]: 100 https://github.com/openbmc/phosphor-logging/blob/master/tools/phosphor-logging/schemas/eventfilter.schema.yaml 101 102### Deprecated Methods for Creating Event Logs 103 104There are two other, but now deprecated, methods to creating event logs in 105OpenBMC code. The first makes use of the systemd journal to store metadata 106needed for the log, and the second is a plain D-Bus method call. 107 108[event-log-design]: 109 https://github.com/openbmc/docs/blob/master/designs/event-logging.md#phosphor-logging 110[logging-cleared]: 111 https://github.com/openbmc/phosphor-dbus-interfaces/blob/6a8507d06e172d8d29c0459f0a0d078553d2ecc7/yaml/xyz/openbmc_project/Logging.events.yaml#L4 112 113#### Journal Based Event Log Creation [deprecated] 114 115Event logs can be created by using phosphor-logging APIs to commit sdbusplus 116exceptions. These APIs write to the journal, and then call a `Commit` D-Bus 117method on the logging daemon to create the event log using the information it 118put in the journal. 119 120The APIs are found in `<phosphor-logging/elog.hpp>`: 121 122- `elog()`: Throw an sdbusplus error. 123- `commit()`: Catch an error thrown by elog(), and commit it to create the event 124 log. 125- `report()`: Create an event log from an sdbusplus error without throwing the 126 exception first. 127 128Any errors passed into these APIs must be known to phosphor-logging, usually by 129being defined in `<phosphor-logging/elog-errors.hpp>`. The errors must also be 130known by sdbusplus, and be defined in their corresponding error.hpp. See below 131for details on how get errors into these headers. 132 133Example: 134 135```cpp 136#include <phosphor-logging/elog-errors.hpp> 137#include <phosphor-logging/elog.hpp> 138#include <xyz/openbmc_project/Common/error.hpp> 139... 140using InternalFailure = 141 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 142... 143if (somethingBadHappened) 144{ 145 phosphor::logging::report<InternalFailure>(); 146} 147 148``` 149 150Alternatively, to throw, catch, and then commit the error: 151 152```cpp 153try 154{ 155 phosphor::logging::elog<InternalFailure>(); 156} 157catch (InternalFailure& e) 158{ 159 phosphor::logging::commit<InternalFailure>(); 160} 161``` 162 163Metadata can be added to event logs to add debug data captured at the time of 164the event. It shows up in the AdditionalData property in the 165`xyz.openbmc_project.Logging.Entry` interface. Metadata is passed in via the 166`elog()` or `report()` functions, which write it to the journal. The metadata 167must be predefined for the error in the metadata YAML so that the daemon knows 168to look for it in the journal when it creates the event log. 169 170Example: 171 172```cpp 173#include <phosphor-logging/elog-errors.hpp> 174#include <phosphor-logging/elog.hpp> 175#include <xyz/openbmc_project/Control/Device/error.hpp> 176... 177using WriteFailure = 178 sdbusplus::xyz::openbmc_project::Control::Device::Error::WriteFailure; 179using metadata = 180 phosphor::logging::xyz::openbmc_project::Control::Device::WriteFailure; 181... 182if (somethingBadHappened) 183{ 184 phosphor::logging::report<WriteFailure>(metadata::CALLOUT_ERRNO(5), 185 metadata::CALLOUT_DEVICE_PATH("some path")); 186} 187``` 188 189In the above example, the AdditionalData property would look like: 190 191```cpp 192["CALLOUT_ERRNO=5", "CALLOUT_DEVICE_PATH=some path"] 193``` 194 195Note that the metadata fields must be all uppercase. 196 197##### Event Log Definition [deprecated] 198 199As mentioned above, both sdbusplus and phosphor-logging must know about the 200event logs in their header files, or the code that uses them will not even 201compile. The standard way to do this to define the event in the appropriate 202`<error-category>.errors.yaml` file, and define any metadata in the 203`<error-category>.metadata.yaml` file in the appropriate `*-dbus-interfaces` 204repository. During the build, phosphor-logging generates the elog-errors.hpp 205file for use by the calling code. 206 207In much the same way, sdbusplus uses the event log definitions to generate an 208error.hpp file that contains the specific exception. The path of the error.hpp 209matches the path of the YAML file. 210 211For example, if in phosphor-dbus-interfaces there is 212`xyz/openbmc_project/Control/Device.errors.yaml`, the errors that come from that 213file will be in the include: `xyz/openbmc_project/Control/Device/error.hpp`. 214 215In rare cases, one may want one to define their errors in the same repository 216that uses them. To do that, one must: 217 2181. Add the error and metadata YAML files to the repository. 2192. Run the sdbus++ script within the makefile to create the error.hpp and .cpp 220 files from the local YAML, and include the error.cpp file in the application 221 that uses it. See [openpower-occ-control] for an example. 2223. Tell phosphor-logging about the error: 223 1. Run phosphor-logging's `elog-gen.py` script on the local yaml to generate 224 an elog-errors.hpp file that just contains the local errors, and check 225 that into the repository and include it where the errors are needed. 226 2. Create a recipe that copies the local YAML files to a place that 227 phosphor-logging can find it during the build. See sample [LED 228 YAML][led-link] for an example. 229 230#### D-Bus Event Log Creation [deprecated] 231 232There is also a [D-Bus method][log-create-link] to create event logs: 233 234- Service: xyz.openbmc_project.Logging 235- Object Path: /xyz/openbmc_project/logging 236- Interface: xyz.openbmc_project.Logging.Create 237- Method: Create 238 - Method Arguments: 239 - Message: The `Message` string property for the 240 `xyz.openbmc_project.Logging.Entry` interface. 241 - Severity: The `severity` property for the 242 `xyz.openbmc_project.Logging.Entry` interface. An 243 `xyz.openbmc_project.Logging.Entry.Level` enum value. 244 - AdditionalData: The `AdditionalData` property for the 245 `xyz.openbmc_project.Logging.Entry` interface, but in a map instead of in 246 a vector of "KEY=VALUE" strings. Example: 247 248```cpp 249 std::map<std::string, std::string> additionalData; 250 additionalData["KEY"] = "VALUE"; 251``` 252 253Unlike the previous APIs where errors could also act as exceptions that could be 254thrown across D-Bus, this API does not require that the error be defined in the 255error YAML in the D-Bus interfaces repository so that sdbusplus knows about it. 256Additionally, as this method passes in everything needed to create the event 257log, the logging daemon doesn't have to know about it ahead of time either. 258 259That being said, it is recommended that users of this API still follow some 260guidelines for the message field, which is normally generated from a combination 261of the path to the error YAML file and the error name itself. For example, the 262`Timeout` error in `xyz/openbmc_project/Common.errors.yaml` will have a Message 263property of `xyz.openbmc_project.Common.Error.Timeout`. 264 265The guidelines are: 266 2671. When it makes sense, one can still use an existing error that has already 268 been defined in an error YAML file, and use the same severity and metadata 269 (AdditionalData) as in the corresponding metadata YAML file. 270 2712. If creating a new error, use the same naming scheme as other errors, which 272 starts with the domain, `xyz.openbmc_project`, `org.open_power`, etc, 273 followed by the capitalized category values, followed by `Error`, followed by 274 the capitalized error name itself, with everything separated by "."s. For 275 example: `xyz.openbmc_project.Some.Category.Error.Name`. 276 2773. If creating a new common error, still add it to the appropriate error and 278 metadata YAML files in the appropriate D-Bus interfaces repository so that 279 others can know about it and use it in the future. This can be done after the 280 fact. 281 282[xyz.openbmc_project.logging.entry]: 283 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Entry.interface.yaml 284[xyz.openbmc_project.association.definitions]: 285 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Association/Definitions.interface.yaml 286[associations-doc]: 287 https://github.com/openbmc/docs/blob/master/architecture/object-mapper.md#associations 288[callout-doc]: 289 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Common/Callout/README.md 290[xyz.openbmc_project.object.delete]: 291 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Object/Delete.interface.yaml 292[xyz.openbmc_project.software.version]: 293 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Software/Version.errors.yaml 294[openpower-occ-control]: https://github.com/openbmc/openpower-occ-control 295[led-link]: 296 https://github.com/openbmc/openbmc/tree/master/meta-phosphor/recipes-phosphor/leds 297[log-create-link]: 298 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Create.interface.yaml 299 300## Event Log Extensions 301 302The extension concept is a way to allow code that creates other formats of error 303logs besides phosphor-logging's event logs to still reside in the 304phosphor-log-manager application. 305 306The extension code lives in the `extensions/<extension>` subdirectories, and is 307enabled with a `--enable-<extension>` configure flag. The extension code won't 308compile unless enabled with this flag. 309 310Extensions can register themselves to have functions called at the following 311points using the REGISTER_EXTENSION_FUNCTION macro. 312 313- On startup 314 - Function type void(internal::Manager&) 315- After an event log is created 316 - Function type void(args) 317 - The args are: 318 - const std::string& - The Message property 319 - uin32_t - The event log ID 320 - uint64_t - The event log timestamp 321 - Level - The event level 322 - const AdditionalDataArg& - the additional data 323 - const AssociationEndpointsArg& - Association endpoints (callouts) 324- Before an event log is deleted, to check if it is allowed. 325 - Function type void(std::uint32_t, bool&) that takes the event ID 326- After an event log is deleted 327 - Function type void(std::uint32_t) that takes the event ID 328 329Using these callback points, they can create their own event log for each 330OpenBMC event log that is created, and delete these logs when the corresponding 331OpenBMC event log is deleted. 332 333In addition, an extension has the option of disabling phosphor-logging's default 334error log capping policy so that it can use its own. The macro 335DISABLE_LOG_ENTRY_CAPS() is used for that. 336 337### Motivation 338 339The reason for adding support for extensions inside the phosphor-log-manager 340daemon as opposed to just creating new daemons that listen for D-Bus signals is 341to allow interactions that would be complicated or expensive if just done over 342D-Bus, such as: 343 344- Allowing for custom old log retention algorithms. 345- Prohibiting manual deleting of certain logs based on an extension's 346 requirements. 347 348### Creating extensions 349 3501. Add a new flag to configure.ac to enable the extension: 351 352 ```autoconf 353 AC_ARG_ENABLE([foo-extension], 354 AS_HELP_STRING([--enable-foo-extension], 355 [Create Foo logs])) 356 AM_CONDITIONAL([ENABLE_FOO_EXTENSION], 357 [test "x$enable_foo_extension" == "xyes"]) 358 ``` 359 3602. Add the code in `extensions/<extension>/`. 3613. Create a makefile include to add the new code to phosphor-log-manager: 362 363 ```make 364 phosphor_log_manager_SOURCES += \ 365 extensions/foo/foo.cpp 366 ``` 367 3684. In `extensions/extensions.mk`, add the makefile include: 369 370 ```make 371 if ENABLE_FOO_EXTENSION 372 include extensions/foo/foo.mk 373 endif 374 ``` 375 3765. In the extension code, register the functions to call and optionally disable 377 log capping using the provided macros: 378 379 ```cpp 380 DISABLE_LOG_ENTRY_CAPS(); 381 382 void fooStartup(internal::Manager& manager) 383 { 384 // Initialize 385 } 386 387 REGISTER_EXTENSION_FUNCTION(fooStartup); 388 389 void fooCreate(const std::string& message, uint32_t id, uint64_t timestamp, 390 Entry::Level severity, const AdditionalDataArg& additionalData, 391 const AssociationEndpointsArg& assocs) 392 { 393 // Create a different type of error log based on 'entry'. 394 } 395 396 REGISTER_EXTENSION_FUNCTION(fooCreate); 397 398 void fooRemove(uint32_t id) 399 { 400 // Delete the extension error log that corresponds to 'id'. 401 } 402 403 REGISTER_EXTENSION_FUNCTION(fooRemove); 404 ``` 405 406### Extension List 407 408The supported extensions are: 409 410- OpenPower PELs 411 - Enabled with --enable-openpower-pel-extension 412 - Detailed information can be found in 413 [extensions/openpower-pels](extensions/openpower-pels/README.md). 414 415## Remote Logging via Rsyslog 416 417The BMC has the ability to stream out local logs (that go to the systemd 418journal) via rsyslog (<https://www.rsyslog.com/>). 419 420The BMC will send everything. Any kind of filtering and appropriate storage will 421have to be managed on the rsyslog server. Various examples are available on the 422internet. Here are few pointers : 423<https://www.rsyslog.com/storing-and-forwarding-remote-messages/> 424<https://www.rsyslog.com/doc/rsyslog%255Fconf%255Ffilter.html> 425<https://www.thegeekdiary.com/understanding-rsyslog-filter-options/> 426 427### Configuring rsyslog server for remote logging 428 429The BMC is an rsyslog client. To stream out logs, it needs to talk to an rsyslog 430server, to which there's connectivity over a network. REST API can be used to 431set the remote server's IP address and port number. 432 433The following presumes a user has logged on to the BMC (see 434<https://github.com/openbmc/docs/blob/master/rest-api.md>). 435 436Set the IP: 437 438```sh 439curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 440 -d '{"data": <IP address>}' \ 441 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Address 442``` 443 444Set the port: 445 446```sh 447curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 448 -d '{"data": <port number>}' \ 449 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Port 450``` 451 452#### Querying the current configuration 453 454```sh 455curl -b cjar -k \ 456 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote 457``` 458 459#### Setting the hostname 460 461Rsyslog can store logs separately for each host. For this reason, it's useful to 462provide a unique hostname to each managed BMC. Here's how that can be done via a 463REST API : 464 465```sh 466curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 467 -d '{"data": "myHostName"}' \ 468 https://<BMC IP address>//xyz/openbmc_project/network/config/attr/HostName 469``` 470 471#### Disabling remote logging 472 473Remote logging can be disabled by writing 0 to the port, or an empty string("") 474to the IP. 475 476#### Changing the rsyslog server 477 478When switching to a new server from an existing one (i.e the address, or port, 479or both change), it is recommended to disable the existing configuration first. 480 481## Boot Fail on Hardware Errors 482 483phosphor-logging supports a setting, which when set, will result in the software 484looking at new phosphor-logging entries being created, and if a CALLOUT\* is 485found within the entry, ensuring the system will not power on. Entries with 486severities of Informational or Debug will not block boots, even if they have 487callouts. 488 489The full design for this can be found in 490[docs](https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md). 491 492To enable this function: 493 494```sh 495busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/logging/settings xyz.openbmc_project.Logging.Settings QuiesceOnHwError b true 496``` 497 498To check if an entry is blocking the boot: 499 500```sh 501obmcutil listbootblock 502``` 503 504Resolve or clear the corresponding entry to allow the system to boot. 505