You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@velocity.apache.org by cb...@apache.org on 2019/09/08 10:42:47 UTC

svn commit: r1866609 [1/2] - in /velocity/engine/trunk/velocity-engine-core/src/main: java/org/apache/velocity/ java/org/apache/velocity/app/event/ java/org/apache/velocity/exception/ java/org/apache/velocity/runtime/ java/org/apache/velocity/runtime/d...

Author: cbrisson
Date: Sun Sep  8 10:42:47 2019
New Revision: 1866609

URL: http://svn.apache.org/viewvc?rev=1866609&view=rev
Log:
[VELOCITY-916] Add a second effect for the debugging flag runtime.log.track_location: display VTL stacktrace on errors



Modified:
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/Template.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/EventHandlerUtil.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MacroOverflowException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MathException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MethodInvocationException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ParseErrorException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ResourceNotFoundException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/TemplateInitException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/VelocityException.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeInstance.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/VelocimacroFactory.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Break.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Define.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Evaluate.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Foreach.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Include.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Parse.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/LogContext.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDirective.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDivNode.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIndex.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTModNode.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNegateNode.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ContentResource.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ResourceManagerImpl.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/JarResourceLoader.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/StringResourceLoader.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/URLResourceLoader.java
    velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/util/introspection/UberspectImpl.java
    velocity/engine/trunk/velocity-engine-core/src/main/parser/Parser.jjt

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/Template.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/Template.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/Template.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/Template.java Sun Sep  8 10:42:47 2019
@@ -26,7 +26,7 @@ import org.apache.velocity.exception.Par
 import org.apache.velocity.exception.ResourceNotFoundException;
 import org.apache.velocity.exception.TemplateInitException;
 import org.apache.velocity.exception.VelocityException;
-import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.RuntimeInstance;
 import org.apache.velocity.runtime.directive.Scope;
 import org.apache.velocity.runtime.directive.StopCommand;
 import org.apache.velocity.runtime.parser.ParseException;
@@ -165,7 +165,7 @@ public class Template extends Resource
             catch( RuntimeException e )
             {
                 errorCondition = new VelocityException("Exception thrown processing Template "
-                    +getName(), e);
+                    +getName(), e, rsvc.getLogContext().getStackTrace());
                 throw errorCondition;
             }
             finally
@@ -183,7 +183,7 @@ public class Template extends Resource
                     // exception to be continued to be thrown, otherwise, throw a new Exception.
                     if (errorCondition == null)
                     {
-                         throw new VelocityException(e);
+                         throw new VelocityException(e, rsvc.getLogContext().getStackTrace());
                     }
                 }
             }
@@ -193,7 +193,7 @@ public class Template extends Resource
             /*
              *  is == null, therefore we have some kind of file issue
              */
-            errorCondition = new ResourceNotFoundException("Unknown resource error for resource " + name );
+            errorCondition = new ResourceNotFoundException("Unknown resource error for resource " + name, null, rsvc.getLogContext().getStackTrace() );
             throw errorCondition;
         }
     }
@@ -280,139 +280,157 @@ public class Template extends Resource
     public void merge( Context context, Writer writer, List macroLibraries)
         throws ResourceNotFoundException, ParseErrorException, MethodInvocationException
     {
-        /*
-         *  we shouldn't have to do this, as if there is an error condition,
-         *  the application code should never get a reference to the
-         *  Template
-         */
-
-        if (errorCondition != null)
-        {
-            throw errorCondition;
-        }
-
-        if( data != null)
+        try
         {
             /*
-             *  create an InternalContextAdapter to carry the user Context down
-             *  into the rendering engine.  Set the template name and render()
+             *  we shouldn't have to do this, as if there is an error condition,
+             *  the application code should never get a reference to the
+             *  Template
              */
 
-            InternalContextAdapterImpl ica = new InternalContextAdapterImpl( context );
-
-            /**
-             * Set the macro libraries
-             */
-            List libTemplates = new ArrayList();
-            ica.setMacroLibraries(libTemplates);
+            if (errorCondition != null)
+            {
+                throw errorCondition;
+            }
 
-            if (macroLibraries != null)
+            if (data != null)
             {
-                for (String macroLibrary : (List<String>)macroLibraries)
+                /*
+                 *  create an InternalContextAdapter to carry the user Context down
+                 *  into the rendering engine.  Set the template name and render()
+                 */
+
+                InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
+
+                /**
+                 * Set the macro libraries
+                 */
+                List libTemplates = new ArrayList();
+                ica.setMacroLibraries(libTemplates);
+
+                if (macroLibraries != null)
                 {
-                    /**
-                     * Build the macro library
-                     */
-                    try
-                    {
-                        Template t = rsvc.getTemplate(macroLibrary);
-                        libTemplates.add(t);
-                    }
-                    catch (ResourceNotFoundException re)
+                    for (String macroLibrary : (List<String>) macroLibraries)
                     {
-                        /*
-                        * the macro lib wasn't found.  Note it and throw
-                        */
-                        log.error("cannot find template {}", macroLibrary);
-                        throw re;
+                        /**
+                         * Build the macro library
+                         */
+                        try
+                        {
+                            Template t = rsvc.getTemplate(macroLibrary);
+                            libTemplates.add(t);
+                        }
+                        catch (ResourceNotFoundException re)
+                        {
+                            /*
+                             * the macro lib wasn't found.  Note it and throw
+                             */
+                            log.error("cannot find template {}", macroLibrary);
+                            throw re;
+                        }
+                        catch (ParseErrorException pe)
+                        {
+                            /*
+                             * the macro lib was found, but didn't parse - syntax error
+                             *  note it and throw
+                             */
+                            rsvc.getLog("parser").error("syntax error in template {}: {}",
+                                macroLibrary, pe.getMessage(), pe);
+                            throw pe;
+                        }
+                        catch (Exception e)
+                        {
+                            throw new RuntimeException("parse failed in template  " +
+                                (String) macroLibrary + ".", e);
+                        }
                     }
-                    catch (ParseErrorException pe)
+                }
+
+                if (provideScope)
+                {
+                    ica.put(scopeName, new Scope(this, ica.get(scopeName)));
+                }
+                try
+                {
+                    ica.pushCurrentTemplateName(name);
+                    ica.setCurrentResource(this);
+
+                    ((SimpleNode) data).render(ica, writer);
+                }
+                catch (StopCommand stop)
+                {
+                    if (!stop.isFor(this))
                     {
-                        /*
-                        * the macro lib was found, but didn't parse - syntax error
-                        *  note it and throw
-                        */
-                        rsvc.getLog("parser").error("syntax error in template {}: {}",
-                            macroLibrary, pe.getMessage(), pe);
-                        throw pe;
+                        throw stop;
                     }
-
-                    catch (Exception e)
+                    else
                     {
-                        throw new RuntimeException("parse failed in template  " +
-                            (String) macroLibrary + ".", e);
+                        Logger renderingLog = rsvc.getLog("rendering");
+                        renderingLog.debug(stop.getMessage());
                     }
                 }
-            }
-
-            if (provideScope)
-            {
-                ica.put(scopeName, new Scope(this, ica.get(scopeName)));
-            }
-            try
-            {
-                ica.pushCurrentTemplateName( name );
-                ica.setCurrentResource( this );
-
-                ( (SimpleNode) data ).render( ica, writer);
-            }
-            catch (StopCommand stop)
-            {
-                if (!stop.isFor(this))
+                catch (IOException e)
                 {
-                    throw stop;
+                    throw new VelocityException("IO Error rendering template '" + name + "'", e, rsvc.getLogContext().getStackTrace());
                 }
-                else
+                finally
                 {
-                    Logger renderingLog = rsvc.getLog("rendering");
-                    renderingLog.debug(stop.getMessage());
-                }
-            }
-            catch (IOException e)
-            {
-                throw new VelocityException("IO Error rendering template '"+ name + "'", e);
-            }
-            finally
-            {
-                /*
-                 *  lets make sure that we always clean up the context
-                 */
-                ica.popCurrentTemplateName();
-                ica.setCurrentResource( null );
+                    /*
+                     *  lets make sure that we always clean up the context
+                     */
+                    ica.popCurrentTemplateName();
+                    ica.setCurrentResource(null);
 
-                if (provideScope)
-                {
-                    Object obj = ica.get(scopeName);
-                    if (obj instanceof Scope)
+                    if (provideScope)
                     {
-                        Scope scope = (Scope)obj;
-                        if (scope.getParent() != null)
-                        {
-                            ica.put(scopeName, scope.getParent());
-                        }
-                        else if (scope.getReplaced() != null)
-                        {
-                            ica.put(scopeName, scope.getReplaced());
-                        }
-                        else
+                        Object obj = ica.get(scopeName);
+                        if (obj instanceof Scope)
                         {
-                            ica.remove(scopeName);
+                            Scope scope = (Scope) obj;
+                            if (scope.getParent() != null)
+                            {
+                                ica.put(scopeName, scope.getParent());
+                            }
+                            else if (scope.getReplaced() != null)
+                            {
+                                ica.put(scopeName, scope.getReplaced());
+                            }
+                            else
+                            {
+                                ica.remove(scopeName);
+                            }
                         }
                     }
                 }
             }
-        }
-        else
-        {
-            /*
-             * this shouldn't happen either, but just in case.
-             */
+            else
+            {
+                /*
+                 * this shouldn't happen either, but just in case.
+                 */
 
-            String msg = "Template merging failed. The document is null, " +
-                "most likely due to a parsing error.";
+                String msg = "Template merging failed. The document is null, " +
+                    "most likely due to a parsing error.";
 
-            throw new RuntimeException(msg);
+                throw new RuntimeException(msg);
 
+            }
+        }
+        catch (VelocityException ve)
+        {
+            /* it's a good place to display the VTL stack trace if we have one */
+            String[] vtlStacktrace = ve.getVtlStackTrace();
+            if (vtlStacktrace != null)
+            {
+                Logger renderingLog = rsvc.getLog("rendering");
+                renderingLog.error(ve.getMessage());
+                renderingLog.error("VTL stacktrace:");
+                for (String level : vtlStacktrace)
+                {
+                    renderingLog.error(level);
+                }
+            }
+            throw ve;
         }
     }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/EventHandlerUtil.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/EventHandlerUtil.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/EventHandlerUtil.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/app/event/EventHandlerUtil.java Sun Sep  8 10:42:47 2019
