Skip to content

Commit 022a8af

Browse files
committed
Added docker healthcheck route, and updated logging filter
1 parent a39562b commit 022a8af

File tree

10 files changed

+83
-3
lines changed

10 files changed

+83
-3
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,4 @@ RUN chmod +x ./entrypoint.sh ./dependencies.sh
5353

5454
ENTRYPOINT ["./entrypoint.sh"]
5555

56-
HEALTHCHECK --interval=30s --timeout=30s --start-period=30s --retries=20 CMD curl --include --request GET http://localhost:8000/health || exit 1
56+
HEALTHCHECK --interval=30s --timeout=30s --start-period=30s --retries=20 CMD curl --include --request GET http://localhost:8000/health/healthcheck || exit 1

config/debug-logger.yml

+13
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ formatters:
4343
use_colors: false
4444

4545

46+
filters:
47+
healthcheck_filter:
48+
# Filter for the `/health/healthcheck` endpoint.
49+
"()": sample_fastapi.app.resources.docker_health.HealthCheckFilter
50+
name: "uvicorn.access"
51+
52+
4653
handlers:
4754
# Root logger
4855
global_console:
@@ -85,6 +92,9 @@ handlers:
8592
uvicorn_access_console:
8693
class: logging.StreamHandler
8794
formatter: uvicorn_access_console_fmt
95+
filters:
96+
# Filters out annoying healthcheck pings
97+
- healthcheck_filter
8898

8999
# Arguments
90100
stream: ext://sys.stdout
@@ -104,6 +114,9 @@ handlers:
104114
uvicorn_access_file:
105115
class: logging.handlers.TimedRotatingFileHandler
106116
formatter: uvicorn_access_file_fmt
117+
filters:
118+
# Filters out annoying healthcheck pings
119+
- healthcheck_filter
107120

108121
# Arguments
109122
filename: *uvicorn_access_log_file

examples/deploy/config/server-logger-config.yml

+13
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ formatters:
4343
use_colors: false
4444

4545

46+
filters:
47+
healthcheck_filter:
48+
# Filter for the `/health/healthcheck` endpoint.
49+
"()": sample_fastapi.app.resources.docker_health.HealthCheckFilter
50+
name: "uvicorn.access"
51+
52+
4653
handlers:
4754
# Root logger
4855
global_console:
@@ -85,6 +92,9 @@ handlers:
8592
uvicorn_access_console:
8693
class: logging.StreamHandler
8794
formatter: uvicorn_access_console_fmt
95+
filters:
96+
# Filters out annoying healthcheck pings
97+
- healthcheck_filter
8898

8999
# Arguments
90100
stream: ext://sys.stdout
@@ -104,6 +114,9 @@ handlers:
104114
uvicorn_access_file:
105115
class: logging.handlers.TimedRotatingFileHandler
106116
formatter: uvicorn_access_file_fmt
117+
filters:
118+
# Filters out annoying healthcheck pings
119+
- healthcheck_filter
107120

108121
# Arguments
109122
filename: *uvicorn_access_log_file

examples/deploy/docker-compose.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
services:
22
server:
3-
image: ghcr.io/nb-programmer/sample-fastapi:latest
3+
image: sample-fastapi:latest
44

55
command:
66
- "--host=0.0.0.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .logging import HealthCheckFilter
2+
from .routes import init_app, init_routes
3+
4+
__all__ = ["init_app", "init_routes", "HealthCheckFilter"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import logging
2+
from collections.abc import Mapping
3+
4+
5+
class HealthCheckFilter(logging.Filter):
6+
"""Filter out healthcheck access logs from uvicorn.access module"""
7+
8+
HEALTHCHECK_ROUTE = "/health/healthcheck"
9+
10+
def filter(self, record: logging.LogRecord) -> bool:
11+
# Check if the log message arguments contain our healthcheck route
12+
if isinstance(record.args, tuple):
13+
return self.HEALTHCHECK_ROUTE not in record.args
14+
elif isinstance(record.args, Mapping):
15+
return self.HEALTHCHECK_ROUTE not in record.args.values()
16+
17+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from enum import Enum
2+
3+
from pydantic import BaseModel
4+
5+
6+
class HealthCheckStatus(str, Enum):
7+
OK = "ok"
8+
9+
10+
class HealthcheckResponse(BaseModel):
11+
status: HealthCheckStatus = HealthCheckStatus.OK
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from fastapi import APIRouter, FastAPI
2+
3+
from .views import respond_healthcheck
4+
5+
6+
def init_routes():
7+
router = APIRouter(prefix="/health", tags=["health"])
8+
9+
router.add_api_route("/healthcheck", respond_healthcheck, methods={"GET"})
10+
11+
return router
12+
13+
14+
def init_app(app: FastAPI):
15+
app.include_router(init_routes())
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from .models import HealthcheckResponse, HealthCheckStatus
2+
3+
4+
async def respond_healthcheck() -> HealthcheckResponse:
5+
"""Docker healthcheck response to validate if the app is up"""
6+
return HealthcheckResponse(status=HealthCheckStatus.OK)

sample_fastapi/app/resources/routes.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
def init_app(app: FastAPI):
55
"""Initialize routes, middleware, sub-apps, etc. to the given Application"""
6-
from . import calculator, hello, user
6+
from . import calculator, docker_health, hello, user
7+
docker_health.init_app(app)
78
hello.init_app(app)
89
calculator.init_app(app)
910
user.init_app(app)

0 commit comments

Comments
 (0)