[Python] New Relic with fastapi

Hi All I am trying to use newrelic with fastapi in python, i have the same setup for the Flask app which is working as expected. There are no errors. But still, I cant see my app in newrelic.

The API is running inside a docker. If there is any tutorial for the same that will be helpful.

Hi there @harsha.vemuluru -

FastApi is not a framework that has been tested to work with the Python agent, while Flask IS a supported framework. That’s why I suspect the one app is reporting fine and the other is not. A list of our compatibility and requirements is available in our documentation:

https://docs.newrelic.com/docs/agents/python-agent/getting-started/compatibility-requirements-python-agent

While we can’t guarantee results with an unsupported framework, you may be able to get what you need by leveraging custom instrumentation:

https://docs.newrelic.com/docs/agents/manage-apm-agents/agent-data/custom-instrumentation

Hopefully that gives you something you can work with!

1 Like

A post was split to a new topic: Feature Idea: FastAPI Support for Python

@hross I also would like to use FastAPI with New Relic, and I echo roy.trudell’s question RE roadmap.

@harsha.vemuluru any luck?

Finally, i was able to set it up. In Flask, NewRelic used to automatically detect everything. Like outgoing requests errors and stuff. Here i had to use the Class from one of the other posts and was able to make it work.

  1. Intialize manually to get the app registered in newrelic website:
    newrelic.agent.initialize('newrelic.ini')
    newrelic.agent.register_application()

  2. NewRelicMiddleware class

    class NewRelicMiddleware:
    def init(self, app):
    self.app = app

     class NewRelicMiddlewareRetrievers:
         @staticmethod
         def get_transaction_name(middleware, scope, *args, **kwargs):
             # Strip off the leading slash
             name = scope.get('path', '/no-path')
             if name == '/':
                 return ''
             return name[1:]
    
         @staticmethod
         def get_headers(middleware, scope, *args, **kwargs):
             return scope.get('headers', [])
    
         @staticmethod
         def get_header_values(header_names):
             def retrieve(middleware, scope, *args, **kwargs):
                 headers = scope.get('headers', [])
                 # Iterate over all header names and get the first one that has a value
                 for header_name in header_names:
                     for header in headers:
                         if header[0] == header_name:
                             return header[1].decode('utf-8')
                 return None
             return retrieve
    
         @staticmethod
         def get_scope_property(prop_name):
             def retrieve(middleware, scope, *args, **kwargs):
                 return scope.get(prop_name)
             return retrieve
    
     @newrelic.agent.web_transaction(
         name=NewRelicMiddlewareRetrievers.get_transaction_name,
         scheme=NewRelicMiddlewareRetrievers.get_scope_property('scheme'),
         host=NewRelicMiddlewareRetrievers.get_header_values([b'x-forwarded-host', b'host']),
         request_path=NewRelicMiddlewareRetrievers.get_scope_property('path'),
         request_method=NewRelicMiddlewareRetrievers.get_scope_property('method'),
         query_string=NewRelicMiddlewareRetrievers.get_scope_property('query_string'),
         headers=NewRelicMiddlewareRetrievers.get_headers,
     )
     async def __call__(self, scope, receive, send):
         try:
             await self.app(scope, receive, send)
         except Exception as e:
             raise e from None
    

app.add_middleware(NewRelicMiddleware)

  1. to add any custom parameters when logging you can do this

    newrelic.agent.add_custom_parameter("test", "123")

3 Likes

Amazing @harsha.vemuluru! Thank you so much for figuring out the customer instrumentation to get this to work and sharing what you learned here. @benjamin.pratt and @roy.trudell - let me know if This also works for you. In the meantime, we can create a feature idea to add support for fastapi directly. I’ll be tagging you in a new topic. Keep your :eyes: peeled.

1 Like