Add multi-host support
This refactoring includes:
- added multi-host mode support;
- added support for graceful shutdown of the service;
- added support to flush the log buffer as it fills;
- D-Bus service xyz.openbmc_project.HostLogger replaced with SIGUSR1
signal handler;
- self diagnostic messages now registered via phosphor-logging;
- added unit tests;
- build system migrated from autotools to meson;
- source code aligned with OpenBMC conventions.
Change-Id: If6c1dfde278af685d8563450543a6587a282c7e4
Signed-off-by: Artem Senichev <a.senichev@yadro.com>
diff --git a/src/log_buffer.cpp b/src/log_buffer.cpp
new file mode 100644
index 0000000..f511a95
--- /dev/null
+++ b/src/log_buffer.cpp
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright (C) 2020 YADRO
+
+#include "log_buffer.hpp"
+
+/** @brief Check if a character is EOL symbol. */
+constexpr bool isEol(char c)
+{
+ return c == '\r' || c == '\n';
+}
+
+LogBuffer::LogBuffer(size_t maxSize, size_t maxTime) :
+ lastComplete(true), sizeLimit(maxSize), timeLimit(maxTime)
+{}
+
+void LogBuffer::append(const char* data, size_t sz)
+{
+ // Split raw data into separate messages by EOL symbols (\r or \n).
+ // Stream may not be ended with EOL, so we handle this situation by
+ // lastComplete flag.
+ size_t pos = 0;
+ while (pos < sz)
+ {
+ // Search for EOL ('\r' or '\n')
+ size_t eol = pos;
+ while (eol < sz)
+ {
+ if (isEol(data[eol]))
+ {
+ break;
+ }
+ ++eol;
+ }
+ const bool eolFound = eol < sz;
+ const char* msgText = data + pos;
+ const size_t msgLen = (eolFound ? eol : sz) - pos;
+
+ // Append message to the container
+ if (!lastComplete && !messages.empty())
+ {
+ // The last message is incomplete, add data as part of it
+ messages.back().text.append(msgText, msgLen);
+ }
+ else
+ {
+ Message msg;
+ time(&msg.timeStamp);
+ msg.text.assign(msgText, msgLen);
+ messages.push_back(msg);
+ }
+ lastComplete = eolFound;
+
+ // Move current position and skip EOL character
+ pos = eol + 1;
+ // Handle EOL sequences '\r\n' or '\n\r' as one delimiter
+ if (eolFound && pos < sz && isEol(data[pos]) && data[eol] != data[pos])
+ {
+ ++pos;
+ }
+ }
+
+ shrink();
+}
+
+void LogBuffer::setFullHandler(std::function<void()> cb)
+{
+ fullHandler = cb;
+}
+
+void LogBuffer::clear()
+{
+ messages.clear();
+ lastComplete = true;
+}
+
+bool LogBuffer::empty() const
+{
+ return messages.empty();
+}
+
+LogBuffer::container_t::const_iterator LogBuffer::begin() const
+{
+ return messages.begin();
+}
+
+LogBuffer::container_t::const_iterator LogBuffer::end() const
+{
+ return messages.end();
+}
+
+void LogBuffer::shrink()
+{
+ if (sizeLimit && messages.size() > sizeLimit)
+ {
+ if (fullHandler)
+ {
+ fullHandler();
+ }
+ while (messages.size() > sizeLimit)
+ {
+ messages.pop_front();
+ }
+ }
+ if (timeLimit && !messages.empty())
+ {
+ time_t oldest;
+ time(&oldest);
+ oldest -= timeLimit * 60 /* sec */;
+ if (messages.begin()->timeStamp < oldest)
+ {
+ if (fullHandler)
+ {
+ fullHandler();
+ }
+ while (!messages.empty() && messages.begin()->timeStamp < oldest)
+ {
+ messages.pop_front();
+ }
+ }
+ }
+}