Skip to content

Commit 8c1a829

Browse files
committed
Add Django example app
1 parent 9f766e4 commit 8c1a829

File tree

12 files changed

+442
-0
lines changed

12 files changed

+442
-0
lines changed

example-django/.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
DEBUG=True
2+
SECRET_KEY=your-secret-key-here
3+
ALLOWED_HOSTS=localhost,127.0.0.1
4+
BETTER_STACK_SOURCE_TOKEN=your-source-token-here
5+
BETTER_STACK_INGESTING_HOST=your-source-ingesting-host-here

example-django/.gitignore

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Python
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
*.so
6+
.Python
7+
build/
8+
develop-eggs/
9+
dist/
10+
downloads/
11+
eggs/
12+
.eggs/
13+
lib/
14+
lib64/
15+
parts/
16+
sdist/
17+
var/
18+
wheels/
19+
*.egg-info/
20+
.installed.cfg
21+
*.egg
22+
23+
# Django
24+
*.log
25+
local_settings.py
26+
db.sqlite3
27+
db.sqlite3-journal
28+
media/
29+
staticfiles/
30+
31+
# Environment
32+
.env
33+
.venv
34+
env/
35+
venv/
36+
ENV/
37+
38+
# IDE
39+
.idea/
40+
.vscode/
41+
*.swp
42+
*.swo
43+
44+
# OS
45+
.DS_Store
46+
Thumbs.db

