Add Engine methods for retrieving current line of source code being executed, current source file name and the concatenation of both.

Add Message.trace() method for tracking of message handling in JS code.



git-svn-id: http://voip.null.ro/svn/yate@6397 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
oana 2020-04-01 11:47:55 +00:00
parent 1fd6d25f05
commit 700b3b1036
3 changed files with 207 additions and 15 deletions

View File

@ -83,11 +83,11 @@ class JsCodeFile : public String
{ {
public: public:
inline JsCodeFile(const String& file) inline JsCodeFile(const String& file)
: String(file), m_fileTime(0) : String(file), m_fileTime(0), m_shortName(file)
{ File::getFileTime(file,m_fileTime); } { File::getFileTime(file,m_fileTime); setShortName(); }
inline JsCodeFile(const String& file, unsigned int fTime) inline JsCodeFile(const String& file, unsigned int fTime)
: String(file), m_fileTime(fTime) : String(file), m_fileTime(fTime), m_shortName(file)
{ } { setShortName(); }
inline unsigned int fileTime() const inline unsigned int fileTime() const
{ return m_fileTime; } { return m_fileTime; }
inline bool fileChanged() const inline bool fileChanged() const
@ -98,8 +98,21 @@ public:
File::getFileTime(c_str(),t); File::getFileTime(c_str(),t);
return t != m_fileTime; return t != m_fileTime;
} }
inline const String& shortName() const
{ return m_shortName; }
private: private:
inline void setShortName()
{
int pos = rfind('/');
#ifdef _WINDOWS
int backPos = rfind('\\');
pos = pos > backPos ? pos : backPos;
#endif
if (pos >= 0 && (pos < (int)length() - 1))
m_shortName = substr(pos + 1);
}
unsigned int m_fileTime; unsigned int m_fileTime;
String m_shortName;
}; };
struct JsEntry struct JsEntry
@ -191,9 +204,9 @@ public:
{ return (line >> 24) & 0xff; } { return (line >> 24) & 0xff; }
inline unsigned int getFileCount() const inline unsigned int getFileCount() const
{ return m_included.length(); } { return m_included.length(); }
const String& getFileAt(unsigned int index) const; const String& getFileAt(unsigned int index, bool wholePath = true) const;
inline const String& getFileName(unsigned int line) const inline const String& getFileName(unsigned int line, bool wholePath = true) const
{ return getFileAt(getFileNo(line)); } { return getFileAt(getFileNo(line),wholePath); }
bool scriptChanged() const; bool scriptChanged() const;
protected: protected:
inline void trace(bool allowed) inline void trace(bool allowed)
@ -381,6 +394,9 @@ public:
void tracePost(const ExpOperation& oper); void tracePost(const ExpOperation& oper);
void traceCall(const ExpOperation& oper, const JsFunction& func); void traceCall(const ExpOperation& oper, const JsFunction& func);
void traceReturn(); void traceReturn();
const ExpOperation* getCurrentOpCode() const;
virtual unsigned int currentLineNo() const;
virtual const String& currentFileName(bool wholePath = false) const;
protected: protected:
virtual Status resume(); virtual Status resume();
void traceDump(); void traceDump();
@ -1048,12 +1064,12 @@ bool JsCode::link()
return true; return true;
} }
const String& JsCode::getFileAt(unsigned int index) const const String& JsCode::getFileAt(unsigned int index, bool wholePath) const
{ {
if (!index) if (!index)
return s_noFile; return s_noFile;
const GenObject* file = m_included[index - 1]; const JsCodeFile* file = static_cast<JsCodeFile*>(m_included[index - 1]);
return file ? file->toString() : s_noFile; return file ? (wholePath ? file->toString() : file->shortName()) : s_noFile;
} }
void JsCode::formatLineNo(String& buf, unsigned int line) const void JsCode::formatLineNo(String& buf, unsigned int line) const
@ -3305,6 +3321,35 @@ void JsFuncStats::updateCall(const char* name, unsigned int caller, unsigned int
l->insert(new JsCallStats(name,caller,called,instr,usec)); l->insert(new JsCallStats(name,caller,called,instr,usec));
} }
const ExpOperation* JsRunner::getCurrentOpCode() const
{
const ExpOperation* o = 0;
if (m_opcode)
o = static_cast<const ExpOperation*>(m_opcode->get());
if (!o)
o = static_cast<const ExpOperation*>(static_cast<const JsCode*>(code())->m_linked[m_index]);
if (!o) {
String str;
static_cast<const JsCode*>(code())->formatLineNo(str,m_lastLine);
Debug(DebugWarn,"Current operation unavailable in %s [%p]",str.c_str(),this);
return 0;
}
return o;
}
unsigned int JsRunner::currentLineNo() const
{
const ExpOperation* o = getCurrentOpCode();
return o ? JsCode::getLineNo(o->lineNumber()) : 0;
}
const String& JsRunner::currentFileName(bool wholePath) const
{
const ExpOperation* o = getCurrentOpCode();
if (!(o && code()))
return YSTRING("???");
return (static_cast<const JsCode*>(code()))->getFileName(o->lineNumber(),wholePath);
}
JsCodeStats::JsCodeStats(JsCode* code, const char* file) JsCodeStats::JsCodeStats(JsCode* code, const char* file)
: Mutex(false,"JsCodeStats"), : Mutex(false,"JsCodeStats"),