@@ -71,7 +71,7 @@ public class EventHandlerUtil {
         }
         catch (Exception e)
         {
-            throw new VelocityException("Exception in event handler.",e);
+            throw new VelocityException("Exception in event handler.",e, rsvc.getLogContext().getStackTrace());
         }
     }
 
@@ -117,7 +117,7 @@ public class EventHandlerUtil {
         }
         catch (Exception ex)
         {
-            throw new VelocityException("Exception in event handler.", ex);
+            throw new VelocityException("Exception in event handler.", ex, rsvc.getLogContext().getStackTrace());
         }
 
         /* default behaviour is to re-throw exception */
@@ -165,7 +165,7 @@ public class EventHandlerUtil {
         }
         catch (Exception e)
         {
-            throw new VelocityException("Exception in event handler.",e);
+            throw new VelocityException("Exception in event handler.", e, rsvc.getLogContext().getStackTrace());
         }
     }
 
@@ -202,7 +202,7 @@ public class EventHandlerUtil {
         }
         catch (Exception e)
         {
-            throw new VelocityException("Exception in event handler.",e);
+            throw new VelocityException("Exception in event handler.", e, rsvc.getLogContext().getStackTrace());
         }
     }
 
@@ -237,7 +237,7 @@ public class EventHandlerUtil {
         }
         catch (Exception e)
         {
-            throw new VelocityException("Exception in event handler.",e);
+            throw new VelocityException("Exception in event handler.", e, rsvc.getLogContext().getStackTrace());
         }
     }
 
@@ -273,7 +273,7 @@ public class EventHandlerUtil {
         }
         catch (Exception e)
         {
-            throw new VelocityException("Exception in event handler.",e);
+            throw new VelocityException("Exception in event handler.", e, rsvc.getLogContext().getStackTrace());
         }
     }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MacroOverflowException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MacroOverflowException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MacroOverflowException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MacroOverflowException.java Sun Sep  8 10:42:47 2019
@@ -50,10 +50,32 @@ public class MacroOverflowException exte
     }
 
     /**
+     * @param exceptionMessage The message to register.
+     * @param wrapped A throwable object that caused the Exception.
+     * @param stacktrace VTL stacktrace
+     * @since 2.2
+     */
+    public MacroOverflowException(final String exceptionMessage, final Throwable wrapped, final String[] stacktrace)
+    {
+        super(exceptionMessage, wrapped, stacktrace);
+    }
+
+    /**
      * @param wrapped A throwable object that caused the Exception.
      */
     public MacroOverflowException(final Throwable wrapped)
     {
         super(wrapped);
     }
