TS-3145: implement remote backtrace for traffic_server Implement the ServerBacktrace API in traffic_manager using libunwind and ptrace(2). This allow operators to log a back trace of all the traffic_server threads.
Add the --backtrace option to traffic_line to display the backtrace. Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/3e5a3f13 Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/3e5a3f13 Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/3e5a3f13 Branch: refs/heads/master Commit: 3e5a3f134ca08a364e9ec38f02fb7cd85ba5425d Parents: d27b31b Author: James Peach <[email protected]> Authored: Tue Sep 30 15:22:20 2014 -0700 Committer: James Peach <[email protected]> Committed: Sat Oct 18 12:24:23 2014 -0700 ---------------------------------------------------------------------- cmd/traffic_line/traffic_line.cc | 13 +++ cmd/traffic_manager/Makefile.am | 1 + configure.ac | 12 +++ lib/ts/ink_cap.cc | 4 + lib/ts/ink_config.h.in | 1 + lib/ts/ink_file.h | 12 +++ mgmt/api/CoreAPI.cc | 187 ++++++++++++++++++++++++++++++++-- mgmt/api/CoreAPI.h | 1 + mgmt/api/CoreAPIRemote.cc | 42 ++++++++ mgmt/api/INKMgmtAPI.cc | 17 ++++ mgmt/api/Makefile.am | 3 +- mgmt/api/NetworkMessage.cc | 2 + mgmt/api/NetworkMessage.h | 1 + mgmt/api/TSControlMain.cc | 22 +++- mgmt/api/include/mgmtapi.h | 9 ++ 15 files changed, 314 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/cmd/traffic_line/traffic_line.cc ---------------------------------------------------------------------- diff --git a/cmd/traffic_line/traffic_line.cc b/cmd/traffic_line/traffic_line.cc index d5356c2..e40ecf5 100644 --- a/cmd/traffic_line/traffic_line.cc +++ b/cmd/traffic_line/traffic_line.cc @@ -52,6 +52,7 @@ static char ZeroNode[1024]; static char StorageCmdOffline[1024]; static int ShowAlarms; static int ShowStatus; +static int ShowBacktrace; static char ClearAlarms[1024]; static int VersionFlag; static char viaHeader[1024]; @@ -389,6 +390,17 @@ handleArgInvocation() break; } return TS_ERR_OKAY; + } else if (ShowBacktrace == 1) { + TSString trace = NULL; + TSMgmtError err; + + err = TSProxyBacktraceGet(0, &trace); + if (err == TS_ERR_OKAY) { + printf("%s\n", trace); + TSfree(trace); + } + + return err; } else if (*ReadVar != '\0') { // Handle a value read if (*SetVar != '\0' || *VarValue != '\0') { fprintf(stderr, "%s: Invalid Argument Combination: Can not read and set values at the same time\n", programName); @@ -566,6 +578,7 @@ main(int /* argc ATS_UNUSED */, char **argv) {"alarms", '-', "Show all alarms", "F", &ShowAlarms, NULL, NULL}, {"clear_alarms", '-', "Clear specified, or all, alarms", "S1024", &ClearAlarms, NULL, NULL}, {"status", '-', "Show proxy server status", "F", &ShowStatus, NULL, NULL}, + {"backtrace", '-', "Show proxy stack backtrace", "F", &ShowBacktrace, NULL, NULL}, {"version", 'V', "Print Version Id", "T", &VersionFlag, NULL, NULL}, {"decode_via", '-', "Decode Via Header", "S1024", &viaHeader, NULL, NULL}, }; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/cmd/traffic_manager/Makefile.am ---------------------------------------------------------------------- diff --git a/cmd/traffic_manager/Makefile.am b/cmd/traffic_manager/Makefile.am index 009671b..289c01c 100644 --- a/cmd/traffic_manager/Makefile.am +++ b/cmd/traffic_manager/Makefile.am @@ -53,6 +53,7 @@ traffic_manager_LDADD = \ $(top_builddir)/iocore/eventsystem/libinkevent.a \ $(top_builddir)/proxy/shared/liberror.a \ $(top_builddir)/proxy/shared/libdiagsconfig.a \ + $(LIBUNWIND_LIBS) \ @LIBRESOLV@ @LIBEXPAT@ @LIBPCRE@ @LIBTCL@ @LIBCAP@ @HWLOC_LIBS@ \ -lm http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/configure.ac ---------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index ed54039..c5f31b7 100644 --- a/configure.ac +++ b/configure.ac @@ -1200,6 +1200,18 @@ fi AC_SUBST(execinfoh) AC_SUBST(has_backtrace) +# Remote process unwinding is only implemented on Linux because it depends on various Linux-specific +# features such as /proc filesystem nodes, ptrace(2) and waitpid(2) extensions. +AS_IF([test "$host_os_def" = "linux"], [ + PKG_CHECK_MODULES([LIBUNWIND], [libunwind-ptrace], [ + enable_remote_unwinding=yes + ], [ + dnl no remote unwind support + ]) +]) +TS_ARG_ENABLE_VAR([use], [remote_unwinding]) +AC_SUBST(use_remote_unwinding) + use_epoll=0 use_kqueue=0 use_port=0 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/lib/ts/ink_cap.cc ---------------------------------------------------------------------- diff --git a/lib/ts/ink_cap.cc b/lib/ts/ink_cap.cc index e49ec6f..66af2e2 100644 --- a/lib/ts/ink_cap.cc +++ b/lib/ts/ink_cap.cc @@ -360,6 +360,10 @@ elevateFileAccess(unsigned level, bool state) ElevateAccess::ElevateAccess(const bool state, unsigned lvl) : elevated(false), saved_uid(geteuid()), level(lvl) { + // XXX Squash a clang [-Wunused-private-field] warning. The right solution is probably to extract + // the capabilities into a policy class. + (void)level; + if (state == true) { elevate(); #if !TS_USE_POSIX_CAP http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/lib/ts/ink_config.h.in ---------------------------------------------------------------------- diff --git a/lib/ts/ink_config.h.in b/lib/ts/ink_config.h.in index cde3103..c9ca78f 100644 --- a/lib/ts/ink_config.h.in +++ b/lib/ts/ink_config.h.in @@ -74,6 +74,7 @@ #define TS_USE_LINUX_NATIVE_AIO @use_linux_native_aio@ #define TS_USE_INTERIM_CACHE @has_interim_cache@ +#define TS_USE_REMOTE_UNWINDING @use_remote_unwinding@ /* OS API definitions */ #define GETHOSTBYNAME_R_GLIBC2 @gethostbyname_r_glibc2@ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/lib/ts/ink_file.h ---------------------------------------------------------------------- diff --git a/lib/ts/ink_file.h b/lib/ts/ink_file.h index 326710c..1feda36 100644 --- a/lib/ts/ink_file.h +++ b/lib/ts/ink_file.h @@ -118,4 +118,16 @@ struct ink_device_geometry bool ink_file_get_geometry(int fd, ink_device_geometry& geometry); +// Is the given path "."? +static inline bool +isdot(const char * path) { + return path[0] == '.' && path[1] == '\0'; +} + +// Is the given path ".."? +static inline bool +isdotdot(const char * path) { + return path[0] == '.' && path[1] == '.' && path[2] == '\0'; +} + #endif // _ink_file_h_ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/CoreAPI.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/CoreAPI.cc b/mgmt/api/CoreAPI.cc index 258ffe3..0c13b65 100644 --- a/mgmt/api/CoreAPI.cc +++ b/mgmt/api/CoreAPI.cc @@ -46,6 +46,7 @@ #include "CfgContextUtils.h" #include "EventCallback.h" #include "I_Layout.h" +#include "ink_cap.h" // global variable CallbackTable *local_event_callbacks; @@ -87,7 +88,6 @@ Terminate() return TS_ERR_OKAY; } - /*------------------------------------------------------------------------- * Diags *------------------------------------------------------------------------- @@ -137,7 +137,6 @@ Diags(TSDiagsT mode, const char *fmt, va_list ap) } } - /*************************************************************************** * Control Operations ***************************************************************************/ @@ -228,6 +227,181 @@ Lerror: return TS_ERR_FAIL; /* failed to set proxy state */ } +#if TS_USE_REMOTE_UNWINDING + +#include <libunwind.h> +#include <libunwind-ptrace.h> +#include <sys/ptrace.h> +#include <cxxabi.h> + +typedef Vec<pid_t> threadlist; + +static threadlist +threads_for_process(pid_t proc) +{ + DIR * dir = NULL; + struct dirent * entry = NULL; + + char path[64]; + threadlist threads; + + if (snprintf(path, sizeof(path), "/proc/%ld/task", (long)proc) >= (int)sizeof(path)) { + goto done; + } + + dir = opendir(path); + if (dir == NULL) { + goto done; + } + + while ((entry = readdir(dir))) { + pid_t threadid; + + if (isdot(entry->d_name) || isdotdot(entry->d_name)) { + continue; + } + + threadid = strtol(entry->d_name, NULL, 10); + if (threadid > 0) { + threads.push_back(threadid); + Debug("backtrace", "found thread %ld", (long)threadid); + } + } + + +done: + if (dir) { + closedir(dir); + } + + return threads; +} + +static void +backtrace_for_thread(pid_t threadid, textBuffer& text) +{ + int status; + unw_addr_space_t addr_space = NULL; + unw_cursor_t cursor; + void * ap = NULL; + pid_t target = -1; + unsigned level = 0; + + // First, attach to the child, causing it to stop. + status = ptrace(PTRACE_ATTACH, threadid, 0, 0); + if (status < 0) { + Debug("backtrace", "ptrace(ATTACH, %ld) -> %s (%d)", (long)threadid, strerror(errno), errno); + return; + } + + // Wait for it to stop (XXX should be a timed wait ...) + target = waitpid(threadid, &status, __WALL | WUNTRACED); + Debug("backtrace", "waited for target %ld, found PID %ld, %s", (long)threadid, (long)target, + WIFSTOPPED(status) ? "STOPPED" : "???"); + if (target < 0) { + goto done; + } + + ap = _UPT_create(threadid); + Debug("backtrace", "created UPT %p", ap); + if (ap == NULL) { + goto done; + } + + addr_space = unw_create_addr_space(&_UPT_accessors, 0 /* byteorder */); + Debug("backtrace", "created address space %p", addr_space); + if (addr_space == NULL) { + goto done; + } + + status = unw_init_remote(&cursor, addr_space, ap); + Debug("backtrace", "unw_init_remote(...) -> %d", status); + if (status != 0) { + goto done; + } + + while (unw_step(&cursor) > 0) { + unw_word_t ip; + unw_word_t offset; + char buf[256]; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + + if (unw_get_proc_name(&cursor, buf, sizeof(buf), &offset) == 0) { + int status; + char * name = abi::__cxa_demangle(buf, NULL, NULL, &status); + text.format("%-4u 0x%016llx %s + %p\n", level, (unsigned long long)ip, name ? name : buf, (void *)offset); + free(name); + } else { + text.format("%-4u 0x%016llx 0x0 + %p\n", level, (unsigned long long)ip, (void *)offset); + } + + ++level; + } + +done: + if (addr_space) { + unw_destroy_addr_space(addr_space); + } + + if (ap) { + _UPT_destroy(ap); + } + + status = ptrace(PTRACE_DETACH, target, NULL, NULL); + Debug("backtrace", "ptrace(DETACH, %ld) -> %d (errno %d)", (long)target, status, errno); +} + +TSMgmtError +ServerBacktrace(unsigned /* options */, char ** trace) +{ + *trace = NULL; + + // Unfortunately, we need to be privileged here. We either need to be root or to be holding + // the CAP_SYS_PTRACE capability. Even though we are the parent traffic_manager, it is not + // traceable without privilege because the process credentials do not match. + ElevateAccess access(true, ElevateAccess::TRACE_PRIVILEGE); + threadlist threads(threads_for_process(lmgmt->watched_process_pid)); + textBuffer text(0); + + Debug("backtrace", "tracing %zd threads for traffic_server PID %ld", threads.count(), (long)lmgmt->watched_process_pid); + for_Vec(pid_t, threadid, threads) { + Debug("backtrace", "tracing thread %zd", (long)threadid); + // Get the thread name using /proc/PID/comm + ats_scoped_fd fd; + char threadname[128]; + + snprintf(threadname, sizeof(threadname), "/proc/%ld/comm", (long)threadid); + fd = open(threadname, O_RDONLY); + if (fd) { + text.format("Thread %ld, ", (long)threadid); + text.readFromFD(fd); + text.chomp(); + } else { + text.format("Thread %ld", (long)threadid); + } + + text.format(":\n"); + + backtrace_for_thread(threadid, text); + text.format("\n"); + } + + *trace = text.release(); + return TS_ERR_OKAY; +} + +#else /* TS_USE_REMOTE_UNWINDING */ + +TSMgmtError +ServerBacktrace(unsigned /* options */, char ** trace) +{ + *trace = NULL; + return TS_ERR_NOT_SUPPORTED; +} + +#endif + /*------------------------------------------------------------------------- * Reconfigure *------------------------------------------------------------------------- @@ -350,7 +524,6 @@ MgmtRecordGet(const char *rec_name, TSRecordEle * rec_ele) if (!varStrFromName(rec_name, rec_val, MAX_BUF_SIZE)) return TS_ERR_FAIL; - if (rec_val[0] != '\0') { // non-NULL string value // allocate memory & duplicate string value str_val = ats_strdup(rec_val); @@ -414,7 +587,6 @@ determine_action_need(const char *rec_name) return TS_ACTION_UNDEFINED; // ERROR } - /*------------------------------------------------------------------------- * MgmtRecordSet *------------------------------------------------------------------------- @@ -445,7 +617,6 @@ MgmtRecordSet(const char *rec_name, const char *val, TSActionNeedT * action_need return TS_ERR_FAIL; } - /*------------------------------------------------------------------------- * MgmtRecordSetInt *------------------------------------------------------------------------- @@ -468,7 +639,6 @@ MgmtRecordSetInt(const char *rec_name, MgmtInt int_val, TSActionNeedT * action_n return MgmtRecordSet(rec_name, str_val, action_need); } - /*------------------------------------------------------------------------- * MgmtRecordSetCounter *------------------------------------------------------------------------- @@ -489,7 +659,6 @@ MgmtRecordSetCounter(const char *rec_name, MgmtIntCounter counter_val, TSActionN return MgmtRecordSet(rec_name, str_val, action_need); } - /*------------------------------------------------------------------------- * MgmtRecordSetFloat *------------------------------------------------------------------------- @@ -511,7 +680,6 @@ MgmtRecordSetFloat(const char *rec_name, MgmtFloat float_val, TSActionNeedT * ac return MgmtRecordSet(rec_name, str_val, action_need); } - /*------------------------------------------------------------------------- * MgmtRecordSetString *------------------------------------------------------------------------- @@ -523,7 +691,6 @@ MgmtRecordSetString(const char *rec_name, const char *string_val, TSActionNeedT return MgmtRecordSet(rec_name, string_val, action_need); } - /************************************************************************** * FILE OPERATIONS *************************************************************************/ @@ -550,7 +717,6 @@ ReadFile(TSFileNameT file, char **text, int *size, int *version) Debug("FileOp", "[get_lines_from_file] START\n"); - fname = filename_to_string(file); if (!fname) return TS_ERR_READ_FILE; @@ -597,7 +763,6 @@ WriteFile(TSFileNameT file, const char *text, int size, int version) int ret; version_t ver; - fname = filename_to_string(file); if (!fname) return TS_ERR_WRITE_FILE; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/CoreAPI.h ---------------------------------------------------------------------- diff --git a/mgmt/api/CoreAPI.h b/mgmt/api/CoreAPI.h index 2585b16..a1b2f89 100644 --- a/mgmt/api/CoreAPI.h +++ b/mgmt/api/CoreAPI.h @@ -45,6 +45,7 @@ void Diags(TSDiagsT mode, const char * fmt, va_list ap); ***************************************************************************/ TSProxyStateT ProxyStateGet(); TSMgmtError ProxyStateSet(TSProxyStateT state, TSCacheClearT clear); +TSMgmtError ServerBacktrace(unsigned options, char ** trace); TSMgmtError Reconfigure(); // TS reread config files TSMgmtError Restart(bool cluster); //restart TM http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/CoreAPIRemote.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/CoreAPIRemote.cc b/mgmt/api/CoreAPIRemote.cc index 5ebfa36..00b2bda 100644 --- a/mgmt/api/CoreAPIRemote.cc +++ b/mgmt/api/CoreAPIRemote.cc @@ -348,6 +348,47 @@ ProxyStateSet(TSProxyStateT state, TSCacheClearT clear) } TSMgmtError +ServerBacktrace(unsigned options, char ** trace) +{ + ink_release_assert(trace != NULL); + TSMgmtError ret; + MgmtMarshallInt optype = SERVER_BACKTRACE; + MgmtMarshallInt err; + MgmtMarshallInt flags = options; + MgmtMarshallData reply = { NULL, 0 }; + MgmtMarshallString strval = NULL; + + ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, SERVER_BACKTRACE, &optype, &flags); + if (ret != TS_ERR_OKAY) { + goto fail; + } + + ret = recv_mgmt_message(main_socket_fd, reply); + if (ret != TS_ERR_OKAY) { + goto fail; + } + + ret = recv_mgmt_response(reply.ptr, reply.len, SERVER_BACKTRACE, &err, &strval); + if (ret != TS_ERR_OKAY) { + goto fail; + } + + if (err != TS_ERR_OKAY) { + ret = (TSMgmtError)err; + goto fail; + } + + ats_free(reply.ptr); + *trace = strval; + return TS_ERR_OKAY; + +fail: + ats_free(reply.ptr); + ats_free(strval); + return ret; +} + +TSMgmtError Reconfigure() { TSMgmtError ret; @@ -942,3 +983,4 @@ StatsReset(bool cluster, const char * stat_name) ret = MGMTAPI_SEND_MESSAGE(main_socket_fd, op, &optype, &name); return (ret == TS_ERR_OKAY) ? parse_generic_response(op, main_socket_fd) : ret; } + http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/INKMgmtAPI.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/INKMgmtAPI.cc b/mgmt/api/INKMgmtAPI.cc index 32879b4..814a90f 100644 --- a/mgmt/api/INKMgmtAPI.cc +++ b/mgmt/api/INKMgmtAPI.cc @@ -1756,6 +1756,20 @@ TSProxyStateSet(TSProxyStateT proxy_state, TSCacheClearT clear) return ProxyStateSet(proxy_state, clear); } +tsapi TSMgmtError +TSProxyBacktraceGet(unsigned options, TSString * trace) +{ + if (options != 0) { + return TS_ERR_PARAMS; + } + + if (trace == NULL) { + return TS_ERR_PARAMS; + } + + return ServerBacktrace(options, trace); +} + /* TSReconfigure: tell traffic_server to re-read its configuration files * Input: <none> * Output: TSMgmtError @@ -1881,6 +1895,9 @@ TSGetErrorMessage(TSMgmtError err_id) case TS_ERR_FAIL: snprintf(msg, sizeof(msg), "[%d] Generic Fail message (ie. CoreAPI call).", err_id); break; + case TS_ERR_NOT_SUPPORTED: + snprintf(msg, sizeof(msg), "[%d] Operation not supported on this platform.", err_id); + break; default: snprintf(msg, sizeof(msg), "[%d] Invalid error type.", err_id); http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/Makefile.am ---------------------------------------------------------------------- diff --git a/mgmt/api/Makefile.am b/mgmt/api/Makefile.am index 999d93d..0845ea4 100644 --- a/mgmt/api/Makefile.am +++ b/mgmt/api/Makefile.am @@ -28,7 +28,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/mgmt/utils \ -I$(top_srcdir)/mgmt/api/include \ -I$(top_srcdir)/lib \ - -I$(top_builddir)/lib + -I$(top_builddir)/lib \ + $(LIBUNWIND_CFLAGS) noinst_LTLIBRARIES = libmgmtapilocal.la libmgmtapi.la lib_LTLIBRARIES = libtsmgmt.la http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/NetworkMessage.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/NetworkMessage.cc b/mgmt/api/NetworkMessage.cc index 1869bf9..c0c0b4c 100644 --- a/mgmt/api/NetworkMessage.cc +++ b/mgmt/api/NetworkMessage.cc @@ -64,6 +64,7 @@ static const struct NetCmdOperation requests[] = { /* STORAGE_DEVICE_CMD_OFFLINE */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING } }, /* RECORD_MATCH_GET */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING } }, /* API_PING */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_INT } }, + /* SERVER_BACKTRACE */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_INT } }, }; // Responses always begin with a TSMgmtError code, followed by additional fields. @@ -93,6 +94,7 @@ static const struct NetCmdOperation responses[] = { /* STORAGE_DEVICE_CMD_OFFLINE */ { 1, { MGMT_MARSHALL_INT } }, /* RECORD_MATCH_GET */ { 4, { MGMT_MARSHALL_INT, MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING, MGMT_MARSHALL_DATA } }, /* API_PING */ { 0, {} }, // no reply + /* SERVER_BACKTRACE */ { 2, { MGMT_MARSHALL_INT, MGMT_MARSHALL_STRING } }, }; #define GETCMD(ops, optype, cmd) do { \ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/NetworkMessage.h ---------------------------------------------------------------------- diff --git a/mgmt/api/NetworkMessage.h b/mgmt/api/NetworkMessage.h index ae94185..e8dd58c 100644 --- a/mgmt/api/NetworkMessage.h +++ b/mgmt/api/NetworkMessage.h @@ -59,6 +59,7 @@ typedef enum STORAGE_DEVICE_CMD_OFFLINE, RECORD_MATCH_GET, API_PING, + SERVER_BACKTRACE, UNDEFINED_OP /* This must be last */ } OpType; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/TSControlMain.cc ---------------------------------------------------------------------- diff --git a/mgmt/api/TSControlMain.cc b/mgmt/api/TSControlMain.cc index ba5ba3f..474918f 100644 --- a/mgmt/api/TSControlMain.cc +++ b/mgmt/api/TSControlMain.cc @@ -967,6 +967,25 @@ handle_api_ping(int /* fd */, void * req, size_t reqlen) return recv_mgmt_request(req, reqlen, API_PING, &optype, &stamp); } +static TSMgmtError +handle_server_backtrace(int fd, void * req, size_t reqlen) +{ + MgmtMarshallInt optype; + MgmtMarshallInt options; + MgmtMarshallString trace = NULL; + MgmtMarshallInt err; + + err = recv_mgmt_request(req, reqlen, SERVER_BACKTRACE, &optype, &options); + if (err == TS_ERR_OKAY) { + err = ServerBacktrace(options, &trace); + } + + err = send_mgmt_response(fd, SERVER_BACKTRACE, &err, &trace); + ats_free(trace); + + return (TSMgmtError)err; +} + typedef TSMgmtError (*control_message_handler)(int, void *, size_t); static const control_message_handler handlers[] = { @@ -994,7 +1013,8 @@ static const control_message_handler handlers[] = { handle_stats_reset, // STATS_RESET_CLUSTER handle_storage_device_cmd_offline, // STORAGE_DEVICE_CMD_OFFLINE handle_record_match, // RECORD_MATCH_GET - handle_api_ping // API_PING + handle_api_ping, // API_PING + handle_server_backtrace // SERVER_BACKTRACE }; static TSMgmtError http://git-wip-us.apache.org/repos/asf/trafficserver/blob/3e5a3f13/mgmt/api/include/mgmtapi.h ---------------------------------------------------------------------- diff --git a/mgmt/api/include/mgmtapi.h b/mgmt/api/include/mgmtapi.h index c9fc90d..581c69e 100644 --- a/mgmt/api/include/mgmtapi.h +++ b/mgmt/api/include/mgmtapi.h @@ -71,6 +71,8 @@ extern "C" TS_ERR_SYS_CALL, /* Error in basic system call, eg. malloc */ TS_ERR_PARAMS, /* Invalid parameters for a fn */ + TS_ERR_NOT_SUPPORTED, /* Operation not supported */ + TS_ERR_FAIL } TSMgmtError; @@ -961,6 +963,13 @@ extern "C" */ tsapi TSMgmtError TSProxyStateSet(TSProxyStateT proxy_state, TSCacheClearT clear); +/* TSProxyBacktraceGet: get a backtrace of the proxy + * Input: unsigned options - stack trace options + * Output: formatted backtrace of the proxy + * the caller must free this with TSfree + */ + tsapi TSMgmtError TSProxyBacktraceGet(unsigned, TSString *); + /* TSReconfigure: tell traffic_server to re-read its configuration files * Input: <none> * Output: TSMgmtError
