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