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