blob: 5117f10134bc89ecd7c5bfc9149efcd09bd6c100 [file] [log] [blame]
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "google3/host_commands.h"
#include "message_util.hpp"
#include <fmt/format.h>
#include <stdplus/raw.hpp>
#include <algorithm>
#include <chrono>
#include <condition_variable>
#include <cstdint>
#include <cstring>
#include <functional>
#include <iostream>
#include <mutex>
#include <optional>
#include <queue>
#include <thread>
#include <unordered_map>
constexpr int kTransactionBufferSize = 1024;
constexpr int kBufferReadTimeoutMs = 1000;
constexpr int kMaxReadBufferIterations = 35;
constexpr bool kDebug = false;
constexpr int kHothBufferSize = 4096;
constexpr int kRateLimiterMilliSeconds = 500;
constexpr int kTransactionTimeoutInMicroSec = 1000;
constexpr int kMaxFileSizeInBytes = 4 * 1024 * 1024; // 4 MB in bytes
constexpr int kAsyncWaitTimeInSeconds = 30;
constexpr int kHeartBeatUpperLimit = 25;
const std::string kSyslogFileNamePrefix = "/tmp/syslog_file_";
// This is required to get a read-offset that is guaranteed to be out of the
// Hoth buffer, thus clients can offset the write-buffer with a big-enough value
// and let Hoth point to the correct read-offset.
// Use the same value as the upstreamed libhoth/htool:
// https://github.com/google/libhoth/commit/e4827163741e0804f12ac96c81b8e97649be6795
constexpr uint32_t kReadOffsetTweak = 0x80000000;
namespace google
{
namespace hoth
{
namespace internal
{
enum class PublishType : uint8_t
{
Stderr,
File
};
/**
* @brief Supports rate limit for a single threaded mechanism, where requests
* are discarded when the elapsed time < rate limit time
*/
class RateLimiter
{
public:
explicit RateLimiter(int rateLimitInMilliseconds) :
rateLimitInMilliseconds(rateLimitInMilliseconds)
{
std::chrono::hours one_day(24);
std::chrono::steady_clock::time_point yesterday =
std::chrono::steady_clock::now() - one_day;
lastTimeStamp = yesterday;
};
bool allowedByLimiter()
{
auto now = std::chrono::steady_clock::now();
auto timeElapsed = now - lastTimeStamp;
if (timeElapsed > std::chrono::milliseconds(rateLimitInMilliseconds))
{
lastTimeStamp = now;
return true;
}
return false;
};
std::chrono::steady_clock::time_point getTimeStamp()
{
return lastTimeStamp;
}
private:
int rateLimitInMilliseconds;
std::chrono::steady_clock::time_point lastTimeStamp;
};
class LogCollectorUtil
{
public:
LogCollectorUtil(RateLimiter& rateLimiter, int asyncWaitTime);
~LogCollectorUtil() = default;
/**
* @brief Generates a request for snapshotting hoth buffer
*
* @return request as a vector of bytes
*/
static std::vector<uint8_t> generateSnapshotRequest();
/**
* @brief Generates a request for getting the snapshot of the hoth buffer
*
* @return request as a vector of bytes
*/
static std::vector<uint8_t> generateGrabSnapshotRequest();
/**
* @brief Verifies the response header
*
* @return true or false (in terms of validity)
*/
static bool isResponseValid(std::vector<uint8_t> response);
/**
* @brief Generates Collect Uart Request
*
* @param[in] channelId - Channel Id for Uart
* @param[in] readOffset - Offset from where the buffer is to be read
*/
static std::vector<uint8_t>
generateCollectUartLogsRequest(uint32_t channelId, uint32_t readOffset);
/**
* @brief Publishes the snapshot based on publish type
*
* @param[in] response - Response vector
* @param[in] publishType - Stderr or file
* @param[in] filePathSuffix - File path name suffix if Publish type is file
* @param[in] meta - If any meta data is to be printed in the logs
*
*/
static void publishSnapshot(std::vector<uint8_t> response,
PublishType publishType,
std::string_view filePathSuffix = "",
std::string_view meta = "");
/**
* @brief Generate unique request id
*
* @return request id
*/
int generateRequestId();
/**
* @brief Gets the wait time set during initialization
*
* @return wait time in seconds
*/
int getAsyncWaitTime() const;
/**
* @brief Current request counter
*/
int requestCounter = 0;
/**
* @brief Create GetChannelWriteOffset request
*
* @param[in] channelId - Unique channel id
*
* @return request bytes for channel write offset
*/
static std::vector<uint8_t>
generateGetChannelWriteOffsetRequest(const uint32_t &channelId);
/**
* @brief Writes to file
*
* @param[in] data - string of data to be dumped in a file
* @param[in] name - suffix of the file name (gets attached to prefix -
* "syslog_file")
*/
static void writeToFile(std::string_view data, std::string_view name);
/**
* @brief Sends a heartbeat once every kHeartBeatLimit when invoked
*
* @param[in] data - Message for the heartbeat
*/
static void heartbeat(std::string_view message);
/**
* @brief Rate Limits the requests to be sent to log collector
*/
RateLimiter rateLimiter;
/**
* @brief Async wait timer for uart logs
*/
int asyncWaitTime = 0;
};
} // namespace internal
} // namespace hoth
} // namespace google