Skip to content
Open
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
187 changes: 183 additions & 4 deletions cmdlog.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <fcntl.h>
#include <assert.h>
#include <errno.h>
#include <ctype.h>

#include "memcached/util.h"

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

#define CMDLOG_FILTER_MAXNUM 10
#define CMDLOG_FILTER_CMD_MAXLEN 15
#define CMDLOG_FILTER_KEY_MAXLEN 16000

/* cmdlog state */
#define CMDLOG_NOT_STARTED 0 /* not started */
#define CMDLOG_OVERFLOW_STOP 1 /* stop by command log overflow */
Expand All @@ -59,6 +64,12 @@ struct cmd_log_buffer {
uint32_t last;
};

/* command log filter structure */
struct cmd_log_filter {
char command[CMDLOG_FILTER_CMD_MAXLEN + 1];
char key[CMDLOG_FILTER_KEY_MAXLEN + 1];
};

/*command log flush structure */
struct cmd_log_flush {
pthread_t tid; /* flush thread id */
Expand All @@ -85,6 +96,8 @@ struct cmd_log_global {
struct cmd_log_buffer buffer;
struct cmd_log_flush flush;
struct cmd_log_stats stats;
struct cmd_log_filter filters[CMDLOG_FILTER_MAXNUM];
int nfilters;
volatile bool reqstop;
};
struct cmd_log_global cmdlog;
Expand Down Expand Up @@ -397,25 +410,42 @@ char *cmdlog_stats(void)
return str;
}

