]> git.saurik.com Git - redis.git/commitdiff
better bug report info on crash
authorantirez <antirez@gmail.com>
Thu, 24 Nov 2011 14:47:26 +0000 (15:47 +0100)
committerantirez <antirez@gmail.com>
Thu, 24 Nov 2011 14:47:26 +0000 (15:47 +0100)
src/debug.c
src/redis.c
src/redis.h

index 376e07125df988bf1942813879635619f2877bb3..d610d2a97d4fe96d677d1d7edcff3a12c422b492 100644 (file)
@@ -297,10 +297,14 @@ void debugCommand(redisClient *c) {
 }
 
 void _redisAssert(char *estr, char *file, int line) {
+    bugReportStart();
     redisLog(REDIS_WARNING,"=== ASSERTION FAILED ===");
     redisLog(REDIS_WARNING,"==> %s:%d '%s' is not true",file,line,estr);
 #ifdef HAVE_BACKTRACE
-    redisLog(REDIS_WARNING,"(forcing SIGSEGV in order to print the stack trace)");
+    server.assert_failed = estr;
+    server.assert_file = file;
+    server.assert_line = line;
+    redisLog(REDIS_WARNING,"(forcing SIGSEGV to print the bug report.)");
     *((char*)-1) = 'x';
 #endif
 }
@@ -308,6 +312,7 @@ void _redisAssert(char *estr, char *file, int line) {
 void _redisAssertPrintClientInfo(redisClient *c) {
     int j;
 
+    bugReportStart();
     redisLog(REDIS_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ===");
     redisLog(REDIS_WARNING,"client->flags = %d", c->flags);
     redisLog(REDIS_WARNING,"client->fd = %d", c->fd);
@@ -331,6 +336,7 @@ void _redisAssertPrintClientInfo(redisClient *c) {
 }
 
 void _redisAssertPrintObject(robj *o) {
+    bugReportStart();
     redisLog(REDIS_WARNING,"=== ASSERTION FAILED OBJECT CONTEXT ===");
     redisLog(REDIS_WARNING,"Object type: %d", o->type);
     redisLog(REDIS_WARNING,"Object encoding: %d", o->encoding);
@@ -349,6 +355,7 @@ void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int l
 }
 
 void _redisPanic(char *msg, char *file, int line) {
+    bugReportStart();
     redisLog(REDIS_WARNING,"------------------------------------------------");
     redisLog(REDIS_WARNING,"!!! Software Failure. Press left mouse button to continue");
     redisLog(REDIS_WARNING,"Guru Meditation: %s #%s:%d",msg,file,line);
index eb391f1a7ba2b57263b329b85b4dce688446f387..735de9d650897c9b6fc161e7b6d6e87298e45ea2 100644 (file)
@@ -946,6 +946,12 @@ void initServerConfig() {
     /* Slow log */
     server.slowlog_log_slower_than = REDIS_SLOWLOG_LOG_SLOWER_THAN;
     server.slowlog_max_len = REDIS_SLOWLOG_MAX_LEN;
+
+    /* Assert */
+    server.assert_failed = "<no assertion failed>";
+    server.assert_file = "<no file>";
+    server.assert_line = 0;
+    server.bug_report_start = 0;
 }
 
 void initServer() {
@@ -1946,32 +1952,56 @@ static void *getMcontextEip(ucontext_t *uc) {
 #endif
 }
 
+void bugReportStart(void) {
+    if (server.bug_report_start == 0) {
+        redisLog(REDIS_WARNING,
+            "=== REDIS BUG REPORT START: Cut & paste starting from here ===");
+        server.bug_report_start = 1;
+    }
+}
+
 static void sigsegvHandler(int sig, siginfo_t *info, void *secret) {
     void *trace[100];
     char **messages = NULL;
     int i, trace_size = 0;
     ucontext_t *uc = (ucontext_t*) secret;
-    sds infostring;
+    sds infostring, clients;
     struct sigaction act;
     REDIS_NOTUSED(info);
 
+    bugReportStart();
     redisLog(REDIS_WARNING,
-        "======= Ooops! Redis %s got signal: -%d- =======", REDIS_VERSION, sig);
-    infostring = genRedisInfoString("all");
-    redisLogRaw(REDIS_WARNING, infostring);
-    /* It's not safe to sdsfree() the returned string under memory
-     * corruption conditions. Let it leak as we are going to abort */
+        "    Redis %s crashed by signal: %d", REDIS_VERSION, sig);
+    redisLog(REDIS_WARNING,
+        "    Failed assertion: %s (%s:%d)", server.assert_failed,
+                        server.assert_file, server.assert_line);
 
+    /* Generate the stack trace */
     trace_size = backtrace(trace, 100);
+
     /* overwrite sigaction with caller's address */
     if (getMcontextEip(uc) != NULL) {
         trace[1] = getMcontextEip(uc);
     }
     messages = backtrace_symbols(trace, trace_size);
-
+    redisLog(REDIS_WARNING, "--- STACK TRACE");
     for (i=1; i<trace_size; ++i)
         redisLog(REDIS_WARNING,"%s", messages[i]);
 
+    /* Log INFO and CLIENT LIST */
+    redisLog(REDIS_WARNING, "--- INFO OUTPUT");
+    infostring = genRedisInfoString("all");
+    redisLogRaw(REDIS_WARNING, infostring);
+    redisLog(REDIS_WARNING, "--- CLIENT LIST OUTPUT");
+    clients = getAllClientsInfoString();
+    redisLogRaw(REDIS_WARNING, clients);
+    /* Don't sdsfree() strings to avoid a crash. Memory may be corrupted. */
+
+    redisLog(REDIS_WARNING,
+"=== REDIS BUG REPORT END. Make sure to include from START to END. ===\n\n"
+"    Please report the crash opening an issue on github:\n\n"
+"        http://github.com/antirez/redis/issues\n\n"
+);
     /* free(messages); Don't call free() with possibly corrupted memory. */
     if (server.daemonize) unlink(server.pidfile);
 
index 218d72fbf13cd776ee3a378fcc2f93944e2fde2f..431eeb1404b16487a35631ac54381c333ed2b1ec 100644 (file)
@@ -634,6 +634,11 @@ struct redisServer {
     int lua_timedout;     /* True if we reached the time limit for script
                              execution. */
     int lua_kill;         /* Kill the script if true. */
+    /* Assert & bug reportign */
+    char *assert_failed;
+    char *assert_file;
+    int assert_line;
+    int bug_report_start; /* True if bug report header already logged. */
 };
 
 typedef struct pubsubPattern {
@@ -1148,5 +1153,6 @@ void *realloc(void *ptr, size_t size) __attribute__ ((deprecated));
 void _redisAssertWithInfo(redisClient *c, robj *o, char *estr, char *file, int line);
 void _redisAssert(char *estr, char *file, int line);
 void _redisPanic(char *msg, char *file, int line);
+void bugReportStart(void);
 
 #endif