+
+    /**
+     * @param wrapped A throwable object that caused the Exception.
+     * @param stacktrace VTL stacktrace
+     * @since 2.2
+     */
+    public MacroOverflowException(final Throwable wrapped, final String[] stacktrace)
+    {
+        super(wrapped, stacktrace);
+    }
+
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MathException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MathException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MathException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MathException.java Sun Sep  8 10:42:47 2019
@@ -30,8 +30,21 @@ public class MathException extends Veloc
 {
     private static final long serialVersionUID = -7966507088645215583L;
 
+    /**
+     * @param exceptionMessage The message to register.
+     */
     public MathException(final String exceptionMessage)
     {
         super(exceptionMessage);
     }
+
+    /**
+     * @param exceptionMessage The message to register.
+     * @param stacktrace VTL stacktrace
+     * @since 2.2
+     */
+    public MathException(final String exceptionMessage, final String[] stacktrace)
+    {
+        super(exceptionMessage, null, stacktrace);
+    }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MethodInvocationException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MethodInvocationException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MethodInvocationException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/MethodInvocationException.java Sun Sep  8 10:42:47 2019
@@ -69,6 +69,28 @@ public class MethodInvocationException e
     }
 
     /**
+     *  CTOR - wraps the passed in exception for
+     *  examination later
+     *
+     * @param message
+     * @param e Throwable that we are wrapping
+     * @param stacktrace VTL stacktrace
+     * @param methodName name of method that threw the exception
+     * @param templateName The name of the template where the exception occurred
+     * @param lineNumber line number
+     * @param columnNumber  column number
+     */
+    public MethodInvocationException(final String message, final Throwable e, final String[] stacktrace, final String methodName, final String templateName, final int lineNumber, final int columnNumber)
+    {
+        super(message, e, stacktrace);
+
+        this.methodName = methodName;
+        this.templateName = templateName;
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+    }
+
+    /**
      *  Returns the name of the method that threw the
      *  exception.
      *

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ParseErrorException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ParseErrorException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ParseErrorException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ParseErrorException.java Sun Sep  8 10:42:47 2019
@@ -186,11 +186,25 @@ public class ParseErrorException extends
      *
      * @param exceptionMessage the error exception message
      * @param info an Info object with the current template info
+     * @since 2.2
+     */
+    public ParseErrorException(String exceptionMessage, Info info, String[] stacktrace)
+    {
+        super(exceptionMessage, null, stacktrace);
+        columnNumber = info.getColumn();
+        lineNumber = info.getLine();
+        templateName = info.getTemplateName();
+    }
+
+    /**
+     * Create a ParseErrorRuntimeException with the given message and info
+     *
+     * @param exceptionMessage the error exception message
+     * @param info an Info object with the current template info
      * @param invalidSyntax the invalid syntax or reference triggering this exception
      * @since 1.5
      */
-    public ParseErrorException(String exceptionMessage,
-            Info info, String invalidSyntax)
+    public ParseErrorException(String exceptionMessage, Info info, String invalidSyntax)
     {
         super(exceptionMessage);
         columnNumber = info.getColumn();

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ResourceNotFoundException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ResourceNotFoundException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ResourceNotFoundException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/ResourceNotFoundException.java Sun Sep  8 10:42:47 2019
@@ -59,6 +59,18 @@ public class ResourceNotFoundException e
     }
 
     /**
+     * @param exceptionMessage
+     * @param t
+     * @param stacktrace VTL stacktrace
+     * @see VelocityException#VelocityException(String, Throwable)
+     * @since 2.2
+     */
+    public ResourceNotFoundException(final String exceptionMessage, final Throwable t, final String[] stacktrace)
+    {
+        super(exceptionMessage, t, stacktrace);
+    }
+
+    /**
      * @param t
      * @see VelocityException#VelocityException(Throwable)
      * @since 1.5
@@ -67,4 +79,15 @@ public class ResourceNotFoundException e
     {
         super(t);
     }
+
+    /**
+     * @param t
+     * @param stacktrace VTL stacktrace
+     * @see VelocityException#VelocityException(Throwable)
+     * @since 2.2
+     */
+    public ResourceNotFoundException(final Throwable t, String[] stacktrace)
+    {
+        super(t, stacktrace);
+    }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/TemplateInitException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/TemplateInitException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/TemplateInitException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/TemplateInitException.java Sun Sep  8 10:42:47 2019
@@ -41,6 +41,12 @@ public class TemplateInitException exten
      */
     private static final long serialVersionUID = -4985224672336070621L;
 
+    /**
+     * @param msg
+     * @param templateName
+     * @param col
+     * @param line
+     */
     public TemplateInitException(final String msg,
             final String templateName, final int col, final int line)
     {
@@ -50,6 +56,14 @@ public class TemplateInitException exten
         this.line = line;
     }
 
+    /**
+     *
+     * @param msg
+     * @param parseException
+     * @param templateName
+     * @param col
+     * @param line
+     */
     public TemplateInitException(final String msg, ParseException parseException,
             final String templateName, final int col, final int line)
     {
@@ -57,6 +71,25 @@ public class TemplateInitException exten
         this.templateName = templateName;
         this.col = col;
         this.line = line;
+    }
+
+    /**
+     *
+     * @param msg
+     * @param parseException
+     * @param stacktrace
+     * @param templateName
+     * @param col
+     * @param line
+     * @since 2.2
+     */
+    public TemplateInitException(final String msg, ParseException parseException, String[] stacktrace,
+                                 final String templateName, final int col, final int line)
+    {
+        super(msg,parseException, stacktrace);
+        this.templateName = templateName;
+        this.col = col;
+        this.line = line;
     }
 
     /**

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/VelocityException.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/VelocityException.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/VelocityException.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/exception/VelocityException.java Sun Sep  8 10:42:47 2019
@@ -19,6 +19,8 @@ package org.apache.velocity.exception;
  * under the License.
  */
 
+import org.apache.velocity.runtime.parser.LogContext;
+
 /**
 *  Base class for Velocity runtime exceptions thrown to the
  * application layer.
@@ -34,6 +36,16 @@ public class VelocityException extends R
     private static final long serialVersionUID = 1251243065134956045L;
 
     /**
+     * LogContext VTL location tracking context
+     */
+    private LogContext logContext = null;
+
+    /**
+     * VTL vtlStackTrace, populated at construction when runtime.log.track_location is true
+     */
+    private String vtlStackTrace[] = null;
+
+    /**
      * @param exceptionMessage The message to register.
      */
     public VelocityException(final String exceptionMessage)
@@ -52,6 +64,18 @@ public class VelocityException extends R
     }
 
     /**
+     * @param exceptionMessage The message to register.
+     * @param wrapped A throwable object that caused the Exception.
+     * @param vtlStackTrace VTL stacktrace
+     * @since 2.2
+     */
+    public VelocityException(final String exceptionMessage, final Throwable wrapped, final String[] vtlStackTrace)
+    {
+        super(exceptionMessage, wrapped);
+        this.vtlStackTrace = vtlStackTrace;
+    }
+
+    /**
      * @param wrapped A throwable object that caused the Exception.
      * @since 1.5
      */
@@ -61,6 +85,17 @@ public class VelocityException extends R
     }
 
     /**
+     * @param wrapped A throwable object that caused the Exception.
+     * @param vtlStackTrace VTL stacktrace
+     * @since 2.2
+     */
+    public VelocityException(final Throwable wrapped, final String[] vtlStackTrace)
+    {
+        super(wrapped);
+        this.vtlStackTrace = vtlStackTrace;
+    }
+
+    /**
      *  returns the wrapped Throwable that caused this
      *  MethodInvocationException to be thrown
      *
@@ -73,4 +108,8 @@ public class VelocityException extends R
         return getCause();
     }
 
+    public String[] getVtlStackTrace()
+    {
+        return vtlStackTrace;
+    }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeConstants.java Sun Sep  8 10:42:47 2019
@@ -57,7 +57,11 @@ public interface RuntimeConstants extend
     /** Logging of invalid method calls. */
     String RUNTIME_LOG_METHOD_CALL_LOG_INVALID = "runtime.log.log_invalid_method_calls";
 
