There's the getStackTrace() function that gets stack trace from the current exception.
But it doesn't work for specific exception, this code won't work error.getStackTrace()
I need it for log function
proc error*(message: string, exception: Exception): void =
stderr.write_line fmt" {message}"
stderr.write_line exception.getStackTrace()
Your sample code does not even compile for me, since getCurrentException returns a reference to an Exception and not a copy of it so there's no way to pass it to error(). Here's a full sample that compiles for me:
proc failHard() =
doAssert toInt(1.49) == 0
proc error*(message: string, exception: ref Exception) =
echo message
echo exception.getStackTrace()
proc main() =
try: failHard()
except: error("oops", getCurrentException())
main()
When I compile and run this program I get the following output:
$ ./t
oops
/private/tmp/t/t.nim(12) t
/private/tmp/t/t.nim(9) main
/private/tmp/t/t.nim(2) failHard
/Users/gradha/.choosenim/toolchains/nim-1.2.6/lib/system/assertions.nim(29) failedAssertImpl
/Users/gradha/.choosenim/toolchains/nim-1.2.6/lib/system/assertions.nim(22) raiseAssert
/Users/gradha/.choosenim/toolchains/nim-1.2.6/lib/system/fatal.nim(49) sysFatal
Note that getStackTrace() documentation mentions it does not offer much information in non debug builds:
$ nim c -d:release -r t.nim
Hint: used config file '/Users/gradha/.choosenim/toolchains/nim-1.2.6/config/nim.cfg' [Conf]
Hint: 320 LOC; 0.096 sec; 5.379MiB peakmem; Release build; proj: /private/tmp/t/t.nim; out: /private/tmp/t/t [SuccessX]
Hint: /private/tmp/t/t [Exec]
oops
fatal.nim(49) sysFatal
Related
I am trying to make a simple feedback loop in my nextflow script. I am getting a weird error message that I do not know how to debug. My attempt is modeled after the NextFlow design pattern described here. I need a value to be calculated from a python3 script that operates on an image but pass that value on to subsequent executions of the script. At this stage I just want to get the structure right by adding numbers but I cannot get that to work yet.
my script
feedback_ch = Channel.create()
input_ch = Channel.from(feedback_ch)
process test {
echo true
input:
val chan_a from Channel.from(1,2,3)
val feedback_val from input_ch
output:
stdout output_val into feedback_ch
shell:
'''
#!/usr/bin/python3
new_val = !{chan_a} + !{feedback_val}
print(new_val)
'''
}
The error message I get
Error executing process > 'test (1)'
Caused by:
Process `test (1)` terminated with an error exit status (1)
Command executed:
#!/usr/bin/python3
new_val = 1 + DataflowQueue(queue=[])
print(new_val)
Command exit status:
1
Command output:
(empty)
Command error:
Traceback (most recent call last):
File ".command.sh", line 3, in <module>
new_val = 1 + DataflowQueue(queue=[])
NameError: name 'DataflowQueue' is not defined
Work dir:
executor > local (1)
[cd/67768e] process > test (1) [100%] 1 of 1, failed: 1 ✘
Error executing process > 'test (1)'
Caused by:
Process `test (1)` terminated with an error exit status (1)
Command executed:
#!/usr/bin/python3
new_val = 1 + DataflowQueue(queue=[])
print(new_val)
Command exit status:
1
Command output:
(empty)
Command error:
Traceback (most recent call last):
File ".command.sh", line 3, in <module>
new_val = 1 + DataflowQueue(queue=[])
NameError: name 'DataflowQueue' is not defined
Work dir:
/home/cv_proj/work/cd/67768e706f50d7675ae93645a0ce6e
Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run`
Anyone have any ideas?
The problem you have says, that you are passing empty DataflowQueue object with input_ch. Nextflow tries to execute it, so it substitutes your python code with variables, resulting in:
#!/usr/bin/python3
new_val = 1 + DataflowQueue(queue=[])
print(new_val)
What is nonsense (You want some number instead of DataflowQueue(queue=[]), don't you?).
Second problem is, that you don't have channels mixed, what seems to be important in this pattern. Anyway, I fixed it, to have proof of concept, working solution:
condition = { it.trim().toInteger() > 10 } // As your output is stdout, you need to trim() to get rid of newline. Then cast to Integer to compare.
feedback_ch = Channel.create()
input_ch = Channel.from(1,2,3).mix( feedback_ch.until(condition) ) // Mixing channel, so we have feedback
process test {
input:
val chan_a from input_ch
output:
stdout output_val into feedback_ch
shell:
var output_val_trimmed = chan_a.toString().trim()
// I am using double quotes, so nextflow interpolates variable above.
"""
#!/usr/bin/python3
new_val = ${output_val_trimmed} + ${output_val_trimmed}
print(new_val)
"""
}
I hope, that it at least set you on right track :)
//Code 1
log.info undefined
When we run the code 1 , we get below error in soapui/readyapi as
please note :- Line number is visible in error message
However to avoid this alert , we used try/catch to print this, so the above code is amended to below as code 2
//code 2
try
{
log.info undefined
}
catch(Exception e)
{
log.info e
}
when we run the code 2 we get below results
Mon Mar 19 15:04:16 IST 2018:INFO:groovy.lang.MissingPropertyException: No such property: undefined for class: Script6
Problem :- How can we see the line number where the problem is just like we are able to see in code1
Requirement :- Our exception block should be able to tell problem is in which line.
Since its a small code we are able to know, Sometimes the code is having 100+ lines and its difficult to know where the exception is
Building on #tim_yates answer of using e.stackTrace.head().linenumber:
import org.codehaus.groovy.runtime.StackTraceUtils
try {
println undefined
} catch (Exception e) {
StackTraceUtils.sanitize(e)
e.stackTrace.head().lineNumber
}
Use sanitize() on your Exception to remove all the weird Groovy internal stuff from the stack trace for your Exception. Otherwise when you look at the first StackTraceElement, it probably won't be the one you want.
deepSanitize() is the same, but also applies the transform to all the nested Exceptions if there are any.
Thanks Chris and Jeremy for solving my problem.
I have used the below solution using Chris answer with all full respect to your answer
try
{
log.info undefined
}
catch(Exception e)
{
log.error "Exception = " + e
String str= e.getStackTrace().toString()
def pattern = ( str =~ /groovy.(\d+)./ )
log.error " Error at line number = " + pattern[0][1]
}
The reason i am using that answer is i can avoid an import in all my scripts.
I have used pattern matching to extract the line number as it always come like
(Script18.groovy:17),
so i have used the pattern
/groovy.(\d+)./
Now i get both the exception details and line number
You can use log.info e.getStackTrace().toString(); to get the full stack trace.
However, it'll be hard to pick out the issue. Here's my Groovy script....
try
{
log.info undefined
}
catch(Exception e)
{
log.info e.getStackTrace().toString();
}
Here's the trace....
Mon Mar 19 17:15:20 GMT 2018:INFO:[org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50), org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49), org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231), Script21.run(Script21.groovy:3), com.eviware.soapui.support.scripting.groovy.SoapUIGroovyScriptEngine.run(SoapUIGroovyScriptEngine.java:100), com.eviware.soapui.support.scripting.groovy.SoapUIProGroovyScriptEngineFactory$SoapUIProGroovyScriptEngine.run(SourceFile:89), com.eviware.soapui.impl.wsdl.teststeps.WsdlGroovyScriptTestStep.run(WsdlGroovyScriptTestStep.java:154), com.eviware.soapui.impl.wsdl.panels.teststeps.GroovyScriptStepDesktopPanel$RunAction$1.run(GroovyScriptStepDesktopPanel.java:277), java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source), java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source), java.lang.Thread.run(Unknown Source)]
Note- the emboldened part. It's line 3 and that is what I expected. However, SoapUI must use internal numbering for scripts as I called the script "Dummy Groovy Script" and the stack trace says "Script21".
Anyhow, I do think you ought look at your Groovy script, 100+ lines in a Try seems a bit much and as you pint out, it's difficult to see the issue.
I'd suggest breaking it down into functions, or even better, call an Java class external to SoapUI, that has nice well-defined functions.
The SmartBear site describes how this can be done. Plus, it remove a lot of the bloat from the SoapUI project file.
I am looking to clean up the normal python unittest output. I want to the console output to still be
test_isupper (__main__.TestStringMethods) ... ok
test_split (__main__.TestStringMethods) ... ok
test_upper (__main__.TestStringMethods) ... ok
test_fail (__main__.TestFail) ... ERROR
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
But for the fail tests I want to capture the detailed output, and put that in a log file. So instead of it being inline with the console output...
======================================================================
FAIL: test_fail (__main__.TestFail)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test.py", line x
self.assertTrue(False)
AssertionError: False is not True
======================================================================
Gets logged to a file for further investigation, along with any debug level logger output. Is there a way to overload the logger in the unittest.testcase to do what I want?
I should mention I am still very new to python...
I ended up being able to get close enough results to what I wanted by using the testResult object. From that object I was able to get tuples with data on different tests that had passed, failed, or had errors. Then it was a simple create a "prettyPrint" method to take this object and print out the contents nicely.
The exact recipe was:
suite = unittest.TestLoader().loadTestsFromModule( className )
testResult = unittest.TextTestRunner(verbosity=3).run( suite )
Hopefully this helps anyone else looking to do something similar.
The TextTestRunner output can be redirected to a file by providing a stream argument to constructor. Later then, using run() on the suite will return TextTestResult, which you can pretty print. Something like this:
logs_filename = 'logs.txt'
def print_test_results_summary(result):
n_failed = len(result.failures) + len(result.unexpectedSuccesses)
n_crashed = len(result.errors)
n_succeeded = result.testsRun - n_failed - n_crashed
print(f'''See for details {logs_filename} file.
Results: Total: {result.testsRun}, Crashed: {n_crashed}, Failed: {n_failed}, Succeeded: {n_succeeded}''')
with open(logs_filename, 'w') as log_file:
suite = unittest.defaultTestLoader.loadTestsFromModule(className)
testResult = unittest.TextTestRunner(log_file, verbosity=3).run(suite)
print_test_results_summary(testResult)
For some reason, I get this error message whenever I try to compile this simple function: Test.hx:1: lines 1-7 : Invalid -main : Test has invalid main function
public static function main(a:Int, b:Int){
trace("Calling main function");
return a+b;
}
I'm not sure why this is happening. What's wrong with this function definition, and how can I get it to compile correctly? I tried reading the documentation, and found it to be unclear in its explanation of how to properly set function return types.
The special main entry function must be a Void->Void function. i.e. No param and no return value is allowed. Remember there is no command line argument concept in JS/Flash, which Haxe also compiles to. So we have to use system targets' API for that:
Sys.args() : Array<String> to get the command line params.
Sys.exit( code : Int ) : Void to exit with exit code.
FYI, the doc of Sys is at http://haxe.org/api/sys
I am having some serious trouble getting a Python 2 based C++ engine to work in Python3. I know the whole IO stack has changed, but everything I seem to try just ends up in failure. Below is the pre-code (Python2) and post code (Python3). I am hoping someone can help me figure out what I'm doing wrong.I am also using boost::python to control the references.
The program is supposed to load a Python Object into memory via a map and then upon using the run function it then finds the file loaded in memory and runs it. I based my code off an example from the delta3d python manager, where they load in a file and run it immediately. I have not seen anything equivalent in Python3.
Python2 Code Begins here:
// what this does is first calls the Python C-API to load the file, then pass the returned
// PyObject* into handle, which takes reference and sets it as a boost::python::object.
// this takes care of all future referencing and dereferencing.
try{
bp::object file_object(bp::handle<>(PyFile_FromString(fullPath(filename), "r" )));
loaded_files_.insert(std::make_pair(std::string(fullPath(filename)), file_object));
}
catch(...)
{
getExceptionFromPy();
}
Next I load the file from the std::map and attempt to execute it:
bp::object loaded_file = getLoadedFile(filename);
try
{
PyRun_SimpleFile( PyFile_AsFile( loaded_file.ptr()), fullPath(filename) );
}
catch(...)
{
getExceptionFromPy();
}
Python3 Code Begins here: This is what I have so far based off some suggestions here... SO Question
Load:
PyObject *ioMod, *opened_file, *fd_obj;
ioMod = PyImport_ImportModule("io");
opened_file = PyObject_CallMethod(ioMod, "open", "ss", fullPath(filename), "r");
bp::handle<> h_open(opened_file);
bp::object file_obj(h_open);
loaded_files_.insert(std::make_pair(std::string(fullPath(filename)), file_obj));
Run:
bp::object loaded_file = getLoadedFile(filename);
int fd = PyObject_AsFileDescriptor(loaded_file.ptr());
PyObject* fileObj = PyFile_FromFd(fd,fullPath(filename),"r",-1,"", "\n","", 0);
FILE* f_open = _fdopen(fd,"r");
PyRun_SimpleFile( f_open, fullPath(filename) );
Lastly, the general state of the program at this point is the file gets loaded in as TextIOWrapper and in the Run: section the fd that is returned is always 3 and for some reason _fdopen can never open the FILE which means I can't do something like PyRun_SimpleFile. The error itself is a debug ASSERTION on _fdopen. Is there a better way to do all this I really appreciate any help.
If you want to see the full program of the Python2 version it's on Github
So this question was pretty hard to understand and I'm sorry, but I found out my old code wasn't quite working as I expected. Here's what I wanted the code to do. Load the python file into memory, store it into a map and then at a later date execute that code in memory. I accomplished this a bit differently than I expected, but it makes a lot of sense now.
Open the file using ifstream, see the code below
Convert the char into a boost::python::str
Execute the boost::python::str with boost::python::exec
Profit ???
Step 1)
vector<char> input;
ifstream file(fullPath(filename), ios::in);
if (!file.is_open())
{
// set our error message here
setCantFindFileError();
input.push_back('\0');
return input;
}
file >> std::noskipws;
copy(istream_iterator<char>(file), istream_iterator<char>(), back_inserter(input));
input.push_back('\n');
input.push_back('\0');
Step 2)
bp::str file_str(string(&input[0]));
loaded_files_.insert(std::make_pair(std::string(fullPath(filename)), file_str));
Step 3)
bp::str loaded_file = getLoadedFile(filename);
// Retrieve the main module
bp::object main = bp::import("__main__");
// Retrieve the main module's namespace
bp::object global(main.attr("__dict__"));
bp::exec(loaded_file, global, global);
Full Code is located on github: