blob: eda85453bfb1485c6ad55021b84e208c0a694488 [file] [log] [blame]
Artem Senicheve8837d52020-06-07 11:59:04 +03001// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2020 YADRO
3
4#include "service.hpp"
5
6#include <phosphor-logging/log.hpp>
7
8#include <vector>
9
10using namespace phosphor::logging;
11
12// clang-format off
13/** @brief Host state properties. */
14static const DbusLoop::WatchProperties watchProperties{
15 {"xyz.openbmc_project.State.Host", {{
16 "RequestedHostTransition", {
17 "xyz.openbmc_project.State.Host.Transition.On"}}}},
18 {"xyz.openbmc_project.State.OperatingSystem.Status", {{
19 "OperatingSystemState", {
20 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.BootComplete",
21 "xyz.openbmc_project.State.OperatingSystem.Status.OSStatus.Inactive"}}}}
22};
23// clang-format on
24
25Service::Service(const Config& config) :
26 config(config), hostConsole(config.socketId),
27 logBuffer(config.bufMaxSize, config.bufMaxTime),
28 fileStorage(config.outDir, config.socketId, config.maxFiles)
29{}
30
31void Service::run()
32{
33 if (config.bufFlushFull)
34 {
35 logBuffer.setFullHandler([this]() { this->flush(); });
36 }
37
38 hostConsole.connect();
39
40 // Add SIGUSR1 signal handler for manual flushing
41 dbusLoop.addSignalHandler(SIGUSR1, [this]() { this->flush(); });
42 // Add SIGTERM signal handler for service shutdown
43 dbusLoop.addSignalHandler(SIGTERM, [this]() { this->dbusLoop.stop(0); });
44
45 // Register callback for socket IO
46 dbusLoop.addIoHandler(hostConsole, [this]() { this->readConsole(); });
47
48 // Register host state watcher
49 if (*config.hostState)
50 {
51 dbusLoop.addPropertyHandler(config.hostState, watchProperties,
52 [this]() { this->flush(); });
53 }
54
55 if (!*config.hostState && !config.bufFlushFull)
56 {
57 log<level::WARNING>("Automatic flush disabled");
58 }
59
60 log<level::DEBUG>("Initialization complete",
61 entry("SocketId=%s", config.socketId),
62 entry("BufMaxSize=%lu", config.bufMaxSize),
63 entry("BufMaxTime=%lu", config.bufMaxTime),
64 entry("BufFlushFull=%s", config.bufFlushFull ? "y" : "n"),
65 entry("HostState=%s", config.hostState),
66 entry("OutDir=%s", config.outDir),
67 entry("MaxFiles=%lu", config.maxFiles));
68
69 // Run D-Bus event loop
70 const int rc = dbusLoop.run();
71 if (!logBuffer.empty())
72 {
73 flush();
74 }
75 if (rc < 0)
76 {
77 std::error_code ec(-rc, std::generic_category());
78 throw std::system_error(ec, "Error in event loop");
79 }
80}
81
82void Service::flush()
83{
84 if (logBuffer.empty())
85 {
86 log<level::INFO>("Ignore flush: buffer is empty");
87 return;
88 }
89 try
90 {
91 const std::string fileName = fileStorage.save(logBuffer);
92 logBuffer.clear();
93
94 std::string msg = "Host logs flushed to ";
95 msg += fileName;
96 log<level::INFO>(msg.c_str());
97 }
98 catch (const std::exception& ex)
99 {
100 log<level::ERR>(ex.what());
101 }
102}
103
104void Service::readConsole()
105{
106 constexpr size_t bufSize = 128; // enough for most line-oriented output
107 std::vector<char> bufData(bufSize);
108 char* buf = bufData.data();
109
110 try
111 {
112 while (const size_t rsz = hostConsole.read(buf, bufSize))
113 {
114 logBuffer.append(buf, rsz);
115 }
116 }
117 catch (const std::system_error& ex)
118 {
119 log<level::ERR>(ex.what());
120 }
121}