Custom Exit Calls

You can use the start_exit_call() and end_exit_call() methods to create a custom exit call from a specific business transaction to a backend that the Python Agent does not automatically detect.

The business transaction must be a custom business transaction.
Tip: If you want to make a custom exit call from a business transaction that is normally automatically detected, you can exclude that business transaction to prevent it from being automatically detected and then create it as a custom business transaction. This enables you to get the BtHandle that you need to create the custom exit call. See Configure Python Web Custom Match and Exclude Rules for information on excluding a business transaction.
Given the code:
try:
    db = custom_db.connect(host='financials-lb', port=3456)
    all_employees = db.query_path('/financials/employees')
    individual_contributors = all_employees.filter(lambda r: r.level < 3)
    salaries_by_dept = individual_contributors.sum(value='salary', group='dept', as='total')

    for dept, total in salaries_by_dept.extract('dept', 'total'):
        report_salary_data(dept, total)

You want to send the query via an exit call to a proprietary database.

You want the database to be labeled Financials Database in the Controller UI.

You want the backend properties that appear in the backend dashboard to appear as:

Host
financials-lb
Port
3456
Vendor
custom db

The following examples assume you are wrapping the exit call in a custom business transaction named department rollup, created in another part of your code.

Use start_exit_call() and end_exit_call()

This example uses start_exit_call() and end_exit_call().
from appdynamics.agent import api as appd
appd.init()

# Set the identifying properties
FINANCIALS_ID_PROPS = {'Host': 'financials-lb', 'Port': 3456, 'Vendor': 'custom db'}

with appd.bt('department rollup') as bt_handle:
    # Start the exit call
    exit_call = appd.start_exit_call(bt_handle, appd.EXIT_DB, 'Financials Database', FINANCIALS_ID_PROPS)
    exc = None

    try:
        db = custom_db.connect(host='financials-lb', port=3456)
        all_employees = db.query_path('/financials/employees')
        individual_contributors = all_employees.filter(lambda r: r.level < 3)
        salaries_by_dept = individual_contributors.sum(value='salary', group='dept', as='total')

        for dept, total in salaries_by_dept.extract('dept', 'total'):
            report_salary_data(dept, total)
    except Exception as exc:
        raise  # Assuming something above handles exceptions for you
    finally:
        #End the exit call
        end_exit_call(exit_call, exc)

Use exit_call context manager

If the business transaction starts and ends in the same context, you can use the simpler exit_call context manager instead.
from appdynamics.agent import api as appd
appd.init()

with appd.bt('department rollup') as bt_handle:
    with appd.exit_call(bt_handle, appd.EXIT_DB, 'Financials Database', FINANCIALS_ID_PROPS):
        db = custom_db.connect(host='financials-lb', port=3456)
        all_employees = db.query_path('/financials/employees')
        individual_contributors = all_employees.filter(lambda r: r.level < 3)
        salaries_by_dept = individual_contributors.sum(value='salary', group='dept', as='total')

        for dept, total in salaries_by_dept.extract('dept', 'total'):
            report_salary_data(dept, total)

The next example starts a custom exit call to a Cassandra backend from a business transaction that was auto-detected by the Python Agent default Flask instrumentation. It uses the Flask import feature to get the request object which it passes to appd_get_active_bt_handle().

Get bt handle using the flask request context:
from flask import request
from appdynamics.agent import api as appd

@app.route('/metrics/recent')
def metrics_recent():
    bt = appd.get_active_bt_handle(request)  # Get the active BT from the Flask request object
    with appd.exit_call(bt, appd.EXIT_DB, 'cassandra time-series', {'VENDOR': 'Cassandra', 'SERVER POOL': '10.0.0.1'}):
        load_recent_data_from_cassandra()

Other supported frameworks have different mechanisms for getting the request object.