I'll add some more context as to how I found this. The VSCode extension offers a debugging facility. As part of that, when an exception occurs it queries the current call stack. Internally in the Debug Server, I've monkey patched the compiler so I can trap the exception and then query the available Puppet Stack. As per my original ticket title, because the PuppetStack is popped BEFORE the exception is handled I couldn't get access to the Puppet call stack. This behaviour is different to a regular Ruby Stack, where the call stack is not modified. Now I know that my use case is far from normal, and that I'm using monkey patches and private APIs, so any breakages aren't really a Puppet problem. The missing tracing information in the stacktrace as all I could think of from a regular user point of view. Given this nested manifest
class nest1 { |
fail('somethinng') |
} |
|
class nest2 { |
include nest1 |
} |
|
include nest2
|
And some basic puts debugging .... STACK PUSH - An object is pushed onto the PuppetStack STACK CALLING - PuppetStack is calling the actual code. STACK POP - An object is popped onto the PuppetStack So you can see the stack calling the evaluator, then the include function twice, and finally the fail function
C:\Source\puppet [master ≡ +0 ~4 -0 !]> be puppet apply tmp\test.pp |
Warning: Facter: Fact resolution fact='puppet_classes', resolution='<anonymous>' resolved to an invalid value: Expected all to be one of [Integer, Float, TrueClass, FalseClass, NilClass, String, Array, Hash], but was Symbol |
STACK PUSH |
STACK CALLING #<Puppet::Pops::Evaluator::EvaluatorImpl:0x00000000076eb778 @migration_checker=#<Puppet::Pops::Migration::MigrationChecker:0x00000000076eb110>>.evaluate Puppet::Pops::Evaluator::EvaluatorImpl |
STACK PUSH |
STACK CALLING #<#<Class:0x00000000076dbe18>:0x00000000076dba30 @closure_scope=nil, @loader=(ModuleLoader::FileBased 'puppet_system' '')>.call include |
STACK PUSH |
STACK CALLING #<#<Class:0x00000000076dbe18>:0x00000000076dba30 @closure_scope=nil, @loader=(ModuleLoader::FileBased 'puppet_system' '')>.call include |
STACK PUSH |
STACK CALLING #<#<Class:0x00000000076a2578>:0x00000000076a2230 @closure_scope=nil, @loader=(ModuleLoader::FileBased 'puppet_system' '')>.call fail |
CALLING function 3x function_fail |
STACK POP |
Puppet::Pops::Evaluator RESCUE Puppet::ParseError <--------- This is where the exception object is created |
Puppet::Pops::Evaluator RESCUE Puppet::PreformattedError |
STACK POP |
Puppet::Pops::Evaluator RESCUE Puppet::PreformattedError |
Puppet::Pops::Evaluator RESCUE Puppet::PreformattedError |
STACK POP |
Puppet::Pops::Evaluator RESCUE Puppet::PreformattedError |
Puppet::Pops::Evaluator RESCUE Puppet::PreformattedError |
STACK POP |
Puppet::Pops::Evaluator RESCUE Puppet::PreformattedError |
|
<--------- This is where the exception can be trapped |
|
Error: Evaluation Error: Error while evaluating a Function Call, somethinng (file: C:/Source/puppet/tmp/test.pp, line: 2, column: 3) on node glenn.sarti-r90qu2hx
|
You can see that the exception object is created at the beginning, but by the time the compiler can actually trapped/rescued, the PuppetStack stack has been modified. Therefore the exception is out-of-sync with the Puppetstack. Previously this wasn't a problem because the ruby call stack is preserved for us. |