apm-agent-python icon indicating copy to clipboard operation
apm-agent-python copied to clipboard

Transaction: Context Manager & Decorator

Open romulorosa opened this issue 3 years ago • 3 comments

Is your feature request related to a problem? Please describe. No, it is not.

Describe the solution you'd like Just for increasing the convenience of using Transactions, it would be nice to have an option for using them as a context manager and/or decorator, instead of calling start_transaction and end_transaction every time. It would be something like this:

with transaction('my_transaction_type'):
    calling_my_transaction()

as a decorator it would look like this

@elasticapm.transaction('my_transaction_type', 'my_transaction_name')
def this_is_my_view_method():
    pass

Describe alternatives you've considered The alternative is use what is already provided (start_transaction and end_transaction)

Additional context Just to illustrate, the context manager implementation would be similar to the following code

    def transaction(self, transaction_type, transaction_name=None, trace_parent=None, start=None):
        transaction = self.begin_transaction(
            transaction_type,
            transaction_name=transaction_name,
            trace_parent=trace_parent, 
            start=start
        )
        yield
        self.tracer.end_transaction(transaction.name)

romulorosa avatar Oct 28 '20 14:10 romulorosa

Hey @romulorosa! We considered to implement this in the past, as it would indeed provide a very nice way to create transactions. The problem is that as far as we know, there is no good way to get a reference to the agent in the decorator (the self in your example).

One option would be to store it in a threadlocal variable, similar to what we do with the current transaction and current span, but that might introduce other problems... hmm.

beniwohli avatar Oct 28 '20 14:10 beniwohli

@beniwohli Thanks for the quick feedback! You are right, it is not so that easy to get the agent reference (specially in the decorator). I will try to find some time to dive deeper in the code and see if I can get some insights here. But at first glance, maybe it is possible to create both the decorator and the context manager in different files (decorators.py and contextmanagers.py) as stand alone functions which receives the agent as a dependency which can be injected during the bootstrap. The final user, then, needs to import these structures separately like from elasticapm.decorators import transaction and from elasticapm.contextmanagers import transaction. Not sure if it is feasible but maybe it is an idea.

romulorosa avatar Oct 28 '20 15:10 romulorosa

@beniwohli As I briefly described before here is my idea for having convenient contextmanager and decorators for transactions. I drafted some code to share with you and see if it makes any sense.

You can check it here https://github.com/romulorosa/apm-agent-python/pull/1

The basic idea here is to have a bootstrap method/class and use dependency injection in order to inject the client into the methods that makes usage of that, guaranteeing that we always have the client reference.

What do you think?

In [1]: from elasticapm.base import bootstrap

In [2]: cli = bootstrap({'SERVICE_NAME': 'foo'})

In [3]: from elasticapm.contextmanagers import transaction

In [4]: with transaction('TRANSACTION_TYPE', 'TRANSACTION TEST'):
   ...:     print('hi there')
   ...: 
Begin transaction
hi there
End transaction

romulorosa avatar Nov 01 '20 19:11 romulorosa