-    /** Whether to populate slf4j's MDC with location in template file
+    /** <p>Whether to:</p>
+     *  <ul>
+     *      <li>populate slf4j's MDC with location in template file</li>
+     *      <li>display VTL stack trace on errors</li>
+     *  </ul>
      *  @since 2.2
      */
     String RUNTIME_LOG_TRACK_LOCATION = "runtime.log.track_location";

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeInstance.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeInstance.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeInstance.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/RuntimeInstance.java Sun Sep  8 10:42:47 2019
@@ -1488,7 +1488,7 @@ public class RuntimeInstance implements
             {
                 String msg = "RuntimeInstance.render(): init exception for tag = "+logTag;
                 log.error(msg, e);
-                throw new VelocityException(msg, e);
+                throw new VelocityException(msg, e, getLogContext().getStackTrace());
             }
 
             try
@@ -1518,7 +1518,7 @@ public class RuntimeInstance implements
             }
             catch (IOException e)
             {
-                throw new VelocityException("IO Error in writer: " + e.getMessage(), e);
+                throw new VelocityException("IO Error in writer: " + e.getMessage(), e, getLogContext().getStackTrace());
             }
         }
         finally
@@ -1596,7 +1596,7 @@ public class RuntimeInstance implements
             String msg = "RuntimeInstance.invokeVelocimacro(): VM '" + vmName
                          + "' is not registered.";
             log.error(msg);
-            throw new VelocityException(msg);
+            throw new VelocityException(msg, null, getLogContext().getStackTrace());
         }
 
         /* now just create the VM call, and use evaluate */

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/VelocimacroFactory.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/VelocimacroFactory.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/VelocimacroFactory.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/VelocimacroFactory.java Sun Sep  8 10:42:47 2019
@@ -219,7 +219,7 @@ public class VelocimacroFactory
                          {
                              String msg = "Velocimacro: Error using VM library: " + lib;
                              log.error(msg, e);
-                             throw new VelocityException(msg, e);
+                             throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
                          }
 
                          log.trace("VM library registration complete.");
@@ -548,7 +548,7 @@ public class VelocimacroFactory
                     {
                         String msg = "Velocimacro: Error using VM library: " + lib;
                         log.error(msg, e);
-                        throw new VelocityException(msg, e);
+                        throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
                     }
 
                     vp = vmManager.get(vmName, sourceTemplate, renderingTemplate);

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Break.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Break.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Break.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Break.java Sun Sep  8 10:42:47 2019
@@ -99,7 +99,9 @@ public class Break extends Directive
         {
             throw new VelocityException(node.jjtGetChild(0).literal()+
                 " is not a valid " + Scope.class.getName() + " instance at "
-                + StringUtils.formatFileString(this));
+                + StringUtils.formatFileString(this),
+                null,
+                rsvc.getLogContext().getStackTrace());
         }
     }
 

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Define.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Define.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Define.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Define.java Sun Sep  8 10:42:47 2019
@@ -64,7 +64,9 @@ public class Define extends Block
         if ( node.jjtGetNumChildren() != 2 )
         {
             throw new VelocityException("parameter missing: block name at "
-                 + StringUtils.formatFileString(this));
+                 + StringUtils.formatFileString(this),
+                null,
+                rsvc.getLogContext().getStackTrace());
         }
 
         /*

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Evaluate.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Evaluate.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Evaluate.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Evaluate.java Sun Sep  8 10:42:47 2019
@@ -87,6 +87,8 @@ public class Evaluate extends Directive
         {
             throw new TemplateInitException(
                     "#" + getName() + "() requires exactly one argument",
+                    null,
+                    rsvc.getLogContext().getStackTrace(),
                     context.getCurrentTemplateName(),
                     node.getColumn(),
                     node.getLine());
@@ -99,6 +101,8 @@ public class Evaluate extends Directive
 
             throw new TemplateInitException(
                     "#" + getName() + "() requires exactly one argument",
+                    null,
+                    rsvc.getLogContext().getStackTrace(),
                     context.getCurrentTemplateName(),
                     node.jjtGetChild(1).getColumn(),
                     node.jjtGetChild(1).getLine());
@@ -110,6 +114,8 @@ public class Evaluate extends Directive
         {
            throw new TemplateInitException(
                    "#" + getName() + "()  argument must be a string literal or reference",
+                   null,
+                   rsvc.getLogContext().getStackTrace(),
                    context.getCurrentTemplateName(),
                    childNode.getColumn(),
                    childNode.getLine());
@@ -169,7 +175,7 @@ public class Evaluate extends Directive
         {
             // use the line/column from the template
             Info info = new Info( templateName, node.getLine(), node.getColumn() );
-            throw  new ParseErrorException( pex.getMessage(), info );
+            throw  new ParseErrorException( pex.getMessage(), info, rsvc.getLogContext().getStackTrace() );
         }
 
         /*
@@ -190,7 +196,7 @@ public class Evaluate extends Directive
                 catch (TemplateInitException pex)
                 {
                     Info info = new Info( templateName, node.getLine(), node.getColumn() );
-                    throw  new ParseErrorException( pex.getMessage(), info );
+                    throw  new ParseErrorException( pex.getMessage(), info, rsvc.getLogContext().getStackTrace() );
                 }
 
                 try
@@ -213,7 +219,7 @@ public class Evaluate extends Directive
                 {
                     // convert any parsing errors to the correct line/col
                     Info info = new Info( templateName, node.getLine(), node.getColumn() );
-                    throw  new ParseErrorException( pex.getMessage(), info );
+                    throw  new ParseErrorException( pex.getMessage(), info, rsvc.getLogContext().getStackTrace() );
                 }
             }
             finally

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Foreach.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Foreach.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Foreach.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Foreach.java Sun Sep  8 10:42:47 2019
@@ -192,7 +192,7 @@ public class Foreach extends Directive
                 String msg = "Error getting iterator for #foreach parameter "
                     + node.literal() + " at " + StringUtils.formatFileString(node);
                 log.error(msg, ee);
-                throw new VelocityException(msg, ee);
+                throw new VelocityException(msg, ee, rsvc.getLogContext().getStackTrace());
             }
 
             if (i == null && !skipInvalidIterator)
@@ -201,7 +201,7 @@ public class Foreach extends Directive
                     + StringUtils.formatFileString(node) + " is of type " + iterable.getClass().getName()
                     + " and cannot be iterated by " + rsvc.getUberspect().getClass().getName();
                 log.error(msg);
-                throw new VelocityException(msg);
+                throw new VelocityException(msg, null, rsvc.getLogContext().getStackTrace());
             }
         }
         return i;

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Include.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Include.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Include.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Include.java Sun Sep  8 10:42:47 2019
@@ -172,7 +172,7 @@ public class Include extends InputBase
                 log.error(msg);
                 outputErrorToStream( writer, "error with arg " + i
                     + " please see log.");
-                throw new VelocityException(msg);
+                throw new VelocityException(msg, null, rsvc.getLogContext().getStackTrace());
             }
         }
 
@@ -261,7 +261,7 @@ public class Include extends InputBase
             String msg = "#include(): arg = '" + arg +
                         "', called at " + StringUtils.formatFileString(this);
             log.error(msg, e);
-            throw new VelocityException(msg, e);
+            throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
         }
 
 

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Parse.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Parse.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Parse.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/Parse.java Sun Sep  8 10:42:47 2019
@@ -142,7 +142,7 @@ public class Parse extends InputBase
         if ( node.jjtGetNumChildren() == 0 )
         {
             throw new VelocityException("#parse(): argument missing at " +
-                                        StringUtils.formatFileString(this));
+                StringUtils.formatFileString(this), null, rsvc.getLogContext().getStackTrace());
         }
 
         /*
@@ -170,7 +170,7 @@ public class Parse extends InputBase
         if (strictRef && value == null && arg == null)
         {
             throw new VelocityException("The argument to #parse returned null at "
-              + StringUtils.formatFileString(this));
+              + StringUtils.formatFileString(this), null, rsvc.getLogContext().getStackTrace());
         }
 
         /*
@@ -247,7 +247,7 @@ public class Parse extends InputBase
             String msg = "Exception rendering #parse(" + arg + ") at " +
                          StringUtils.formatFileString(this);
             log.error(msg, e);
-            throw new VelocityException(msg, e);
+            throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
         }
 
         /**
@@ -302,7 +302,7 @@ public class Parse extends InputBase
             String msg = "Exception rendering #parse(" + arg + ") at " +
                          StringUtils.formatFileString(this);
             log.error(msg, e);
-            throw new VelocityException(msg, e);
+            throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
         }
         finally
         {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/RuntimeMacro.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/RuntimeMacro.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/RuntimeMacro.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/RuntimeMacro.java Sun Sep  8 10:42:47 2019
@@ -161,7 +161,9 @@ public class RuntimeMacro extends Direct
                     /* indicate col/line assuming it starts at 0
                      * this will be corrected one call up  */
                     throw new TemplateInitException(badArgsErrorMsg,
-                        context.getCurrentTemplateName(), 0, 0);
+                    null,
+                    rsvc.getLogContext().getStackTrace(),
+                    context.getCurrentTemplateName(), 0, 0);
                 }
             }
         }
