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``` 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``` 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``` 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``` 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``` 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[elog-errors.hpp]: 253 https://github.com/openbmc/phosphor-logging/blob/master/phosphor-logging/elog.hpp 254[openpower-occ-control]: https://github.com/openbmc/openpower-occ-control 255[led-link]: 256 https://github.com/openbmc/openbmc/tree/master/meta-phosphor/recipes-phosphor/leds 257[log-create-link]: 258 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Create.interface.yaml 259 260## Adding application specific error YAML 261 262- This document captures steps for adding application specific error YAML files 263 and generating local elog-errors.hpp header file for application use. 264- Should cater for continuous integration (CI) build, bitbake image build, and 265 local repository build. 266 267#### Continuous Integration (CI) build 268 269- Make is called on the repository that is modified. 270- Dependent packages are pulled based on the dependency list specified in the 271 configure.ac script. 272 273#### Recipe build 274 275- Native recipes copy error YAML files to shared location. 276- phosphor-logging builds elog-errors.hpp by parsing the error YAML files from 277 the shared location. 278 279#### Local repository build 280 281- Copies local error YAML files to the shared location in SDK 282- Make generates elog-errors.hpp by parsing the error YAML files from the shared 283 location. 284 285#### Makefile changes 286 287**Reference** 288 289- https://github.com/openbmc/openpower-debug-collector/blob/master/Makefile.am 290 291###### Export error YAML to shared location 292 293_Modify Makefile.am to export newly added error YAML to shared location_ 294 295``` 296yamldir = ${datadir}/phosphor-dbus-yaml/yaml 297nobase_yaml_DATA = \ 298 org/open_power/Host.errors.yaml 299``` 300 301###### Generate elog-errors.hpp using elog parser from SDK location 302 303- Add a conditional check "GEN_ERRORS" 304- Disable the check for recipe bitbake image build 305- Enable it for local repository build 306- If "GEN_ERRORS" is enabled, build generates elog-errors.hpp header file. 307 308``` 309 # Generate phosphor-logging/elog-errors.hpp 310 if GEN_ERRORS 311 ELOG_MAKO ?= elog-gen-template.mako.hpp 312 ELOG_DIR ?= ${OECORE_NATIVE_SYSROOT}${datadir}/phosphor-logging/elog 313 ELOG_GEN_DIR ?= ${ELOG_DIR}/tools/ 314 ELOG_MAKO_DIR ?= ${ELOG_DIR}/tools/phosphor-logging/templates/ 315 YAML_DIR ?= ${OECORE_NATIVE_SYSROOT}${datadir}/phosphor-dbus-yaml/yaml 316 phosphor-logging/elog-errors.hpp: 317 @mkdir -p ${YAML_DIR}/org/open_power/ 318 @cp ${top_srcdir}/org/open_power/Host.errors.yaml \ 319 ${YAML_DIR}/org/open_power/Host.errors.yaml 320 @mkdir -p `dirname $@` 321 @chmod 777 $(ELOG_GEN_DIR)/elog-gen.py 322 $(AM_V_at)$(PYTHON) $(ELOG_GEN_DIR)/elog-gen.py -y ${YAML_DIR} \ 323 -t ${ELOG_MAKO_DIR} -m ${ELOG_MAKO} -o $@ 324 endif 325``` 326 327###### Update BUILT_SOURCES 328 329- Append elog-errors.hpp to BUILT_SOURCES list and put it in conditional check 330 GEN_ERRORS so that the elog-errors.hpp is generated only during local 331 repository build. 332 333``` 334 if GEN_ERRORS 335 nobase_nodist_include_HEADERS += \ 336 phosphor-logging/elog-errors.hpp 337 endif 338 if GEN_ERRORS 339 BUILT_SOURCES += phosphor-logging/elog-errors.hpp 340 endif 341``` 342 343###### Conditional check for native build 344 345- As the same Makefile is used both for recipe image build and native recipe 346 build, add a conditional to ensure that only installation of error yaml files 347 happens during native build. It is not required to build repository during 348 native build. 349 350``` 351 if !INSTALL_ERROR_YAML 352 endif 353``` 354 355#### Autotools changes 356 357**Reference** 358 359- https://github.com/openbmc/openpower-debug-collector/blob/master/configure.ac 360 361###### Add option(argument) to enable/disable installing error yaml file 362 363- Install error yaml option(argument) is enabled for native recipe build and 364 disabled for bitbake build. 365 366- When install error yaml option is disabled do not check for target specific 367 packages in autotools configure script. 368 369###### Add option(argument) to install error yaml files 370 371``` 372AC_ARG_ENABLE([install_error_yaml], 373 AS_HELP_STRING([--enable-install_error_yaml], 374 [Enable installing error yaml file]),[], [install_error_yaml=no]) 375AM_CONDITIONAL([INSTALL_ERROR_YAML], 376 [test "x$enable_install_error_yaml" = "xyes"]) 377AS_IF([test "x$enable_install_error_yaml" != "xyes"], [ 378.. 379.. 380]) 381``` 382 383###### Add option(argument) to enable/disable generating elog-errors header file 384 385``` 386AC_ARG_ENABLE([gen_errors], 387 AS_HELP_STRING([--enable-gen_errors], [Enable elog-errors.hpp generation ]), 388 [],[gen_errors=yes]) 389AM_CONDITIONAL([GEN_ERRORS], [test "x$enable_gen_errors" != "xno"]) 390``` 391 392#### Recipe changes 393 394**Reference** 395 396- https://github.com/openbmc/openbmc/blob/master/meta-openbmc-machines\ 397 /meta-openpower/common/recipes-phosphor/debug/openpower-debug-collector.bb 398 399###### Extend recipe for native and nativesdk 400 401- Extend the recipe for native and native SDK builds 402 403``` 404BBCLASSEXTEND += "native nativesdk" 405``` 406 407###### Remove dependencies for native and native SDK build 408 409- Native recipe caters only for copying error yaml files to shared location. 410- For native and native SDK build remove dependency on packages that recipe 411 build depends 412 413###### Remove dependency on phosphor-logging for native build 414 415``` 416DEPENDS_remove_class-native = "phosphor-logging" 417``` 418 419###### Remove dependency on phosphor-logging for native SDK build 420 421``` 422DEPENDS_remove_class-nativesdk = "phosphor-logging" 423``` 424 425###### Add install_error_yaml argument during native build 426 427- Add package config to enable/disable install_error_yaml feature. 428 429###### Add package config to enable/disable install_error_yaml feature 430 431``` 432PACKAGECONFIG ??= "install_error_yaml" 433PACKAGECONFIG[install_error_yaml] = " \ 434 --enable-install_error_yaml, \ 435 --disable-install_error_yaml, ,\ 436 " 437``` 438 439###### Enable install_error_yaml check for native build 440 441``` 442PACKAGECONFIG_add_class-native = "install_error_yaml" 443PACKAGECONFIG_add_class-nativesdk = "install_error_yaml" 444``` 445 446###### Disable install_error_yaml during target build 447 448``` 449PACKAGECONFIG_remove_class-target = "install_error_yaml" 450``` 451 452###### Disable generating elog-errors.hpp for bitbake build 453 454- Disable gen_errors argument for bitbake image build as the application uses 455 the elog-errors.hpp generated by phosphor-logging 456- Argument is enabled by default for local repository build in the configure 457 script of the local repository. 458 459``` 460 XTRA_OECONF += "--disable-gen_errors" 461``` 462 463#### Local build 464 465- During local build use --prefix=/usr for the configure script. 466 467**Reference** 468 469- https://github.com/openbmc/openpower-debug-collector/blob/master/README.md 470 471## Event Log Extensions 472 473The extension concept is a way to allow code that creates other formats of error 474logs besides phosphor-logging's event logs to still reside in the 475phosphor-log-manager application. 476 477The extension code lives in the `extensions/<extension>` subdirectories, and is 478enabled with a `--enable-<extension>` configure flag. The extension code won't 479compile unless enabled with this flag. 480 481Extensions can register themselves to have functions called at the following 482points using the REGISTER_EXTENSION_FUNCTION macro. 483 484- On startup 485 - Function type void(internal::Manager&) 486- After an event log is created 487 - Function type void(args) 488 - The args are: 489 - const std::string& - The Message property 490 - uin32_t - The event log ID 491 - uint64_t - The event log timestamp 492 - Level - The event level 493 - const AdditionalDataArg& - the additional data 494 - const AssociationEndpointsArg& - Association endpoints (callouts) 495- Before an event log is deleted, to check if it is allowed. 496 - Function type void(std::uint32_t, bool&) that takes the event ID 497- After an event log is deleted 498 - Function type void(std::uint32_t) that takes the event ID 499 500Using these callback points, they can create their own event log for each 501OpenBMC event log that is created, and delete these logs when the corresponding 502OpenBMC event log is deleted. 503 504In addition, an extension has the option of disabling phosphor-logging's default 505error log capping policy so that it can use its own. The macro 506DISABLE_LOG_ENTRY_CAPS() is used for that. 507 508### Motivation 509 510The reason for adding support for extensions inside the phosphor-log-manager 511daemon as opposed to just creating new daemons that listen for D-Bus signals is 512to allow interactions that would be complicated or expensive if just done over 513D-Bus, such as: 514 515- Allowing for custom old log retention algorithms. 516- Prohibiting manual deleting of certain logs based on an extension's 517 requirements. 518 519### Creating extensions 520 5211. Add a new flag to configure.ac to enable the extension: 522 523``` 524AC_ARG_ENABLE([foo-extension], 525 AS_HELP_STRING([--enable-foo-extension], 526 [Create Foo logs])) 527AM_CONDITIONAL([ENABLE_FOO_EXTENSION], 528 [test "x$enable_foo_extension" == "xyes"]) 529``` 530 5312. Add the code in `extensions/<extension>/`. 5323. Create a makefile include to add the new code to phosphor-log-manager: 533 534``` 535phosphor_log_manager_SOURCES += \ 536 extensions/foo/foo.cpp 537``` 538 5394. In `extensions/extensions.mk`, add the makefile include: 540 541``` 542if ENABLE_FOO_EXTENSION 543include extensions/foo/foo.mk 544endif 545``` 546 5475. In the extension code, register the functions to call and optionally disable 548 log capping using the provided macros: 549 550``` 551DISABLE_LOG_ENTRY_CAPS(); 552 553void fooStartup(internal::Manager& manager) 554{ 555 // Initialize 556} 557 558REGISTER_EXTENSION_FUNCTION(fooStartup); 559 560void fooCreate(const std::string& message, uint32_t id, uint64_t timestamp, 561 Entry::Level severity, const AdditionalDataArg& additionalData, 562 const AssociationEndpointsArg& assocs) 563{ 564 // Create a different type of error log based on 'entry'. 565} 566 567REGISTER_EXTENSION_FUNCTION(fooCreate); 568 569void fooRemove(uint32_t id) 570{ 571 // Delete the extension error log that corresponds to 'id'. 572} 573 574REGISTER_EXTENSION_FUNCTION(fooRemove); 575``` 576 577### Extension List 578 579The supported extensions are: 580 581- OpenPower PELs 582 - Enabled with --enable-openpower-pel-extension 583 - Detailed information can be found 584 [here](extensions/openpower-pels/README.md) 585 586## Remote Logging via Rsyslog 587 588The BMC has the ability to stream out local logs (that go to the systemd 589journal) via rsyslog (https://www.rsyslog.com/). 590 591The BMC will send everything. Any kind of filtering and appropriate storage will 592have to be managed on the rsyslog server. Various examples are available on the 593internet. Here are few pointers : 594https://www.rsyslog.com/storing-and-forwarding-remote-messages/ 595https://www.rsyslog.com/doc/rsyslog%255Fconf%255Ffilter.html 596https://www.thegeekdiary.com/understanding-rsyslog-filter-options/ 597 598#### Configuring rsyslog server for remote logging 599 600The BMC is an rsyslog client. To stream out logs, it needs to talk to an rsyslog 601server, to which there's connectivity over a network. REST API can be used to 602set the remote server's IP address and port number. 603 604The following presumes a user has logged on to the BMC (see 605https://github.com/openbmc/docs/blob/master/rest-api.md). 606 607Set the IP: 608 609``` 610curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 611 -d '{"data": <IP address>}' \ 612 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Address 613``` 614 615Set the port: 616 617``` 618curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 619 -d '{"data": <port number>}' \ 620 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Port 621``` 622 623#### Querying the current configuration 624 625``` 626curl -b cjar -k \ 627 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote 628``` 629 630#### Setting the hostname 631 632Rsyslog can store logs separately for each host. For this reason, it's useful to 633provide a unique hostname to each managed BMC. Here's how that can be done via a 634REST API : 635 636``` 637curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 638 -d '{"data": "myHostName"}' \ 639 https://<BMC IP address>//xyz/openbmc_project/network/config/attr/HostName 640``` 641 642#### Disabling remote logging 643 644Remote logging can be disabled by writing 0 to the port, or an empty string("") 645to the IP. 646 647#### Changing the rsyslog server 648 649When switching to a new server from an existing one (i.e the address, or port, 650or both change), it is recommended to disable the existing configuration first. 651 652## Boot Fail on Hardware Errors 653 654phosphor-logging supports a setting, which when set, will result in the software 655looking at new phosphor-logging entries being created, and if a CALLOUT\* is 656found within the entry, ensuring the system will not power on. Entries with 657severities of Informational or Debug will not block boots, even if they have 658callouts. 659 660The full design for this can be found 661[here](https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md) 662 663To enable this function: 664 665``` 666busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/logging/settings xyz.openbmc_project.Logging.Settings QuiesceOnHwError b true 667``` 668 669To check if an entry is blocking the boot: 670 671``` 672obmcutil listbootblock 673``` 674 675Resolve or clear the corresponding entry to allow the system to boot. 676