add skynet.trace()

This commit is contained in:
Cloud Wu
2018-05-26 16:26:50 +08:00
parent 348e53245b
commit e53d985c4f
3 changed files with 113 additions and 5 deletions

View File

@@ -11,6 +11,29 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <inttypes.h>
#include <time.h>
#if defined(__APPLE__)
#include <sys/time.h>
#endif
#include "skynet.h"
// return nsec
static int64_t
get_time() {
#if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
struct timespec ti;
clock_gettime(CLOCK_MONOTONIC, &ti);
return (int64_t)1000000000 * ti.tv_sec + ti.tv_nsec;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)1000000000 * tv.tv_sec + tv.tv_usec * 1000;
#endif
}
struct snlua { struct snlua {
lua_State * L; lua_State * L;
@@ -378,6 +401,40 @@ lnow(lua_State *L) {
return 1; return 1;
} }
static int
lhpc(lua_State *L) {
lua_pushinteger(L, get_time());
return 1;
}
/*
string tag
string userstring
thread co (default nil)
integer level (default is 3)
*/
static int
ltrace(lua_State *L) {
struct skynet_context * context = lua_touserdata(L, lua_upvalueindex(1));
const char * tag = luaL_checkstring(L, 1);
const char * user = luaL_checkstring(L, 2);
if (lua_isthread(L, 3)) {
lua_State * co = lua_tothread (L, 3);
lua_Debug d;
int level = luaL_optinteger(L, 4, 3);
do {
if (!lua_getstack(co, level, &d))
break;
lua_getinfo(co, "Sl", &d);
level++;
} while (d.currentline < 0);
skynet_error(context, "<TRACE %s> %" PRId64 " %s : %s:%d", tag, get_time(), user, d.short_src, d.currentline);
return 0;
}
skynet_error(context, "<TRACE %s> %" PRId64 " %s", tag, get_time(), user);
return 0;
}
LUAMOD_API int LUAMOD_API int
luaopen_skynet_core(lua_State *L) { luaopen_skynet_core(lua_State *L) {
luaL_checkversion(L); luaL_checkversion(L);
@@ -390,18 +447,25 @@ luaopen_skynet_core(lua_State *L) {
{ "intcommand", lintcommand }, { "intcommand", lintcommand },
{ "addresscommand", laddresscommand }, { "addresscommand", laddresscommand },
{ "error", lerror }, { "error", lerror },
{ "tostring", ltostring },
{ "harbor", lharbor }, { "harbor", lharbor },
{ "callback", lcallback },
{ "trace", ltrace },
{ NULL, NULL },
};
// functions without skynet_context
luaL_Reg l2[] = {
{ "tostring", ltostring },
{ "pack", luaseri_pack }, { "pack", luaseri_pack },
{ "unpack", luaseri_unpack }, { "unpack", luaseri_unpack },
{ "packstring", lpackstring }, { "packstring", lpackstring },
{ "trash" , ltrash }, { "trash" , ltrash },
{ "callback", lcallback },
{ "now", lnow }, { "now", lnow },
{ "hpc", lhpc }, // getHPCounter
{ NULL, NULL }, { NULL, NULL },
}; };
luaL_newlibtable(L, l); lua_createtable(L, 0, sizeof(l)/sizeof(l[0]) + sizeof(l2)/sizeof(l2[0]) -2);
lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context"); lua_getfield(L, LUA_REGISTRYINDEX, "skynet_context");
struct skynet_context *ctx = lua_touserdata(L,-1); struct skynet_context *ctx = lua_touserdata(L,-1);
@@ -409,7 +473,10 @@ luaopen_skynet_core(lua_State *L) {
return luaL_error(L, "Init skynet context first"); return luaL_error(L, "Init skynet context first");
} }
luaL_setfuncs(L,l,1); luaL_setfuncs(L,l,1);
luaL_setfuncs(L,l2,0);
return 1; return 1;
} }

View File