@@ -316,6 +318,7 @@ public class RuntimeMacro extends Direct
             if (badArgsErrorMsg != null)
             {
                 throw new TemplateInitException(badArgsErrorMsg,
+                  null, rsvc.getLogContext().getStackTrace(),
                   context.getCurrentTemplateName(), node.getColumn(), node.getLine());
             }
 
@@ -353,7 +356,7 @@ public class RuntimeMacro extends Direct
         else if (strictRef)
         {
             throw new VelocityException("Macro '#" + macroName + "' is not defined at "
-                + StringUtils.formatFileString(node));
+                + StringUtils.formatFileString(node), null, rsvc.getLogContext().getStackTrace());
         }
 
         /**

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/directive/VelocimacroProxy.java Sun Sep  8 10:42:47 2019
@@ -218,7 +218,7 @@ public class VelocimacroProxy extends Di
         {
             String msg = "VelocimacroProxy.render() : exception VM = #" + macroName + "()";
             log.error(msg, e);
-            throw new VelocityException(msg, e);
+            throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
         }
         finally
         {
@@ -280,7 +280,7 @@ public class VelocimacroProxy extends Di
             {
                 throw new VelocityException("Provided " + callArgNum + " arguments but macro #"
                     + macroArgs.get(0).name + " accepts at most " + (macroArgs.size()-1)
-                    + " at " + StringUtils.formatFileString(node));
+                    + " at " + StringUtils.formatFileString(node), null, rsvc.getLogContext().getStackTrace());
             }
             // Backward compatibility logging, Mainly for MacroForwardDefinedTestCase
             log.debug("VM #{}: too many arguments to macro. Wanted {} got {}",
@@ -319,7 +319,7 @@ public class VelocimacroProxy extends Di
             {
                 context.popCurrentMacroName();
             }
-            throw new MacroOverflowException(out.toString());
+            throw new MacroOverflowException(out.toString(), null, rsvc.getLogContext().getStackTrace());
         }
     }
 
@@ -371,7 +371,7 @@ public class VelocimacroProxy extends Di
                 }
                 throw new VelocityException("Need at least " + minArgNum + " argument for macro #"
                     + macroArgs.get(0).name + " but only " + callArgNum + " where provided at "
-                    + StringUtils.formatFileString(node));
+                    + StringUtils.formatFileString(node), null, rsvc.getLogContext().getStackTrace());
             }
             else
             {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/LogContext.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/LogContext.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/LogContext.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/LogContext.java Sun Sep  8 10:42:47 2019
@@ -19,13 +19,17 @@ package org.apache.velocity.runtime.pars
  * under the License.
  */
 
+import org.apache.velocity.runtime.parser.node.SimpleNode;
 import org.apache.velocity.util.introspection.Info;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
 
 import java.util.ArrayDeque;
