mirror of
https://github.com/tbnobody/OpenDTU.git
synced 2025-12-10 16:59:52 +01:00
logging: centralize rate limiting
This commit is contained in:
committed by
Thomas Basler
parent
20003a0f92
commit
c106224052
@@ -24,8 +24,6 @@ private:
|
|||||||
|
|
||||||
Task _loopTask;
|
Task _loopTask;
|
||||||
|
|
||||||
int log_vprintf_locked(const char *fmt, va_list arguments);
|
|
||||||
|
|
||||||
static constexpr size_t BUFFER_SIZE = 8192;
|
static constexpr size_t BUFFER_SIZE = 8192;
|
||||||
char _buffer[BUFFER_SIZE];
|
char _buffer[BUFFER_SIZE];
|
||||||
size_t _buffer_in = 0;
|
size_t _buffer_in = 0;
|
||||||
@@ -60,6 +58,18 @@ private:
|
|||||||
std::mutex _msgLock;
|
std::mutex _msgLock;
|
||||||
|
|
||||||
void serialWrite(const uint8_t* buffer, size_t size);
|
void serialWrite(const uint8_t* buffer, size_t size);
|
||||||
|
|
||||||
|
static constexpr uint32_t RATE_LIMIT_WINDOW_MS = 1000;
|
||||||
|
static constexpr size_t RATE_LIMIT_MAX_TOKENS = 128;
|
||||||
|
size_t _available_tokens = RATE_LIMIT_MAX_TOKENS;
|
||||||
|
uint32_t _last_token_refill_millis = 0;
|
||||||
|
size_t _rate_limited_packets = 0;
|
||||||
|
uint32_t _last_rate_limit_warning_millis = 0;
|
||||||
|
static constexpr uint32_t RATE_LIMIT_WARNING_INTERVAL_MS = 1000;
|
||||||
|
bool consumeToken();
|
||||||
|
int log_self(const char* fmt, ...);
|
||||||
|
int log_vprintf_rate_limited(const char* fmt, va_list arguments);
|
||||||
|
int log_vprintf_recursive(const char* fmt, va_list arguments);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MessageOutputClass MessageOutput;
|
extern MessageOutputClass MessageOutput;
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ private:
|
|||||||
return _address != INADDR_NONE;
|
return _address != INADDR_NONE;
|
||||||
}
|
}
|
||||||
static uint8_t calculatePrival(uint8_t facility, char errorCode);
|
static uint8_t calculatePrival(uint8_t facility, char errorCode);
|
||||||
bool consumeToken();
|
|
||||||
|
|
||||||
Task _loopTask;
|
Task _loopTask;
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
@@ -31,14 +30,6 @@ private:
|
|||||||
String _header;
|
String _header;
|
||||||
uint16_t _port;
|
uint16_t _port;
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
|
|
||||||
static constexpr uint32_t RATE_LIMIT_WINDOW_MS = 1000;
|
|
||||||
static constexpr size_t RATE_LIMIT_MAX_TOKENS = 100;
|
|
||||||
size_t _available_tokens = RATE_LIMIT_MAX_TOKENS;
|
|
||||||
uint32_t _last_token_refill_millis = 0;
|
|
||||||
size_t _rate_limited_packets = 0;
|
|
||||||
uint32_t _last_rate_limit_warning_millis = 0;
|
|
||||||
static constexpr uint32_t RATE_LIMIT_WARNING_INTERVAL_MS = 1000;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SyslogLogger Syslog;
|
extern SyslogLogger Syslog;
|
||||||
|
|||||||
@@ -30,10 +30,63 @@ void MessageOutputClass::register_ws_output(AsyncWebSocket* output)
|
|||||||
int MessageOutputClass::log_vprintf(const char* fmt, va_list arguments)
|
int MessageOutputClass::log_vprintf(const char* fmt, va_list arguments)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(MessageOutput._msgLock);
|
std::lock_guard<std::mutex> lock(MessageOutput._msgLock);
|
||||||
return MessageOutput.log_vprintf_locked(fmt, arguments);
|
return MessageOutput.log_vprintf_rate_limited(fmt, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MessageOutputClass::log_vprintf_locked(const char* fmt, va_list arguments)
|
bool MessageOutputClass::consumeToken()
|
||||||
|
{
|
||||||
|
uint32_t now = millis();
|
||||||
|
|
||||||
|
uint32_t elapsed = now - _last_token_refill_millis;
|
||||||
|
size_t new_tokens = RATE_LIMIT_MAX_TOKENS * elapsed / RATE_LIMIT_WINDOW_MS;
|
||||||
|
|
||||||
|
if (new_tokens > 0) {
|
||||||
|
_available_tokens = std::min(_available_tokens + new_tokens, RATE_LIMIT_MAX_TOKENS);
|
||||||
|
_last_token_refill_millis = now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_available_tokens > 0) {
|
||||||
|
--_available_tokens;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MessageOutputClass::log_self(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
int ret = log_vprintf_recursive(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MessageOutputClass::log_vprintf_rate_limited(const char* fmt, va_list arguments)
|
||||||
|
{
|
||||||
|
if (!consumeToken()) {
|
||||||
|
if (_rate_limited_packets == 0) {
|
||||||
|
_last_rate_limit_warning_millis = millis();
|
||||||
|
}
|
||||||
|
++_rate_limited_packets;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rate_limited_packets > 0) {
|
||||||
|
uint32_t elapsed = millis() - _last_rate_limit_warning_millis;
|
||||||
|
if (elapsed > RATE_LIMIT_WARNING_INTERVAL_MS) {
|
||||||
|
log_self("W (%d) logging: Rate limited %d message%s in the last %d ms\n",
|
||||||
|
millis(), _rate_limited_packets,
|
||||||
|
(_rate_limited_packets > 1 ? "s" : ""), elapsed);
|
||||||
|
_rate_limited_packets = 0;
|
||||||
|
_last_rate_limit_warning_millis = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return log_vprintf_recursive(fmt, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MessageOutputClass::log_vprintf_recursive(const char* fmt, va_list arguments)
|
||||||
{
|
{
|
||||||
// we can only write up to the end of the buffer
|
// we can only write up to the end of the buffer
|
||||||
auto len = sizeof(_buffer) - _buffer_in;
|
auto len = sizeof(_buffer) - _buffer_in;
|
||||||
@@ -71,7 +124,7 @@ int MessageOutputClass::log_vprintf_locked(const char* fmt, va_list arguments)
|
|||||||
// we can safely reset the buffer as there is no data ahead that
|
// we can safely reset the buffer as there is no data ahead that
|
||||||
// still needs processing, so we try again from the beginning.
|
// still needs processing, so we try again from the beginning.
|
||||||
_buffer_in = 0;
|
_buffer_in = 0;
|
||||||
return log_vprintf_locked(fmt, arguments);
|
return log_vprintf_recursive(fmt, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Serial) {
|
if (Serial) {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
#include "defaults.h"
|
#include "defaults.h"
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#undef TAG
|
#undef TAG
|
||||||
static const char* TAG = "syslog";
|
static const char* TAG = "syslog";
|
||||||
@@ -66,27 +65,6 @@ void SyslogLogger::write(const uint8_t* buffer, size_t size)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check rate limiting using token bucket
|
|
||||||
if (!consumeToken()) {
|
|
||||||
if (_rate_limited_packets == 0) {
|
|
||||||
_last_rate_limit_warning_millis = millis();
|
|
||||||
}
|
|
||||||
++_rate_limited_packets;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_rate_limited_packets > 0) {
|
|
||||||
uint32_t elapsed = (millis() - _last_rate_limit_warning_millis);
|
|
||||||
if (elapsed > RATE_LIMIT_WARNING_INTERVAL_MS) {
|
|
||||||
char buffer[128];
|
|
||||||
snprintf(buffer, sizeof(buffer), "Rate limited %d packets in the last %dms",
|
|
||||||
_rate_limited_packets, elapsed);
|
|
||||||
Serial.println(buffer);
|
|
||||||
_rate_limited_packets = 0;
|
|
||||||
_last_rate_limit_warning_millis = millis();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String header = "<";
|
String header = "<";
|
||||||
header += String(calculatePrival(1, buffer[0]));
|
header += String(calculatePrival(1, buffer[0]));
|
||||||
|
|
||||||
@@ -104,26 +82,6 @@ void SyslogLogger::write(const uint8_t* buffer, size_t size)
|
|||||||
_udp.endPacket();
|
_udp.endPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SyslogLogger::consumeToken()
|
|
||||||
{
|
|
||||||
uint32_t now = millis();
|
|
||||||
|
|
||||||
uint32_t elapsed = now - _last_token_refill_millis;
|
|
||||||
size_t new_tokens = RATE_LIMIT_MAX_TOKENS * elapsed / RATE_LIMIT_WINDOW_MS;
|
|
||||||
|
|
||||||
if (new_tokens > 0) {
|
|
||||||
_available_tokens = std::min(_available_tokens + new_tokens, RATE_LIMIT_MAX_TOKENS);
|
|
||||||
_last_token_refill_millis = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_available_tokens > 0) {
|
|
||||||
--_available_tokens;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SyslogLogger::disable()
|
void SyslogLogger::disable()
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Disable");
|
ESP_LOGI(TAG, "Disable");
|
||||||
@@ -145,8 +103,6 @@ void SyslogLogger::enable()
|
|||||||
|
|
||||||
std::lock_guard<std::mutex> lock(_mutex);
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
_enabled = true;
|
_enabled = true;
|
||||||
_available_tokens = RATE_LIMIT_MAX_TOKENS;
|
|
||||||
_last_token_refill_millis = millis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SyslogLogger::resolveAndStart()
|
bool SyslogLogger::resolveAndStart()
|
||||||
|
|||||||
Reference in New Issue
Block a user