@@ -28,6 +28,7 @@ local skynet = {
PTYPE_DEBUG = 9, PTYPE_DEBUG = 9,
PTYPE_LUA = 10, PTYPE_LUA = 10,
PTYPE_SNAX = 11, PTYPE_SNAX = 11,
PTYPE_TRACE = 12, -- use for debug trace
} }
-- code cache -- code cache
@@ -45,6 +46,7 @@ end
local session_id_coroutine = {} local session_id_coroutine = {}
local session_coroutine_id = {} local session_coroutine_id = {}
local session_coroutine_address = {} local session_coroutine_address = {}
local session_coroutine_tracetag = {}
local unresponse = {} local unresponse = {}
local wakeup_queue = {} local wakeup_queue = {}
@@ -151,28 +153,37 @@ end
-- suspend is local function -- suspend is local function
function suspend(co, result, command, param, param2) function suspend(co, result, command, param, param2)
local tag = session_coroutine_tracetag[co]
if not result then if not result then
local session = session_coroutine_id[co] local session = session_coroutine_id[co]
if session then -- coroutine may fork by others (session is nil) if session then -- coroutine may fork by others (session is nil)
local addr = session_coroutine_address[co] local addr = session_coroutine_address[co]
if session ~= 0 then if session ~= 0 then
-- only call response error -- only call response error
if tag then c.trace(tag, "error", co) end
c.send(addr, skynet.PTYPE_ERROR, session, "") c.send(addr, skynet.PTYPE_ERROR, session, "")
end end
session_coroutine_id[co] = nil session_coroutine_id[co] = nil
session_coroutine_address[co] = nil session_coroutine_address[co] = nil
session_coroutine_tracetag[co] = nil
end end
error(debug.traceback(co,tostring(command))) error(debug.traceback(co,tostring(command)))
end end
if command == "CALL" then if command == "CALL" then
if tag then
c.trace(tag, "call", co)
c.send(param2, skynet.PTYPE_TRACE, 0, tag)
end
session_id_coroutine[param] = co session_id_coroutine[param] = co
elseif command == "SLEEP" then elseif command == "SLEEP" then
if tag then c.trace(tag, "sleep", co) end
session_id_coroutine[param] = co session_id_coroutine[param] = co
if sleep_session[param2] then if sleep_session[param2] then
error(debug.traceback(co, "token duplicative")) error(debug.traceback(co, "token duplicative"))
end end
sleep_session[param2] = param sleep_session[param2] = param
elseif command == "RETURN" then elseif command == "RETURN" then
if tag then c.trace(tag, "response") end
local co_session = session_coroutine_id[co] local co_session = session_coroutine_id[co]
session_coroutine_id[co] = nil session_coroutine_id[co] = nil
if co_session == 0 then if co_session == 0 then
@@ -254,6 +265,7 @@ function suspend(co, result, command, param, param2)
release_watching(address) release_watching(address)
session_coroutine_id[co] = nil session_coroutine_id[co] = nil
session_coroutine_address[co] = nil session_coroutine_address[co] = nil
session_coroutine_tracetag[co] = nil
end end
elseif command == "QUIT" then elseif command == "QUIT" then
-- service exit -- service exit
@@ -265,6 +277,10 @@ function suspend(co, result, command, param, param2)
-- We use session for other uses -- We use session for other uses
session_coroutine_id[co] = nil session_coroutine_id[co] = nil
return suspend(co, coroutine_resume(co)) return suspend(co, coroutine_resume(co))
elseif command == "TRACE" then
session_coroutine_tracetag[co] = param
c.trace(param, "trace")
return suspend(co, coroutine_resume(co))
elseif command == nil then elseif command == nil then
-- debug trace -- debug trace
return return
@@ -320,6 +336,13 @@ function skynet.localname(name)
end end
skynet.now = c.now skynet.now = c.now
skynet.hpc = c.hpc -- high performance counter
local traceid = 0
function skynet.trace()
traceid = traceid + 1
coroutine_yield("TRACE", string.format(":%08x-%d",skynet.self(), traceid))
end
local starttime local starttime
@@ -393,7 +416,7 @@ skynet.trash = assert(c.trash)
local function yield_call(service, session) local function yield_call(service, session)
watching_session[session] = service watching_session[session] = service
local succ, msg, sz = coroutine_yield("CALL", session) local succ, msg, sz = coroutine_yield("CALL", session, service)
watching_session[session] = nil watching_session[session] = nil
if not succ then if not succ then
error "call failed" error "call failed"
@@ -483,6 +506,8 @@ function skynet.fork(func,...)
return co return co
end end
local trace_source = {}
local function raw_dispatch_message(prototype, msg, sz, session, source) local function raw_dispatch_message(prototype, msg, sz, session, source)
-- skynet.PTYPE_RESPONSE = 1, read skynet.h -- skynet.PTYPE_RESPONSE = 1, read skynet.h
if prototype == 1 then if prototype == 1 then
@@ -492,13 +517,27 @@ local function raw_dispatch_message(prototype, msg, sz, session, source)
elseif co == nil then elseif co == nil then
unknown_response(session, source, msg, sz) unknown_response(session, source, msg, sz)
else else
local tag = session_coroutine_tracetag[co]
if tag then c.trace(tag, "resume") end
session_id_coroutine[session] = nil session_id_coroutine[session] = nil
suspend(co, coroutine_resume(co, true, msg, sz)) suspend(co, coroutine_resume(co, true, msg, sz))
end end
else else
local tag = trace_source[source]
if tag then
if session ~= 0 then
c.trace(tag, "request")
trace_source[source] = nil
else
tag = nil
end
end
local p = proto[prototype] local p = proto[prototype]
if p == nil then if p == nil then
if session ~= 0 then if prototype == skynet.PTYPE_TRACE then
-- trace next request
trace_source[source] = c.tostring(msg,sz)
elseif session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "") c.send(source, skynet.PTYPE_ERROR, session, "")
else else
unknown_request(session, source, msg, sz, prototype) unknown_request(session, source, msg, sz, prototype)
@@ -516,6 +555,7 @@ local function raw_dispatch_message(prototype, msg, sz, session, source)
local co = co_create(f) local co = co_create(f)
session_coroutine_id[co] = session session_coroutine_id[co] = session
session_coroutine_address[co] = source session_coroutine_address[co] = source
session_coroutine_tracetag[co] = tag
suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz))) suspend(co, coroutine_resume(co, session,source, p.unpack(msg,sz)))
elseif session ~= 0 then elseif session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "") c.send(source, skynet.PTYPE_ERROR, session, "")

View File

@@ -2,6 +2,7 @@ local skynet = require "skynet"
local snax = require "skynet.snax" local snax = require "skynet.snax"
skynet.start(function() skynet.start(function()
skynet.trace()
local ps = snax.newservice ("pingserver", "hello world") local ps = snax.newservice ("pingserver", "hello world")
print(ps.req.ping("foobar")) print(ps.req.ping("foobar"))
print(ps.post.hello()) print(ps.post.hello())