+import java.util.ArrayList;
 import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
 
 /**
  * <p>Track location in template files during rendering by populating the slf4j MDC tags <code>file</code>, <code>line</code> and <code>column</code>.</p>
@@ -42,7 +46,7 @@ import java.util.Deque;
 
 public class LogContext
 {
-    protected static Logger logger = LoggerFactory.getLogger(LogContext.class);
+    protected static Logger logger = LoggerFactory.getLogger("rendering");
 
     public static final String MDC_FILE = "file";
     public static final String MDC_LINE = "line";
@@ -66,18 +70,18 @@ public class LogContext
 
     private static class StackElement
     {
-        protected StackElement(Object src, Info info)
+        protected StackElement(SimpleNode src, Info info)
         {
             this.src = src;
             this.info = info;
         }
 
-        protected Object src;
+        protected SimpleNode src;
         protected int count = 1;
         protected Info info;
     }
 
-    public void pushLogContext(Object src, Info info)
+    public void pushLogContext(SimpleNode src, Info info)
     {
         if (!trackLocation)
         {
@@ -137,4 +141,26 @@ public class LogContext
         MDC.remove(MDC_LINE);
         MDC.remove(MDC_COLUMN);
     }
+
+    private static final String STACKTRACE_LINE = "    %s at %s[line %d, column %d]";
+
+    public String[] getStackTrace()
+    {
+        if (!trackLocation)
+        {
+            return null;
+        }
+        Deque<StackElement> stack = contextStack.get();
+        List<String> levels = new ArrayList<>();
+        for (StackElement level : stack)
+        {
+            String line = String.format(STACKTRACE_LINE,
+                level.src.literal(),
+                level.info.getTemplateName(),
+                level.info.getLine(),
+                level.info.getColumn());
+            levels.add(line);
+        }
+        return levels.size() > 0 ? levels.toArray(new String[levels.size()]) : null;
+    }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTComparisonNode.java Sun Sep  8 10:42:47 2019
@@ -98,7 +98,7 @@ public abstract class ASTComparisonNode
                        + StringUtils.formatFileString(this);
         if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
         {
-            throw new VelocityException(msg);
+            throw new VelocityException(msg, null, rsvc.getLogContext().getStackTrace());
         }
         log.error(msg);
         return false;
@@ -152,7 +152,7 @@ public abstract class ASTComparisonNode
                        + StringUtils.formatFileString(this);
         if (rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false))
         {
-            throw new VelocityException(msg);
+            throw new VelocityException(msg, null, rsvc.getLogContext().getStackTrace());
         }
         log.error(msg);
         return false;

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDirective.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDirective.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDirective.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDirective.java Sun Sep  8 10:42:47 2019
@@ -139,7 +139,7 @@ public class ASTDirective extends Simple
                     throw new VelocityException(
                             "Couldn't initialize directive of class " +
                             parser.getDirective(directiveName).getClass().getName(),
-                            e);
+                            e, rsvc.getLogContext().getStackTrace());
                 }
 
                 t = getFirstToken();
@@ -165,6 +165,7 @@ public class ASTDirective extends Simple
                     {
                         throw new TemplateInitException(die.getMessage(),
                             (ParseException) die.getCause(),
+                            rsvc.getLogContext().getStackTrace(),
                             die.getTemplateName(),
                             die.getColumnNumber() + getColumn(),
                             die.getLineNumber() + getLine());
@@ -201,6 +202,7 @@ public class ASTDirective extends Simple
                 {
                     throw new TemplateInitException(die.getMessage(),
                             (ParseException) die.getCause(),
+                            rsvc.getLogContext().getStackTrace(),
                             die.getTemplateName(),
                             die.getColumnNumber() + getColumn(),
                             die.getLineNumber() + getLine());
@@ -346,4 +348,22 @@ public class ASTDirective extends Simple
 		        + directiveName + "]";
     }
 
+    /**
+     * Returns the string "#<i>directive_name</i>(...)". Arguments literals are not rendered. This method is only
+     * used for displaying the VTL stacktrace when a rendering error is encountered when runtime.log.track_location is true.
+     * @return
+     */
+    @Override
+    public String literal()
+    {
+        if (literal != null)
+        {
+            return literal;
+        }
+        StringBuilder builder = new StringBuilder();
+        builder.append('#').append(getDirectiveName()).append("(...)");
+
+        return literal = builder.toString();
+    }
+
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDivNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDivNode.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDivNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTDivNode.java Sun Sep  8 10:42:47 2019
@@ -72,7 +72,7 @@ public class ASTDivNode extends ASTMathN
             if (strictMode)
             {
                 log.error(msg);
-                throw new MathException(msg);
+                throw new MathException(msg, rsvc.getLogContext().getStackTrace());
             }
             else
             {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIdentifier.java Sun Sep  8 10:42:47 2019
@@ -184,7 +184,7 @@ public class ASTIdentifier extends Simpl
             {
                 String msg = "ASTIdentifier.execute() : identifier = "+identifier;
                 log.error(msg, e);
-                throw new VelocityException(msg, e);
+                throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
             }
 
             /*
@@ -196,7 +196,8 @@ public class ASTIdentifier extends Simpl
                 if (strictRef)
                 {
                     throw new MethodInvocationException("Object '" + o.getClass().getName() +
-                        "' does not contain property '" + identifier + "'", null, identifier,
+                        "' does not contain property '" + identifier + "'",
+                        null, rsvc.getLogContext().getStackTrace(), identifier,
                         uberInfo.getTemplateName(), uberInfo.getLine(), uberInfo.getColumn());
                 }
                 else
@@ -240,7 +241,7 @@ public class ASTIdentifier extends Simpl
                           + " in  " + o.getClass()
                           + " threw exception "
                           + ite.getTargetException().toString(),
-                          ite.getTargetException(), vg.getMethodName(), getTemplateName(), this.getLine(), this.getColumn());
+                          ite.getTargetException(), rsvc.getLogContext().getStackTrace(), vg.getMethodName(), getTemplateName(), this.getLine(), this.getColumn());
                     }
                 }
                 else
@@ -254,7 +255,7 @@ public class ASTIdentifier extends Simpl
                     + " in  " + o.getClass()
                     + " threw exception "
                     + ite.getTargetException().toString(),
-                    ite.getTargetException(), vg.getMethodName(), getTemplateName(), this.getLine(), this.getColumn());
+                    ite.getTargetException(), rsvc.getLogContext().getStackTrace(), vg.getMethodName(), getTemplateName(), this.getLine(), this.getColumn());
 
 
                 }
@@ -276,7 +277,7 @@ public class ASTIdentifier extends Simpl
                             + "for identifier '" + identifier + "' in "
                             + o.getClass();
                 log.error(msg, e);
-                throw new VelocityException(msg, e);
+                throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
             }
         }
         finally
@@ -284,4 +285,19 @@ public class ASTIdentifier extends Simpl
             rsvc.getLogContext().popLogContext();
         }
     }
+
+    /**
+     * Returns the string ".<i>identifier</i>". This method is only used for displaying the VTL stacktrace
+     * when a rendering error is encountered when runtime.log.track_location is true.
+     * @return
+     */
+    @Override
+    public String literal()
+    {
+        if (literal != null)
+        {
+            return literal;
+        }
+        return literal = '.' + getIdentifier();
+    }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIndex.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIndex.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIndex.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTIndex.java Sun Sep  8 10:42:47 2019
@@ -122,7 +122,8 @@ public class ASTIndex extends SimpleNode
               throw new VelocityException(
                 "A 'size()' method required for negative value "
                  + (Integer) argument + " does not exist for class '"
-                 + o.getClass().getName() + "' at " + StringUtils.formatFileString(node));
+                 + o.getClass().getName() + "' at " + StringUtils.formatFileString(node),
+                  null, node.getRuntimeServices().getLogContext().getStackTrace());
           }
 
           Object size = null;
@@ -133,7 +134,8 @@ public class ASTIndex extends SimpleNode
           catch (Exception e)
           {
               throw new VelocityException("Error trying to calls the 'size()' method on '"
-                + o.getClass().getName() + "' at " + StringUtils.formatFileString(node), e);
+                + o.getClass().getName() + "' at " + StringUtils.formatFileString(node), e,
+                  node.getRuntimeServices().getLogContext().getStackTrace());
           }
 
           int sizeint = 0;
