How to Instantly Trace Java Method Call Stacks for Faster Debugging
This article explains how to build and use a Java StackTrace utility that extracts and filters method call chains, enabling developers to quickly locate error sources, streamline debugging, and improve operational efficiency by visualizing execution paths through customizable parameters and integration examples.
Introduction
This article starts from the pain points of daily on‑call issue investigation, analyzes the call‑chain reuse and business context, and presents a chain‑tracking tool built with stack frames to display a request's serial method calls, helping quickly locate code origins and traffic entry points, thereby improving debugging efficiency.
Current Situation Analysis
During on‑call duty, developers often receive screenshots of error messages and need as much information as possible to analyze the scenario.
Below is a typical error screenshot.
From the screenshot we can initially obtain:
Menu name: "Change Order Off‑Shelf" – the operation that triggered the error.
Error message: "Serial number status is off‑stock, please check."
Other auxiliary info: user‑scanned or entered code starting with 86, SKU, product name, location, etc.
Common troubleshooting steps:
Check the user‑entered 86 code against the serial number data to see if it exists and is truly off‑stock.
If the 86 code is a serial number and is off‑stock, the case can be closed quickly.
If the code is not a serial number or not off‑stock, locate the source of the error message in the code by searching the codebase or logs.
Search the codebase for the error message text or retrieve it from logs (requires the message to be printed with appropriate log level).
If the same message appears in multiple places, further identify which occurrence is relevant to the current error.
In complex systems, method reuse is common; different contexts and parameters lead to different business logic paths.
The core pain point: how to quickly locate the code source based on limited hint information.
Inspiration
The idea comes from Java's exception mechanism. While exception stacks are useful for locating problems, they can also be overwhelming.
Four types of information are present in a stack trace:
Fully qualified class name
Method name
File name
Line number
These allow precise location of code origins, and the order reflects the sequence of execution (first scene, second scene, etc.).
This is similar to JVM method stack frames: each method call creates a new stack frame containing local variables, operand stack, constant pool references, etc.
Approach
From java.lang.Throwable we can obtain the StackTraceElement[], which contains the same information shown in exception stacks.
Tool Development
The core code is simple: StackTraceElement is provided by the JDK, and the tool filters necessary information and formats it into an ordered chain for easy visual inspection.
Parameters
pretty : only concatenate class and method names (no file name or line number). Non‑pretty includes all four parts.
simple : filters out proxy‑enhanced methods that appear in our code.
specifiedPrefix : keep stack information for specified package prefixes, removing excessive middleware details.
Additional filters for common proxy artifacts:
FastClassBySpringCGLIB
EnhancerBySpringCGLIB
lambda$
Aspect
Interceptor
Convenient wrapper methods are also provided.
Usage Examples
1. Call chain without filtering middleware or proxy methods:
Thread#run => ThreadPoolExecutor$Worker#run => ThreadPoolExecutor#runWorker => BaseTask#run => JSFTask#doRun => ProviderProxyInvoker#invoke => FilterChain#invoke => SystemTimeCheckFilter#invoke => ProviderExceptionFilter#invoke => ProviderContextFilter#invoke => InstMethodsInter#intercept => ProviderContextFilter$eone$auxiliary$9f9kd21#call => ProviderContextFilter#eone$original$invoke$p882ot3$accessor$eone$pclcbe2 => ProviderContextFilter#eone$original$invoke$p882ot3 => ProviderGenericFilter#invoke => ProviderUnitValidationFilter#invoke => ProviderHttpGWFilter#invoke => ProviderInvokeLimitFilter#invoke => ProviderMethodCheckFilter#invoke => ProviderTimeoutFilter#invoke => ValidationFilter#invoke => ProviderConcurrentsFilter#invoke => ProviderSecurityFilter#invoke => WmsRpcExceptionFilter#invoke => ... (continues)2. Call chain after specifying package prefix filtering:
LockAspect#lock => StockTransferAppServiceImpl#increaseStock => MonitorAspect#monitor => StockRetryExecutor#operateStock => ...3. Call chain after removing Spring proxy methods:
LogAspect#log => LockAspect#lock => ValidationAspect#validate => ProviderContextFilter#eone$original$invoke => StockTransferAppServiceImpl#decreaseStock => ...4. Call chain after removing custom proxies:
StockTransferAppServiceImpl#increaseStock => StockTransferServiceImpl#increaseStock => BaseStockOperation#go => DataBaseExecutor#operate => StockRetryExecutor#operateStock => StockRepositoryImpl#operateStock5. Call chain with file names and line numbers:
StockTransferAppServiceImpl#increaseStock(StockTransferAppServiceImpl.java:103) => StockTransferServiceImpl#increaseStock(StockTransferServiceImpl.java:168) => BaseStockOperation#go(BaseStockOperation.java:152) => DataBaseExecutor#operate(DataBaseExecutor.java:34) => ...Online Application Practice
After integrating the stack‑trace tool, error hint words can be used to retrieve corresponding logs and quickly locate the entry point code, e.g., from ImmediateTransferController#offShelf through a chain of proxies to the business method.
Applicable Scenarios
Output stack trace to logs when business exceptions occur.
Include call‑stack information in monitoring alerts.
Print call chains in complex method‑reuse scenarios for analysis.
Other similar use cases.
Extension
The tool was later integrated into a SQL‑coloring MyBatis plugin to add method‑call information to SQL logs.
Upgrade steps:
Upgrade sword-mybatis-plugins to version 1.0.6‑SNAPSHOT.
Add the stack‑trace utility dependency.
<dependency>
<groupId>com.jd.sword</groupId>
<artifactId>sword-utils-common</artifactId>
<version>1.0.0‑SNAPSHOT</version>
</dependency>Configure MyBatis plugin:
<plugin interceptor="com.jd.sword.mybatis.plugin.sql.SQLMarkingInterceptor">
<property name="enabled" value="true"/>
<property name="stackTraceEnabled" value="true"/>
<property name="specifiedStackTracePackages" value="com.jdwl.wms.stock"/>
<property name="stackTraceSamplingRate" value="1/2"/>
</plugin>How to Integrate This Tool?
Add the Maven dependency shown above, then use the static methods provided by StackTraceUtils:
com.jd.sword.utils.common.runtime.StackTraceUtils#simpleTrace() com.jd.sword.utils.common.runtime.StackTraceUtils#simpleTrace(String...) com.jd.sword.utils.common.runtime.StackTraceUtils#trace() com.jd.sword.utils.common.runtime.StackTraceUtils#trace(String...) com.jd.sword.utils.common.runtime.StackTraceUtils#trace(boolean) com.jd.sword.utils.common.runtime.StackTraceUtils#trace(boolean, boolean, String...)JD Cloud Developers
JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
