blob: e17f7f05bc4b6a95b2c92f0788c35e1bc35a16e9 [file] [log] [blame]
Artem Senicheve8837d52020-06-07 11:59:04 +03001// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2020 YADRO
3
Nan Zhou042b5ba2021-06-18 09:32:45 -07004#include "buffer_service.hpp"
Artem Senicheve8837d52020-06-07 11:59:04 +03005
6#include <phosphor-logging/log.hpp>
7
8#include <vector>
9
10using namespace phosphor::logging;
11
12// clang-format off
Artem Senichev90608dc2021-04-07 15:32:24 +030013/** @brief Host state monitor properties.
14 * Used for automatic flushing the log buffer to the persistent file.
15 * Contains a list of properties and a set of their values that trigger the
16 * flush operation.
17 * For example, the current log buffer will be saved to a file when the
18 * "OperatingSystemState" property obtains one of the
19 * listed values ("xyz.openbmc_project...BootComplete", "Inactive", etc).
20 */
Artem Senicheve8837d52020-06-07 11:59:04 +030021static const DbusLoop::WatchProperties watchProperties{
22 {"xyz.openbmc_project.State.Host", {{
23 "RequestedHostTransition", {
24 "xyz.openbmc_project.State.Host.Transition.On"}}}},
25 {"xyz.openbmc_project.State.OperatingSystem.Status", {{
26 "OperatingSystemState", {
27 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.BootComplete",
Artem Senichev90608dc2021-04-07 15:32:24 +030028 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive",
29 "Inactive",
30 "Standby"}}}}
Artem Senicheve8837d52020-06-07 11:59:04 +030031};
32// clang-format on
33
Nan Zhou042b5ba2021-06-18 09:32:45 -070034BufferService::BufferService(const Config& config, DbusLoop& dbusLoop,
35 HostConsole& hostConsole, LogBuffer& logBuffer,
36 FileStorage& fileStorage) :
37 config(config),
38 dbusLoop(&dbusLoop), hostConsole(&hostConsole), logBuffer(&logBuffer),
39 fileStorage(&fileStorage)
Artem Senicheve8837d52020-06-07 11:59:04 +030040{}
41
Nan Zhou042b5ba2021-06-18 09:32:45 -070042void BufferService::run()
Artem Senicheve8837d52020-06-07 11:59:04 +030043{
44 if (config.bufFlushFull)
45 {
Nan Zhou042b5ba2021-06-18 09:32:45 -070046 logBuffer->setFullHandler([this]() { this->flush(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030047 }
48
Nan Zhou042b5ba2021-06-18 09:32:45 -070049 hostConsole->connect();
Artem Senicheve8837d52020-06-07 11:59:04 +030050
51 // Add SIGUSR1 signal handler for manual flushing
Nan Zhou042b5ba2021-06-18 09:32:45 -070052 dbusLoop->addSignalHandler(SIGUSR1, [this]() { this->flush(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030053 // Add SIGTERM signal handler for service shutdown
Nan Zhou042b5ba2021-06-18 09:32:45 -070054 dbusLoop->addSignalHandler(SIGTERM, [this]() { this->dbusLoop->stop(0); });
Artem Senicheve8837d52020-06-07 11:59:04 +030055
56 // Register callback for socket IO
Nan Zhou042b5ba2021-06-18 09:32:45 -070057 dbusLoop->addIoHandler(*hostConsole, [this]() { this->readConsole(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030058
59 // Register host state watcher
60 if (*config.hostState)
61 {
Nan Zhou042b5ba2021-06-18 09:32:45 -070062 dbusLoop->addPropertyHandler(config.hostState, watchProperties,
63 [this]() { this->flush(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030064 }
65
66 if (!*config.hostState && !config.bufFlushFull)
67 {
68 log<level::WARNING>("Automatic flush disabled");
69 }
70
71 log<level::DEBUG>("Initialization complete",
72 entry("SocketId=%s", config.socketId),
73 entry("BufMaxSize=%lu", config.bufMaxSize),
74 entry("BufMaxTime=%lu", config.bufMaxTime),
75 entry("BufFlushFull=%s", config.bufFlushFull ? "y" : "n"),
76 entry("HostState=%s", config.hostState),
77 entry("OutDir=%s", config.outDir),
78 entry("MaxFiles=%lu", config.maxFiles));
79
80 // Run D-Bus event loop
Nan Zhou042b5ba2021-06-18 09:32:45 -070081 const int rc = dbusLoop->run();
82 if (!logBuffer->empty())
Artem Senicheve8837d52020-06-07 11:59:04 +030083 {
84 flush();
85 }
86 if (rc < 0)
87 {
88 std::error_code ec(-rc, std::generic_category());
89 throw std::system_error(ec, "Error in event loop");
90 }
91}
92
Nan Zhou042b5ba2021-06-18 09:32:45 -070093void BufferService::flush()
Artem Senicheve8837d52020-06-07 11:59:04 +030094{
Nan Zhou042b5ba2021-06-18 09:32:45 -070095 if (logBuffer->empty())
Artem Senicheve8837d52020-06-07 11:59:04 +030096 {
97 log<level::INFO>("Ignore flush: buffer is empty");
98 return;
99 }
100 try
101 {
Nan Zhou042b5ba2021-06-18 09:32:45 -0700102 const std::string fileName = fileStorage->save(*logBuffer);
103 logBuffer->clear();
Artem Senicheve8837d52020-06-07 11:59:04 +0300104
105 std::string msg = "Host logs flushed to ";
106 msg += fileName;
107 log<level::INFO>(msg.c_str());
108 }
109 catch (const std::exception& ex)
110 {
111 log<level::ERR>(ex.what());
112 }
113}
114
Nan Zhou042b5ba2021-06-18 09:32:45 -0700115void BufferService::readConsole()
Artem Senicheve8837d52020-06-07 11:59:04 +0300116{
117 constexpr size_t bufSize = 128; // enough for most line-oriented output
118 std::vector<char> bufData(bufSize);
119 char* buf = bufData.data();
120
121 try
122 {
Nan Zhou042b5ba2021-06-18 09:32:45 -0700123 while (const size_t rsz = hostConsole->read(buf, bufSize))
Artem Senicheve8837d52020-06-07 11:59:04 +0300124 {
Nan Zhou042b5ba2021-06-18 09:32:45 -0700125 logBuffer->append(buf, rsz);
Artem Senicheve8837d52020-06-07 11:59:04 +0300126 }
127 }
128 catch (const std::system_error& ex)
129 {
130 log<level::ERR>(ex.what());
131 }
132}