Skip to content

Commit d8ae576

Browse files
committed
FEATURE: Add cmdlog optional filtering
1 parent 77e7950 commit d8ae576

File tree

3 files changed

+297
-21
lines changed

3 files changed

+297
-21
lines changed

cmdlog.c

Lines changed: 182 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <fcntl.h>
2626
#include <assert.h>
2727
#include <errno.h>
28+
#include <ctype.h>
2829

2930
#include "memcached/util.h"
3031

@@ -38,6 +39,10 @@
3839
#define CMDLOG_FILENAME_LENGTH CMDLOG_DIRPATH_LENGTH + 128
3940
#define CMDLOG_FILENAME_FORMAT "%s/command_%d_%d_%d_%d.log"
4041

42+
#define CMDLOG_FILTER_MAXNUM 10
43+
#define CMDLOG_FILTER_CMD_MAXLEN 15
44+
#define CMDLOG_FILTER_KEY_MAXLEN 16000
45+
4146
/* cmdlog state */
4247
#define CMDLOG_NOT_STARTED 0 /* not started */
4348
#define CMDLOG_OVERFLOW_STOP 1 /* stop by command log overflow */
@@ -59,6 +64,12 @@ struct cmd_log_buffer {
5964
uint32_t last;
6065
};
6166

67+
/* command log filter structure */
68+
struct cmd_log_filter {
69+
char command[CMDLOG_FILTER_CMD_MAXLEN + 1];
70+
char key[CMDLOG_FILTER_KEY_MAXLEN + 1];
71+
};
72+
6273
/*command log flush structure */
6374
struct cmd_log_flush {
6475
pthread_t tid; /* flush thread id */
@@ -85,6 +96,8 @@ struct cmd_log_global {
8596
struct cmd_log_buffer buffer;
8697
struct cmd_log_flush flush;
8798
struct cmd_log_stats stats;
99+
struct cmd_log_filter filters[CMDLOG_FILTER_MAXNUM];
100+
int nfilters;
88101
volatile bool reqstop;
89102
};
90103
struct cmd_log_global cmdlog;
@@ -397,25 +410,42 @@ char *cmdlog_stats(void)
397410
return str;
398411
}
399412

