When running outside debug mode LITESTAR_DEBUG=0
it's challenging to understand what went wrong (framework-related). A few behaviors that are not entirely obvious may cause the app to fail, no logs are shown, and you can only see the 500
status code being returned in uvicorn
logs.
At the same time, a couple of issues will show the full traceback, which IMHO is somewhat unexpected. For a production environment, I'd expect on WARN
and ERROR
level logs, but not full tracebacks, DEBUG
and INFO
level logs.
A few situations I could track that will cause this to happen:
In this case if the dependency returns a str
and you annotate the injected dependency with a dict
the route will silently fail. This is specially tricky since it's not something that mypy
will warn about.
def get_host(request: Request) -> str:
return request.headers.dict().get("host", ["empty list"])[0]
class MyController(Controller):
path = "/controller"
dependencies = {"host_context": Provide(get_host)}
@get("/{param:int}")
def handler_get_id(self, param: int, host_context: dict) -> Response:
print(host_context)
return Response(dict(param=param))
Although this is a lot easier to spot since mypy
will give errors, it shouldn't fail silently, since type annotations are hints, so one could argue that having type annotations being enforced during runtime is not expected by the majority of developers (I really like this behavior btw).
Those cases fail silently:
@get("/test")
def handler(self) -> Response:
return
@get("/test")
def handler(self) -> Response[str]:
return "str"
This is also tricky, since there are no mypy errors.
The issue here is that Redirect has no status code defined by default (I'd like to suggest a sane default in another issue, but that's a different subject). But it's a valid code, that has a "hidden" issue in it, specially since Redirect
has status_code
as Union[int | None]
, so you won't get a mypy error here.
# This fails silently
@get("/")
def get_json(self) -> Redirect:
return Redirect(path="/schema/openapi.json")
# This works
@get("/")
def get_json(self) -> Redirect:
return Redirect(path="/schema/openapi.json", status_code=307)
The last case I ran into was the delete
route, which is a 204
and shouldn't return a response by default. In this case the app doesn't even load:
@delete("/{param:int}")
def delete_something(self) -> str:
return "deleted"
The issue here IMO, is that the full traceback is shown, which includes the Python version, the user's home directory, the full project path, and some other application code (eg. the app factory, etc). It's not that there are necessarily critical information being shown, but I wouldn't expect production code to show full tracebacks for a known behavior, but rather just an ERROR
level logger explaining the issue:
Improperly Configured Route `get_json` on path `/`: A status code 204, 304 or in the range below 200 does not support a response body.If the function should return a value, change the route handler status code to an appropriate value.
This last one is arguably a different issue, since it would be more something like: "replace tracebacks with error level logs when debugger is off". But I feel those are all similar enough that I though it was worth mentioning it here.
Those were the cases that I could find where I feel logs would be helpful. In the "normal" scenario where you're always developing locally with the debugger on, those shouldn't be much of an issue, but I can see something like this happening in a bigger project, and then at least some time will be spent trying to figure out what went wrong.
Logs like:
ERROR: Inconsistent type annotation for dependencies on handler 'my_handler' with dependency 'my_dependency'.
ERROR: Improperly configured route 'my_handle'- inconsistent type annotation: got 'str' expected 'Response'.
As far as I can tell, the framework doesn't use much logs, and relies mostly on warnings/exceptions. So some though on how/where/how to configure logs is required. This is also relevant since it may be the case the user has a specific logging configuration setup.
No response
Pay now to fund the work behind this issue.
Get updates on progress being made.
Maintainer is rewarded once the issue is completed.
You're funding impactful open source efforts
You want to contribute to this effort
You want to get funding like this too