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