1# phosphor-logging 2The phosphor logging repository provides mechanisms for event and journal 3logging. 4 5## Table Of Contents 6* [Building](#to-build) 7* [Structured Logging](#structured-logging) 8* [Event Logs](#event-logs) 9* [Application Specific Error YAML](#adding-application-specific-error-yaml) 10* [Event Log Extensions](#event-log-extensions) 11* [Remote Logging](#remote-logging-via-rsyslog) 12* [Boot Fail on Hardware Errors](#boot-fail-on-hardware-errors) 13 14## To Build 15To build this package, do the following steps: 16 171. meson builddir 182. ninja -c builddir 19 20## Structured Logging 21phosphor-logging provides APIs to add program logging information to the 22systemd-journal and it is preferred that this logging data is formatted in 23a structured manner (using the facilities provided by the APIs). 24 25See [Structured Logging](./docs/structured-logging.md) for more details on 26this API. 27 28## Event Logs 29OpenBMC event logs are a collection of D-Bus interfaces owned by 30phosphor-log-manager that reside at `/xyz/openbmc_project/logging/entry/X`, 31where X starts at 1 and is incremented for each new log. 32 33The interfaces are: 34* [xyz.openbmc_project.Logging.Entry] 35 * The main event log interface. 36* [xyz.openbmc_project.Association.Definitions] 37 * Used for specifying inventory items as the cause of the event. 38 * For more information on associations, see [here][associations-doc]. 39* [xyz.openbmc_project.Object.Delete] 40 * Provides a Delete method to delete the event. 41* [xyz.openbmc_project.Software.Version] 42 * Stores the code version that the error occurred on. 43 44On platforms that make use of these event logs, the intent is that they are 45the common event log representation that other types of event logs can be 46created from. For example, there is code to convert these into both Redfish 47and IPMI event logs, in addition to the event log extensions mentioned 48[below](#event-log-extensions). 49 50The logging daemon has the ability to add `callout` associations to an event 51log based on text in the AdditionalData property. A callout is a link to the 52inventory item(s) that were the cause of the event log. See [here][callout-doc] 53for details. 54 55### Creating Event Logs In Code 56There are two approaches to creating event logs in OpenBMC code. The first 57makes use of the systemd journal to store metadata needed for the log, and the 58second is a plain D-Bus method call. 59 60#### Journal Based Event Log Creation 61Event logs can be created by using phosphor-logging APIs to commit sdbusplus 62exceptions. These APIs write to the journal, and then call a `Commit` 63D-Bus method on the logging daemon to create the event log using the information 64it put in the journal. 65 66The APIs are found in `<phosphor-logging/elog.hpp>`: 67* `elog()`: Throw an sdbusplus error. 68* `commit()`: Catch an error thrown by elog(), and commit it to create the 69 event log. 70* `report()`: Create an event log from an sdbusplus error without throwing the 71 exception first. 72 73Any errors passed into these APIs must be known to phosphor-logging, usually 74by being defined in `<phosphor-logging/elog-errors.hpp>`. The errors must 75also be known by sdbusplus, and be defined in their corresponding error.hpp. 76See below for details on how get errors into these headers. 77 78Example: 79``` 80#include <phosphor-logging/elog-errors.hpp> 81#include <phosphor-logging/elog.hpp> 82#include <xyz/openbmc_project/Common/error.hpp> 83... 84using InternalFailure = 85 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 86... 87if (somethingBadHappened) 88{ 89 phosphor::logging::report<InternalFailure>(); 90} 91 92``` 93Alternatively, to throw, catch, and then commit the error: 94``` 95try 96{ 97 phosphor::logging::elog<InternalFailure>(); 98} 99catch (InternalFailure& e) 100{ 101 phosphor::logging::commit<InternalFailure>(); 102} 103``` 104 105Metadata can be added to event logs to add debug data captured at the time of 106the event. It shows up in the AdditionalData property in the 107`xyz.openbmc_project.Logging.Entry` interface. Metadata is passed in via the 108`elog()` or `report()` functions, which write it to the journal. The metadata 109must be predefined for the error in the [metadata YAML](#event-log-definition) 110so that the daemon knows to look for it in the journal when it creates the 111event log. 112 113Example: 114``` 115#include <phosphor-logging/elog-errors.hpp> 116#include <phosphor-logging/elog.hpp> 117#include <xyz/openbmc_project/Control/Device/error.hpp> 118... 119using WriteFailure = 120 sdbusplus::xyz::openbmc_project::Control::Device::Error::WriteFailure; 121using metadata = 122 xyz::openbmc_project::Control::Device::WriteFailure; 123... 124if (somethingBadHappened) 125{ 126 phosphor::logging::report<WriteFailure>(metadata::CALLOUT_ERRNO(5), 127 metadata::CALLOUT_DEVICE_PATH("some path")); 128} 129``` 130In the above example, the AdditionalData property would look like: 131``` 132["CALLOUT_ERRNO=5", "CALLOUT_DEVICE_PATH=some path"] 133``` 134Note that the metadata fields must be all uppercase. 135 136##### Event Log Definition 137As mentioned above, both sdbusplus and phosphor-logging must know about the 138event logs in their header files, or the code that uses them will not even 139compile. The standard way to do this to define the event in the appropriate 140`<error-category>.errors.yaml` file, and define any metadata in the 141`<error-category>.metadata.yaml` file in the appropriate `*-dbus-interfaces` 142repository. During the build, phosphor-logging generates the elog-errors.hpp 143file for use by the calling code. 144 145In much the same way, sdbusplus uses the event log definitions to generate an 146error.hpp file that contains the specific exception. The path of the error.hpp 147matches the path of the YAML file. 148 149For example, if in phosphor-dbus-interfaces there is 150`xyz/openbmc_project/Control/Device.errors.yaml`, the errors that come from 151that file will be in the include: 152`xyz/openbmc_project/Control/Device/error.hpp`. 153 154In rare cases, one may want one to define their errors in the same repository 155that uses them. To do that, one must: 156 1571. Add the error and metadata YAML files to the repository. 1582. Run the sdbus++ script within the makefile to create the error.hpp and .cpp 159 files from the local YAML, and include the error.cpp file in the application 160 that uses it. See [openpower-occ-control] for an example. 1613. Tell phosphor-logging about the error. This is done by either: 162 * Following the [directions](#adding-application-specific-error-yaml) 163 defined in this README, or 164 * Running the script yourself: 165 1. Run phosphor-logging\'s `elog-gen.py` script on the local yaml to 166 generate an elog-errors.hpp file that just contains the local errors, 167 and check that into the repository and include it where the errors are 168 needed. 169 2. Create a recipe that copies the local YAML files to a place that 170 phosphor-logging can find it during the build. See [here][led-link] 171 for an example. 172 173#### D-Bus Event Log Creation 174There is also a [D-Bus method][log-create-link] to create event logs: 175* Service: xyz.openbmc_project.Logging 176* Object Path: /xyz/openbmc_project/logging 177* Interface: xyz.openbmc_project.Logging.Create 178* Method: Create 179 * Method Arguments: 180 * Message: The `Message` string property for the 181 `xyz.openbmc_project.Logging.Entry` interface. 182 * Severity: The `severity` property for the 183 `xyz.openbmc_project.Logging.Entry` interface. 184 An `xyz.openbmc_project.Logging.Entry.Level` enum value. 185 * AdditionalData: The `AdditionalData` property for the 186 `xyz.openbmc_project.Logging.Entry` interface, but in a map 187 instead of in a vector of "KEY=VALUE" strings. 188 Example: 189``` 190 std::map<std::string, std::string> additionalData; 191 additionalData["KEY"] = "VALUE"; 192``` 193 194 195Unlike the previous APIs where errors could also act as exceptions that could 196be thrown across D-Bus, this API does not require that the error be defined in 197the error YAML in the D-Bus interfaces repository so that sdbusplus knows about 198it. Additionally, as this method passes in everything needed to create the 199event log, the logging daemon doesn't have to know about it ahead of time 200either. 201 202That being said, it is recommended that users of this API still follow some 203guidelines for the message field, which is normally generated from a 204combination of the path to the error YAML file and the error name itself. For 205example, the `Timeout` error in `xyz/openbmc_project/Common.errors.yaml` will 206have a Message property of `xyz.openbmc_project.Common.Error.Timeout`. 207 208The guidelines are: 2091. When it makes sense, one can still use an existing error that has already 210 been defined in an error YAML file, and use the same severity and metadata 211 (AdditionalData) as in the corresponding metadata YAML file. 212 2132. If creating a new error, use the same naming scheme as other errors, which 214 starts with the domain, `xyz.openbmc_project`, `org.open_power`, etc, 215 followed by the capitalized category values, followed by `Error`, followed 216 by the capitalized error name itself, with everything separated by "."s. 217 For example: `xyz.openbmc_project.Some.Category.Error.Name`. 218 2193. If creating a new common error, still add it to the appropriate error and 220 metadata YAML files in the appropriate D-Bus interfaces repository so that 221 others can know about it and use it in the future. This can be done after 222 the fact. 223 224[xyz.openbmc_project.Logging.Entry]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Entry.interface.yaml 225[xyz.openbmc_project.Association.Definitions]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Association/Definitions.interface.yaml 226[associations-doc]: https://github.com/openbmc/docs/blob/master/architecture/object-mapper.md#associations 227[callout-doc]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Common/Callout/README.md 228[xyz.openbmc_project.Object.Delete]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Object/Delete.interface.yaml 229[xyz.openbmc_project.Software.Version]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Software/Version.errors.yaml 230[elog-errors.hpp]: https://github.com/openbmc/phosphor-logging/blob/master/phosphor-logging/elog.hpp 231[openpower-occ-control]: https://github.com/openbmc/openpower-occ-control 232[led-link]: https://github.com/openbmc/openbmc/tree/master/meta-phosphor/recipes-phosphor/leds 233[log-create-link]: https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Create.interface.yaml 234 235## Adding application specific error YAML 236* This document captures steps for adding application specific error YAML files 237 and generating local elog-errors.hpp header file for application use. 238* Should cater for continuous integration (CI) build, bitbake image build, and 239 local repository build. 240 241#### Continuous Integration (CI) build 242 * Make is called on the repository that is modified. 243 * Dependent packages are pulled based on the dependency list specified in the 244 configure.ac script. 245 246#### Recipe build 247 * Native recipes copy error YAML files to shared location. 248 * phosphor-logging builds elog-errors.hpp by parsing the error YAML files from 249 the shared location. 250 251#### Local repository build 252 * Copies local error YAML files to the shared location in SDK 253 * Make generates elog-errors.hpp by parsing the error YAML files from the 254 shared location. 255 256#### Makefile changes 257**Reference** 258 * https://github.com/openbmc/openpower-debug-collector/blob/master/Makefile.am 259 260###### Export error YAML to shared location 261*Modify Makefile.am to export newly added error YAML to shared location* 262``` 263yamldir = ${datadir}/phosphor-dbus-yaml/yaml 264nobase_yaml_DATA = \ 265 org/open_power/Host.errors.yaml 266``` 267 268###### Generate elog-errors.hpp using elog parser from SDK location 269 * Add a conditional check "GEN_ERRORS" 270 * Disable the check for recipe bitbake image build 271 * Enable it for local repository build 272 * If "GEN_ERRORS" is enabled, build generates elog-errors.hpp header file. 273``` 274 # Generate phosphor-logging/elog-errors.hpp 275 if GEN_ERRORS 276 ELOG_MAKO ?= elog-gen-template.mako.hpp 277 ELOG_DIR ?= ${OECORE_NATIVE_SYSROOT}${datadir}/phosphor-logging/elog 278 ELOG_GEN_DIR ?= ${ELOG_DIR}/tools/ 279 ELOG_MAKO_DIR ?= ${ELOG_DIR}/tools/phosphor-logging/templates/ 280 YAML_DIR ?= ${OECORE_NATIVE_SYSROOT}${datadir}/phosphor-dbus-yaml/yaml 281 phosphor-logging/elog-errors.hpp: 282 @mkdir -p ${YAML_DIR}/org/open_power/ 283 @cp ${top_srcdir}/org/open_power/Host.errors.yaml \ 284 ${YAML_DIR}/org/open_power/Host.errors.yaml 285 @mkdir -p `dirname $@` 286 @chmod 777 $(ELOG_GEN_DIR)/elog-gen.py 287 $(AM_V_at)$(PYTHON) $(ELOG_GEN_DIR)/elog-gen.py -y ${YAML_DIR} \ 288 -t ${ELOG_MAKO_DIR} -m ${ELOG_MAKO} -o $@ 289 endif 290``` 291 292###### Update BUILT_SOURCES 293 * Append elog-errors.hpp to BUILT_SOURCES list and put it in conditional check 294 GEN_ERRORS so that the elog-errors.hpp is generated only during local 295 repository build. 296``` 297 if GEN_ERRORS 298 nobase_nodist_include_HEADERS += \ 299 phosphor-logging/elog-errors.hpp 300 endif 301 if GEN_ERRORS 302 BUILT_SOURCES += phosphor-logging/elog-errors.hpp 303 endif 304``` 305 306###### Conditional check for native build 307 * As the same Makefile is used both for recipe image build and native recipe 308 build, add a conditional to ensure that only installation of error yaml files 309 happens during native build. It is not required to build repository during 310 native build. 311``` 312 if !INSTALL_ERROR_YAML 313 endif 314``` 315 316#### Autotools changes 317**Reference** 318 * https://github.com/openbmc/openpower-debug-collector/blob/master/configure.ac 319 320###### Add option(argument) to enable/disable installing error yaml file 321 * Install error yaml option(argument) is enabled for native recipe build 322 and disabled for bitbake build. 323 324 * When install error yaml option is disabled do not check for target specific 325 packages in autotools configure script. 326 327###### Add option(argument) to install error yaml files 328``` 329AC_ARG_ENABLE([install_error_yaml], 330 AS_HELP_STRING([--enable-install_error_yaml], 331 [Enable installing error yaml file]),[], [install_error_yaml=no]) 332AM_CONDITIONAL([INSTALL_ERROR_YAML], 333 [test "x$enable_install_error_yaml" = "xyes"]) 334AS_IF([test "x$enable_install_error_yaml" != "xyes"], [ 335.. 336.. 337]) 338``` 339 340###### Add option(argument) to enable/disable generating elog-errors header file 341``` 342AC_ARG_ENABLE([gen_errors], 343 AS_HELP_STRING([--enable-gen_errors], [Enable elog-errors.hpp generation ]), 344 [],[gen_errors=yes]) 345AM_CONDITIONAL([GEN_ERRORS], [test "x$enable_gen_errors" != "xno"]) 346``` 347 348#### Recipe changes 349**Reference** 350* https://github.com/openbmc/openbmc/blob/master/meta-openbmc-machines\ 351/meta-openpower/common/recipes-phosphor/debug/openpower-debug-collector.bb 352 353###### Extend recipe for native and nativesdk 354* Extend the recipe for native and native SDK builds 355``` 356BBCLASSEXTEND += "native nativesdk" 357``` 358###### Remove dependencies for native and native SDK build 359* Native recipe caters only for copying error yaml files to shared location. 360* For native and native SDK build remove dependency on packages that recipe 361 build depends 362 363###### Remove dependency on phosphor-logging for native build 364``` 365DEPENDS_remove_class-native = "phosphor-logging" 366``` 367 368###### Remove dependency on phosphor-logging for native SDK build 369``` 370DEPENDS_remove_class-nativesdk = "phosphor-logging" 371``` 372 373###### Add install_error_yaml argument during native build 374* Add package config to enable/disable install_error_yaml feature. 375 376###### Add package config to enable/disable install_error_yaml feature 377``` 378PACKAGECONFIG ??= "install_error_yaml" 379PACKAGECONFIG[install_error_yaml] = " \ 380 --enable-install_error_yaml, \ 381 --disable-install_error_yaml, ,\ 382 " 383``` 384###### Enable install_error_yaml check for native build 385``` 386PACKAGECONFIG_add_class-native = "install_error_yaml" 387PACKAGECONFIG_add_class-nativesdk = "install_error_yaml" 388``` 389###### Disable install_error_yaml during target build 390``` 391PACKAGECONFIG_remove_class-target = "install_error_yaml" 392``` 393 394###### Disable generating elog-errors.hpp for bitbake build 395* Disable gen_errors argument for bitbake image build as the application uses 396 the elog-errors.hpp generated by phosphor-logging 397* Argument is enabled by default for local repository build in the configure 398 script of the local repository. 399``` 400 XTRA_OECONF += "--disable-gen_errors" 401``` 402 403#### Local build 404* During local build use --prefix=/usr for the configure script. 405 406**Reference** 407* https://github.com/openbmc/openpower-debug-collector/blob/master/README.md 408 409## Event Log Extensions 410 411The extension concept is a way to allow code that creates other formats of 412error logs besides phosphor-logging's event logs to still reside in the 413phosphor-log-manager application. 414 415The extension code lives in the `extensions/<extension>` subdirectories, 416and is enabled with a `--enable-<extension>` configure flag. The 417extension code won't compile unless enabled with this flag. 418 419Extensions can register themselves to have functions called at the following 420points using the REGISTER_EXTENSION_FUNCTION macro. 421* On startup 422 * Function type void(internal::Manager&) 423* After an event log is created 424 * Function type void(args) 425 * The args are: 426 * const std::string& - The Message property 427 * uin32_t - The event log ID 428 * uint64_t - The event log timestamp 429 * Level - The event level 430 * const AdditionalDataArg& - the additional data 431 * const AssociationEndpointsArg& - Association endpoints (callouts) 432* Before an event log is deleted, to check if it is allowed. 433 * Function type void(std::uint32_t, bool&) that takes the event ID 434* After an event log is deleted 435 * Function type void(std::uint32_t) that takes the event ID 436 437Using these callback points, they can create their own event log for each 438OpenBMC event log that is created, and delete these logs when the corresponding 439OpenBMC event log is deleted. 440 441In addition, an extension has the option of disabling phosphor-logging's 442default error log capping policy so that it can use its own. The macro 443DISABLE_LOG_ENTRY_CAPS() is used for that. 444 445### Motivation 446 447The reason for adding support for extensions inside the phosphor-log-manager 448daemon as opposed to just creating new daemons that listen for D-Bus signals is 449to allow interactions that would be complicated or expensive if just done over 450D-Bus, such as: 451* Allowing for custom old log retention algorithms. 452* Prohibiting manual deleting of certain logs based on an extension's 453 requirements. 454 455### Creating extensions 456 4571. Add a new flag to configure.ac to enable the extension: 458``` 459AC_ARG_ENABLE([foo-extension], 460 AS_HELP_STRING([--enable-foo-extension], 461 [Create Foo logs])) 462AM_CONDITIONAL([ENABLE_FOO_EXTENSION], 463 [test "x$enable_foo_extension" == "xyes"]) 464``` 4652. Add the code in `extensions/<extension>/`. 4663. Create a makefile include to add the new code to phosphor-log-manager: 467``` 468phosphor_log_manager_SOURCES += \ 469 extensions/foo/foo.cpp 470``` 4714. In `extensions/extensions.mk`, add the makefile include: 472``` 473if ENABLE_FOO_EXTENSION 474include extensions/foo/foo.mk 475endif 476``` 4775. In the extension code, register the functions to call and optionally disable 478 log capping using the provided macros: 479``` 480DISABLE_LOG_ENTRY_CAPS(); 481 482void fooStartup(internal::Manager& manager) 483{ 484 // Initialize 485} 486 487REGISTER_EXTENSION_FUNCTION(fooStartup); 488 489void fooCreate(const std::string& message, uint32_t id, uint64_t timestamp, 490 Entry::Level severity, const AdditionalDataArg& additionalData, 491 const AssociationEndpointsArg& assocs) 492{ 493 // Create a different type of error log based on 'entry'. 494} 495 496REGISTER_EXTENSION_FUNCTION(fooCreate); 497 498void fooRemove(uint32_t id) 499{ 500 // Delete the extension error log that corresponds to 'id'. 501} 502 503REGISTER_EXTENSION_FUNCTION(fooRemove); 504``` 505### Extension List 506 507The supported extensions are: 508 509* OpenPower PELs 510 * Enabled with --enable-openpower-pel-extension 511 * Detailed information can be found 512 [here](extensions/openpower-pels/README.md) 513 514## Remote Logging via Rsyslog 515The BMC has the ability to stream out local logs (that go to the systemd journal) 516via rsyslog (https://www.rsyslog.com/). 517 518The BMC will send everything. Any kind of filtering and appropriate storage 519will have to be managed on the rsyslog server. Various examples are available 520on the internet. Here are few pointers : 521https://www.rsyslog.com/storing-and-forwarding-remote-messages/ 522https://www.rsyslog.com/doc/rsyslog%255Fconf%255Ffilter.html 523https://www.thegeekdiary.com/understanding-rsyslog-filter-options/ 524 525#### Configuring rsyslog server for remote logging 526The BMC is an rsyslog client. To stream out logs, it needs to talk to an rsyslog 527server, to which there's connectivity over a network. REST API can be used to 528set the remote server's IP address and port number. 529 530The following presumes a user has logged on to the BMC (see 531https://github.com/openbmc/docs/blob/master/rest-api.md). 532 533Set the IP: 534``` 535curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 536 -d '{"data": <IP address>}' \ 537 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Address 538``` 539 540Set the port: 541``` 542curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 543 -d '{"data": <port number>}' \ 544 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Port 545``` 546 547#### Querying the current configuration 548``` 549curl -b cjar -k \ 550 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote 551``` 552 553#### Setting the hostname 554Rsyslog can store logs separately for each host. For this reason, it's useful to 555provide a unique hostname to each managed BMC. Here's how that can be done via a 556REST API : 557``` 558curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 559 -d '{"data": "myHostName"}' \ 560 https://<BMC IP address>//xyz/openbmc_project/network/config/attr/HostName 561``` 562 563#### Disabling remote logging 564Remote logging can be disabled by writing 0 to the port, or an empty string("") 565to the IP. 566 567#### Changing the rsyslog server 568When switching to a new server from an existing one (i.e the address, or port, 569or both change), it is recommended to disable the existing configuration first. 570 571## Boot Fail on Hardware Errors 572 573phosphor-logging supports a setting, which when set, will result in the 574software looking at new phosphor-logging entries being created, and if a 575CALLOUT* is found within the entry, ensuring the system will not power 576on. Entries with severities of Informational or Debug will not block boots, 577even if they have callouts. 578 579The full design for this can be found 580[here](https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md) 581 582To enable this function: 583 584``` 585busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/logging/settings xyz.openbmc_project.Logging.Settings QuiesceOnHwError b true 586``` 587 588To check if an entry is blocking the boot: 589``` 590obmcutil listbootblock 591``` 592 593Resolve or clear the corresponding entry to allow the system to boot. 594