blob: 7ee2def9f072dbbaabd01c24c1b50783923206d5 [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) :
Patrick Williams87c333e2024-08-16 15:20:11 -040037 config(config), dbusLoop(&dbusLoop), hostConsole(&hostConsole),
38 logBuffer(&logBuffer), fileStorage(&fileStorage)
Artem Senicheve8837d52020-06-07 11:59:04 +030039{}
40
Nan Zhou042b5ba2021-06-18 09:32:45 -070041void BufferService::run()
Artem Senicheve8837d52020-06-07 11:59:04 +030042{
43 if (config.bufFlushFull)
44 {
Nan Zhou042b5ba2021-06-18 09:32:45 -070045 logBuffer->setFullHandler([this]() { this->flush(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030046 }
47
Nan Zhou042b5ba2021-06-18 09:32:45 -070048 hostConsole->connect();
Artem Senicheve8837d52020-06-07 11:59:04 +030049
50 // Add SIGUSR1 signal handler for manual flushing
Nan Zhou042b5ba2021-06-18 09:32:45 -070051 dbusLoop->addSignalHandler(SIGUSR1, [this]() { this->flush(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030052 // Add SIGTERM signal handler for service shutdown
Nan Zhou042b5ba2021-06-18 09:32:45 -070053 dbusLoop->addSignalHandler(SIGTERM, [this]() { this->dbusLoop->stop(0); });
Artem Senicheve8837d52020-06-07 11:59:04 +030054
55 // Register callback for socket IO
Nan Zhou042b5ba2021-06-18 09:32:45 -070056 dbusLoop->addIoHandler(*hostConsole, [this]() { this->readConsole(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030057
58 // Register host state watcher
59 if (*config.hostState)
60 {
Nan Zhou042b5ba2021-06-18 09:32:45 -070061 dbusLoop->addPropertyHandler(config.hostState, watchProperties,
62 [this]() { this->flush(); });
Artem Senicheve8837d52020-06-07 11:59:04 +030063 }
64
65 if (!*config.hostState && !config.bufFlushFull)
66 {
67 log<level::WARNING>("Automatic flush disabled");
68 }
69
Patrick Williams87c333e2024-08-16 15:20:11 -040070 log<level::DEBUG>(
71 "Initialization complete", entry("SocketId=%s", config.socketId),
72 entry("BufMaxSize=%lu", config.bufMaxSize),
73 entry("BufMaxTime=%lu", config.bufMaxTime),
74 entry("BufFlushFull=%s", config.bufFlushFull ? "y" : "n"),
75 entry("HostState=%s", config.hostState),
76 entry("OutDir=%s", config.outDir),
77 entry("MaxFiles=%lu", config.maxFiles));
Artem Senicheve8837d52020-06-07 11:59:04 +030078
79 // Run D-Bus event loop
Nan Zhou042b5ba2021-06-18 09:32:45 -070080 const int rc = dbusLoop->run();
81 if (!logBuffer->empty())
Artem Senicheve8837d52020-06-07 11:59:04 +030082 {
83 flush();
84 }
85 if (rc < 0)
86 {
87 std::error_code ec(-rc, std::generic_category());
88 throw std::system_error(ec, "Error in event loop");
89 }
90}
91
Nan Zhou042b5ba2021-06-18 09:32:45 -070092void BufferService::flush()
Artem Senicheve8837d52020-06-07 11:59:04 +030093{
Nan Zhou042b5ba2021-06-18 09:32:45 -070094 if (logBuffer->empty())
Artem Senicheve8837d52020-06-07 11:59:04 +030095 {
96 log<level::INFO>("Ignore flush: buffer is empty");
97 return;
98 }
99 try
100 {
Nan Zhou042b5ba2021-06-18 09:32:45 -0700101 const std::string fileName = fileStorage->save(*logBuffer);
102 logBuffer->clear();
Artem Senicheve8837d52020-06-07 11:59:04 +0300103
104 std::string msg = "Host logs flushed to ";
105 msg += fileName;
106 log<level::INFO>(msg.c_str());
107 }
108 catch (const std::exception& ex)
109 {
110 log<level::ERR>(ex.what());
111 }
112}
113
Nan Zhou042b5ba2021-06-18 09:32:45 -0700114void BufferService::readConsole()
Artem Senicheve8837d52020-06-07 11:59:04 +0300115{
116 constexpr size_t bufSize = 128; // enough for most line-oriented output
117 std::vector<char> bufData(bufSize);
118 char* buf = bufData.data();
119
120 try
121 {
Nan Zhou042b5ba2021-06-18 09:32:45 -0700122 while (const size_t rsz = hostConsole->read(buf, bufSize))
Artem Senicheve8837d52020-06-07 11:59:04 +0300123 {
Nan Zhou042b5ba2021-06-18 09:32:45 -0700124 logBuffer->append(buf, rsz);
Artem Senicheve8837d52020-06-07 11:59:04 +0300125 }
126 }
127 catch (const std::system_error& ex)
128 {
129 log<level::ERR>(ex.what());
130 }
131}