example-django/Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
FROM python:3.11-slim
2+
3+
WORKDIR /app
4+
5+
# Install system dependencies
6+
RUN apt-get update && \
7+
apt-get install -y --no-install-recommends \
8+
build-essential \
9+
&& rm -rf /var/lib/apt/lists/*
10+
11+
# Install Python dependencies
12+
COPY requirements.txt .
13+
RUN pip install --no-cache-dir -r requirements.txt
14+
15+
# Copy project files
16+
COPY . .
17+
18+
# Expose port
19+
EXPOSE 8000
20+
21+
# Run the application
22+
CMD ["gunicorn", "demo.wsgi:application", "--bind", "0.0.0.0:8000"]

example-django/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Logtail Django Demo
2+
3+
This is a sample Django application that demonstrates how to integrate Logtail for structured logging in a Django project.
4+
5+
## Features
6+
7+
- Structured logging with Logtail
8+
- Different log levels (INFO, WARNING, ERROR)
9+
- Custom context and extra data in logs
10+
- Exception handling and logging
11+
- Docker support
12+
13+
## Prerequisites
14+
15+
- Docker
16+
- A Better Stack account
17+
18+
## Setup
19+
20+
1. Go to Better Stack -> Telemetry -> [Sources](https://telemetry.betterstack.com/team/260195/sources/new?platform=python), and create new Python source
21+
2. Clone this repository
22+
3. Copy `.env.example` to `.env` and update the values:
23+
```
24+
BETTER_STACK_SOURCE_TOKEN=your-source-token-here
25+
BETTER_STACK_INGESTING_HOST=your-source-ingesting-host-here
26+
```
27+
28+
## Running with Docker
29+
30+
1. Build the Docker image:
31+
```bash
32+
docker build -t logtail-django-demo .
33+
```
34+
35+
2. Run the container:
36+
```bash
37+
docker run -p 8000:8000 --env-file .env logtail-django-demo
38+
```
39+
40+
3. Visit http://localhost:8000 in your browser
41+
42+
## Testing the Logging
43+
44+
The demo includes three endpoints that trigger different types of logs:
45+
46+
1. **Info Log** (Homepage): Logs basic request information
47+
2. **Warning Log** (/trigger-warning/): Logs a warning with custom data
48+
3. **Error Log** (/trigger-error/): Triggers and logs an exception
49+
50+
Check your Logtail dashboard to see the logged events.
51+
52+
## Project Structure
53+
54+
```
55+
example-django/
56+
├── demo/
57+
│ ├── templates/
58+
│ │ └── index.html
59+
│ ├── __init__.py
60+
│ ├── settings.py
61+
│ ├── urls.py
62+
│ ├── views.py
63+
│ └── wsgi.py
64+
├── .env
65+
├── Dockerfile
66+
├── README.md
67+
├── manage.py
68+
└── requirements.txt
69+
```
70+
71+
## Logging Configuration
72+
73+
The logging configuration can be found in `settings.py`. It sets up both console and Logtail handlers with a verbose formatter.

example-django/demo/__init__.py

Whitespace-only changes.

example-django/demo/settings.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import os
2+
from pathlib import Path
3+
from dotenv import load_dotenv
4+
5+
# Load environment variables
6+
load_dotenv()
7+
8+
# Build paths inside the project
9+
BASE_DIR = Path(__file__).resolve().parent.parent
10+
11+
# SECURITY WARNING: keep the secret key used in production secret!
12+
SECRET_KEY = os.getenv('SECRET_KEY', 'your-secret-key-here')
13+
14+
# SECURITY WARNING: don't run with debug turned on in production!
15+
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
16+
17+
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', '').split(',')
18+
19+
# Application definition
20+
INSTALLED_APPS = [
21+
'django.contrib.admin',
22+
'django.contrib.auth',
23+
'django.contrib.contenttypes',
24+
'django.contrib.sessions',
25+
'django.contrib.messages',
26+
'django.contrib.staticfiles',
27+
]
28+
29+
MIDDLEWARE = [
30+
'django.middleware.security.SecurityMiddleware',
31+
'django.contrib.sessions.middleware.SessionMiddleware',
32+
'django.middleware.common.CommonMiddleware',
33+
'django.middleware.csrf.CsrfViewMiddleware',
34+
'django.contrib.auth.middleware.AuthenticationMiddleware',
35+
'django.contrib.messages.middleware.MessageMiddleware',
36+
'django.middleware.clickjacking.XFrameOptionsMiddleware',
37+
]
38+
39+
ROOT_URLCONF = 'demo.urls'
40+
41+
TEMPLATES = [
42+
{
43+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
44+
'DIRS': [os.path.join(BASE_DIR, 'demo', 'templates')],
45+
'APP_DIRS': True,
46+
'OPTIONS': {
47+
'context_processors': [
48+
'django.template.context_processors.debug',
49+
'django.template.context_processors.request',
50+
'django.contrib.auth.context_processors.auth',
51+
'django.contrib.messages.context_processors.messages',
52+
],
53+
},
54+
},
55+
]
56+
57+
WSGI_APPLICATION = 'demo.wsgi.application'
58+
59+
# Database
60+
DATABASES = {
61+
'default': {
62+
'ENGINE': 'django.db.backends.sqlite3',
63+
'NAME': BASE_DIR / 'db.sqlite3',
64+
}
65+
}
66+
67+
# Password validation
68+
AUTH_PASSWORD_VALIDATORS = [
69+
{
70+
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
71+
},
72+
{
73+
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
74+
},
75+
{
76+
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
77+
},
78+
{
79+
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
80+
},
81+
]
82+
83+
# Internationalization
84+
LANGUAGE_CODE = 'en-us'
85+
TIME_ZONE = 'UTC'
86+
USE_I18N = True
87+
USE_TZ = True
88+
89+
# Static files (CSS, JavaScript, Images)
90+
STATIC_URL = 'static/'
91+
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
92+
STATICFILES_DIRS = [
93+
os.path.join(BASE_DIR, 'demo', 'static'),
94+
]
95+
96+
# Default primary key field type
97+
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
98+
99+
# Logging configuration with Logtail
100+
LOGGING = {
101+
'version': 1,
102+
'disable_existing_loggers': False,
103+
'formatters': {
104+
'verbose': {
105+
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
106+
'style': '{',
107+
},
108+
},
109+
'handlers': {
110+
'console': {
111+
'class': 'logging.StreamHandler',
112+
'formatter': 'verbose',
113+
},
114+
'logtail': {
115+
'class': 'logtail.LogtailHandler',
116+
'source_token': os.getenv('BETTER_STACK_SOURCE_TOKEN'),
117+
'host': 'https://' + os.getenv('BETTER_STACK_INGESTING_HOST'),
118+
'formatter': 'verbose',
119+
},
120+
},
121+
'root': {
122+
'handlers': ['console', 'logtail'],
123+
'level': 'INFO',
124+
},
125+
'loggers': {
126+
'django': {
127+
'handlers': ['console', 'logtail'],
128+
'level': 'INFO',
129+
'propagate': False,
130+
},
131+
},
132+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Logtail Django Demo</title>
7+
<style>
8+
body {
9+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
10+
line-height: 1.6;
11+
max-width: 800px;
12+
margin: 0 auto;
13+
padding: 20px;
14+
background-color: #f5f5f5;
15+
}
16+
.container {
17+
background-color: white;
18+
padding: 30px;
19+
border-radius: 8px;
20+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
21+
}
22+
h1 {
23+
color: #2c3e50;
24+
margin-bottom: 30px;
25+
}
26+
.button-container {
27+
display: flex;
28+
gap: 15px;
29+
flex-wrap: wrap;
30+
}
31+
.button {
32+
display: inline-block;
33+
padding: 10px 20px;
34+
background-color: #3498db;
35+
color: white;
36+
text-decoration: none;
37+
border-radius: 4px;
38+
transition: background-color 0.3s;
39+
}
40+
.button:hover {
41+
background-color: #2980b9;
42+
}
43+
.button.error {
44+
background-color: #e74c3c;
45+
}
46+
.button.error:hover {
47+
background-color: #c0392b;
48+
}
49+
.button.warning {
50+
background-color: #f1c40f;
51+
}
52+
.button.warning:hover {
53+
background-color: #f39c12;
54+
}
55+
.description {
56+
margin-top: 30px;
57+
padding: 20px;
58+
background-color: #f8f9fa;
59+
border-radius: 4px;
60+
}
61+
</style>
62+
</head>
63+
<body>
64+
<div class="container">
65+
<h1>Logtail Django Demo</h1>
66+
67+
<div class="button-container">
68+
<a href="/" class="button">Trigger Info Log</a>
69+
<a href="/trigger-warning/" class="button warning">Trigger Warning Log</a>
70+
<a href="/trigger-error/" class="button error">Trigger Error Log</a>
71+
</div>
72+
73+
<div class="description">
74+
<h2>About this Demo</h2>
75+
<p>This demo shows how to integrate Logtail with Django for structured logging. Each button above triggers a different type of log:</p>
76+
<ul>
77+
<li><strong>Info Log:</strong> Logs basic information about the request including the user agent</li>
78+
<li><strong>Warning Log:</strong> Demonstrates logging with custom data structures</li>
79+
<li><strong>Error Log:</strong> Shows how exceptions are logged with full stack traces</li>
80+
</ul>
81+
<p>Check your Logtail dashboard to see the logged events!</p>
82+
</div>
83+
</div>
84+
</body>
85+
</html>

example-django/demo/urls.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.contrib import admin
2+
from django.urls import path
3+
from django.views.generic import TemplateView
4+
from . import views
5+
6+
urlpatterns = [
7+
path('admin/', admin.site.urls),
8+
path('', views.index, name='index'),
9+
path('trigger-error/', views.trigger_error, name='trigger-error'),
10+
path('trigger-warning/', views.trigger_warning, name='trigger-warning'),
11+
]

0 commit comments

Comments
 (0)