Skip to content

Commit

Permalink
Add new queries per second (QPS) metric exposed via GET /api/stats/su…
Browse files Browse the repository at this point in the history
…mmary as .queries.frequency and /api/info/ftl as .query_frequency. The QPS value is averaged over 30 seconds

Signed-off-by: DL6ER <[email protected]>
  • Loading branch information
DL6ER committed Sep 7, 2024
1 parent a2dbfed commit e82056a
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/FTL.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@
// Default: 2592000 (once per month)
#define DATABASE_MACVENDOR_INTERVAL 2592000

// Over how many seonds should the query-per-second (QPS) value be averaged?

Check failure on line 146 in src/FTL.h

View workflow job for this annotation

GitHub Actions / spell-check

seonds ==> seconds, sends
// Default: 30 (seconds)
#define QPS_AVGLEN 30

// Use out own syscalls handling functions that will detect possible errors
// and report accordingly in the log. This will make debugging FTL crash
// caused by insufficient memory or by code bugs (not properly dealing
Expand Down
4 changes: 4 additions & 0 deletions src/api/docs/content/specs/info.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,10 @@ components:
type: integer
description: Currently used privacy level
example: 0
query_frequency:
type: number
description: Average number of queries per second
example: 1.1
clients:
type: object
properties:
Expand Down
4 changes: 4 additions & 0 deletions src/api/docs/content/specs/stats.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,10 @@ components:
type: integer
description: Number of queries replied to from cache or local configuration
example: 9765
frequency:
type: number
description: Average number of queries per second
example: 1.1
types:
type: object
description: Number of individual queries
Expand Down
2 changes: 2 additions & 0 deletions src/api/info.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,7 @@ static int get_ftl_obj(struct ftl_conn *api, cJSON *ftl)
const int db_denied = counters->database.domains.denied;
const int clients_total = counters->clients;
const int privacylevel = config.misc.privacylevel.v.privacy_level;
const double qps = get_qps();

// unique_clients: count only clients that have been active within the most recent 24 hours
int activeclients = 0;
Expand Down Expand Up @@ -575,6 +576,7 @@ static int get_ftl_obj(struct ftl_conn *api, cJSON *ftl)
JSON_ADD_ITEM_TO_OBJECT(ftl, "database", database);

JSON_ADD_NUMBER_TO_OBJECT(ftl, "privacy_level", privacylevel);
JSON_ADD_NUMBER_TO_OBJECT(ftl, "query_frequency", qps);

cJSON *clients = JSON_NEW_OBJECT();
JSON_ADD_NUMBER_TO_OBJECT(clients, "total",clients_total);
Expand Down
2 changes: 2 additions & 0 deletions src/api/stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ int api_stats_summary(struct ftl_conn *api)
JSON_ADD_NUMBER_TO_OBJECT(queries, "forwarded", forwarded);
JSON_ADD_NUMBER_TO_OBJECT(queries, "cached", cached);

JSON_ADD_NUMBER_TO_OBJECT(queries, "frequency", get_qps());

cJSON *types = JSON_NEW_OBJECT();
int ret = get_query_types_obj(api, types);
if(ret != 0)
Expand Down
3 changes: 3 additions & 0 deletions src/dnsmasq_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,9 @@ bool _FTL_new_query(const unsigned int flags, const char *name,
return false;
}

// Update rolling window of queries per second
update_qps(querytimestamp);

// Interface name is only available for regular queries, not for
// automatically generated DNSSEC queries
const char *interface = internal_query ? "-" : next_iface.name;
Expand Down
43 changes: 43 additions & 0 deletions src/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,3 +1206,46 @@ int __attribute__((pure)) is_shm_fd(const int fd)
// Not found
return 0;
}

// Update queries per second (qps) value
// This is done in shared memory to allow for both UDP and TCP workers to
// contribute.
void update_qps(const double timestamp)
{
// Get the timeslot for the current timestamp
const unsigned int slot = (unsigned int)timestamp % QPS_AVGLEN;

// Check if the timestamp is in the same slot as the last one
if(shmSettings->qps.last != slot)
{
// Reset all the slots in between
// This is relevant if less than one query per second is
// received and the intermediate slots are not updated
for(unsigned int i = (shmSettings->qps.last + 1) % QPS_AVGLEN; i != slot; i = (i + 1) % QPS_AVGLEN)
shmSettings->qps.buf[i] = 0;

// Reset the current slot
shmSettings->qps.buf[slot] = 0;

// Update the last slot index
shmSettings->qps.last = slot;
}

// Add the query
shmSettings->qps.buf[slot]++;
}

// Compute queries per second (qps) value
double __attribute__((pure)) get_qps(void)
{
// Compute the arithmetic mean of all slots
// 1 N
// QPS = --- Σ buf[i]
// N i=0
//
double qps = 0.0;
for(unsigned int i = 0; i < QPS_AVGLEN; i++)
qps += shmSettings->qps.buf[i];

return qps / QPS_AVGLEN;
}
7 changes: 7 additions & 0 deletions src/shmem.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ typedef struct {
pid_t pid;
unsigned int global_shm_counter;
unsigned int next_str_pos;
struct {
unsigned int last;
unsigned int buf[QPS_AVGLEN];
} qps;
} ShmSettings;

typedef struct {
Expand Down Expand Up @@ -145,4 +149,7 @@ void set_per_client_regex(const int clientID, const int regexID, const bool valu
// Used in dnsmasq/utils.c
int is_shm_fd(const int fd);

void update_qps(const double timestamp);
double get_qps(void) __attribute__((pure));

#endif //SHARED_MEMORY_SERVER_H

0 comments on commit e82056a

Please sign in to comment.