To access the latest features keep your code editor plug-in up to date.
AppMap is a powerful tool for reverse-engineering legacy code. Unlike telemetry-based approaches, no modifications to the source code are needed. Simply run the application with the AppMap recording agent enabled, and all the details of code execution are recorded into plain JSON files. These files contain HTTP server requests, internal function calls, SQL, HTTP client requests, and more. AppMap can render this data in powerful interactive visualizations, including dependency map, sequence diagram, trace view, and flame graph.
The data can be further combined, compared, and analyzed to obtain key insights about how the code works and how it can be improved. The purpose of this guide is to provide a step-by-step procedure for characterizing a large codebase with AppMap and obtaining these insights.
You should first review our guide on how to make AppMap Data.
This section provides a procedure for characterizing your code using AppMap. Consider this procedure as a recommendation on how to get started. For your specific needs, you’ll likely find useful ways to extend and customize these recommendations.
The code editor is the best way to get started using AppMap. Install the AppMap extension for VSCode or JetBrains, then follow the install workflow that will be prompted inside the code editor.
Note (Monorepo / Multi-project) If you have an “umbrella” project that contains multiple sub-projects, aka “monorepo”, choose one project to start. The best choice is a web application or web service API, since AppMap is optimized for web apps.
Here’s a checklist:
install-appmap
.npx appmap-node
to it.Note (Java) AppMap recording depends on having the AppMap Java agent enabled in your process using the javaagent JVM argument. The AppMap extension will download the AppMap Java agent to $HOME/lib/java. However this may be blocked in certain corporate environments. You can download the AppMap Java agent manually from GitHub. Different tools (IntelliJ, Maven, Gradle, Tomcat etc) have different ways of specifying JVM arguments. AppMap does provide plugins for Maven and Gradle - these can be helpful in many cases. Or you can configure the javaagent flag yourself using online resources and examples.
At this point, you’ve added AppMap to your project and confirmed that it’s working. Prepare a commit that includes:
pom.xml
, requirements.txt
, Gemfile
, package.json
, yarn.lock
, etc.).appmap.yml
extensions.json
.gitignore
of the AppMap directoryNote (Monorepo / Multi-project) The package management and appmap.yml
changes should be within the sub-project that you’re configuring for AppMap. The extensions.json
will be in the project root directory.
In a large project, it’s best to start making AppMap Diagrams in one functional area. For example, suppose you want to characterize the login and password reset functionality.
Start by recording any test cases that are applicable to this functional area. Test cases that traverse through the HTTP and SQL stack are the most useful. Unit tests and tests that mock or stub SQL are of less utility, since they don’t show the actual behavior of the application API and interactions with the data store. If you don’t have relevant tests - or just can’t easily determine if you do or not - proceed to the next step: requests recording.
If you have a really large test suite, it’s useful to start generating AppMap Data of a subset of it, to make the turnaround times quicker for getting through this process.
Language | Test Framework | Subsetting Strategy |
---|---|---|
Ruby | rspec |
Enable tests selectively with the rspec tag appmap: true .Run rspec -t @appmap=true |
Java | JUnit |
Run specific tests from the IDE UI. Use VSCode Launch configuration or IntelliJ “Start with AppMap” |
Python | pytest |
Filter by test names using the -k argument. |
Python | unittest |
Specify tests using the -m argument, or aggregate using unittest.TestSuite |
Node | jest |
Pass jest a path to a directory of tests, or use -t to run tests matching a regex pattern |
Node | mocha |
Pass mocha a path to a directory of tests, or use --grep to run tests matching a regex pattern |
Test subsetting strategies
You can expand your AppMap coverage beyond what’s available with your test suite using Requests recording.
Requests recording is like a “live mode” for making AppMap Diagrams - it emits AppMap Data as you use the app. To continue the example of characterizing the login + password flow, start your application with AppMap enabled. Then proceed through a predefined user flow - for example: login in, unable to login, request a password reset. QA scripts will often provide reproducible scenarios like this for stepping through the application. If no QA scripts are available, just step through the application as a user would. As you interact with the application, “requests recording” will be create an AppMap Diagram for every request. You can find them in $appmap_dir/requests
. Open any AppMap from this folder to visualize the end-to-end code behavior for that request.
AppMap Diagrams that contain HTTP server requests contain the most rich and useful data. Open the AppMap view in your code editor. There you’ll find a section called “Code objects”. It contains all the HTTP server routes and SQL statements that have been recorded in your AppMap Diagram. It also contains a tree of Code, which you can expand from packages into classes and functions.
Choose an HTTP server request and click on it. If there is one AppMap of that route, it will open in your code editor. If there are multiple AppMap Diagrams of that route, you’ll be prompted to choose one.
This is an example of a test case AppMap. It includes 4 HTTP server requests, plus code and SQL.
You can download this file if you’d like to open it within your code editor.
One of the challenges with reverse engineering large applications is that the AppMap Data can be large and complicated. AppMap offers tools to declutter and filter your AppMap Data. We will look more closely at that here.
In most code bases, there are a few very frequently occurring functions that are mostly noise. You can take two steps to declutter your diagram and reduce the noise.
Open the AppMap stats using the icon in the top-right corner of the AppMap.
You’ll see a list of the most frequently occurring methods.
Click on one of these methods to reveal it in the diagram, and on the left hand side panel. Then click “Hide” to remove all occurrences from the display.
To reveal it again, you can use “Reset all”, or open the Filter menu pop up where you will see a list of all hidden code objects.
You can also go further, by excluding a class function from the AppMap at recording time. To do this, you’ll add a line to your appmap.yml
. Consult the reference for your language agent. For example, in Java you can exclude specific functions like this:
packages:
- path: com.mycorp.myproject
exclude: [ com.mycorp.myproject.MyClass#MyMethod ]
This function will be excluded from all future AppMap Diagrams. Some language agents also support exclusion by wildcard.
You can also choose any event in the AppMap to be the root event. Only descendants of this event will be displayed.
You can clear the root by clicking Reset all
.
Use the filter Hide elapsed time under
to focus the diagram only on slow functions and queries.
You can also drill into timing data using the Flame Graph view.
In the previous section, we covered how to analyze the implementation of an HTTP route. You can do the same thing starting with a function or class.
Expand the Code tree until you find the class or function you’re interested in. When you click on it, you’ll either be taken to the AppMap, or prompted to choose an AppMap.
The AppMap will open to the Dependency Map with the function pre-selected. You can click the “Eye” icon to open the event in the Sequence Diagram.
If you’ve made any more updates to appmap.yml
, be sure and commit the changes to the repo. It’s time to share AppMap with other members of your team!
When a new user pulls down your branch, they will automatically inherit the AppMap configuration that you’ve created. So, a new team member only needs to do the following steps in order to start using AppMap:
Record AppMap
step. There, they can start making their own AppMap Diagrams using any of the supported Recording methods. The work that you’ve done to configure the code paths and exclusions will apply automatically to their installation.In addition to code paths and exclusions, your team members might want to share AppMap Diagram configuration with each other as well - for example Filter settings.
You can use the Saved Filters within your own installation. To share Filter settings with other users, create a new entry in appmap.yml
called filters
. Use the VSCode command Copy Current AppMap State to Clipboard
to place the Filter configuration on your clipboard. It will be a Base64 encoded string - which is just a wrapper around JSON.
Add that filter configuration to appmap.yml
:
# appmap.yml
filters:
my_filter: eyJjdXJyZW50VmlldyI6InZpZXdDb21wb25lbnQiLCJzZWxlY3RlZE9iamVjdCI6ImV2ZW50OjUxMiIsImZpbHRlcnMiOnsiaGlkZUV4dGVybmFsUGF0aHMiOlsidmVuZG9yIiwibm9kZV9tb2R1bGVzIl19fQ
Commit and push your changes to appmap.yml
.
When a user wants to apply that filter to their AppMap, they can copy the filter string out of the appmap.yml
and then run the command Set AppMap State from Serialized String
.
Of course, you can also share filter strings using other channels, like Slack, or store them in a common location such as a Wiki.
Now that the project is configured for AppMap and you’ve decided if you want to ignore any code in the AppMap, it’s time to run AppMap on the full test suite (or, if you prefer, an expanded subset). Doing this will enable you to see how well your app is covered by tests, and understand how you need to augment the tests in order to cover the app fully. You’ll also be ready to take future steps such as:
Note: You can do all these steps in your current branch, or you can merge the install-appmap
branch and create a new branch called install-appmap-ci
. In either case, you don’t have to change the CI configuration on the main/master branch until you’re fully done integrating and evaluating AppMap.
To create AppMap Data in CI, you’ll need to confirm that the test command you’re using in your CI job is AppMap-enabled. In Ruby and Python, this is already going to be the case because adding the appmap dependency is all that’s needed. In Java, you need to configure the test command to load the javaagent
. Specific instructions are available for doing this with Maven and Gradle. Confirm that your test command makes AppMap Data locally before pushing it up to CI.
Once you’re ready, go ahead and push the branch to kick off a CI run. In the meantime, we’ll work on the next steps for your CI job.
Once you’ve created AppMap in CI, you don’t want them to disappear when the job ends. AppMap provides tool support for saving AppMap Data as a build artifact.
getappmap/archive-action is a GitHub Action that will save a GitHub Artifact containing all the AppMap Data created in a workflow. To use the archive action, you need to install the AppMap CLI tools, then run the archive-action. It looks like this:
- name: Install AppMap tools
uses: getappmap/install-action@v1
with:
install-appmap-library: false
(run your tests)
- name: Archive AppMap Data
uses: getappmap/archive-action@v1
with:
commit: ${{ github.event.pull_request.base.sha }}
If you’re using a CI environment other than GitHub Actions, you can use the AppMap CLI tools directly.
Start by downloading the latest @appland/appmap distribution for your platform. The appmap CLI includes an archive
command, which performs the following steps:
You can then store this archive anywhere you keep large files. The appmap restore
command can be used to expand this archive back into individual AppMap files, along with the indexes, sequence diagram files, findings, and OpenAPI definitions.
So, once the AppMap Data is created by the CI job, run appmap archive
to create an AppMap archive file. You can save this archive file to the artifact store of your CI provider.
appmap archive
command to save AppMap DataAt this point, you have archives of AppMap Data for different versions of your code, and you can restore those archives into your code editor to use the AppMap extension to investigate any type of code problem.
Let’s take a deeper dive into how that works. Suppose your team has recently deployed new code, and you’re getting an alarm from the production monitoring system. There is a web route that’s performing badly, a SQL query that’s running slow, or an exception that keeps being raised and disrupting user sessions.
Note If you don’t have saved archives yet, you can build AppMap Data for troubleshooting using remote recording or requests recording. This section shows how restoring AppMap archives can enable you to skip that step and get right to code investigation.
Once you’ve integrated AppMap with CI, you’ll have a saved AppMap archive for each version of the code that’s been merged to the main branch. So your first troubleshooting step is to determine which version of the code is affected. Then you can obtain the AppMap archive for that version of the code.
You can use the AppMap restore
command to expand the AppMap archive into your local, working environment. Copy the archive file into the project directory .appmap/archive/full/<revision>.tar
. Then run the restore command to unpack it:
appmap restore --revision <revision> --exact --output-dir tmp/appmap
Now the AppMap Data are unpacked into the tmp/appmap
directory and they will be detected and listed by the AppMap extension in your code editor. You can use all the techniques described in the Use AppMap Diagrams section to investigate the problem.
You probably have some idea of the test coverage of your application from applying a dedicated code coverage tool. These types of tools will tell you whether you have code that is completely uncovered by tests. But AppMap goes beyond that, to tell you:
The Code Objects view is a good starting point for doing this investigation. You’re looking for:
Similarly, with SQL. The Code Objects view provides the inventory of known SQL queries. If there is known code behavior that’s NOT reflected in the Code Objects view, then test coverage that actually exercises the SQL is lacking.
When the web stack or SQL queries are not exercised by the test suite, the application is at much higher risk of production security, stability, and performance problems. It’s also very difficult to know how a code change will affect the application when it’s deployed, because a simple code change might turn out to affect many different API routes - or none at all…
Thus far, we’ve shown how to build, maintain and use AppMap archives to investigate, learn and fix code. The next step with AppMap is to use AppMap in CI to analyze each Pull Request. Request access to our AppMap in CI solution.