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