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