From a7d12cbaf1425bf86f18b7dfac99f7b1ee1500e2 Mon Sep 17 00:00:00 2001 From: antirez Date: Wed, 28 Mar 2012 13:45:39 +0200 Subject: [PATCH] Log from signal handlers is now safer. --- src/debug.c | 15 +++------------ src/redis.c | 30 +++++++++++++++++++++++++++++- src/redis.h | 1 + 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/debug.c b/src/debug.c index 49c76824..e7b3ba40 100644 --- a/src/debug.c +++ b/src/debug.c @@ -682,25 +682,16 @@ void watchdogSignalHandler(int sig, siginfo_t *info, void *secret) { REDIS_NOTUSED(info); REDIS_NOTUSED(sig); sds st, log; - time_t now = time(NULL); - char date[128]; - FILE *fp; - fp = (server.logfile == NULL) ? stdout : fopen(server.logfile,"a"); - if (fp == NULL) return; - - strftime(date,sizeof(date),"%d %b %H:%M:%S",localtime(&now)); - log = sdscatprintf(sdsempty(), - "\n--- WATCHDOG TIMER EXPIRED (%s) ---\n",date); + log = sdsnew("\n--- WATCHDOG TIMER EXPIRED ---\n"); #ifdef HAVE_BACKTRACE st = getStackTrace(uc); #else st = sdsnew("Sorry: no support for backtrace().\n"); #endif log = sdscatsds(log,st); - log = sdscat(log,"------\n\n"); - fprintf(fp,"%s",log); - if (server.logfile) fclose(fp); + log = sdscat(log,"------\n"); + redisLogFromHandler(REDIS_WARNING,log); sdsfree(st); sdsfree(log); } diff --git a/src/redis.c b/src/redis.c index 5ee44a31..5af2b1df 100644 --- a/src/redis.c +++ b/src/redis.c @@ -293,6 +293,34 @@ void redisLog(int level, const char *fmt, ...) { redisLogRaw(level,msg); } +/* Log a fixed message without printf-alike capabilities, in a way that is + * safe to call from a signal handler. + * + * We actually use this only for signals that are not fatal from the point + * of view of Redis. Signals that are going to kill the server anyway and + * where we need printf-alike features are served by redisLog(). */ +void redisLogFromHandler(int level, const char *msg) { + int fd; + char buf[64]; + + if ((level&0xff) < server.verbosity || + (server.logfile == NULL && server.daemonize)) return; + fd = server.logfile ? + open(server.logfile, O_APPEND|O_CREAT|O_WRONLY, 0644) : + STDIN_FILENO; + if (fd == -1) return; + ll2string(buf,sizeof(buf),getpid()); + write(fd,"[",1); + write(fd,buf,strlen(buf)); + write(fd," | signal handler] (",20); + ll2string(buf,sizeof(buf),time(NULL)); + write(fd,buf,strlen(buf)); + write(fd,") ",2); + write(fd,msg,strlen(msg)); + write(fd,"\n",1); + close(fd); +} + /* Redis generally does not try to recover from out of memory conditions * when allocating objects or strings, it is not clear if it will be possible * to report this condition to the client since the networking layer itself @@ -2282,7 +2310,7 @@ void redisAsciiArt(void) { static void sigtermHandler(int sig) { REDIS_NOTUSED(sig); - redisLog(REDIS_WARNING,"Received SIGTERM, scheduling shutdown..."); + redisLogFromHandler(REDIS_WARNING,"Received SIGTERM, scheduling shutdown..."); server.shutdown_asap = 1; } diff --git a/src/redis.h b/src/redis.h index c5812f0a..41e24557 100644 --- a/src/redis.h +++ b/src/redis.h @@ -1004,6 +1004,7 @@ void alsoPropagate(struct redisCommand *cmd, int dbid, robj **argv, int argc, in int prepareForShutdown(); void redisLog(int level, const char *fmt, ...); void redisLogRaw(int level, const char *msg); +void redisLogFromHandler(int level, const char *msg); void usage(); void updateDictResizePolicy(void); int htNeedsResize(dict *dict); -- 2.45.2