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