View File

@ -1782,6 +1782,21 @@ public:
*/ */
virtual bool appendAsync(ScriptAsync* oper); virtual bool appendAsync(ScriptAsync* oper);
/**
* Retrieve current file line being executed
* @return The file line being evaluated
*/
virtual unsigned int currentLineNo() const
{ return 0; }
/**
* Retrieve the name of the source file from which code is being executed
* @parma wholePath Retrieve name including path
* @return The file name
*/
virtual const String& currentFileName(bool wholePath = false) const
{ return String::empty(); }
/** /**
* Try to assign a value to a single field in the script context * Try to assign a value to a single field in the script context
* @param oper Field to assign to, contains the field name and new value * @param oper Field to assign to, contains the field name and new value

View File

@ -41,6 +41,21 @@
using namespace TelEngine; using namespace TelEngine;
namespace { // anonymous namespace { // anonymous
static inline void dumpTraceToMsg(Message* msg, ObjList* lst)
{
if (!(msg && lst))
return;
unsigned int count = msg->getIntValue(YSTRING("trace_msg_count"),0);
static String s_tracePref = "trace_msg_";
for (ObjList* o = lst->skipNull(); o; o = o->skipNext()) {
String* s = static_cast<String*>(o->get());
if (TelEngine::null(s))
continue;
msg->setParam(s_tracePref + String(count++),*s);
}
msg->setParam(YSTRING("trace_msg_count"),String(count));
}
class JsEngineWorker; class JsEngineWorker;
class JsEngine; class JsEngine;
@ -375,6 +390,9 @@ public:
params().addParam(new ExpFunction("output")); params().addParam(new ExpFunction("output"));
params().addParam(new ExpFunction("debug")); params().addParam(new ExpFunction("debug"));
params().addParam(new ExpFunction("alarm")); params().addParam(new ExpFunction("alarm"));
params().addParam(new ExpFunction("lineNo"));
params().addParam(new ExpFunction("fileName"));
params().addParam(new ExpFunction("fileNo"));
params().addParam(new ExpFunction("sleep")); params().addParam(new ExpFunction("sleep"));
params().addParam(new ExpFunction("usleep")); params().addParam(new ExpFunction("usleep"));
params().addParam(new ExpFunction("yield")); params().addParam(new ExpFunction("yield"));
@ -435,7 +453,8 @@ public:
inline JsMessage(Mutex* mtx) inline JsMessage(Mutex* mtx)
: JsObject("Message",mtx,true), : JsObject("Message",mtx,true),
m_message(0), m_dispatch(false), m_owned(false), m_trackPrio(true) m_message(0), m_dispatch(false), m_owned(false), m_trackPrio(true),
m_traceLvl(DebugInfo), m_traceLst(0)
{ {
XDebug(&__plugin,DebugAll,"JsMessage::JsMessage() [%p]",this); XDebug(&__plugin,DebugAll,"JsMessage::JsMessage() [%p]",this);
params().addParam(new ExpFunction("enqueue")); params().addParam(new ExpFunction("enqueue"));
@ -452,12 +471,15 @@ public:
params().addParam(new ExpFunction("getResult")); params().addParam(new ExpFunction("getResult"));
params().addParam(new ExpFunction("copyParams")); params().addParam(new ExpFunction("copyParams"));
params().addParam(new ExpFunction("clearParam")); params().addParam(new ExpFunction("clearParam"));
params().addParam(new ExpFunction("trace"));
} }
inline JsMessage(Message* message, Mutex* mtx, bool disp, bool owned = false) inline JsMessage(Message* message, Mutex* mtx, bool disp, bool owned = false)
: JsObject(mtx,"[object Message]"), : JsObject(mtx,"[object Message]"),
m_message(message), m_dispatch(disp), m_owned(owned), m_trackPrio(true) m_message(message), m_dispatch(disp), m_owned(owned), m_trackPrio(true),
m_traceLvl(DebugInfo), m_traceLst(0)
{ {
XDebug(&__plugin,DebugAll,"JsMessage::JsMessage(%p) [%p]",message,this); XDebug(&__plugin,DebugAll,"JsMessage::JsMessage(%p) [%p]",message,this);
setTrace();
} }
virtual ~JsMessage() virtual ~JsMessage()
{ {
@ -471,6 +493,7 @@ public:
MessageHook* hook = static_cast<MessageHook*>(o->get()); MessageHook* hook = static_cast<MessageHook*>(o->get());
Engine::uninstallHook(hook); Engine::uninstallHook(hook);
} }
TelEngine::destruct(m_traceLst);
} }
virtual void* getObject(const String& name) const; virtual void* getObject(const String& name) const;
virtual NamedList* nativeParams() const virtual NamedList* nativeParams() const
@ -489,9 +512,15 @@ public:
construct->params().addParam(new ExpFunction("trackName")); construct->params().addParam(new ExpFunction("trackName"));
} }
inline void clearMsg() inline void clearMsg()
{ m_message = 0; m_owned = false; m_dispatch = false; } {
dumpTraceToMsg(m_message,m_traceLst);
m_message = 0;
m_owned = false;
m_dispatch = false;
setTrace();
}
inline void setMsg(Message* message) inline void setMsg(Message* message)
{ m_message = message; m_owned = false; m_dispatch = false; } { m_message = message; m_owned = false; m_dispatch = false; setTrace(); }
static void initialize(ScriptContext* context); static void initialize(ScriptContext* context);
void runAsync(ObjList& stack, Message* msg, bool owned); void runAsync(ObjList& stack, Message* msg, bool owned);
protected: protected:
@ -500,6 +529,13 @@ protected:
void getRow(ObjList& stack, const ExpOperation* row, GenObject* context); void getRow(ObjList& stack, const ExpOperation* row, GenObject* context);
void getResult(ObjList& stack, const ExpOperation& row, const ExpOperation& col, GenObject* context); void getResult(ObjList& stack, const ExpOperation& row, const ExpOperation& col, GenObject* context);
bool installHook(ObjList& stack, const ExpOperation& oper, GenObject* context); bool installHook(ObjList& stack, const ExpOperation& oper, GenObject* context);
inline void setTrace()
{
m_traceId = m_message ? m_message->getValue(YSTRING("trace_id")) : "";
m_traceLvl = m_message ? m_message->getIntValue(YSTRING("trace_lvl"),DebugInfo,DebugGoOn,DebugAll) : DebugInfo;
TelEngine::destruct(m_traceLst);
m_traceLst = m_message ? (m_message->getBoolValue(YSTRING("trace_to_msg"),false) ? new ObjList() : 0) : 0;
}
ObjList m_handlers; ObjList m_handlers;
ObjList m_hooks; ObjList m_hooks;
String m_trackName; String m_trackName;
@ -507,6 +543,9 @@ protected:
bool m_dispatch; bool m_dispatch;
bool m_owned; bool m_owned;
bool m_trackPrio; bool m_trackPrio;
String m_traceId;
int m_traceLvl;
ObjList* m_traceLst;
}; };
class JsHandler : public MessageHandler class JsHandler : public MessageHandler
@ -1287,6 +1326,32 @@ bool JsEngine::runNative(ObjList& stack, const ExpOperation& oper, GenObject* co
Alarm(this,info,level,"%s",str.c_str()); Alarm(this,info,level,"%s",str.c_str());
} }
} }
else if (oper.name() == YSTRING("lineNo")) {
if (oper.number())
return false;
ScriptRun* runner = YOBJECT(ScriptRun,context);
if (!runner)
return false;
ExpEvaluator::pushOne(stack,new ExpOperation((int64_t)runner->currentLineNo()));
}
else if (oper.name() == YSTRING("fileName") || oper.name() == YSTRING("fileNo")) {
if (oper.number() > 1)
return false;
bool wholePath = false;
if (oper.number() == 1) {
ExpOperation* op = popValue(stack,context);
if (!op)
return false;
wholePath = op->valBoolean();
}
ScriptRun* runner = YOBJECT(ScriptRun,context);
if (!runner)
return false;
String fileName = runner->currentFileName(wholePath);
if (oper.name() == YSTRING("fileNo"))
fileName << ":" << runner->currentLineNo();
ExpEvaluator::pushOne(stack,new ExpOperation(fileName));
}
else if (oper.name() == YSTRING("sleep")) { else if (oper.name() == YSTRING("sleep")) {
if (oper.number() != 1) if (oper.number() != 1)
return false; return false;
@ -2365,6 +2430,73 @@ bool JsMessage::runNative(ObjList& stack, const ExpOperation& oper, GenObject* c
return false; return false;
} }
} }
else if (oper.name() == YSTRING("trace")) {
if (!m_message)
return true;
ObjList args;
unsigned int c = extractArgs(stack,oper,context,args);
if (c < 2)
return false;
ExpOperation* ret = static_cast<ExpOperation*>(args[0]);
ExpOperation* op = static_cast<ExpOperation*>(args[1]);
int level = -1;
int limit = s_allowAbort ? DebugFail : DebugTest;
if (op->number() > 1 && op->isInteger()) {
level = (int)op->number();
if (level > DebugAll)
level = DebugAll;
else if (level < limit)
level = limit;
}
String str;
ScriptRun* runner = YOBJECT(ScriptRun,context);
if (m_traceId) {
if (!runner)
return false;
str = runner->currentFileName();
str << ":" << runner->currentLineNo();
if (ret->isBoolean())
str << " - return:" << ret->valBoolean();
}
for (unsigned int i = 2; i < c; i++) {
ExpOperation* op = static_cast<ExpOperation*>(args[i]);
if (!op)
continue;
else if (*op) {
if (str)
str << " ";
str << *op;
}
}
DebugEnabler* dbg = &__plugin;
if (runner && runner->context()) {
JsEngine* engine = YOBJECT(JsEngine,runner->context()->params().getParam(YSTRING("Engine")));
if (engine)
dbg = engine;
}
if (m_traceId) {
if (level > m_traceLvl || level == -1)
level = m_traceLvl;
if (level < limit)
level = limit;
Debug(dbg,level,"Trace:%s %s",m_traceId.c_str(),str.c_str());
if (m_traceLst)
m_traceLst->append(new String(str));
}
else if (level > -1 && str)
Debug(dbg,level,"%s",str.c_str());
if (!JsParser::isUndefined(*ret))
ExpEvaluator::pushOne(stack,JsParser::isNull(*ret) ?
JsParser::nullClone() : new ExpOperation(*ret));
else
ExpEvaluator::pushOne(stack,new ExpWrapper(0,0));
}
else else
return JsObject::runNative(stack,oper,context); return JsObject::runNative(stack,oper,context);
return true; return true;