xref: /openbmc/phosphor-logging/README.md (revision 81a91e3e)
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