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- [Event Log Extensions](#event-log-extensions) 12- [Remote Logging](#remote-logging-via-rsyslog) 13- [Boot Fail on Hardware Errors](#boot-fail-on-hardware-errors) 14 15## To Build 16 17To build this package, do the following steps: 18 191. meson builddir 202. ninja -c builddir 21 22## Structured Logging 23 24phosphor-logging provides APIs to add program logging information to the 25systemd-journal and it is preferred that this logging data is formatted in a 26structured manner (using the facilities provided by the APIs). 27 28See [Structured Logging](./docs/structured-logging.md) for more details on this 29API. 30 31## Event Logs 32 33OpenBMC event logs are a collection of D-Bus interfaces owned by 34phosphor-log-manager that reside at `/xyz/openbmc_project/logging/entry/X`, 35where X starts at 1 and is incremented for each new log. 36 37The interfaces are: 38 39- [xyz.openbmc_project.Logging.Entry] 40 - The main event log interface. 41- [xyz.openbmc_project.Association.Definitions] 42 - Used for specifying inventory items as the cause of the event. 43 - For more information on associations, see [here][associations-doc]. 44- [xyz.openbmc_project.Object.Delete] 45 - Provides a Delete method to delete the event. 46- [xyz.openbmc_project.Software.Version] 47 - Stores the code version that the error occurred on. 48 49On platforms that make use of these event logs, the intent is that they are the 50common event log representation that other types of event logs can be created 51from. For example, there is code to convert these into both Redfish and IPMI 52event logs, in addition to the event log extensions mentioned 53[below](#event-log-extensions). 54 55The logging daemon has the ability to add `callout` associations to an event log 56based on text in the AdditionalData property. A callout is a link to the 57inventory item(s) that were the cause of the event log. See [here][callout-doc] 58for details. 59 60### Creating Event Logs In Code 61 62The preferred method for creating event logs is specified in the project-level 63[event log design][event-log-design]. Events are defined using YAML in the 64phosphor-dbus-interfaces repository, such as the 65[Logging.Cleared][logging-cleared] event, which will generate a C++ class for 66the event. Then a call to `lg2::commit` is made on a constructed event to add it 67to the event log. 68 69```cpp 70lg2::commit(sdbusplus::event::xyz::openbmc_project::Logging::Cleared( 71 "NUMBER_OF_LOGS", count)); 72``` 73 74The above function will return the object path of the created log entry. This 75log-entry can be resolved with the helper `lg2::resolve` fuction. 76 77```cpp 78lg2::resolve(logPath); 79``` 80 81### Event Log Filtering 82 83Vendors customizing phosphor-logging for their platforms may decide that they 84would like to prevent certain events from being added to the event log. This is 85especially true for informational / tracing events. The `lg2::commit` supports a 86compile-time event filtering mechanism that can accomplish this. 87 88The meson option `event-filter` can be used to specify a file containing 89filtering policy. When left unspecified, the [default 90policy][default-policy-json] of "allow all" is enabled. For both events and 91errors, a default policy of "allowed" or "blocked" can be specified and an 92additional set of events can be given for which the non-defaulted action should 93be taken. A JSON-Schema is available for the [policy 94JSON][filter-policy-schema]. 95 96[default-policy-json]: 97 https://github.com/openbmc/phosphor-logging/blob/master/tools/phosphor-logging/default-eventfilter.json 98[filter-policy-schema]: 99 https://github.com/openbmc/phosphor-logging/blob/master/tools/phosphor-logging/schemas/eventfilter.schema.yaml 100 101### Deprecated Methods for Creating Event Logs 102 103There are two other, but now deprecated, methods to creating event logs in 104OpenBMC code. The first makes use of the systemd journal to store metadata 105needed for the log, and the second is a plain D-Bus method call. 106 107[event-log-design]: 108 https://github.com/openbmc/docs/blob/master/designs/event-logging.md#phosphor-logging 109[logging-cleared]: 110 https://github.com/openbmc/phosphor-dbus-interfaces/blob/6a8507d06e172d8d29c0459f0a0d078553d2ecc7/yaml/xyz/openbmc_project/Logging.events.yaml#L4 111 112#### Journal Based Event Log Creation [deprecated] 113 114Event logs can be created by using phosphor-logging APIs to commit sdbusplus 115exceptions. These APIs write to the journal, and then call a `Commit` D-Bus 116method on the logging daemon to create the event log using the information it 117put in the journal. 118 119The APIs are found in `<phosphor-logging/elog.hpp>`: 120 121- `elog()`: Throw an sdbusplus error. 122- `commit()`: Catch an error thrown by elog(), and commit it to create the event 123 log. 124- `report()`: Create an event log from an sdbusplus error without throwing the 125 exception first. 126 127Any errors passed into these APIs must be known to phosphor-logging, usually by 128being defined in `<phosphor-logging/elog-errors.hpp>`. The errors must also be 129known by sdbusplus, and be defined in their corresponding error.hpp. See below 130for details on how get errors into these headers. 131 132Example: 133 134```cpp 135#include <phosphor-logging/elog-errors.hpp> 136#include <phosphor-logging/elog.hpp> 137#include <xyz/openbmc_project/Common/error.hpp> 138... 139using InternalFailure = 140 sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 141... 142if (somethingBadHappened) 143{ 144 phosphor::logging::report<InternalFailure>(); 145} 146 147``` 148 149Alternatively, to throw, catch, and then commit the error: 150 151```cpp 152try 153{ 154 phosphor::logging::elog<InternalFailure>(); 155} 156catch (InternalFailure& e) 157{ 158 phosphor::logging::commit<InternalFailure>(); 159} 160``` 161 162Metadata can be added to event logs to add debug data captured at the time of 163the event. It shows up in the AdditionalData property in the 164`xyz.openbmc_project.Logging.Entry` interface. Metadata is passed in via the 165`elog()` or `report()` functions, which write it to the journal. The metadata 166must be predefined for the error in the metadata YAML so that the daemon knows 167to look for it in the journal when it creates the event log. 168 169Example: 170 171```cpp 172#include <phosphor-logging/elog-errors.hpp> 173#include <phosphor-logging/elog.hpp> 174#include <xyz/openbmc_project/Control/Device/error.hpp> 175... 176using WriteFailure = 177 sdbusplus::xyz::openbmc_project::Control::Device::Error::WriteFailure; 178using metadata = 179 phosphor::logging::xyz::openbmc_project::Control::Device::WriteFailure; 180... 181if (somethingBadHappened) 182{ 183 phosphor::logging::report<WriteFailure>(metadata::CALLOUT_ERRNO(5), 184 metadata::CALLOUT_DEVICE_PATH("some path")); 185} 186``` 187 188In the above example, the AdditionalData property would look like: 189 190```cpp 191["CALLOUT_ERRNO=5", "CALLOUT_DEVICE_PATH=some path"] 192``` 193 194Note that the metadata fields must be all uppercase. 195 196##### Event Log Definition [deprecated] 197 198As mentioned above, both sdbusplus and phosphor-logging must know about the 199event logs in their header files, or the code that uses them will not even 200compile. The standard way to do this to define the event in the appropriate 201`<error-category>.errors.yaml` file, and define any metadata in the 202`<error-category>.metadata.yaml` file in the appropriate `*-dbus-interfaces` 203repository. During the build, phosphor-logging generates the elog-errors.hpp 204file for use by the calling code. 205 206In much the same way, sdbusplus uses the event log definitions to generate an 207error.hpp file that contains the specific exception. The path of the error.hpp 208matches the path of the YAML file. 209 210For example, if in phosphor-dbus-interfaces there is 211`xyz/openbmc_project/Control/Device.errors.yaml`, the errors that come from that 212file will be in the include: `xyz/openbmc_project/Control/Device/error.hpp`. 213 214In rare cases, one may want one to define their errors in the same repository 215that uses them. To do that, one must: 216 2171. Add the error and metadata YAML files to the repository. 2182. Run the sdbus++ script within the makefile to create the error.hpp and .cpp 219 files from the local YAML, and include the error.cpp file in the application 220 that uses it. See [openpower-occ-control] for an example. 2213. Tell phosphor-logging about the error: 222 1. Run phosphor-logging's `elog-gen.py` script on the local yaml to generate 223 an elog-errors.hpp file that just contains the local errors, and check 224 that into the repository and include it where the errors are needed. 225 2. Create a recipe that copies the local YAML files to a place that 226 phosphor-logging can find it during the build. See [here][led-link] for an 227 example. 228 229#### D-Bus Event Log Creation [deprecated] 230 231There is also a [D-Bus method][log-create-link] to create event logs: 232 233- Service: xyz.openbmc_project.Logging 234- Object Path: /xyz/openbmc_project/logging 235- Interface: xyz.openbmc_project.Logging.Create 236- Method: Create 237 - Method Arguments: 238 - Message: The `Message` string property for the 239 `xyz.openbmc_project.Logging.Entry` interface. 240 - Severity: The `severity` property for the 241 `xyz.openbmc_project.Logging.Entry` interface. An 242 `xyz.openbmc_project.Logging.Entry.Level` enum value. 243 - AdditionalData: The `AdditionalData` property for the 244 `xyz.openbmc_project.Logging.Entry` interface, but in a map instead of in 245 a vector of "KEY=VALUE" strings. Example: 246 247```cpp 248 std::map<std::string, std::string> additionalData; 249 additionalData["KEY"] = "VALUE"; 250``` 251 252Unlike the previous APIs where errors could also act as exceptions that could be 253thrown across D-Bus, this API does not require that the error be defined in the 254error YAML in the D-Bus interfaces repository so that sdbusplus knows about it. 255Additionally, as this method passes in everything needed to create the event 256log, the logging daemon doesn't have to know about it ahead of time either. 257 258That being said, it is recommended that users of this API still follow some 259guidelines for the message field, which is normally generated from a combination 260of the path to the error YAML file and the error name itself. For example, the 261`Timeout` error in `xyz/openbmc_project/Common.errors.yaml` will have a Message 262property of `xyz.openbmc_project.Common.Error.Timeout`. 263 264The guidelines are: 265 2661. When it makes sense, one can still use an existing error that has already 267 been defined in an error YAML file, and use the same severity and metadata 268 (AdditionalData) as in the corresponding metadata YAML file. 269 2702. If creating a new error, use the same naming scheme as other errors, which 271 starts with the domain, `xyz.openbmc_project`, `org.open_power`, etc, 272 followed by the capitalized category values, followed by `Error`, followed by 273 the capitalized error name itself, with everything separated by "."s. For 274 example: `xyz.openbmc_project.Some.Category.Error.Name`. 275 2763. If creating a new common error, still add it to the appropriate error and 277 metadata YAML files in the appropriate D-Bus interfaces repository so that 278 others can know about it and use it in the future. This can be done after the 279 fact. 280 281[xyz.openbmc_project.logging.entry]: 282 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Entry.interface.yaml 283[xyz.openbmc_project.association.definitions]: 284 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Association/Definitions.interface.yaml 285[associations-doc]: 286 https://github.com/openbmc/docs/blob/master/architecture/object-mapper.md#associations 287[callout-doc]: 288 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Common/Callout/README.md 289[xyz.openbmc_project.object.delete]: 290 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Object/Delete.interface.yaml 291[xyz.openbmc_project.software.version]: 292 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Software/Version.errors.yaml 293[openpower-occ-control]: https://github.com/openbmc/openpower-occ-control 294[led-link]: 295 https://github.com/openbmc/openbmc/tree/master/meta-phosphor/recipes-phosphor/leds 296[log-create-link]: 297 https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/yaml/xyz/openbmc_project/Logging/Create.interface.yaml 298 299## Event Log Extensions 300 301The extension concept is a way to allow code that creates other formats of error 302logs besides phosphor-logging's event logs to still reside in the 303phosphor-log-manager application. 304 305The extension code lives in the `extensions/<extension>` subdirectories, and is 306enabled with a `--enable-<extension>` configure flag. The extension code won't 307compile unless enabled with this flag. 308 309Extensions can register themselves to have functions called at the following 310points using the REGISTER_EXTENSION_FUNCTION macro. 311 312- On startup 313 - Function type void(internal::Manager&) 314- After an event log is created 315 - Function type void(args) 316 - The args are: 317 - const std::string& - The Message property 318 - uin32_t - The event log ID 319 - uint64_t - The event log timestamp 320 - Level - The event level 321 - const AdditionalDataArg& - the additional data 322 - const AssociationEndpointsArg& - Association endpoints (callouts) 323- Before an event log is deleted, to check if it is allowed. 324 - Function type void(std::uint32_t, bool&) that takes the event ID 325- After an event log is deleted 326 - Function type void(std::uint32_t) that takes the event ID 327 328Using these callback points, they can create their own event log for each 329OpenBMC event log that is created, and delete these logs when the corresponding 330OpenBMC event log is deleted. 331 332In addition, an extension has the option of disabling phosphor-logging's default 333error log capping policy so that it can use its own. The macro 334DISABLE_LOG_ENTRY_CAPS() is used for that. 335 336### Motivation 337 338The reason for adding support for extensions inside the phosphor-log-manager 339daemon as opposed to just creating new daemons that listen for D-Bus signals is 340to allow interactions that would be complicated or expensive if just done over 341D-Bus, such as: 342 343- Allowing for custom old log retention algorithms. 344- Prohibiting manual deleting of certain logs based on an extension's 345 requirements. 346 347### Creating extensions 348 3491. Add a new flag to configure.ac to enable the extension: 350 351 ```autoconf 352 AC_ARG_ENABLE([foo-extension], 353 AS_HELP_STRING([--enable-foo-extension], 354 [Create Foo logs])) 355 AM_CONDITIONAL([ENABLE_FOO_EXTENSION], 356 [test "x$enable_foo_extension" == "xyes"]) 357 ``` 358 3592. Add the code in `extensions/<extension>/`. 3603. Create a makefile include to add the new code to phosphor-log-manager: 361 362 ```make 363 phosphor_log_manager_SOURCES += \ 364 extensions/foo/foo.cpp 365 ``` 366 3674. In `extensions/extensions.mk`, add the makefile include: 368 369 ```make 370 if ENABLE_FOO_EXTENSION 371 include extensions/foo/foo.mk 372 endif 373 ``` 374 3755. In the extension code, register the functions to call and optionally disable 376 log capping using the provided macros: 377 378 ```cpp 379 DISABLE_LOG_ENTRY_CAPS(); 380 381 void fooStartup(internal::Manager& manager) 382 { 383 // Initialize 384 } 385 386 REGISTER_EXTENSION_FUNCTION(fooStartup); 387 388 void fooCreate(const std::string& message, uint32_t id, uint64_t timestamp, 389 Entry::Level severity, const AdditionalDataArg& additionalData, 390 const AssociationEndpointsArg& assocs) 391 { 392 // Create a different type of error log based on 'entry'. 393 } 394 395 REGISTER_EXTENSION_FUNCTION(fooCreate); 396 397 void fooRemove(uint32_t id) 398 { 399 // Delete the extension error log that corresponds to 'id'. 400 } 401 402 REGISTER_EXTENSION_FUNCTION(fooRemove); 403 ``` 404 405### Extension List 406 407The supported extensions are: 408 409- OpenPower PELs 410 - Enabled with --enable-openpower-pel-extension 411 - Detailed information can be found 412 [here](extensions/openpower-pels/README.md) 413 414## Remote Logging via Rsyslog 415 416The BMC has the ability to stream out local logs (that go to the systemd 417journal) via rsyslog (<https://www.rsyslog.com/>). 418 419The BMC will send everything. Any kind of filtering and appropriate storage will 420have to be managed on the rsyslog server. Various examples are available on the 421internet. Here are few pointers : 422<https://www.rsyslog.com/storing-and-forwarding-remote-messages/> 423<https://www.rsyslog.com/doc/rsyslog%255Fconf%255Ffilter.html> 424<https://www.thegeekdiary.com/understanding-rsyslog-filter-options/> 425 426### Configuring rsyslog server for remote logging 427 428The BMC is an rsyslog client. To stream out logs, it needs to talk to an rsyslog 429server, to which there's connectivity over a network. REST API can be used to 430set the remote server's IP address and port number. 431 432The following presumes a user has logged on to the BMC (see 433<https://github.com/openbmc/docs/blob/master/rest-api.md>). 434 435Set the IP: 436 437```sh 438curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 439 -d '{"data": <IP address>}' \ 440 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Address 441``` 442 443Set the port: 444 445```sh 446curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 447 -d '{"data": <port number>}' \ 448 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote/attr/Port 449``` 450 451#### Querying the current configuration 452 453```sh 454curl -b cjar -k \ 455 https://<BMC IP address>/xyz/openbmc_project/logging/config/remote 456``` 457 458#### Setting the hostname 459 460Rsyslog can store logs separately for each host. For this reason, it's useful to 461provide a unique hostname to each managed BMC. Here's how that can be done via a 462REST API : 463 464```sh 465curl -b cjar -k -H "Content-Type: application/json" -X PUT \ 466 -d '{"data": "myHostName"}' \ 467 https://<BMC IP address>//xyz/openbmc_project/network/config/attr/HostName 468``` 469 470#### Disabling remote logging 471 472Remote logging can be disabled by writing 0 to the port, or an empty string("") 473to the IP. 474 475#### Changing the rsyslog server 476 477When switching to a new server from an existing one (i.e the address, or port, 478or both change), it is recommended to disable the existing configuration first. 479 480## Boot Fail on Hardware Errors 481 482phosphor-logging supports a setting, which when set, will result in the software 483looking at new phosphor-logging entries being created, and if a CALLOUT\* is 484found within the entry, ensuring the system will not power on. Entries with 485severities of Informational or Debug will not block boots, even if they have 486callouts. 487 488The full design for this can be found 489[here](https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md) 490 491To enable this function: 492 493```sh 494busctl set-property xyz.openbmc_project.Settings /xyz/openbmc_project/logging/settings xyz.openbmc_project.Logging.Settings QuiesceOnHwError b true 495``` 496 497To check if an entry is blocking the boot: 498 499```sh 500obmcutil listbootblock 501``` 502 503Resolve or clear the corresponding entry to allow the system to boot. 504