@@ -146,7 +148,8 @@ public class ASTIndex extends SimpleNode
               // If size() doesn't return an Integer we want to report a pretty error
               throw new VelocityException("Method 'size()' on class '"
                   + o.getClass().getName() + "' returned '" + size.getClass().getName()
-                  + "' when Integer was expected at " + StringUtils.formatFileString(node));
+                  + "' when Integer was expected at " + StringUtils.formatFileString(node),
+                  null, node.getRuntimeServices().getLogContext().getStackTrace());
           }
 
           argument = sizeint + ((Integer) argument).intValue();
@@ -212,7 +215,7 @@ public class ASTIndex extends SimpleNode
               + ")' in " + o.getClass().getName()
               + " at " + StringUtils.formatFileString(this);
             log.error(msg, e);
-            throw new VelocityException(msg, e);
+            throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
         }
     }
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMathNode.java Sun Sep  8 10:42:47 2019
@@ -121,7 +121,7 @@ public abstract class ASTMathNode extend
             if (strictMode)
             {
                 log.error(msg);
-                throw new MathException(msg);
+                throw new MathException(msg, rsvc.getLogContext().getStackTrace());
             }
             else
             {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMethod.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMethod.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMethod.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTMethod.java Sun Sep  8 10:42:47 2019
@@ -251,7 +251,7 @@ public class ASTMethod extends SimpleNod
                 String msg = "ASTMethod.execute() : exception invoking method '"
                              + methodName + "' in " + o.getClass();
                 log.error(msg, e);
-                throw new VelocityException(msg, e);
+                throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
             }
         }
         finally
@@ -303,7 +303,7 @@ public class ASTMethod extends SimpleNod
                     + methodName + "' in  " + o.getClass()
                     + " threw exception "
                     + e.toString(),
-                    e, methodName, getTemplateName(), this.getLine(), this.getColumn());
+                    e, rsvc.getLogContext().getStackTrace(), methodName, getTemplateName(), this.getLine(), this.getColumn());
             }
         }
 
@@ -321,7 +321,7 @@ public class ASTMethod extends SimpleNod
             + methodName + "' in  " + o.getClass()
             + " threw exception "
             + t.toString(),
-            t, methodName, getTemplateName(), this.getLine(), this.getColumn());
+            t, rsvc.getLogContext().getStackTrace(), methodName, getTemplateName(), this.getLine(), this.getColumn());
         }
     }
 
@@ -417,5 +417,23 @@ public class ASTMethod extends SimpleNod
         return methodName;
     }
 
+    /**
+     * Returns the string ".<i>method_name</i>(...)". Arguments literals are not rendered. This method is only
+     * used for displaying the VTL stacktrace when a rendering error is encountered when runtime.log.track_location is true.
+     * @return
+     */
+    @Override
+    public String literal()
+    {
+        if (literal != null)
+        {
+            return literal;
+        }
+        StringBuilder builder = new StringBuilder();
+        builder.append('.').append(getMethodName()).append("(...)");
+
+        return literal = builder.toString();
+    }
+
 
 }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTModNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTModNode.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTModNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTModNode.java Sun Sep  8 10:42:47 2019
