-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #26 from codex-team/feat/fastapi
feat: added fastapi integration
- Loading branch information
Showing
10 changed files
with
279 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# Flask integration | ||
|
||
This extension adds support for the [FastAPI](https://fastapi.tiangolo.com/) web framework. | ||
|
||
## Installation | ||
|
||
```bash | ||
pip install hawkcatcher[fastapi] | ||
``` | ||
|
||
import Catcher module to your project. | ||
|
||
```python | ||
from hawkcatcher.modules.fastapi import HawkFastapi | ||
``` | ||
|
||
```python | ||
app = FastAPI() | ||
|
||
hawk = HawkFastapi( | ||
'app_instance': app, | ||
'token': '1234567-abcd-8901-efgh-123456789012' | ||
) | ||
``` | ||
|
||
Now all global fastapi errors would be sent to Hawk. | ||
|
||
### Try-except | ||
|
||
If you want to catch errors in try-except blocks see [this](../README.md#try-except) | ||
|
||
## Manual sending | ||
|
||
You can send any error to Hawk. See [this](../README.md#manual-sending) | ||
|
||
### Event context | ||
|
||
See [this](../README.md#event-context) | ||
|
||
### Affected user | ||
|
||
See [this](../README.md#affected-user) | ||
|
||
### Addons | ||
|
||
When some event handled by FastAPI Catcher, it adds some addons to the event data for Hawk. | ||
|
||
| name | type | description | | ||
| --------- | ---- | --------------- | | ||
| `url` | str | Request URL | | ||
| `method` | str | Request method | | ||
| `headers` | dict | Request headers | | ||
| `cookies` | dict | Request cookies | | ||
| `params` | dict | Request params | | ||
|
||
## Init params | ||
|
||
To init Hawk Catcher just pass a project token and FastAPI app instance. | ||
|
||
```python | ||
app = FastAPI() | ||
|
||
hawk = HawkFastapi( | ||
'app_instance': app, | ||
'token': '1234567-abcd-8901-efgh-123456789012' | ||
) | ||
``` | ||
|
||
### Additional params | ||
|
||
If you need to use custom Hawk server then pass a dictionary with params. | ||
|
||
```python | ||
hawk = HawkFastapi({ | ||
'app_instance': app, | ||
'token': '1234567-abcd-8901-efgh-123456789012', | ||
'collector_endpoint': 'https://<id>.k1.hawk.so', | ||
}) | ||
``` | ||
|
||
Parameters: | ||
|
||
| name | type | required | description | | ||
| -------------------- | ------------------------- | ------------ | ------------------------------------------------------------------------------ | | ||
| `app_instance` | FastAPI | **required** | FastAPI app instance | | ||
| `token` | str | **required** | Your project's Integration Token | | ||
| `release` | str | optional | Release name for Suspected Commits feature | | ||
| `collector_endpoint` | string | optional | Collector endpoint for sending event to | | ||
| `context` | dict | optional | Additional context to be send with every event | | ||
| `before_send` | Callable[[dict], None] | optional | This Method allows you to filter any data you don't want sending to Hawk | | ||
| `set_user` | Callable[[Request], User] | optional | This Method allows you to set user for every request by fastapi request object | | ||
| `with_addons` | bool | optional | Add framework addons to event data | | ||
|
||
## Requirements | ||
|
||
See [this](../README.md#requirements) | ||
|
||
And for fastapi you need: | ||
|
||
- fastapi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from .fastapi import HawkFastapi | ||
from .types import HawkCatcherSettings | ||
from .types import FastapiSettings | ||
|
||
hawk = HawkFastapi() | ||
|
||
|
||
def init(*args, **kwargs): | ||
hawk.init(*args, **kwargs) | ||
|
||
|
||
def send(*args, **kwargs): | ||
hawk.send(*args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
from hawkcatcher.types import HawkCatcherSettings | ||
from ...core import Hawk | ||
from hawkcatcher.modules.fastapi.types import FastapiSettings, FastapiAddons | ||
from starlette.types import ASGIApp, Receive, Scope, Send | ||
from starlette.requests import Request | ||
from starlette.middleware.base import BaseHTTPMiddleware | ||
from typing import Union | ||
from hawkcatcher.errors import ModuleError | ||
import asyncio | ||
from contextvars import ContextVar | ||
from fastapi import Request | ||
import asyncio | ||
|
||
# Variable for saving current request, work with async tasks | ||
current_request: ContextVar[Union[Request, None]] = ContextVar("current_request", default=None) | ||
|
||
|
||
# class for catching errors in fastapi app | ||
class HawkFastapi(Hawk): | ||
params: FastapiSettings = {} | ||
|
||
def init(self, settings: Union[str, FastapiSettings] = None): | ||
self.params = self.get_params(settings) | ||
|
||
if self.params.get('app_instance') is None: | ||
raise ModuleError('Fastapi app instance not passed to HawkFastapi') | ||
|
||
self.params.get('app_instance').add_middleware(self._get_starlette_middleware()) | ||
|
||
def _get_starlette_middleware(self): | ||
""" | ||
Create middleware for starlette to identify request exception and storing current request for manual sending | ||
""" | ||
|
||
# Create method to use it in middleware class with Hawk class context | ||
def send_func(err): | ||
return self.send(err) | ||
|
||
class StarletteMiddleware: | ||
def __init__(self, app: ASGIApp): | ||
self.app = app | ||
|
||
async def __call__(self, scope: Scope, receive: Receive, send: Send): | ||
if scope["type"] == "http": | ||
request = Request(scope, receive, send) | ||
current_request.set(request) | ||
try: | ||
await self.app(scope, receive, send) | ||
except Exception as err: | ||
return send_func(err) | ||
else: | ||
await self.app(scope, receive, send) | ||
return None | ||
|
||
return StarletteMiddleware | ||
|
||
def send(self, event: Exception = None, context=None, user=None): | ||
""" | ||
Method for manually send error to Hawk, make it async for starlette | ||
:param exception: exception | ||
:param context: additional context to send with error | ||
:param user: user information who faced with that event | ||
""" | ||
|
||
request = current_request.get() | ||
|
||
if user is None and request is not None: | ||
user = self._set_user(request) | ||
|
||
return super().send(event, context, user) | ||
|
||
def _set_addons(self) -> Union[FastapiAddons, None]: | ||
request = current_request.get() | ||
|
||
if request is None: | ||
return None | ||
|
||
return { | ||
'fastapi': { | ||
'url': str(request.url), | ||
'method': request.method, | ||
'headers': dict(request.headers), | ||
'cookies': dict(request.cookies), | ||
'params': dict(request.query_params) | ||
} | ||
} | ||
|
||
@staticmethod | ||
def get_params(settings) -> FastapiSettings | None: | ||
hawk_params = Hawk.get_params(settings) | ||
|
||
if hawk_params is None: | ||
return None | ||
|
||
return { | ||
**hawk_params, | ||
'app_instance': settings.get('app_instance'), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from hawkcatcher.types import HawkCatcherSettings, User, Addons | ||
from typing import Callable, TypedDict | ||
from starlette.applications import Starlette | ||
from fastapi import Request | ||
|
||
class FastapiAddons(TypedDict): | ||
url: str # url of request | ||
method: str # method of request | ||
headers: dict # headers of request | ||
cookies: dict # cookies of request | ||
params: dict # request params | ||
|
||
class Addons(Addons): | ||
fastapi: FastapiAddons | ||
|
||
class FastapiSettings(HawkCatcherSettings[Request]): | ||
"""Settings for Fastapi catcher for errors tracking""" | ||
|
||
app_instance: Starlette # Fastapi app instance to add catching |
Oops, something went wrong.