]> git.saurik.com Git - redis.git/blob - src/slowlog.c
More redis.conf self-documentation. Now even queries that took exactly server.slow_lo...
[redis.git] / src / slowlog.c
1 #include "redis.h"
2 #include "slowlog.h"
3
4 /* Slowlog implements a system that is able to remember the latest N
5 * queries that took more than M microseconds to execute.
6 *
7 * The execution time to reach to be logged in the slow log is set
8 * using the 'slowlog-log-slower-than' config directive, that is also
9 * readable and writable using the CONFIG SET/GET command.
10 *
11 * The slow queries log is actually not "logged" in the Redis log file
12 * but is accessible thanks to the SLOWLOG command. */
13
14 /* Create a new slowlog entry.
15 * Incrementing the ref count of all the objects retained is up to
16 * this function. */
17 slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) {
18 slowlogEntry *se = zmalloc(sizeof(*se));
19 int j;
20
21 se->argc = argc;
22 se->argv = zmalloc(sizeof(robj*)*argc);
23 for (j = 0; j < argc; j++) {
24 se->argv[j] = argv[j];
25 incrRefCount(argv[j]);
26 }
27 se->time = time(NULL);
28 se->duration = duration;
29 return se;
30 }
31
32 /* Free a slow log entry. The argument is void so that the prototype of this
33 * function matches the one of the 'free' method of adlist.c.
34 *
35 * This function will take care to release all the retained object. */
36 void slowlogFreeEntry(void *septr) {
37 slowlogEntry *se = septr;
38 int j;
39
40 for (j = 0; j < se->argc; j++)
41 decrRefCount(se->argv[j]);
42 zfree(se->argv);
43 zfree(se);
44 }
45
46 /* Initialize the slow log. This function should be called a single time
47 * at server startup. */
48 void slowlogInit(void) {
49 server.slowlog = listCreate();
50 listSetFreeMethod(server.slowlog,slowlogFreeEntry);
51 }
52
53 /* Push a new entry into the slow log.
54 * This function will make sure to trim the slow log accordingly to the
55 * configured max length. */
56 void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) {
57 if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */
58 if (duration >= server.slowlog_log_slower_than)
59 listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration));
60
61 /* Remove old entries if needed. */
62 while (listLength(server.slowlog) > server.slowlog_max_len)
63 listDelNode(server.slowlog,listLast(server.slowlog));
64 }
65
66 /* Remove all the entries from the current slow log. */
67 void slowlogReset(void) {
68 while (listLength(server.slowlog) > 0)
69 listDelNode(server.slowlog,listLast(server.slowlog));
70 }
71
72 /* The SLOWLOG command. Implements all the subcommands needed to handle the
73 * Redis slow log. */
74 void slowlogCommand(redisClient *c) {
75 if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"reset")) {
76 slowlogReset();
77 addReply(c,shared.ok);
78 } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"len")) {
79 addReplyLongLong(c,listLength(server.slowlog));
80 } else if ((c->argc == 2 || c->argc == 3) &&
81 !strcasecmp(c->argv[1]->ptr,"get"))
82 {
83 long count = 10, sent = 0;
84 listIter li;
85 void *totentries;
86 listNode *ln;
87 slowlogEntry *se;
88
89 if (c->argc == 3 &&
90 getLongFromObjectOrReply(c,c->argv[2],&count,NULL) != REDIS_OK)
91 return;
92
93 listRewind(server.slowlog,&li);
94 totentries = addDeferredMultiBulkLength(c);
95 while(count-- && (ln = listNext(&li))) {
96 int j;
97
98 se = ln->value;
99 addReplyMultiBulkLen(c,3);
100 addReplyLongLong(c,se->time);
101 addReplyLongLong(c,se->duration);
102 addReplyMultiBulkLen(c,se->argc);
103 for (j = 0; j < se->argc; j++)
104 addReplyBulk(c,se->argv[j]);
105 sent++;
106 }
107 setDeferredMultiBulkLength(c,totentries,sent);
108 } else {
109 addReplyError(c,
110 "Unknown SLOWLOG subcommand or wrong # of args. Try GET, RESET, LEN.");
111 }
112 }