Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions Documentation/components/drivers/special/syslog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,73 @@ Other miscellaneous settings
- ``CONFIG_RAMLOG_NPOLLWAITERS``: The maximum number of threads
that may be waiting on the poll method.

RAMLOG Rate Limiting
--------------------

The RAMLOG SYSLOG channel supports rate limiting to prevent log flooding.
You can set or get the rate limit using the following IOCTLs:

- ``SYSLOGIOC_SETRATELIMIT``: Set the rate limit.
- ``SYSLOGIOC_GETRATELIMIT``: Get the current rate limit.

The argument is a pointer to:

.. code-block:: c

struct syslog_ratelimit_s
{
unsigned int interval; /* The interval in seconds */
unsigned int burst; /* The max allowed log entries during interval */
};

**Example (C code):**

.. code-block:: c

struct syslog_ratelimit_s limit = { .interval = 1, .burst = 100 };
ioctl(fd, SYSLOGIOC_SETRATELIMIT, (unsigned long)&limit);

**NSH Tool Example: setlograte**

You can implement a simple NSH command to control the RAMLOG rate limit at runtime, similar to setlogmask:

.. code-block:: c

int cmd_setlograte(int argc, char **argv)
{
int fd;
struct syslog_ratelimit_s limit;

if (argc != 3)
{
printf("Usage: setlograte <interval_sec> <burst>\n");
return -1;
}

limit.interval = atoi(argv[1]);
limit.burst = atoi(argv[2]);

fd = open("/dev/ramlog", O_RDWR);
if (fd < 0)
{
printf("Failed to open /dev/ramlog\n");
return -1;
}

if (ioctl(fd, SYSLOGIOC_SETRATELIMIT, (unsigned long)&limit) < 0)
{
printf("Failed to set rate limit\n");
close(fd);
return -1;
}

printf("Set RAMLOG rate limit: interval=%u sec, burst=%u\n", limit.interval, limit.burst);
close(fd);
return 0;
}

This command allows you to set the maximum number of log entries (burst) allowed in a given interval (seconds) for the RAMLOG device at runtime.

SYSLOG Protocol (RFC 5424)
==========================

Expand Down
111 changes: 109 additions & 2 deletions drivers/syslog/ramlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@
* Private Types
****************************************************************************/

struct ramlog_ratelimit_s
{
unsigned int interval; /* The interval in seconds */
unsigned int burst; /* The max allowed note number during interval */
unsigned int printed; /* The number of printed note during interval */
unsigned long begin; /* The timestamp in seconds */
};

struct ramlog_header_s
{
uint32_t rl_magic; /* The rl_magic number for ramlog buffer init */
Expand Down Expand Up @@ -98,8 +106,9 @@ struct ramlog_dev_s

FAR struct ramlog_header_s *rl_header;

uint32_t rl_bufsize; /* Size of the Circular RAM buffer */
struct list_node rl_list; /* The head of ramlog_user_s list */
uint32_t rl_bufsize; /* Size of the circular buffer */
struct list_node rl_list; /* The list of ramlog_user_s */
struct ramlog_ratelimit_s rl_ratelimit; /* The ratelimit for ramlog */
};

/****************************************************************************
Expand Down Expand Up @@ -173,6 +182,65 @@ static struct ramlog_dev_s g_sysdev =
* Private Functions
****************************************************************************/

/****************************************************************************
* Name: ramlog_ratelimit
*
* Description:
* Check whether the log is limited.
*
* Input Parameters:
* dev - The pointer of ramlog device.
*
* Returned Value:
* True is returned if the log is limited.
*
****************************************************************************/

static bool ramlog_ratelimit(FAR struct ramlog_dev_s *dev)
{
bool ret;
clock_t ticks;
uint32_t seconds;
FAR struct ramlog_ratelimit_s *limit;

limit = &dev->rl_ratelimit;

if (limit->interval == 0)
{
return false;
}

ticks = clock_systime_ticks();
seconds = ticks * CONFIG_USEC_PER_TICK / 1000000;

if (limit->begin == 0)
{
limit->begin = seconds;
}

/* Reset statistical information */

if ((seconds - limit->begin) >= limit->interval)
{
limit->begin = seconds;
limit->printed = 0;
}

/* Check if the note is limited */

if (limit->burst && limit->burst > limit->printed)
{
limit->printed++;
ret = false;
}
else
{
ret = true;
}

return ret;
}

/****************************************************************************
* Name: ramlog_bufferused
****************************************************************************/
Expand Down Expand Up @@ -301,6 +369,12 @@ static ssize_t ramlog_addbuf(FAR struct ramlog_dev_s *priv,

flags = enter_critical_section();

if (ramlog_ratelimit(priv))
{
leave_critical_section(flags);
return len;
}

#ifdef CONFIG_RAMLOG_SYSLOG
if (header->rl_magic != RAMLOG_MAGIC_NUMBER && priv == &g_sysdev)
{
Expand Down Expand Up @@ -521,6 +595,39 @@ static int ramlog_file_ioctl(FAR struct file *filep, int cmd,
case BIOC_FLUSH:
ramlog_bufferflush(priv);
break;

case SYSLOGIOC_SETRATELIMIT:
if (arg == 0)
{
ret = -EINVAL;
}
else
{
FAR struct syslog_ratelimit_s *limit =
(FAR struct syslog_ratelimit_s *)arg;

priv->rl_ratelimit.interval = limit->interval;
priv->rl_ratelimit.burst = limit->burst;
ret = 0;
}
break;

case SYSLOGIOC_GETRATELIMIT:
if (arg == 0)
{
ret = -EINVAL;
}
else
{
FAR struct syslog_ratelimit_s *limit =
(FAR struct syslog_ratelimit_s *)arg;

limit->interval = priv->rl_ratelimit.interval;
limit->burst = priv->rl_ratelimit.burst;
ret = 0;
}
break;

default:
ret = -ENOTTY;
break;
Expand Down
11 changes: 11 additions & 0 deletions include/nuttx/syslog/syslog.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@

#define SYSLOGIOC_SETFILTER _SYSLOGIOC(0x0002)

/* Set/Get syslog ratelimit */

#define SYSLOGIOC_SETRATELIMIT _SYSLOGIOC(0x0003)
#define SYSLOGIOC_GETRATELIMIT _SYSLOGIOC(0x0004)

#define SYSLOG_CHANNEL_NAME_LEN 32

#define SYSLOG_CHANNEL_DISABLE 0x01
Expand Down Expand Up @@ -127,6 +132,12 @@ struct syslog_channel_ops_s
syslog_close_t sc_close; /* Channel close callback */
};

struct syslog_ratelimit_s
{
unsigned int interval; /* The interval in seconds */
unsigned int burst; /* The max allowed note number during interval */
};

struct syslog_channel_info_s
{
char sc_name[SYSLOG_CHANNEL_NAME_LEN];
Expand Down
Loading