]>
git.saurik.com Git - redis.git/blob - src/slowlog.c
1 /* Slowlog implements a system that is able to remember the latest N
2 * queries that took more than M microseconds to execute.
4 * The execution time to reach to be logged in the slow log is set
5 * using the 'slowlog-log-slower-than' config directive, that is also
6 * readable and writable using the CONFIG SET/GET command.
8 * The slow queries log is actually not "logged" in the Redis log file
9 * but is accessible thanks to the SLOWLOG command.
11 * ----------------------------------------------------------------------------
13 * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com>
14 * All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions are met:
19 * * Redistributions of source code must retain the above copyright notice,
20 * this list of conditions and the following disclaimer.
21 * * Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * * Neither the name of Redis nor the names of its contributors may be used
25 * to endorse or promote products derived from this software without
26 * specific prior written permission.
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
45 /* Create a new slowlog entry.
46 * Incrementing the ref count of all the objects retained is up to
48 slowlogEntry
*slowlogCreateEntry(robj
**argv
, int argc
, long long duration
) {
49 slowlogEntry
*se
= zmalloc(sizeof(*se
));
52 if (slargc
> SLOWLOG_ENTRY_MAX_ARGC
) slargc
= SLOWLOG_ENTRY_MAX_ARGC
;
54 se
->argv
= zmalloc(sizeof(robj
*)*slargc
);
55 for (j
= 0; j
< slargc
; j
++) {
56 /* Logging too many arguments is a useless memory waste, so we stop
57 * at SLOWLOG_ENTRY_MAX_ARGC, but use the last argument to specify
58 * how many remaining arguments there were in the original command. */
59 if (slargc
!= argc
&& j
== slargc
-1) {
60 se
->argv
[j
] = createObject(REDIS_STRING
,
61 sdscatprintf(sdsempty(),"... (%d more arguments)",
64 /* Trim too long strings as well... */
65 if (argv
[j
]->type
== REDIS_STRING
&&
66 argv
[j
]->encoding
== REDIS_ENCODING_RAW
&&
67 sdslen(argv
[j
]->ptr
) > SLOWLOG_ENTRY_MAX_STRING
)
69 sds s
= sdsnewlen(argv
[j
]->ptr
, SLOWLOG_ENTRY_MAX_STRING
);
71 s
= sdscatprintf(s
,"... (%lu more bytes)",
73 sdslen(argv
[j
]->ptr
) - SLOWLOG_ENTRY_MAX_STRING
);
74 se
->argv
[j
] = createObject(REDIS_STRING
,s
);
76 se
->argv
[j
] = argv
[j
];
77 incrRefCount(argv
[j
]);
81 se
->time
= time(NULL
);
82 se
->duration
= duration
;
83 se
->id
= server
.slowlog_entry_id
++;
87 /* Free a slow log entry. The argument is void so that the prototype of this
88 * function matches the one of the 'free' method of adlist.c.
90 * This function will take care to release all the retained object. */
91 void slowlogFreeEntry(void *septr
) {
92 slowlogEntry
*se
= septr
;
95 for (j
= 0; j
< se
->argc
; j
++)
96 decrRefCount(se
->argv
[j
]);
101 /* Initialize the slow log. This function should be called a single time
102 * at server startup. */
103 void slowlogInit(void) {
104 server
.slowlog
= listCreate();
105 server
.slowlog_entry_id
= 0;
106 listSetFreeMethod(server
.slowlog
,slowlogFreeEntry
);
109 /* Push a new entry into the slow log.
110 * This function will make sure to trim the slow log accordingly to the
111 * configured max length. */
112 void slowlogPushEntryIfNeeded(robj
**argv
, int argc
, long long duration
) {
113 if (server
.slowlog_log_slower_than
< 0) return; /* Slowlog disabled */
114 if (duration
>= server
.slowlog_log_slower_than
)
115 listAddNodeHead(server
.slowlog
,slowlogCreateEntry(argv
,argc
,duration
));
117 /* Remove old entries if needed. */
118 while (listLength(server
.slowlog
) > server
.slowlog_max_len
)
119 listDelNode(server
.slowlog
,listLast(server
.slowlog
));
122 /* Remove all the entries from the current slow log. */
123 void slowlogReset(void) {
124 while (listLength(server
.slowlog
) > 0)
125 listDelNode(server
.slowlog
,listLast(server
.slowlog
));
128 /* The SLOWLOG command. Implements all the subcommands needed to handle the
130 void slowlogCommand(redisClient
*c
) {
131 if (c
->argc
== 2 && !strcasecmp(c
->argv
[1]->ptr
,"reset")) {
133 addReply(c
,shared
.ok
);
134 } else if (c
->argc
== 2 && !strcasecmp(c
->argv
[1]->ptr
,"len")) {
135 addReplyLongLong(c
,listLength(server
.slowlog
));
136 } else if ((c
->argc
== 2 || c
->argc
== 3) &&
137 !strcasecmp(c
->argv
[1]->ptr
,"get"))
139 long count
= 10, sent
= 0;
146 getLongFromObjectOrReply(c
,c
->argv
[2],&count
,NULL
) != REDIS_OK
)
149 listRewind(server
.slowlog
,&li
);
150 totentries
= addDeferredMultiBulkLength(c
);
151 while(count
-- && (ln
= listNext(&li
))) {
155 addReplyMultiBulkLen(c
,4);
156 addReplyLongLong(c
,se
->id
);
157 addReplyLongLong(c
,se
->time
);
158 addReplyLongLong(c
,se
->duration
);
159 addReplyMultiBulkLen(c
,se
->argc
);
160 for (j
= 0; j
< se
->argc
; j
++)
161 addReplyBulk(c
,se
->argv
[j
]);
164 setDeferredMultiBulkLength(c
,totentries
,sent
);
167 "Unknown SLOWLOG subcommand or wrong # of args. Try GET, RESET, LEN.");