blob: f511a95ab9edb2d39bf5accee5b1bb04b8178eb8 [file] [log] [blame]
// 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();
}
}
}
}