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