@@ -66,7 +66,7 @@ public class ASTModNode extends ASTMathN
             if (strictMode)
             {
                 log.error(msg);
-                throw new MathException(msg);
+                throw new MathException(msg, rsvc.getLogContext().getStackTrace());
             }
             else
             {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNegateNode.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNegateNode.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNegateNode.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTNegateNode.java Sun Sep  8 10:42:47 2019
@@ -72,7 +72,7 @@ public class ASTNegateNode extends Simpl
             if (strictMode)
             {
                 log.error(msg);
-                throw new MathException(msg);
+                throw new MathException(msg, rsvc.getLogContext().getStackTrace());
             }
             else
             {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTReference.java Sun Sep  8 10:42:47 2019
@@ -76,8 +76,6 @@ public class ASTReference extends Simple
 
     private boolean checkEmpty;
 
-    private String literal = null;
-
     /**
      * Indicates if we are running in strict reference mode.
      */
@@ -171,7 +169,7 @@ public class ASTReference extends Simple
         numChildren = jjtGetNumChildren();
 
         // This is an expensive call, so get it now.
-        literal = literal();
+        literal();
 
         /*
          * and if appropriate...
@@ -358,7 +356,8 @@ public class ASTReference extends Simple
                         throw new VelocityException("Attempted to access '"
                             + name + "' on a null value at "
                             + StringUtils.formatFileString(uberInfo.getTemplateName(),
-                            + jjtGetChild(i).getLine(), jjtGetChild(i).getColumn()));
+                            + jjtGetChild(i).getLine(), jjtGetChild(i).getColumn()),
+                            null, rsvc.getLogContext().getStackTrace());
                     }
                     previousResult = result;
                     result = jjtGetChild(i).execute(result,context);
@@ -563,7 +562,8 @@ public class ASTReference extends Simple
                       {
                         throw new VelocityException("Reference " + literal()
                             + " evaluated to null when attempting to render at "
-                            + StringUtils.formatFileString(this));
+                            + StringUtils.formatFileString(this)
+                        , null, rsvc.getLogContext().getStackTrace());
                       }
                       else  // toString == null
                       {
@@ -573,7 +573,8 @@ public class ASTReference extends Simple
                         throw new VelocityException("Reference " + literal()
                             + " evaluated to object " + value.getClass().getName()
                             + " whose toString() method returned null at "
-                            + StringUtils.formatFileString(this));
+                            + StringUtils.formatFileString(this)
+                            , null, rsvc.getLogContext().getStackTrace());
                       }
                     }
                     return true;
@@ -677,7 +678,7 @@ public class ASTReference extends Simple
         catch(Exception e)
         {
             throw new VelocityException("Reference evaluation threw an exception at "
-                + StringUtils.formatFileString(this), e);
+                + StringUtils.formatFileString(this), e, rsvc.getLogContext().getStackTrace());
         }
         finally
         {
@@ -766,7 +767,7 @@ public class ASTReference extends Simple
                     {
                         String name = jjtGetChild(i+1).getFirstTokenImage();
                         throw new MethodInvocationException("Attempted to access '"
-                            + name + "' on a null value", null, name, uberInfo.getTemplateName(),
+                            + name + "' on a null value", null, rsvc.getLogContext().getStackTrace(), name, uberInfo.getTemplateName(),
                             jjtGetChild(i+1).getLine(), jjtGetChild(i+1).getColumn());
                     }
 
@@ -816,7 +817,8 @@ public class ASTReference extends Simple
                             "Found neither a 'set' or 'put' method with param types '("
                             + printClass(paramClasses[0]) + "," + printClass(paramClasses[1])
                             + ")' on class '" + result.getClass().getName()
-                            + "' at " + StringUtils.formatFileString(astIndex));
+                            + "' at " + StringUtils.formatFileString(astIndex)
+                            , null, rsvc.getLogContext().getStackTrace());
                     }
                     return false;
                 }
@@ -837,7 +839,7 @@ public class ASTReference extends Simple
                       + methodName + "("
                       + printClass(paramClasses[0]) + "," + printClass(paramClasses[1])
                       + ")' in  " + result.getClass(),
-                      e.getCause(), identifier, astIndex.getTemplateName(), astIndex.getLine(),
+                      e.getCause(), rsvc.getLogContext().getStackTrace(), identifier, astIndex.getTemplateName(), astIndex.getLine(),
                         astIndex.getColumn());
                 }
 
@@ -862,7 +864,7 @@ public class ASTReference extends Simple
                     if (strictRef)
                     {
                         throw new MethodInvocationException("Object '" + result.getClass().getName() +
-                           "' does not contain property '" + identifier + "'", null, identifier,
+                           "' does not contain property '" + identifier + "'", null, rsvc.getLogContext().getStackTrace(), identifier,
                            uberInfo.getTemplateName(), uberInfo.getLine(), uberInfo.getColumn());
                     }
                     else
@@ -884,7 +886,7 @@ public class ASTReference extends Simple
                     + identifier + "' in  " + result.getClass()
                     + " threw exception "
                     + ite.getTargetException().toString(),
-                   ite.getTargetException(), identifier, getTemplateName(), this.getLine(), this.getColumn());
+                   ite.getTargetException(), rsvc.getLogContext().getStackTrace(), identifier, getTemplateName(), this.getLine(), this.getColumn());
             }
             /**
              * pass through application level runtime exceptions
@@ -901,7 +903,7 @@ public class ASTReference extends Simple
                 String msg = "ASTReference setValue(): exception: " + e
                               + " template at " + StringUtils.formatFileString(uberInfo);
                 log.error(msg, e);
-                throw new VelocityException(msg, e);
+                throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
             }
 
             return true;
@@ -1145,7 +1147,7 @@ public class ASTReference extends Simple
               log.error("Variable ${} has not been set at {}",
                         rootString, StringUtils.formatFileString(uberInfo));
               throw new MethodInvocationException("Variable $" + rootString +
-                  " has not been set", null, identifier,
+                  " has not been set", null, rsvc.getLogContext().getStackTrace(), identifier,
                   uberInfo.getTemplateName(), uberInfo.getLine(), uberInfo.getColumn());
           }
         }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTSetDirective.java Sun Sep  8 10:42:47 2019
@@ -264,6 +264,23 @@ public class ASTSetDirective extends Sim
     }
 
     /**
+     * Returns the string "#set($<i>reference</i> = ...)". RHS is not rendered. This method is only
+     * used for displaying the VTL stacktrace when a rendering error is encountered when runtime.log.track_location is true.
+     * @return
+     */
+    @Override
+    public String literal()
+    {
+        if (literal != null)
+        {
+            return literal;
+        }
+        StringBuilder builder = new StringBuilder();
+        builder.append("#set(").append(left.literal()).append(" = ...)");
+        return literal = builder.toString();
+    }
+
+    /**
      *  returns the ASTReference that is the LHS of the set statement
      *
      *  @return left hand side of #set statement

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/parser/node/ASTStringLiteral.java Sun Sep  8 10:42:47 2019
@@ -149,7 +149,7 @@ public class ASTStringLiteral extends Si
             {
                 String msg = "Failed to parse String literal at "+
                     StringUtils.formatFileString(template.getName(), getLine(), getColumn());
-                throw new TemplateInitException(msg, e, template.getName(), getColumn(), getLine());
+                throw new TemplateInitException(msg, e, rsvc.getLogContext().getStackTrace(), template.getName(), getColumn(), getLine());
             }
 
             adjTokenLineNums(nodeTree);
@@ -335,7 +335,7 @@ public class ASTStringLiteral extends Si
             {
                 String msg = "Error in interpolating string literal";
                 log.error(msg, e);
-                throw new VelocityException(msg, e);
+                throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
             }
 
         }

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ContentResource.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ContentResource.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ContentResource.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ContentResource.java Sun Sep  8 10:42:47 2019
@@ -85,7 +85,7 @@ public class ContentResource extends Res
         {
             String msg = "Cannot process content resource";
             log.error(msg, e);
-            throw new VelocityException(msg, e);
+            throw new VelocityException(msg, e, rsvc.getLogContext().getStackTrace());
         }
         finally
         {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ResourceManagerImpl.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ResourceManagerImpl.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ResourceManagerImpl.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/ResourceManagerImpl.java Sun Sep  8 10:42:47 2019
@@ -132,7 +132,7 @@ public class ResourceManagerImpl
                     ".class' specification in configuration." +
                     " This is a critical value.  Please adjust configuration.";
                 log.error(msg);
-                throw new VelocityException(msg);
+                throw new VelocityException(msg, null, rsvc.getLogContext().getStackTrace());
             }
 
             resourceLoader.commonInit(rsvc, configuration);
@@ -458,7 +458,7 @@ public class ResourceManagerImpl
          */
         if (resource.getData() == null)
         {
-            throw new ResourceNotFoundException("Unable to find resource '" + resourceName + "'");
+            throw new ResourceNotFoundException("Unable to find resource '" + resourceName + "'", null, rsvc.getLogContext().getStackTrace());
         }
 
         /*

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/ClasspathResourceLoader.java Sun Sep  8 10:42:47 2019
@@ -133,14 +133,14 @@ public class ClasspathResourceLoader ext
                 }
                 catch (IOException ioe) {}
             }
-            throw new ResourceNotFoundException("ClasspathResourceLoader problem with template: " + name, fnfe );
+            throw new ResourceNotFoundException("ClasspathResourceLoader problem with template: " + name, fnfe, rsvc.getLogContext().getStackTrace() );
         }
 
         if (result == null)
         {
             String msg = "ClasspathResourceLoader Error: cannot find resource " + name;
 
-            throw new ResourceNotFoundException( msg );
+            throw new ResourceNotFoundException( msg, null, rsvc.getLogContext().getStackTrace() );
         }
 
         return result;

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/DataSourceResourceLoader.java Sun Sep  8 10:42:47 2019
@@ -340,7 +340,7 @@ public class DataSourceResourceLoader ex
                             + operation + " of '" + name + "': ";
 
                 log.error(msg, sqle);
-                throw new VelocityException(msg, sqle);
+                throw new VelocityException(msg, sqle, rsvc.getLogContext().getStackTrace());
             }
             finally
             {

Modified: velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java
URL: http://svn.apache.org/viewvc/velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java?rev=1866609&r1=1866608&r2=1866609&view=diff
==============================================================================
--- velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java (original)
+++ velocity/engine/trunk/velocity-engine-core/src/main/java/org/apache/velocity/runtime/resource/loader/FileResourceLoader.java Sun Sep  8 10:42:47 2019
@@ -143,7 +143,7 @@ public class FileResourceLoader extends
                 closeQuiet(rawStream);
                 String msg = "Exception while loading Template " + template;
                 log.error(msg, ioe);
-                throw new VelocityException(msg, ioe);
+                throw new VelocityException(msg, ioe, rsvc.getLogContext().getStackTrace());
             }
             if (reader != null)
             {