Hi team, Had a question about instrumentation using decorators and Phoenix. Will post the steps I followed and questions in this thread. 馃У
Right now, we are trying to do manual instrumentation for our application and we want to use decorators. The main problem we are running is the following:
@tracer.start_as_current_span("Processing Question")
def process_question(self, user_input: str, bypass_cache: bool = False) -> str:
"""process flow for a single question, following architecture diagram.
See if question yields a semantic cache hit. If not, sort question by type.
For each type of question, make the appropriate function/LLM call
and return the response.
"""
tracer.get_current_span().set_attribute("question", user_input)When we try this code, we get: 2024-06-10 09:12:38 example_provider-1 | 'Tracer' object has no attribute 'get_current_span'
The docs say that It鈥檚 common to have a single span track the execution of an entire function. In that scenario, there is a decorator you can use to reduce code
def do_work():
print("doing some work...")Use of the decorator is equivalent to creating the span inside do_work() and ending it when do_work() is finished. To use the decorator, you must have a tracer instance available global to your function declaration. If you need to add attributes, events, or links then it鈥檚 less convenient to use a decorator.
Does this mean that its impossible or just less convenient to add attributes while using decorators, I really do not want to add subtasks in my code because I feel as though there is a way to do this with the decorator strategy and just was curious if it is possible
So I guess a summary question is: If I go with decorators, how can I add attributes to my spans in my code?
hey Hakan T., you're going to have to slightly tweak your decorator strategy if you want to modify the span without changing the decorated function one way is to modify the decorator itself, prior to closing the span, you can configure the decorator to add any attributes you want when instantiating it:
def new_decorator(**attributes):
def wrapper(func):
def wrapped(*args, **kwargs):
with start_span(): # this is pseudocode
output = func(*args, **kwargs)
tracer.get_current_span().set_attributes(**attributes)
return output
return wrapped
return wrappergot it, that is what I expected but wanted to ask, thank you!
