appmap
is a Python package for recording AppMaps of your code.
The AppMap data format includes code structure (packages, modules, classes, and methods), trace events (function calls, web services, RPC calls, SQL, parameters, return values, exceptions, etc), and code metadata (repo URL, commit SHA, etc). It’s more granular than a performance profile, but it’s less granular than a full debug trace. It’s designed to be optimal for understanding the design intent and structure of code and key data flows.
AppMap for Python is currently in early access.
Requirements:
Supported Frameworks:
Using a framework we don't support yet? Let us know in Slack!
Support for new versions is added frequently, please check back regularly for updates.
If your project uses pip
for dependency management, add the appmap
package to the requirements
file or install it directly with
pip install appmap
For projects that use poetry
, add the appmap
package to pyproject.toml
.
poetry add --dev appmap
Add your modules as path
entries in appmap.yml
, and external packages
(distributions) as dist
:
name: my_python_app
packages:
- path: app.mod1
shallow: true
- path: app.mod2
exclude:
- MyClass
- MyOtherClass.my_instance_method
- MyOtherClass.my_class_method
# You can record dependency packages, such as Django.
# We don't recommend recording Django by default though, your AppMaps will be quite large
# and mostly about Django itself, not your own code.
#- dist: Django
# exclude:
# - django.db
Note that exclude
s are resolved relative to the associated path. So, for example, this
configuration excludes app.mod2.MyClass
.
For external distribution packages
use the dist
specifier; the names are looked up in the
database of installed Python distributions.
This is generally the same package name as you’d give to pip install
or put
in pyproject.toml
. You can additionally use path
and exclude
on dist
entries to limit the capture to specific patterns.
Note by default shallow capture is enabled on dist
packages, supressing tracking
of most internal execution flow, which allows you to capture the interaction without
getting bogged down with detail. If this isn’t what you want, use shallow: false
.
You can also use shallow: true
on path
entries.
The AppMap data format provides for class and
function labels
, which can be used to enhance the AppMap visualizations, and to
programatically analyze the data.
You can apply function labels using the appmap.labels
decorator in your Python code. To
apply a labels to a function, decorate the function with @appmap.labels
.
For example
import appmap
class ApiKey
@appmap.labels('provider.authentication', 'security')
def authenticate(self, key):
# logic to verify the key here...
Then the AppMap metadata section for this function will include:
{
"name": "authenticate",
"type": "function",
"labels": [ "provider.authentication", "security" ]
}
appmap
supports recording pytest and
unittest test cases.
appmap
is a pytest
plugin. When it’s installed in a project that uses
pytest
, it will be available to generate AppMaps.
root@e9987eaa93c8:/src/appmap/test/data/pytest# pip show appmap
Name: appmap
Version: 0.0.0
Summary: Create AppMap files by recording a Python application.
Home-page: None
Author: Alan Potter
Author-email: alan@app.land
License: None
Location: /usr/local/lib/python3.9/site-packages
Requires: orjson, PyYAML, inflection
Required-by:
root@e9987eaa93c8:/src/appmap/test/data/pytest# APPMAP=true APPMAP_LOG_LEVEL=info pytest -svv
[2021-02-10 11:37:59,345] INFO root: appmap enabled: True
[2021-02-10 11:37:59,350] INFO appmap._implementation.configuration: ConfigFilter, includes {'simple'}
[2021-02-10 11:37:59,350] INFO appmap._implementation.configuration: ConfigFilter, excludes set()
===================================================================== test session starts =====================================================================
platform linux -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1 -- /usr/local/bin/python
cachedir: .pytest_cache
rootdir: /src, configfile: pytest.ini
plugins: appmap-0.0.0
collected 1 item
test_simple.py::test_hello_world [2021-02-10 11:37:59,482] INFO appmap.pytest: starting recording /tmp/pytest/test_hello_world.appmap.json
[2021-02-10 11:37:59,484] INFO appmap._implementation.configuration: included class simple.Simple
[2021-02-10 11:37:59,484] INFO appmap._implementation.configuration: included function simple.Simple.hello
[2021-02-10 11:37:59,489] INFO appmap._implementation.configuration: included function simple.Simple.hello_world
[2021-02-10 11:37:59,490] INFO appmap._implementation.configuration: included function simple.Simple.world
[2021-02-10 11:37:59,828] INFO appmap.pytest: wrote recording /tmp/pytest/test_hello_world.appmap.json
PASSED
====================================================================== 1 passed in 0.45s ======================================================================
import appmap.unittest
. Instruments subclasses of unittest.TestCase
and records each
test_*
function in the subclasses. You can also use python -m appmap.unittest
exactly like
python -m unittest
and leave your code unmodified (just remember to set the APPMAP=true
environment variable or set APPMAP=true
on Windows).
Once you’ve configured your tests to generate AppMaps, run the tests with the
APPMAP=true
in the environment (set APPMAP=true
on Windows). For example, to run a pytest test suite:
$ APPMAP=true pytest
The AppMap agent supports remote recording of Django and Flask web applications. Import the appropriate remote recording support into your web app.
Add appmap.django.Middleware
to your MIDDLEWARE
.
For projects that use a Flask application
factory, adding
the appmap
dependency automatically configures the project for remote recording. No further
modifications are required. When the application initializes, appmap
adds
middleware that handles the /_appmap/record
routes.
For projects that don’t provide an application factory, appmap
can be used as a
Flask extension.
For example:
from flask import Flask
from appmap.flask import AppmapFlask
app = Flask(__name__)
appmap_flask = AppmapFlask(app)
This will add the /_appmap/record
routes your app.
Once you’ve configured your web app to add the remote-recording routes, you can use the routes to manage recordings. The AppMap browser extension, CLI, or just plain cURL will all work for this.
As when running tests, start the web server with APPMAP=true
in the environment (set APPMAP=true
on Windows). For
example, to start a Flask app:
$ APPMAP=true flask run
An app with remote recording enabled supports these routes:
POST /_appmap/record
Starts a new recording
200 if the recording was started successfully 409 if there’s already a recording in progress
GET /_appmap/record
Returns JSON describing current recording state
200 with body
{
"enabled": true
}
enabled
indicates whether recording has been enabled
DELETE /_appmap/record
Returns AppMap as JSON
200 with AppMap as body
404 if there’s no recording in progress
You can use appmap.record
as a context manager to record your code.
With a file called record_sample.py
like this
import os
import sys
import appmap
r = appmap.Recording()
with r:
import sample
print(sample.C().hello_world(), file=sys.stderr)
with os.fdopen(sys.stdout.fileno(), "w", closefd=False) as stdout:
stdout.write(appmap.generation.dump(r))
stdout.flush()
and a source file called sample.py
like this
class C:
def make_str(self, s):
return s;
def hello_world(self):
return f'{self.make_str("Hello")} {self.make_str("world!")}'
as well as an appmap.yml
name: sample
packages:
- path: sample
you can generate a recording of the code
% APPMAP=true python record_sample.py > record_sample.appmap.json
% jq '.events | length' record_sample.appmap.json
6
% jq < record_sample.appmap.json | head -10
{
"version": "1.4",
"metadata": {
"language": {
"name": "python",
"engine": "CPython",
"version": "3.9.1"
},
"client": {
"name": "appmap",
These environment variables can be used to control various aspects of the AppMap agent.
APPMAP_CONFIG
specifies the configuration file to use. Defaults to appmap.yml
in the
current directory.
APPMAP_LOG_LEVEL
specifies log level to use, from the set CRITICAL
, ERROR
,
WARNING
, INFO
, DEBUG
. Not case-sensitive, defaults to INFO
.
APPMAP_DISPLAY_PARAMS
enables rendering of parameters as strings. If true
(the
default, not case-sensitive), parameters are rendered using repr
. If
false
, a generic string is used instead.
APPMAP_RECORD_<PYTEST|UNITTEST>
enables or disables recording for individual test frameworks. For example, to manage recording when using pytest
, use the variable APPMAP_RECORD_PYTEST
. If true
(the default), recording for the test type is always enabled. If false
, it’s always disabled.
APPMAP_RECORD_REQUESTS
enables or disables recording of HTTP requests. If true
(the default), requests recording is always enabled. If false
, it’s always disabled.
APPMAP_RECORD_REMOTE
enables or disables remote recording. If true
(the default), remote recording is always enabled. If false
, it’s always disabled.
APPMAP
enables or disables all recording. If true
(the default), recording is enabled. When false
, all recording is disabled.
https://github.com/getappmap/appmap-python