Skip to content

Commit d061b48

Browse files
authored
feat(logging): implement loguru (#473)
1 parent 5fbb445 commit d061b48

26 files changed

+607
-157
lines changed

.github/workflows/deploy-pr.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,9 @@ jobs:
100100
comment-tag: 'pr-preview'
101101
create-if-not-exists: 'true'
102102
message: |
103-
⚙️ Preview environment for PR #${{ env.PR_ID }} is available at:
104-
https://pr-${{ env.PR_ID }}.${{ env.APP_NAME }}.coderamp.dev/
103+
🌐 [Preview environment](https://pr-${{ env.PR_ID }}.${{ env.APP_NAME }}.coderamp.dev/) for PR #${{ env.PR_ID }}
104+
105+
📊 [Log viewer](https://app.datadoghq.eu/logs?query=kube_namespace%3Aprs-gitingest%20version%3Apr-${{ env.PR_ID }})
105106
106107
remove-pr-env:
107108
if: >-

.pre-commit-config.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ repos:
118118
click>=8.0.0,
119119
'fastapi[standard]>=0.109.1',
120120
httpx,
121+
loguru>=0.7.0,
121122
pathspec>=0.12.1,
122123
prometheus-client,
123124
pydantic,
@@ -144,6 +145,7 @@ repos:
144145
click>=8.0.0,
145146
'fastapi[standard]>=0.109.1',
146147
httpx,
148+
loguru>=0.7.0,
147149
pathspec>=0.12.1,
148150
prometheus-client,
149151
pydantic,

.vscode/launch.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"name": "Python Debugger: Module",
55
"type": "debugpy",
66
"request": "launch",
7-
"module": "uvicorn",
8-
"args": ["server.main:app", "--host", "0.0.0.0", "--port", "8000"],
7+
"module": "server",
8+
"args": [],
99
"cwd": "${workspaceFolder}/src"
1010
}
1111
]

CONTRIBUTING.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ If you ever get stuck, reach out on [Discord](https://discord.com/invite/zerRaGK
6565
9. **Run the local server** to sanity-check:
6666

6767
```bash
68-
cd src
69-
uvicorn server.main:app
68+
python -m server
7069
```
7170

7271
Open [http://localhost:8000](http://localhost:8000) to confirm everything works.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ USER appuser
4444

4545
EXPOSE 8000
4646
EXPOSE 9090
47-
CMD ["python", "-m", "uvicorn", "server.main:app", "--host", "0.0.0.0", "--port", "8000"]
47+
CMD ["python", "-m", "server"]

compose.yml

Lines changed: 47 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,45 @@
1-
# Common base configuration for all services
1+
x-base-environment: &base-environment
2+
# Python Configuration
3+
PYTHONUNBUFFERED: "1"
4+
PYTHONDONTWRITEBYTECODE: "1"
5+
# Host Configuration
6+
ALLOWED_HOSTS: ${ALLOWED_HOSTS:-gitingest.com,*.gitingest.com,localhost,127.0.0.1}
7+
# Metrics Configuration
8+
GITINGEST_METRICS_ENABLED: ${GITINGEST_METRICS_ENABLED:-true}
9+
GITINGEST_METRICS_HOST: ${GITINGEST_METRICS_HOST:-0.0.0.0}
10+
GITINGEST_METRICS_PORT: ${GITINGEST_METRICS_PORT:-9090}
11+
# Sentry Configuration
12+
GITINGEST_SENTRY_ENABLED: ${GITINGEST_SENTRY_ENABLED:-false}
13+
GITINGEST_SENTRY_DSN: ${GITINGEST_SENTRY_DSN:-}
14+
GITINGEST_SENTRY_TRACES_SAMPLE_RATE: ${GITINGEST_SENTRY_TRACES_SAMPLE_RATE:-1.0}
15+
GITINGEST_SENTRY_PROFILE_SESSION_SAMPLE_RATE: ${GITINGEST_SENTRY_PROFILE_SESSION_SAMPLE_RATE:-1.0}
16+
GITINGEST_SENTRY_PROFILE_LIFECYCLE: ${GITINGEST_SENTRY_PROFILE_LIFECYCLE:-trace}
17+
GITINGEST_SENTRY_SEND_DEFAULT_PII: ${GITINGEST_SENTRY_SEND_DEFAULT_PII:-true}
18+
19+
x-prod-environment: &prod-environment
20+
GITINGEST_SENTRY_ENVIRONMENT: ${GITINGEST_SENTRY_ENVIRONMENT:-production}
21+
22+
x-dev-environment: &dev-environment
23+
DEBUG: "true"
24+
LOG_LEVEL: "debug"
25+
RELOAD: "true"
26+
GITINGEST_SENTRY_ENVIRONMENT: ${GITINGEST_SENTRY_ENVIRONMENT:-development}
27+
# S3 Configuration for development
28+
S3_ENABLED: "true"
29+
S3_ENDPOINT: http://minio:9000
30+
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-gitingest}
31+
S3_SECRET_KEY: ${S3_SECRET_KEY:-gitingest123}
32+
S3_BUCKET_NAME: ${S3_BUCKET_NAME:-gitingest-bucket}
33+
S3_REGION: ${S3_REGION:-us-east-1}
34+
S3_DIRECTORY_PREFIX: ${S3_DIRECTORY_PREFIX:-dev}
35+
S3_ALIAS_HOST: ${S3_ALIAS_HOST:-http://127.0.0.1:9000/${S3_BUCKET_NAME:-gitingest-bucket}}
36+
237
x-app-base: &app-base
338
ports:
439
- "${APP_WEB_BIND:-8000}:8000" # Main application port
540
- "${GITINGEST_METRICS_HOST:-127.0.0.1}:${GITINGEST_METRICS_PORT:-9090}:9090" # Metrics port
6-
environment:
7-
# Python Configuration
8-
- PYTHONUNBUFFERED=1
9-
- PYTHONDONTWRITEBYTECODE=1
10-
# Host Configuration
11-
- ALLOWED_HOSTS=${ALLOWED_HOSTS:-gitingest.com,*.gitingest.com,localhost,127.0.0.1}
12-
# Metrics Configuration
13-
- GITINGEST_METRICS_ENABLED=${GITINGEST_METRICS_ENABLED:-true}
14-
- GITINGEST_METRICS_HOST=${GITINGEST_METRICS_HOST:-127.0.0.1}
15-
- GITINGEST_METRICS_PORT=${GITINGEST_METRICS_PORT:-9090}
16-
# Sentry Configuration
17-
- GITINGEST_SENTRY_ENABLED=${GITINGEST_SENTRY_ENABLED:-false}
18-
- GITINGEST_SENTRY_DSN=${GITINGEST_SENTRY_DSN:-}
19-
- GITINGEST_SENTRY_TRACES_SAMPLE_RATE=${GITINGEST_SENTRY_TRACES_SAMPLE_RATE:-1.0}
20-
- GITINGEST_SENTRY_PROFILE_SESSION_SAMPLE_RATE=${GITINGEST_SENTRY_PROFILE_SESSION_SAMPLE_RATE:-1.0}
21-
- GITINGEST_SENTRY_PROFILE_LIFECYCLE=${GITINGEST_SENTRY_PROFILE_LIFECYCLE:-trace}
22-
- GITINGEST_SENTRY_SEND_DEFAULT_PII=${GITINGEST_SENTRY_SEND_DEFAULT_PII:-true}
2341
user: "1000:1000"
24-
command: ["python", "-m", "uvicorn", "server.main:app", "--host", "0.0.0.0", "--port", "8000"]
42+
command: ["python", "-m", "server"]
2543

2644
services:
2745
# Production service configuration
@@ -31,7 +49,7 @@ services:
3149
profiles:
3250
- prod
3351
environment:
34-
- GITINGEST_SENTRY_ENVIRONMENT=${GITINGEST_SENTRY_ENVIRONMENT:-production}
52+
<<: [*base-environment, *prod-environment]
3553
restart: unless-stopped
3654

3755
# Development service configuration
@@ -43,24 +61,12 @@ services:
4361
profiles:
4462
- dev
4563
environment:
46-
- DEBUG=true
47-
- GITINGEST_SENTRY_ENVIRONMENT=${GITINGEST_SENTRY_ENVIRONMENT:-development}
48-
# S3 Configuration
49-
- S3_ENABLED=true
50-
- S3_ENDPOINT=http://minio:9000
51-
- S3_ACCESS_KEY=${S3_ACCESS_KEY:-gitingest}
52-
- S3_SECRET_KEY=${S3_SECRET_KEY:-gitingest123}
53-
# Use lowercase bucket name to ensure compatibility with MinIO
54-
- S3_BUCKET_NAME=${S3_BUCKET_NAME:-gitingest-bucket}
55-
- S3_REGION=${S3_REGION:-us-east-1}
56-
- S3_DIRECTORY_PREFIX=${S3_DIRECTORY_PREFIX:-dev}
57-
# Public URL for S3 resources
58-
- S3_ALIAS_HOST=${S3_ALIAS_HOST:-http://127.0.0.1:9000/${S3_BUCKET_NAME:-gitingest-bucket}}
64+
<<: [*base-environment, *dev-environment]
5965
volumes:
6066
# Mount source code for live development
6167
- ./src:/app:ro
6268
# Use --reload flag for hot reloading during development
63-
command: ["python", "-m", "uvicorn", "server.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
69+
command: ["python", "-m", "server"]
6470
depends_on:
6571
minio-setup:
6672
condition: service_completed_successfully
@@ -73,9 +79,9 @@ services:
7379
ports:
7480
- "9000:9000" # API port
7581
- "9001:9001" # Console port
76-
environment:
77-
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-minioadmin}
78-
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-minioadmin}
82+
environment: &minio-environment
83+
MINIO_ROOT_USER: ${MINIO_ROOT_USER:-minioadmin}
84+
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:-minioadmin}
7985
volumes:
8086
- minio-data:/data
8187
command: server /data --console-address ":9001"
@@ -96,11 +102,10 @@ services:
96102
minio:
97103
condition: service_healthy
98104
environment:
99-
- MINIO_ROOT_USER=${MINIO_ROOT_USER:-minioadmin}
100-
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD:-minioadmin}
101-
- S3_ACCESS_KEY=${S3_ACCESS_KEY:-gitingest}
102-
- S3_SECRET_KEY=${S3_SECRET_KEY:-gitingest123}
103-
- S3_BUCKET_NAME=${S3_BUCKET_NAME:-gitingest-bucket}
105+
<<: *minio-environment
106+
S3_ACCESS_KEY: ${S3_ACCESS_KEY:-gitingest}
107+
S3_SECRET_KEY: ${S3_SECRET_KEY:-gitingest123}
108+
S3_BUCKET_NAME: ${S3_BUCKET_NAME:-gitingest-bucket}
104109
volumes:
105110
- ./.docker/minio/setup.sh:/setup.sh:ro
106111
entrypoint: sh

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ requires-python = ">= 3.8"
77
dependencies = [
88
"click>=8.0.0",
99
"httpx",
10+
"loguru>=0.7.0",
1011
"pathspec>=0.12.1",
1112
"pydantic",
1213
"python-dotenv",
@@ -96,7 +97,6 @@ ignore = [ # https://docs.astral.sh/ruff/rules/...
9697

9798
# TODO: fix the following issues:
9899
"TD003", # missing-todo-link, TODO: add issue links
99-
"T201", # print, TODO: replace with logging
100100
"S108", # hardcoded-temp-file, TODO: replace with tempfile
101101
"BLE001", # blind-except, TODO: replace with specific exceptions
102102
"FAST003", # fast-api-unused-path-parameter, TODO: fix

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ boto3>=1.28.0 # AWS SDK for S3 support
22
click>=8.0.0
33
fastapi[standard]>=0.109.1 # Vulnerable to https://osv.dev/vulnerability/PYSEC-2024-38
44
httpx
5+
loguru>=0.7.0
56
pathspec>=0.12.1
67
prometheus-client
78
pydantic

src/gitingest/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@
1212
from gitingest.config import MAX_FILE_SIZE, OUTPUT_FILE_NAME
1313
from gitingest.entrypoint import ingest_async
1414

15+
# Import logging configuration first to intercept all logging
16+
from gitingest.utils.logging_config import get_logger
17+
18+
# Initialize logger for this module
19+
logger = get_logger(__name__)
20+
1521

1622
class _CLIArgs(TypedDict):
1723
source: str

src/gitingest/clone.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616
resolve_commit,
1717
run_command,
1818
)
19+
from gitingest.utils.logging_config import get_logger
1920
from gitingest.utils.os_utils import ensure_directory_exists_or_create
2021
from gitingest.utils.timeout_wrapper import async_timeout
2122

2223
if TYPE_CHECKING:
2324
from gitingest.schemas import CloneConfig
2425

26+
# Initialize logger for this module
27+
logger = get_logger(__name__)
28+
2529

2630
@async_timeout(DEFAULT_TIMEOUT)
2731
async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
@@ -49,14 +53,35 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
4953
local_path: str = config.local_path
5054
partial_clone: bool = config.subpath != "/"
5155

56+
logger.info(
57+
"Starting git clone operation",
58+
extra={
59+
"url": url,
60+
"local_path": local_path,
61+
"partial_clone": partial_clone,
62+
"subpath": config.subpath,
63+
"branch": config.branch,
64+
"tag": config.tag,
65+
"commit": config.commit,
66+
"include_submodules": config.include_submodules,
67+
},
68+
)
69+
70+
logger.debug("Ensuring git is installed")
5271
await ensure_git_installed()
72+
73+
logger.debug("Creating local directory", extra={"parent_path": str(Path(local_path).parent)})
5374
await ensure_directory_exists_or_create(Path(local_path).parent)
5475

76+
logger.debug("Checking if repository exists", extra={"url": url})
5577
if not await check_repo_exists(url, token=token):
78+
logger.error("Repository not found", extra={"url": url})
5679
msg = "Repository not found. Make sure it is public or that you have provided a valid token."
5780
raise ValueError(msg)
5881

82+
logger.debug("Resolving commit reference")
5983
commit = await resolve_commit(config, token=token)
84+
logger.debug("Resolved commit", extra={"commit": commit})
6085

6186
clone_cmd = ["git"]
6287
if token and is_github_host(url):
@@ -69,20 +94,30 @@ async def clone_repo(config: CloneConfig, *, token: str | None = None) -> None:
6994
clone_cmd += [url, local_path]
7095

7196
# Clone the repository
97+
logger.info("Executing git clone command", extra={"command": " ".join([*clone_cmd[:-1], "<url>", local_path])})
7298
await run_command(*clone_cmd)
99+
logger.info("Git clone completed successfully")
73100

74101
# Checkout the subpath if it is a partial clone
75102
if partial_clone:
103+
logger.info("Setting up partial clone for subpath", extra={"subpath": config.subpath})
76104
await checkout_partial_clone(config, token=token)
105+
logger.debug("Partial clone setup completed")
77106

78107
git = create_git_command(["git"], local_path, url, token)
79108

80109
# Ensure the commit is locally available
110+
logger.debug("Fetching specific commit", extra={"commit": commit})
81111
await run_command(*git, "fetch", "--depth=1", "origin", commit)
82112

83113
# Write the work-tree at that commit
114+
logger.info("Checking out commit", extra={"commit": commit})
84115
await run_command(*git, "checkout", commit)
85116

86117
# Update submodules
87118
if config.include_submodules:
119+
logger.info("Updating submodules")
88120
await run_command(*git, "submodule", "update", "--init", "--recursive", "--depth=1")
121+
logger.debug("Submodules updated successfully")
122+
123+
logger.info("Git clone operation completed successfully", extra={"local_path": local_path})

0 commit comments

Comments
 (0)