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 184 : slowlogEntry *slowlogCreateEntry(robj **argv, int argc, long long duration) {
18 184 : slowlogEntry *se = zmalloc(sizeof(*se));
19 : int j;
20 :
21 184 : se->argc = argc;
22 184 : se->argv = zmalloc(sizeof(robj*)*argc);
23 436 : for (j = 0; j < argc; j++) {
24 252 : se->argv[j] = argv[j];
25 252 : incrRefCount(argv[j]);
26 : }
27 184 : se->time = time(NULL);
28 184 : se->duration = duration;
29 184 : se->id = server.slowlog_entry_id++;
30 184 : return se;
31 : }
32 :
33 : /* Free a slow log entry. The argument is void so that the prototype of this
34 : * function matches the one of the 'free' method of adlist.c.
35 : *
36 : * This function will take care to release all the retained object. */
37 105 : void slowlogFreeEntry(void *septr) {
38 105 : slowlogEntry *se = septr;
39 : int j;
40 :
41 221 : for (j = 0; j < se->argc; j++)
42 116 : decrRefCount(se->argv[j]);
43 105 : zfree(se->argv);
44 105 : zfree(se);
45 105 : }
46 :
47 : /* Initialize the slow log. This function should be called a single time
48 : * at server startup. */
49 53 : void slowlogInit(void) {
50 53 : server.slowlog = listCreate();
51 53 : server.slowlog_entry_id = 0;
52 53 : listSetFreeMethod(server.slowlog,slowlogFreeEntry);
53 53 : }
54 :
55 : /* Push a new entry into the slow log.
56 : * This function will make sure to trim the slow log accordingly to the
57 : * configured max length. */
58 1748530 : void slowlogPushEntryIfNeeded(robj **argv, int argc, long long duration) {
59 1748530 : if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */
60 1748530 : if (duration >= server.slowlog_log_slower_than)
61 184 : listAddNodeHead(server.slowlog,slowlogCreateEntry(argv,argc,duration));
62 :
63 : /* Remove old entries if needed. */
64 1748625 : while (listLength(server.slowlog) > server.slowlog_max_len)
65 95 : listDelNode(server.slowlog,listLast(server.slowlog));
66 : }
67 :
68 : /* Remove all the entries from the current slow log. */
69 1 : void slowlogReset(void) {
70 12 : while (listLength(server.slowlog) > 0)
71 10 : listDelNode(server.slowlog,listLast(server.slowlog));
72 1 : }
73 :
74 : /* The SLOWLOG command. Implements all the subcommands needed to handle the
75 : * Redis slow log. */
76 8 : void slowlogCommand(redisClient *c) {
77 9 : if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"reset")) {
78 1 : slowlogReset();
79 1 : addReply(c,shared.ok);
80 12 : } else if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"len")) {
81 5 : addReplyLongLong(c,listLength(server.slowlog));
82 6 : } else if ((c->argc == 2 || c->argc == 3) &&
83 2 : !strcasecmp(c->argv[1]->ptr,"get"))
84 : {
85 2 : long count = 10, sent = 0;
86 : listIter li;
87 : void *totentries;
88 : listNode *ln;
89 : slowlogEntry *se;
90 :
91 3 : if (c->argc == 3 &&
92 1 : getLongFromObjectOrReply(c,c->argv[2],&count,NULL) != REDIS_OK)
93 : return;
94 :
95 2 : listRewind(server.slowlog,&li);
96 2 : totentries = addDeferredMultiBulkLength(c);
97 10 : while(count-- && (ln = listNext(&li))) {
98 : int j;
99 :
100 6 : se = ln->value;
101 6 : addReplyMultiBulkLen(c,4);
102 6 : addReplyLongLong(c,se->id);
103 6 : addReplyLongLong(c,se->time);
104 6 : addReplyLongLong(c,se->duration);
105 6 : addReplyMultiBulkLen(c,se->argc);
106 15 : for (j = 0; j < se->argc; j++)
107 9 : addReplyBulk(c,se->argv[j]);
108 6 : sent++;
109 : }
110 2 : setDeferredMultiBulkLength(c,totentries,sent);
111 : } else {
112 0 : addReplyError(c,
113 : "Unknown SLOWLOG subcommand or wrong # of args. Try GET, RESET, LEN.");
114 : }
115 : }
|