void cmdlog_write(char *client_ip, char *command)
void cmdlog_write(char *client_ip, char *command, int cmdlen)
{
struct tm *ptm;
struct timeval val;
struct cmd_log_buffer *buffer = &cmdlog.buffer;
char inputstr[CMDLOG_INPUT_SIZE];
char *ptr = command;
int inputlen;
int nwritten;
int seglen;

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

nwritten = snprintf(inputstr, CMDLOG_INPUT_SIZE, "%02d:%02d:%02d.%06ld %s %s\n",
ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (long)val.tv_usec, client_ip, command);
nwritten = snprintf(inputstr, CMDLOG_INPUT_SIZE, "%02d:%02d:%02d.%06ld %s ",
ptm->tm_hour, ptm->tm_min, ptm->tm_sec, (long)val.tv_usec, client_ip);

while (ptr < command + cmdlen && nwritten < CMDLOG_INPUT_SIZE) {
seglen = snprintf(inputstr + nwritten, CMDLOG_INPUT_SIZE - nwritten, "%s", ptr);
nwritten += seglen;
ptr += seglen;

if (ptr < command + cmdlen && nwritten < CMDLOG_INPUT_SIZE) {
inputstr[nwritten++] = ' ';
ptr++;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@6unYoung
์—ฌ๊ธฐ ์ฝ”๋“œ ์ˆ˜์ •์€ ๋ฒ„๊ทธ๋ฅผ ์ œ๊ฑฐํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ธ๊ฐ€์š”?
๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์กฐ๊ธˆ ์ˆ˜์ •ํ•ด์„œ๋„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์€ ๋ฐ์š”. ์–ด๋–ค๊ฐ€์š”?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ํ•ด๋‹น ์ฝ”๋“œ๋Š” cmdlog_write() ํ˜ธ์ถœ ์ „์— tokenize_command()๋ฅผ ๋จผ์ € ํ˜ธ์ถœํ•˜๊ฒŒ ์ˆ˜์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค. command๊ฐ€ tokenized๋œ ์ƒํƒœ์ด๋ฏ€๋กœ ๋„ ๋ฌธ์ž๋ฅผ ๊ฑด๋„ˆ๋›ฐ๋ฉด์„œ ์ปค๋งจ๋“œ ๋ผ์ธ ์ „์ฒด๋ฅผ ์ž…๋ ฅ๋ฐ›๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.


/* truncated ? */
if (nwritten > CMDLOG_INPUT_SIZE) {
if (nwritten >= CMDLOG_INPUT_SIZE) {
inputstr[CMDLOG_INPUT_SIZE-4] = '.';
inputstr[CMDLOG_INPUT_SIZE-3] = '.';
inputstr[CMDLOG_INPUT_SIZE-2] = '\n';
} else {
inputstr[nwritten++] = '\n';
inputstr[nwritten] = '\0';
}
inputlen = strlen(inputstr);

Expand Down Expand Up @@ -447,3 +477,152 @@ void cmdlog_write(char *client_ip, char *command)
}
pthread_mutex_unlock(&buffer->lock);
}

static int get_key_idx_by_command(const char *command)
{
assert(command);
int cmdlen = strlen(command);

if (cmdlen < 3) {
return -1;
}

if ((cmdlen == 3 && memcmp(command, "gat", 3) == 0) ||
(cmdlen == 4 && memcmp(command, "gats", 4) == 0) ||
((command[0] == 'l' || command[0] == 's' || command[0] == 'm' || command[0] == 'b') &&
strcmp(command + 1, "op") == 0)) {
if ((cmdlen == 8 && memcmp(command, "bop_mget", 8) == 0) ||
(cmdlen == 9 && memcmp(command, "bop_smget", 9) == 0)) {
return -1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 ๋ฆฌํ„ดํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mget๋ฅ˜ ๋ช…๋ น์˜ ๊ฒฝ์šฐ์— key๋ฅผ ๋ณ„๋„์˜ ๋ผ์ธ์œผ๋กœ ์ž…๋ ฅ๋ฐ›๊ธฐ์— ํ‚ค๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ธฐ์— ๋ฒˆ๊ฑฐ๋กญ๊ณ , ๊ธฐ์กด cmdlog ๋™์ž‘์—์„œ๋„ ํ‚ค ๋ผ์ธ์„ ๋กœ๊น…ํ•˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ mget๋ฅ˜ ๋ช…๋ น์€ key๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ -1์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

}
return 2;
} else if ((cmdlen == 3 && memcmp(command, "get", 3) == 0) ||
(cmdlen == 4 && memcmp(command, "gets", 4) == 0) ||
(cmdlen == 3 && memcmp(command, "add", 3) == 0) ||
(cmdlen == 3 && memcmp(command, "set", 3) == 0) ||
(cmdlen == 7 && memcmp(command, "replace", 7) == 0) ||
(cmdlen == 7 && memcmp(command, "prepend", 7) == 0) ||
(cmdlen == 6 && memcmp(command, "append", 6) == 0) ||
(cmdlen == 3 && memcmp(command, "cas", 3) == 0) ||
(cmdlen == 4 && memcmp(command, "incr", 4) == 0) ||
(cmdlen == 4 && memcmp(command, "decr", 4) == 0) ||
(cmdlen == 6 && memcmp(command, "delete", 6) == 0) ||
(cmdlen == 7 && memcmp(command, "getattr", 7) == 0) ||
(cmdlen == 7 && memcmp(command, "setattr", 7) == 0) ||
(cmdlen == 5 && memcmp(command, "touch", 5) == 0)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๊ธฐ์กด์—๋Š” ๋ชจ๋“  ๋ช…๋ น์„ ๋กœ๊น…ํ•  ์ˆ˜ ์žˆ์—ˆ์ง€๋งŒ,
ํ˜„์žฌ๋Š” config, zkensemble ๋“ฑ์˜ ๋ช…๋ น์„ ๋กœ๊น…ํ•˜์ง€ ์•Š๋„ค์š”.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋กœ๊น… ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

return 1;
}

return -1;
}

bool is_cmdlog_filter_match(token_t *tokens, size_t ntokens)
{
char command[CMDLOG_FILTER_CMD_MAXLEN + 1] = "";
char *key = "";
int key_idx = -1;
bool matched = false;

if (cmdlog.nfilters == 0) {
return true;
}

if (ntokens < 2) {
return false;
}

if (ntokens >= 3 && strcmp(tokens[0].value + 1, "op") == 0) {
snprintf(command, CMDLOG_FILTER_CMD_MAXLEN + 1, "%3s_%s", tokens[0].value, tokens[1].value);
} else {
snprintf(command, CMDLOG_FILTER_CMD_MAXLEN + 1, "%s", tokens[0].value);
}

key_idx = get_key_idx_by_command(command);
if ((key_idx == 2 && ntokens >= 4) || (key_idx == 1 && ntokens >= 3)) {
key = tokens[key_idx].value;
}

pthread_mutex_lock(&cmdlog.lock);
for (int i = 0; i < cmdlog.nfilters; ++i) {
if (cmdlog.filters[i].command[0] == '\0' || strcmp(command, cmdlog.filters[i].command) == 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lop ๋ช…๋ น ์ „์ฒด๋ฅผ ๋กœ๊น…ํ•˜๋Š” ๊ฒƒ์€ ์•ˆ ๋˜๋‚˜์š”?

Copy link
Contributor Author

@6unYoung 6unYoung Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

collection type์— ๋Œ€ํ•ด ๋ถ€๋ถ„ ๋งค์นญ์„ ํ—ˆ์šฉํ•˜๋ฉด ๋‹ค๋ฅธ ๋ช…๋ น์–ด์— ๋Œ€ํ•ด์„œ๋„ ๋™์ผํ•œ ๋™์ž‘์„ ๊ธฐ๋Œ€ํ•  ๊ฒƒ ๊ฐ™์€๋ฐ, ํ•ด๋‹น ๋ถ€๋ถ„์„ ๊ณ ๋ คํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

if (cmdlog.filters[i].key[0] == '\0' || strcmp(key, cmdlog.filters[i].key) == 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exact match๋งŒ ํ—ˆ์šฉ๋˜๋‚˜์š”?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

๋„ค ๋งž์Šต๋‹ˆ๋‹ค

matched = true;
break;
}
}
}
pthread_mutex_unlock(&cmdlog.lock);
return matched;
}

int cmdlog_filter_add(const char *command, int command_len, const char *key, int key_len)
{
int success;

if (command_len > CMDLOG_FILTER_CMD_MAXLEN || key_len > CMDLOG_FILTER_KEY_MAXLEN) {
return -1;
}

if (key_len > 0) {
for (int i = 0; key[i] != '\0' && i < CMDLOG_FILTER_KEY_MAXLEN; ++i) {
if (!isgraph(key[i])) {
return -1;
}
}
}

success = 0;
pthread_mutex_lock(&cmdlog.lock);
if (cmdlog.nfilters < CMDLOG_FILTER_MAXNUM) {
strcpy(cmdlog.filters[cmdlog.nfilters].command, command);
strcpy(cmdlog.filters[cmdlog.nfilters].key, key);
cmdlog.nfilters++;
success++;
}
pthread_mutex_unlock(&cmdlog.lock);
return success;
}

int cmdlog_filter_remove(int idx, bool remove_all)
{
int nremove;

if (remove_all == false && (idx < 0 || idx >= cmdlog.nfilters)) {
return -1;
}

nremove = 0;
pthread_mutex_lock(&cmdlog.lock);
if (remove_all) {
nremove += cmdlog.nfilters;
cmdlog.nfilters = 0;
} else {
for (int i = idx; i < cmdlog.nfilters - 1; ++i) {
cmdlog.filters[i] = cmdlog.filters[i + 1];
}
cmdlog.nfilters--;
nremove++;
}
pthread_mutex_unlock(&cmdlog.lock);
return nremove;
}

char *cmdlog_filter_list(void)
{
char *buf = (char *)malloc((cmdlog.nfilters + 1) * CMDLOG_INPUT_SIZE);
int nwritten;

if (!buf) {
return NULL;
}

nwritten = 0;
pthread_mutex_lock(&cmdlog.lock);
nwritten = snprintf(buf, CMDLOG_INPUT_SIZE, "\t(%d / %d)\n", cmdlog.nfilters, CMDLOG_FILTER_MAXNUM);
for (int i = 0; i < cmdlog.nfilters; ++i) {
nwritten += snprintf(buf + nwritten, CMDLOG_INPUT_SIZE, "\t%d. command = %s, key = %s\n",
i, cmdlog.filters[i].command, cmdlog.filters[i].key);
}
pthread_mutex_unlock(&cmdlog.lock);
return buf;
}
6 changes: 5 additions & 1 deletion cmdlog.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,9 @@ void cmdlog_final(void);
int cmdlog_start(char *file_path, bool *already_started);
void cmdlog_stop(bool *already_stopped);
char *cmdlog_stats(void);
void cmdlog_write(char *client_ip, char *command);
void cmdlog_write(char *client_ip, char *command, int cmdlen);
bool is_cmdlog_filter_match(token_t *tokens, size_t ntokens);
int cmdlog_filter_add(const char *command, int command_len, const char *key, int key_len);
int cmdlog_filter_remove(int idx, bool remove_all);
char *cmdlog_filter_list(void);
#endif
30 changes: 30 additions & 0 deletions docs/ascii-protocol/ch13-command-administration.md
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,9 @@ start ๋ช…๋ น์„ ์‹œ์ž‘์œผ๋กœ logging์ด ์ข…๋ฃŒ๋  ๋•Œ ๊นŒ์ง€์˜ ๋ชจ๋“  command
cmdlog start [<log_file_path>]\r\n
cmdlog stop\r\n
cmdlog stats\r\n
cmdlog filter add (command <cmd>|key <key>|command <cmd> key <key>)\r\n
cmdlog filter remove (all|<idx>)\r\n
cmdlog filter list\r\n
```

\<log_file_path\>๋Š” logging ์ •๋ณด๋ฅผ ์ €์žฅํ•  file์˜ path์ด๋‹ค.
Expand Down Expand Up @@ -910,6 +913,33 @@ The number of log files : 1 //file_coun
The log file name: /Users/temp/command_11211_20160126_192729_{n}.log //path/file_name
```

filter add ๋ช…๋ น์€ ํ•„ํ„ฐ๋งํ•  ๋ช…๋ น์–ด์™€ ํ‚ค ์กฐํ•ฉ์„ ํ•„ํ„ฐ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•œ๋‹ค.
์ž…๋ ฅํ•œ ์กฐํ•ฉ์— ๋Œ€ํ•ด exact matching ๋ฐฉ์‹์œผ๋กœ ํ•„ํ„ฐ๋งํ•œ๋‹ค. response string์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

| Response String | ์„ค๋ช… |
| -------------------------------- | --------------------------------------------------------------------- |
| OK | ์„ฑ๊ณต |
| SERVER_ERROR filter list is full | ์กด์žฌํ•˜๋Š” ํ•„ํ„ฐ ์ˆ˜๊ฐ€ ์ด๋ฏธ ์ตœ๋Œ€์น˜์ด๋ฏ€๋กœ ๋” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†์Œ |
| CLIENT_ERROR invalid parameters | ์ธ์ž๋กœ ์ž…๋ ฅํ•œ command๋‚˜ key๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์€ ๋ฌธ์ž๊ฑฐ๋‚˜ ์ตœ๋Œ€ ๊ธธ์ด๋ฅผ ๋„˜์Œ |

filter remove ๋ช…๋ น์€ ํ•„ํ„ฐ ๋ฆฌ์ŠคํŠธ์—์„œ ํŠน์ • ์ธ๋ฑ์Šค์˜ ํ•„ํ„ฐ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
์ธ๋ฑ์Šค ๋Œ€์‹  all์„ ์ž…๋ ฅํ•˜๋ฉด ์กด์žฌํ•˜๋˜ ๋ชจ๋“  ํ•„ํ„ฐ๋ฅผ ์‚ญ์ œํ•œ๋‹ค. response string์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

| Response String | ์„ค๋ช… |
| -------------------------------- | ---------------------------------------------------- |
| OK | ์„ฑ๊ณต |
| SERVER_ERROR filter list is empty | ์กด์žฌํ•˜๋Š” ํ•„ํ„ฐ๊ฐ€ ์—†์Œ |
| CLIENT_ERROR invalid parameters | ์ธ์ž๋กœ ์ž…๋ ฅํ•œ ์ธ๋ฑ์Šค๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์กด์žฌํ•˜์ง€ ์•Š์Œ |

filter list ๋ช…๋ น์€ ์กด์žฌํ•˜๋Š” ํ•„ํ„ฐ ๋ชฉ๋ก์„ ์ถœ๋ ฅํ•œ๋‹ค.

```
(3 / 10)
0. command = add, key = 123
1. command = , key = kvkey:12
2. command = bop_insert, key =
```

<a id="long-query-detect"></a>
## Long Query Detect ๋ช…๋ น

Expand Down
Loading