[Tarantool-patches] [PATCH v2 1/5] error: Add a Lua backtrace to error

Leonid Vasiliev lvasiliev at tarantool.org
Fri Apr 10 11:10:39 MSK 2020


In accordance with https://github.com/tarantool/tarantool/issues/4398
Lua traceback has been added for box.error.
Has been added a per server flag for turn on/off traceback adding
and ability to force it at creation time.

@TarantoolBot document
Title: error.traceback
Was added:
Per server flag for turn on/off adding a traceback to the errors.
box.error.cfg({traceback_supplementation = true/false})
Adding a traceback can be forced on creation.
box.error.new({type = "CustomType", reason = "reason", traceback = true/false})

Needed for #4398
---
 src/box/lua/error.cc          | 33 ++++++++++++++++++++++++++++++++-
 src/lib/core/diag.c           | 32 ++++++++++++++++++++++++++++++++
 src/lib/core/diag.h           | 11 +++++++++++
 src/lib/core/exception.cc     |  1 +
 src/lua/error.c               | 10 ++++++++++
 src/lua/error.lua             | 12 +++++++++++-
 test/app/fiber.result         |  5 +++--
 test/box/error.result         |  5 +++--
 test/engine/func_index.result | 10 ++++++----
 9 files changed, 109 insertions(+), 10 deletions(-)

diff --git a/src/box/lua/error.cc b/src/box/lua/error.cc
index b2625bf..4432bc8 100644
--- a/src/box/lua/error.cc
+++ b/src/box/lua/error.cc
@@ -54,6 +54,8 @@ luaT_error_create(lua_State *L, int top_base)
 {
 	uint32_t code = 0;
 	const char *reason = NULL;
+	bool tb_parsed = false;
+	bool tb_mode = false;
 	const char *file = "";
 	unsigned line = 0;
 	lua_Debug info;
@@ -87,6 +89,12 @@ luaT_error_create(lua_State *L, int top_base)
 		if (reason == NULL)
 			reason = "";
 		lua_pop(L, 1);
+		lua_getfield(L, top_base, "traceback");
+		if (lua_isboolean(L, -1)) {
+			tb_parsed = true;
+			tb_mode = lua_toboolean(L, -1);
+		}
+		lua_pop(L, -1);
 	} else {
 		return NULL;
 	}
@@ -102,7 +110,12 @@ raise:
 		}
 		line = info.currentline;
 	}
-	return box_error_new(file, line, code, "%s", reason);
+
+	struct error *err = box_error_new(file, line, code, "%s", reason);
+	if (tb_parsed)
+		err->traceback_mode = tb_mode;
+
+	return err;
 }
 
 static int
@@ -180,6 +193,20 @@ luaT_error_set(struct lua_State *L)
 }
 
 static int
+luaT_error_cfg(struct lua_State *L)
+{
+	if (lua_gettop(L) < 1 || !lua_istable(L, 1))
+		return luaL_error(L, "Usage: box.error.cfg({}})");
+
+	lua_getfield(L, 1, "traceback_supplementation");
+	if (lua_isnil(L, -1) == 0)
+		error_set_traceback_supplementation(lua_toboolean(L, -1));
+	lua_pop(L, 1);
+
+	return 0;
+}
+
+static int
 lbox_errinj_set(struct lua_State *L)
 {
 	char *name = (char*)luaL_checkstring(L, 1);
@@ -297,6 +324,10 @@ box_lua_error_init(struct lua_State *L) {
 			lua_pushcfunction(L, luaT_error_set);
 			lua_setfield(L, -2, "set");
 		}
+		{
+			lua_pushcfunction(L, luaT_error_cfg);
+			lua_setfield(L, -2, "cfg");
+		}
 		lua_setfield(L, -2, "__index");
 	}
 	lua_setmetatable(L, -2);
diff --git a/src/lib/core/diag.c b/src/lib/core/diag.c
index e143db1..1caa75e 100644
--- a/src/lib/core/diag.c
+++ b/src/lib/core/diag.c
@@ -31,6 +31,11 @@
 #include "diag.h"
 #include "fiber.h"
 
+/**
+ * Global flag to add or not backtrace to errors.
+ */
+static bool global_traceback_mode = false;
+
 int
 error_set_prev(struct error *e, struct error *prev)
 {
@@ -97,6 +102,8 @@ error_create(struct error *e,
 	e->errmsg[0] = '\0';
 	e->cause = NULL;
 	e->effect = NULL;
+	e->lua_traceback = NULL;
+	e->traceback_mode = global_traceback_mode;
 }
 
 struct diag *
@@ -120,3 +127,28 @@ error_vformat_msg(struct error *e, const char *format, va_list ap)
 	vsnprintf(e->errmsg, sizeof(e->errmsg), format, ap);
 }
 
+void
+error_set_lua_traceback(struct error *e, const char *lua_traceback)
+{
+	if (e == NULL)
+		return;
+
+	if (lua_traceback == NULL) {
+		free(e->lua_traceback);
+		e->lua_traceback = NULL;
+		return;
+	}
+
+	size_t tb_len = strlen(lua_traceback);
+	e->lua_traceback = realloc(e->lua_traceback, tb_len + 1);
+	if (e->lua_traceback == NULL)
+		return;
+	strcpy(e->lua_traceback, lua_traceback);
+	return;
+}
+
+void
+error_set_traceback_supplementation(bool traceback_mode)
+{
+	global_traceback_mode = traceback_mode;
+}
diff --git a/src/lib/core/diag.h b/src/lib/core/diag.h
index 7a5454d..f38009c 100644
--- a/src/lib/core/diag.h
+++ b/src/lib/core/diag.h
@@ -110,6 +110,8 @@ struct error {
 	 */
 	struct error *cause;
 	struct error *effect;
+	char *lua_traceback;
+	bool traceback_mode;
 };
 
 static inline void