400-
void cmdlog_write(char *client_ip, char *command)
413+
void cmdlog_write(char *client_ip, char *command, int cmdlen)
401414
{
402415
struct tm *ptm;
403416
struct timeval val;
404417
struct cmd_log_buffer *buffer = &cmdlog.buffer;
405418
char inputstr[CMDLOG_INPUT_SIZE];
419+
char *ptr = command;
406420
int inputlen;
407421
int nwritten;
422+
int seglen;
408423

409424
gettimeofday(&val, NULL);
410425
ptm = localtime(&val.tv_sec);
411426

412-
nwritten = snprintf(inputstr, CMDLOG_INPUT_SIZE, "%02d:%02d:%02d.%06ld %s %s\n",
413-
ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (long)val.tv_usec, client_ip, command);
427+
nwritten = snprintf(inputstr, CMDLOG_INPUT_SIZE, "%02d:%02d:%02d.%06ld %s ",
428+
ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (long)val.tv_usec, client_ip);
429+
430+
while (ptr < command + cmdlen && nwritten < CMDLOG_INPUT_SIZE) {
431+
seglen = snprintf(inputstr + nwritten, CMDLOG_INPUT_SIZE - nwritten, "%s", ptr);
432+
nwritten += seglen;
433+
ptr += seglen;
434+
435+
if (ptr < command + cmdlen && nwritten < CMDLOG_INPUT_SIZE) {
436+
inputstr[nwritten++] = ' ';
437+
ptr++;
438+
}
439+
}
440+
414441
/* truncated ? */
415-
if (nwritten > CMDLOG_INPUT_SIZE) {
442+
if (nwritten >= CMDLOG_INPUT_SIZE) {
416443
inputstr[CMDLOG_INPUT_SIZE-4] = '.';
417444
inputstr[CMDLOG_INPUT_SIZE-3] = '.';
418445
inputstr[CMDLOG_INPUT_SIZE-2] = '\n';
446+
} else {
447+
inputstr[nwritten++] = '\n';
448+
inputstr[nwritten] = '\0';
419449
}
420450
inputlen = strlen(inputstr);
421451

@@ -447,3 +477,151 @@ void cmdlog_write(char *client_ip, char *command)
447477
}
448478
pthread_mutex_unlock(&buffer->lock);
449479
}
480+
481+
static int get_key_idx_by_command(const char *command)
482+
{
483+
assert(command);
484+
int cmdlen = strlen(command);
485+
if (cmdlen < 3) {
486+
return -1;
487+
}
488+
489+
if ((command[0] == 'l' || command[0] == 's' || command[0] == 'm' || command[0] == 'b') &&
490+
strcmp(command + 1, "op") == 0) {
491+
if ((cmdlen == 8 && memcmp(command, "bop_mget", 8) == 0) ||
492+
(cmdlen == 9 && memcmp(command, "bop_smget", 9) == 0)) {
493+
return -1;
494+
}
495+
return 2;
496+
} else if ((cmdlen == 3 && memcmp(command, "get", 3) == 0) ||
497+
(cmdlen == 4 && memcmp(command, "gets", 4) == 0) ||
498+
(cmdlen == 3 && memcmp(command, "gat", 3) == 0) ||
499+
(cmdlen == 4 && memcmp(command, "gats", 4) == 0) ||
500+
(cmdlen == 3 && memcmp(command, "add", 3) == 0) ||
501+
(cmdlen == 3 && memcmp(command, "set", 3) == 0) ||
502+
(cmdlen == 7 && memcmp(command, "replace", 7) == 0) ||
503+
(cmdlen == 7 && memcmp(command, "prepend", 7) == 0) ||
504+
(cmdlen == 6 && memcmp(command, "append", 6) == 0) ||
505+
(cmdlen == 3 && memcmp(command, "cas", 3) == 0) ||
506+
(cmdlen == 4 && memcmp(command, "incr", 4) == 0) ||
507+
(cmdlen == 4 && memcmp(command, "decr", 4) == 0) ||
508+
(cmdlen == 6 && memcmp(command, "delete", 6) == 0) ||
509+
(cmdlen == 7 && memcmp(command, "getattr", 7) == 0) ||
510+
(cmdlen == 7 && memcmp(command, "setattr", 7) == 0) ||
511+
(cmdlen == 5 && memcmp(command, "touch", 5) == 0)) {
512+
return 1;
513+
}
514+
515+
return -1;
516+
}
517+
518+
bool is_cmdlog_filter_match(token_t *tokens, size_t ntokens)
519+
{
520+
char command[CMDLOG_FILTER_CMD_MAXLEN + 1] = "";
521+
char *key = "";
522+
int key_idx = -1;
523+
bool matched = false;
524+
525+
if (cmdlog.nfilters == 0) {
526+
return true;
527+
}
528+
529+
if (ntokens < 2) {
530+
return false;
531+
}
532+
533+
if (ntokens >= 3 && strcmp(tokens[0].value + 1, "op") == 0) {
534+
snprintf(command, CMDLOG_FILTER_CMD_MAXLEN + 1, "%3s_%s", tokens[0].value, tokens[1].value);
535+
} else {
536+
snprintf(command, CMDLOG_FILTER_CMD_MAXLEN + 1, "%s", tokens[0].value);
537+
}
538+
539+
key_idx = get_key_idx_by_command(command);
540+
if ((key_idx == 2 && ntokens >= 4) || (key_idx == 1 && ntokens >= 3)) {
541+
key = tokens[key_idx].value;
542+
}
543+
544+
pthread_mutex_lock(&cmdlog.lock);
545+
for (int i = 0; i < cmdlog.nfilters; ++i) {
546+
if (cmdlog.filters[i].command[0] == '\0' || strcmp(command, cmdlog.filters[i].command) == 0) {
547+
if (cmdlog.filters[i].key[0] == '\0' || strcmp(key, cmdlog.filters[i].key) == 0) {
548+
matched = true;
549+
break;
550+
}
551+
}
552+
}
553+
pthread_mutex_unlock(&cmdlog.lock);
554+
return matched;
555+
}
556+
557+
int cmdlog_filter_add(const char *command, int command_len, const char *key, int key_len)
558+
{
559+
int success;
560+
561+
if (command_len > CMDLOG_FILTER_CMD_MAXLEN || key_len > CMDLOG_FILTER_KEY_MAXLEN) {
562+
return -1;
563+
}
564+
565+
if (key_len > 0) {
566+
for (int i = 0; key[i] != '\0' && i < CMDLOG_FILTER_KEY_MAXLEN; ++i) {
567+
if (!isgraph(key[i])) {
568+
return -1;
569+
}
570+
}
571+
}
572+
573+
success = 0;
574+
pthread_mutex_lock(&cmdlog.lock);
575+
if (cmdlog.nfilters < CMDLOG_FILTER_MAXNUM) {
576+
strcpy(cmdlog.filters[cmdlog.nfilters].command, command);
577+
strcpy(cmdlog.filters[cmdlog.nfilters].key, key);
578+
cmdlog.nfilters++;
579+
success++;
580+
}
581+
pthread_mutex_unlock(&cmdlog.lock);
582+
return success;
583+
}
584+
585+
int cmdlog_filter_remove(int idx, bool remove_all)
586+
{
587+
int nremove;
588+
589+
if (remove_all == false && (idx < 0 || idx >= cmdlog.nfilters)) {
590+
return -1;
591+
}
592+
593+
nremove = 0;
594+
pthread_mutex_lock(&cmdlog.lock);
595+
if (remove_all) {
596+
nremove += cmdlog.nfilters;
597+
cmdlog.nfilters = 0;
598+
} else {
599+
for (int i = idx; i < cmdlog.nfilters - 1; ++i) {
600+
cmdlog.filters[i] = cmdlog.filters[i + 1];
601+
}
602+
cmdlog.nfilters--;
603+
nremove++;
604+
}
605+
pthread_mutex_unlock(&cmdlog.lock);
606+
return nremove;
607+
}
608+
609+
char *cmdlog_filter_list(void)
610+
{
611+
char *buf = (char *)malloc((cmdlog.nfilters + 1) * CMDLOG_INPUT_SIZE);
612+
int nwritten;
613+
614+
if (!buf) {
615+
return NULL;
616+
}
617+
618+
nwritten = 0;
619+
pthread_mutex_lock(&cmdlog.lock);
620+
nwritten = snprintf(buf, CMDLOG_INPUT_SIZE, "\t(%d / %d)\n", cmdlog.nfilters, CMDLOG_FILTER_MAXNUM);
621+
for (int i = 0; i < cmdlog.nfilters; ++i) {
622+
nwritten += snprintf(buf + nwritten, CMDLOG_INPUT_SIZE, "\t%d. command = %s, key = %s\n",
623+
i, cmdlog.filters[i].command, cmdlog.filters[i].key);
624+
}
625+
pthread_mutex_unlock(&cmdlog.lock);
626+
return buf;
627+
}

cmdlog.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,9 @@ void cmdlog_final(void);
3030
int cmdlog_start(char *file_path, bool *already_started);
3131
void cmdlog_stop(bool *already_stopped);
3232
char *cmdlog_stats(void);
33-
void cmdlog_write(char *client_ip, char *command);
33+
void cmdlog_write(char *client_ip, char *command, int cmdlen);
34+
bool is_cmdlog_filter_match(token_t *tokens, size_t ntokens);
35+
int cmdlog_filter_add(const char *command, int command_len, const char *key, int key_len);
36+
int cmdlog_filter_remove(int idx, bool remove_all);
37+
char *cmdlog_filter_list(void);
3438
#endif

0 commit comments

Comments
 (0)