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