@@ -197,6 +199,15 @@ error_format_msg(struct error *e, const char *format, ...);
 void
 error_vformat_msg(struct error *e, const char *format, va_list ap);
 
+void
+error_set_lua_traceback(struct error *e, const char *lua_traceback);
+
+/**
+* Sets the global flag to add or not backtrace to errors.
+*/
+void
+error_set_traceback_supplementation(bool traceback_mode);
+
 /**
  * Diagnostics Area - a container for errors
  */
diff --git a/src/lib/core/exception.cc b/src/lib/core/exception.cc
index 180cb0e..0e4b6ca 100644
--- a/src/lib/core/exception.cc
+++ b/src/lib/core/exception.cc
@@ -42,6 +42,7 @@ extern "C" {
 static void
 exception_destroy(struct error *e)
 {
+	free(e->lua_traceback);
 	delete (Exception *) e;
 }
 
diff --git a/src/lua/error.c b/src/lua/error.c
index 18a990a..cd6ab54 100644
--- a/src/lua/error.c
+++ b/src/lua/error.c
@@ -85,6 +85,16 @@ luaT_pusherror(struct lua_State *L, struct error *e)
 	 * then set the finalizer.
 	 */
 	error_ref(e);
+
+	if (e->lua_traceback == NULL && e->traceback_mode) {
+		int top = lua_gettop(L);
+		luaL_traceback(L, L, NULL, 0);
+		if (lua_isstring(L, -1)) {
+			error_set_lua_traceback(e, lua_tostring(L, -1));
+		}
+		lua_settop(L, top);
+	}
+
 	assert(CTID_CONST_STRUCT_ERROR_REF != 0);
 	struct error **ptr = (struct error **)
 		luaL_pushcdata(L, CTID_CONST_STRUCT_ERROR_REF);
diff --git a/src/lua/error.lua b/src/lua/error.lua
index bdc9c71..46d2866 100644
--- a/src/lua/error.lua
+++ b/src/lua/error.lua
@@ -26,6 +26,8 @@ struct error {
     char _errmsg[DIAG_ERRMSG_MAX];
     struct error *_cause;
     struct error *_effect;
+    char *lua_traceback;
+    bool traceback_mode;
 };
 
 char *
@@ -92,6 +94,14 @@ local function error_trace(err)
     }
 end
 
+local function error_traceback(err)
+    local result = "Traceback is absent"
+    if err.lua_traceback ~= ffi.nullptr then
+        result = ffi.string(err.lua_traceback)
+    end
+    return result
+end
+
 local function error_errno(err)
     local e = err._saved_errno
     if e == 0 then
@@ -122,7 +132,6 @@ local function error_set_prev(err, prev)
     if ok ~= 0 then
         error("Cycles are not allowed")
     end
-
 end
 
 local error_fields = {
@@ -131,6 +140,7 @@ local error_fields = {
     ["trace"]       = error_trace;
     ["errno"]       = error_errno;
     ["prev"]        = error_prev;
+    ["traceback"]   = error_traceback;
 }
 
 local function error_unpack(err)
diff --git a/test/app/fiber.result b/test/app/fiber.result
index debfc67..fc6b3c9 100644
--- a/test/app/fiber.result
+++ b/test/app/fiber.result
@@ -1038,12 +1038,13 @@ st;
 ...
 e:unpack();
 ---
-- type: ClientError
+- traceback: Traceback is absent
   code: 1
-  message: Illegal parameters, oh my
   trace:
   - file: '[string "function err() box.error(box.error.ILLEGAL_PA..."]'
     line: 1
+  type: ClientError
+  message: Illegal parameters, oh my
 ...
 flag = false;
 ---
diff --git a/test/box/error.result b/test/box/error.result
index 234c263..22788a1 100644
--- a/test/box/error.result
+++ b/test/box/error.result
@@ -34,12 +34,13 @@ e
  | ...
 e:unpack()
  | ---
- | - type: ClientError
+ | - traceback: Traceback is absent
  |   code: 1
- |   message: Illegal parameters, bla bla
  |   trace:
  |   - file: '[C]'
  |     line: 4294967295
+ |   type: ClientError
+ |   message: Illegal parameters, bla bla
  | ...
 e.type
  | ---
diff --git a/test/engine/func_index.result b/test/engine/func_index.result
index a827c92..28befca 100644
--- a/test/engine/func_index.result
+++ b/test/engine/func_index.result
@@ -276,7 +276,8 @@ e = box.error.last()
  | ...
 e:unpack()
  | ---
- | - code: 198
+ | - traceback: Traceback is absent
+ |   code: 198
  |   trace:
  |   - file: <filename>
  |     line: <line>
@@ -291,12 +292,13 @@ e = e.prev
  | ...
 e:unpack()
  | ---
- | - type: LuajitError
- |   message: '[string "return function(tuple)                 local ..."]:1: attempt
- |     to call global ''require'' (a nil value)'
+ | - traceback: Traceback is absent
  |   trace:
  |   - file: <filename>
  |     line: <line>
+ |   type: LuajitError
+ |   message: '[string "return function(tuple)                 local ..."]:1: attempt
+ |     to call global ''require'' (a nil value)'
  | ...
 e = e.prev
  | ---
-- 
2.7.4



More information about the Tarantool-patches mailing list