├── README.markdown ├── config └── ngx_backtrace_module.c /README.markdown: -------------------------------------------------------------------------------- 1 | Name 2 | ==== 3 | 4 | * Backtrace module. It comes from [Tengine](http://tengine.taobao.org), an Nginx distribution with quite a few advanced features. 5 | 6 | Description 7 | =========== 8 | 9 | * It can be used to dump backtrace of nginx in case a worker process exits abnormally, e.g. when some signal is received (SIGABR, SIGBUS, SIGFPE, SIGILL, SIGIOT, SIGSEGV). It's quite handy for debugging purpose. 10 | * This module requires the backtrace(3) function in glibc. You can't enable it on systems lack of this function (FreeBSD, Darwin). 11 | 12 | Directives 13 | ========== 14 | 15 | backtrace_log 16 | ------------- 17 | 18 | **Syntax**: *backtrace_log log_path* 19 | **Default**: *backtrace_log error.log* 20 | **Context**: *main* 21 | 22 | Specify the log file name of backtrace. 23 | backtrace_log /path/to/backtrace.log 24 | 25 | backtrace_max_stack_size 26 | ------------------------ 27 | 28 | **Syntax**: *backtrace_max_stack_size size* 29 | **Default**: *backtrace_max_stack_size 30* 30 | **Context**: *main* 31 | 32 | Specify the maximum stack depth for backtrace 33 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_feature="BACKTRACE" 2 | ngx_feature_name= 3 | ngx_feature_run=no 4 | ngx_feature_incs="#include " 5 | ngx_feature_path= 6 | ngx_feature_test="void *buffer[10]; 7 | backtrace(buffer, sizeof(buffer) / sizeof(buffer[0]));" 8 | . auto/feature 9 | 10 | if [ $ngx_found = no ]; then 11 | 12 | cat << END 13 | 14 | $0: error: the backtrace module requires backtrace function. 15 | You can either do not enable the module or update your libc library. 16 | 17 | END 18 | exit 1 19 | fi 20 | 21 | ngx_addon_name=ngx_backtrace_module 22 | LINK="$LINK -rdynamic" 23 | HTTP_MODULES="$HTTP_MODULES ngx_backtrace_module" 24 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_backtrace_module.c" 25 | -------------------------------------------------------------------------------- /ngx_backtrace_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) 2010-2012 Alibaba Group Holding Limited 4 | */ 5 | 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | 13 | #define NGX_BACKTRACE_DEFAULT_STACK_MAX_SIZE 30 14 | 15 | 16 | static char *ngx_backtrace_files(ngx_conf_t *cf, ngx_command_t *cmd, 17 | void *conf); 18 | static void ngx_error_signal_handler(int signo); 19 | static ngx_int_t ngx_backtrace_init_worker(ngx_cycle_t *cycle); 20 | static void *ngx_backtrace_create_conf(ngx_cycle_t *cycle); 21 | 22 | 23 | typedef struct { 24 | int signo; 25 | char *signame; 26 | char *name; 27 | void (*handler)(int signo); 28 | } ngx_signal_t; 29 | 30 | 31 | typedef struct { 32 | ngx_log_t *log; 33 | ngx_int_t max_stack_size; 34 | } ngx_backtrace_conf_t; 35 | 36 | 37 | static ngx_signal_t ngx_backtrace_signals[] = { 38 | { SIGABRT, "SIGABRT", "", ngx_error_signal_handler }, 39 | 40 | #ifdef SIGBUS 41 | { SIGBUS, "SIGBUS", "", ngx_error_signal_handler }, 42 | #endif 43 | 44 | { SIGFPE, "SIGFPE", "", ngx_error_signal_handler }, 45 | 46 | { SIGILL, "SIGILL", "", ngx_error_signal_handler }, 47 | 48 | { SIGIOT, "SIGIOT", "", ngx_error_signal_handler }, 49 | 50 | { SIGSEGV, "SIGSEGV", "", ngx_error_signal_handler }, 51 | 52 | { 0, NULL, "", NULL } 53 | }; 54 | 55 | 56 | static ngx_command_t ngx_backtrace_commands[] = { 57 | 58 | { ngx_string("backtrace_log"), 59 | NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 60 | ngx_backtrace_files, 61 | 0, 62 | 0, 63 | NULL }, 64 | 65 | { ngx_string("backtrace_max_stack_size"), 66 | NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, 67 | ngx_conf_set_num_slot, 68 | 0, 69 | offsetof(ngx_backtrace_conf_t, max_stack_size), 70 | NULL }, 71 | 72 | ngx_null_command 73 | }; 74 | 75 | 76 | static ngx_core_module_t ngx_backtrace_module_ctx = { 77 | ngx_string("backtrace"), 78 | ngx_backtrace_create_conf, 79 | NULL 80 | }; 81 | 82 | 83 | ngx_module_t ngx_backtrace_module = { 84 | NGX_MODULE_V1, 85 | &ngx_backtrace_module_ctx, /* module context */ 86 | ngx_backtrace_commands, /* module directives */ 87 | NGX_CORE_MODULE, /* module type */ 88 | NULL, /* init master */ 89 | NULL, /* init module */ 90 | ngx_backtrace_init_worker, /* init process */ 91 | NULL, /* init thread */ 92 | NULL, /* exit thread */ 93 | NULL, /* exit process */ 94 | NULL, /* exit master */ 95 | NGX_MODULE_V1_PADDING 96 | }; 97 | 98 | 99 | static ngx_int_t 100 | ngx_init_error_signals(ngx_log_t *log) 101 | { 102 | ngx_signal_t *sig; 103 | struct sigaction sa; 104 | 105 | for (sig = ngx_backtrace_signals; sig->signo != 0; sig++) { 106 | ngx_memzero(&sa, sizeof(struct sigaction)); 107 | sa.sa_handler = sig->handler; 108 | sigemptyset(&sa.sa_mask); 109 | if (sigaction(sig->signo, &sa, NULL) == -1) { 110 | ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, 111 | "sigaction(%s) failed", sig->signame); 112 | return NGX_ERROR; 113 | } 114 | } 115 | 116 | return NGX_OK; 117 | } 118 | 119 | 120 | static void 121 | ngx_error_signal_handler(int signo) 122 | { 123 | void *buffer; 124 | size_t size; 125 | ngx_log_t *log; 126 | ngx_signal_t *sig; 127 | struct sigaction sa; 128 | ngx_backtrace_conf_t *bcf; 129 | 130 | for (sig = ngx_backtrace_signals; sig->signo != 0; sig++) { 131 | if (sig->signo == signo) { 132 | break; 133 | } 134 | } 135 | 136 | bcf = (ngx_backtrace_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, 137 | ngx_backtrace_module); 138 | 139 | log = bcf->log ? bcf->log : ngx_cycle->log; 140 | ngx_log_error(NGX_LOG_ERR, log, 0, 141 | "nginx coredump by signal %d (%s)", signo, sig->signame); 142 | 143 | ngx_memzero(&sa, sizeof(struct sigaction)); 144 | sa.sa_handler = SIG_DFL; 145 | sigemptyset(&sa.sa_mask); 146 | if (sigaction(signo, &sa, NULL) == -1) { 147 | ngx_log_error(NGX_LOG_ERR, log, ngx_errno, 148 | "sigaction(%s) failed", sig->signame); 149 | } 150 | 151 | if (bcf->max_stack_size == NGX_CONF_UNSET) { 152 | bcf->max_stack_size = NGX_BACKTRACE_DEFAULT_STACK_MAX_SIZE; 153 | } 154 | 155 | buffer = ngx_pcalloc(ngx_cycle->pool, sizeof(void *) * bcf->max_stack_size); 156 | if (buffer == NULL) { 157 | goto invalid; 158 | } 159 | 160 | size = backtrace(buffer, bcf->max_stack_size); 161 | backtrace_symbols_fd(buffer, size, log->file->fd); 162 | 163 | invalid: 164 | 165 | kill(ngx_getpid(), signo); 166 | } 167 | 168 | 169 | static char * 170 | ngx_backtrace_files(ngx_conf_t *cf, ngx_command_t *cmd, 171 | void *conf) 172 | { 173 | ngx_str_t file, *value; 174 | ngx_log_t *log; 175 | ngx_backtrace_conf_t *bcf; 176 | 177 | bcf = (ngx_backtrace_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, 178 | ngx_backtrace_module); 179 | 180 | value = cf->args->elts; 181 | file = value[1]; 182 | 183 | if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { 184 | return NGX_CONF_ERROR; 185 | } 186 | 187 | log = ngx_log_create(cf->cycle, &file); 188 | if (log == NULL) { 189 | return NGX_CONF_ERROR; 190 | } 191 | 192 | bcf->log = log; 193 | 194 | return NGX_CONF_OK; 195 | } 196 | 197 | 198 | static ngx_int_t 199 | ngx_backtrace_init_worker(ngx_cycle_t *cycle) 200 | { 201 | if (ngx_init_error_signals(cycle->log) == NGX_ERROR) { 202 | return NGX_ERROR; 203 | } 204 | 205 | return NGX_OK; 206 | } 207 | 208 | 209 | static void * 210 | ngx_backtrace_create_conf(ngx_cycle_t *cycle) 211 | { 212 | ngx_backtrace_conf_t *bcf; 213 | 214 | bcf = ngx_pcalloc(cycle->pool, sizeof(ngx_backtrace_conf_t)); 215 | if (bcf == NULL) { 216 | return NULL; 217 | } 218 | 219 | /* 220 | * set by ngx_pcalloc() 221 | * 222 | * bcf->log = NULL; 223 | */ 224 | 225 | bcf->max_stack_size = NGX_CONF_UNSET; 226 | 227 | return bcf; 228 | } 229 | --------------------------------------------------------------------------------