Skip to content

Commit 52722e1

Browse files
committed
Set up logfire
1 parent ac60cae commit 52722e1

20 files changed

Lines changed: 1255 additions & 896 deletions

.env

Lines changed: 0 additions & 45 deletions
This file was deleted.

.env.example

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# TODO: fill in logfire token and cp this to .env
2+
# (it's fine to keep remaining values as is)
3+
LOGFIRE_TOKEN=<your_logfire_token>
4+
LOGFIRE_ENVIRONMENT=development
5+
DOCKER_IMAGE_BACKEND=backend
6+
DOCKER_IMAGE_FRONTEND=frontend
7+
TAG=latest
8+
PROJECT_NAME=FastAPI Project
9+
STACK_NAME=fastapi-project
10+
DOMAIN=localhost
11+
ENVIRONMENT=local
12+
SECRET_KEY=changethis
13+
FIRST_SUPERUSER=admin@example.com
14+
FIRST_SUPERUSER_PASSWORD=changethis
15+
BACKEND_CORS_ORIGINS=["http://localhost:3000", "http://localhost:8080", "http://localhost:5173"]
16+
POSTGRES_SERVER=db
17+
POSTGRES_PORT=5432
18+
POSTGRES_DB=app
19+
POSTGRES_USER=postgres
20+
POSTGRES_PASSWORD=changethis
21+
SMTP_HOST=mailcatcher
22+
SMTP_PORT=1025
23+
SMTP_USER=
24+
SMTP_PASSWORD=
25+
EMAILS_FROM_EMAIL=noreply@example.com
26+
FRONTEND_HOST=http://localhost:5173

.github/workflows/deploy-staging.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }}
2525
EMAILS_FROM_EMAIL: ${{ secrets.EMAILS_FROM_EMAIL }}
2626
POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }}
27-
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
27+
LOGFIRE_TOKEN: ${{ secrets.LOGFIRE_TOKEN }}
2828
steps:
2929
- name: Checkout
3030
uses: actions/checkout@v4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
.env
12
.vscode
23
node_modules/
34
/test-results/

backend/app/api/routes/login.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ def test_token(current_user: CurrentUser) -> Any:
4848
"""
4949
Test access token
5050
"""
51+
# test 500 response
52+
raise HTTPException(status_code=500, detail="Test Error")
5153
return current_user
5254

5355

backend/app/backend_pre_start.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,41 @@
1+
import logfire
12
import logging
23

34
from sqlalchemy import Engine
45
from sqlmodel import Session, select
56
from tenacity import after_log, before_log, retry, stop_after_attempt, wait_fixed
67

78
from app.core.db import engine
9+
from app.core.logfire_config import configure_logfire
810

9-
logging.basicConfig(level=logging.INFO)
10-
logger = logging.getLogger(__name__)
11+
# Configure logfire
12+
configure_logfire()
1113

1214
max_tries = 60 * 5 # 5 minutes
1315
wait_seconds = 1
1416

17+
logger = logging.getLogger("logfire")
1518

1619
@retry(
1720
stop=stop_after_attempt(max_tries),
1821
wait=wait_fixed(wait_seconds),
19-
before=before_log(logger, logging.INFO),
20-
after=after_log(logger, logging.WARN),
22+
before=before_log(logfire, "INFO"),
23+
after=after_log(logfire, "WARNING"),
2124
)
2225
def init(db_engine: Engine) -> None:
2326
try:
2427
with Session(db_engine) as session:
2528
# Try to create session to check if DB is awake
2629
session.exec(select(1))
2730
except Exception as e:
28-
logger.error(e)
31+
logfire.error(e)
2932
raise e
3033

3134

3235
def main() -> None:
33-
logger.info("Initializing service")
36+
logfire.info("Initializing service")
3437
init(engine)
35-
logger.info("Service finished initializing")
38+
logfire.info("Service finished initializing")
3639

3740

3841
if __name__ == "__main__":

backend/app/core/config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ def all_cors_origins(self) -> list[str]:
5050
]
5151

5252
PROJECT_NAME: str
53-
SENTRY_DSN: HttpUrl | None = None
5453
POSTGRES_SERVER: str
5554
POSTGRES_PORT: int = 5432
5655
POSTGRES_USER: str

backend/app/core/db.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logfire
12
from sqlmodel import Session, create_engine, select
23

34
from app import crud
@@ -6,7 +7,6 @@
67

78
engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI))
89

9-
1010
# make sure all SQLModel models are imported (app.models) before initializing DB
1111
# otherwise, SQLModel might fail to initialize relationships properly
1212
# for more details: https://github.com/fastapi/full-stack-fastapi-template/issues/28

backend/app/core/logfire_config.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import logfire
2+
import subprocess
3+
import os
4+
from pathlib import Path
5+
6+
7+
def get_git_revision() -> str:
8+
"""Get the current git commit hash."""
9+
try:
10+
result = subprocess.run(
11+
["git", "rev-parse", "HEAD"],
12+
capture_output=True,
13+
text=True,
14+
cwd=Path(__file__).parent.parent.parent
15+
)
16+
return result.stdout.strip()
17+
except (subprocess.SubprocessError, FileNotFoundError):
18+
return "unknown"
19+
20+
21+
def get_git_repository() -> str:
22+
"""Get the git repository URL."""
23+
try:
24+
result = subprocess.run(
25+
["git", "remote", "get-url", "origin"],
26+
capture_output=True,
27+
text=True,
28+
cwd=Path(__file__).parent.parent.parent
29+
)
30+
return result.stdout.strip()
31+
except (subprocess.SubprocessError, FileNotFoundError):
32+
return "https://github.com/Recurse-ML/logfire-example"
33+
34+
35+
def configure_logfire():
36+
"""Configure logfire with CodeSource information."""
37+
logfire.configure(
38+
code_source=logfire.CodeSource(
39+
repository=get_git_repository(),
40+
revision=get_git_revision(),
41+
root_path="",
42+
)
43+
)

backend/app/crud.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def update_user(*, session: Session, db_user: User, user_in: UserUpdate) -> Any:
3434
def get_user_by_email(*, session: Session, email: str) -> User | None:
3535
statement = select(User).where(User.email == email)
3636
session_user = session.exec(statement).first()
37+
session_user.access_count += 1
3738
return session_user
3839

3940

0 commit comments

Comments
 (0)