Glitchtip is a open-source exception monitoring system, it's similar to Sentry, which collects errors reported from your applications and helps you discover errors in real time and also helps you to understand the health of your applications.
What are we doing today?
In this tutorial we will setup Glitchtip on Docker using Traefik as our Load Balancer and SSL terminations for LetsEncrypt certificates, then we will create a Python Flask application and initiate a error so that we can see how these errors are collected by Glitchtip and we will also add an Webhook Server to demonstrate logging errors to a Webhook Endpoint for further development on errors.
So that we can see our exceptions in our applications like this:
Assumptions
I will assume that you have docker and docker-compose installed. If you need more info on Traefik you can have a look at their website, but I have also written a post on setting up Traefik v2 in detail, but we will touch on that in this post.
Code Source
I will publish the code for this tutorial under my Github Repository:
Environment Details
I have 3 DNS Entries:
- Glitchtip:
gc.civo.rbkr.xyz
- Flask App:
flask-app.civo.rbkr.xyz
- Webhook:
flask-webhook.civo.rbkr.xyz
Which all points to the host running Glitchtip.
Directory Structure
First create the directory structure for our glitchtip demo and change to the directory:
mkdir glitchtip-tutorial
cd glitchtip-tutorial
Create the traefik directory for acme.json
where certificate data will be stored, create the file and change permissions on the file:
mkdir traefik
touch traefik/acme.json
chmod 600 traefik/acme.json
Traefik
Open the docker-compose.yml
and add the first bit which will Traefik, ensure that you replace me@example.com
with your email under certificatesResolvers.letsencrypt.acme.email
:
version: '3.8'
x-logging:
&default-logging
driver: "json-file"
options:
max-size: "1m"
services:
glitchtip-traefik:
image: traefik:2.4
container_name: glitchtip-traefik
restart: unless-stopped
volumes:
- ./traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock
networks:
- glitchtip
ports:
- 80:80
- 443:443
command:
- '--api'
- '--providers.docker=true'
- '--providers.docker.exposedByDefault=false'
- '--entrypoints.http=true'
- '--entrypoints.http.address=:80'
- '--entrypoints.http.http.redirections.entrypoint.to=https'
- '--entrypoints.http.http.redirections.entrypoint.scheme=https'
- '--entrypoints.https=true'
- '--entrypoints.https.address=:443'
- '--certificatesResolvers.letsencrypt.acme.email=me@example.com'
- '--certificatesResolvers.letsencrypt.acme.storage=acme.json'
- '--certificatesResolvers.letsencrypt.acme.httpChallenge.entryPoint=http'
- '--log=true'
- '--log.level=INFO'
logging:
driver: "json-file"
options:
max-size: "1m"
networks:
glitchtip:
name: glitchtip
You can now start Traefik so long:
docker-compose up -d
Glitchtip
Now we will add the Glitchtip components, you can refer to their documentation if you want to read more into these configuration options. Add the following services below glitchtip-traefk
:
glitchtip-postgres:
image: postgres:13
container_name: glitchtip-postgres
restart: unless-stopped
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
- glitchtip
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
retries: 5
logging: *default-logging
glitchtip-redis:
image: redis
container_name: glitchtip-redis
restart: unless-stopped
networks:
- glitchtip
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 30s
retries: 50
logging: *default-logging
glitchtip-web:
image: glitchtip/glitchtip
container_name: glitchtip-web
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
ENABLE_OPEN_USER_REGISTRATION: "True"
GLITCHTIP_MAX_EVENT_LIFE_DAYS: 90
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.glitchtip.rule=Host(`gt.civo.rbkr.xyz`)'
- 'traefik.http.routers.glitchtip.entrypoints=https'
- 'traefik.http.routers.glitchtip.tls=true'
- 'traefik.http.routers.glitchtip.tls.certresolver=letsencrypt'
- 'traefik.http.routers.glitchtip.service=glitchtip-service'
- 'traefik.http.services.glitchtip-service.loadbalancer.server.port=8000'
logging: *default-logging
glitchtip-worker:
image: glitchtip/glitchtip
container_name: glitchtip-worker
restart: unless-stopped
command: celery -A glitchtip worker -B -l INFO
depends_on:
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
networks:
- glitchtip
logging: *default-logging
glitchtip-migrate:
image: glitchtip/glitchtip
container_name: glitchtip-migrate
depends_on:
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
command: "./manage.py migrate"
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
networks:
- glitchtip
logging: *default-logging
Ensure that you change the following:
EMAIL_URL
eg.smtp://apikey:your-password@smtp.sendgrid.net:587
(sendgrid offers free mail delivery)DEFAULT_FROM_EMAIL
eg.no-reply@yourdomain.com
- Your FQDN for glitchtip in
'traefik.http.routers.glitchtip.rule=Host()'
Once your configuration is updated, start glitchtip:
docker-compose pull
docker-compose up -d
Once all the services are started you should be able to access the UI and will look more or less like this:
Since ENABLE_OPEN_USER_REGISTRATION
is set to True
, we can register our user:
Once you register you will be logged in and on the organization page to create a organization:
For this tutorial, I will be using the name my-org
:
I will go ahead and create a application in my organisation called flask-service-dev
and I will be selecting Python Flask for this tutorial, and I want to associate this project to a team called engineering
, at the bottom select team and create your team:
Once the team has been created and selected, select the framework and name your service:
Once you created your project you will get a getting started guide on how to configure your application:
On the right hand side you will get the configuration values, which we will use as environment variables on our application that we want to emit errors to glitchtip:
https://6ee24c1a446347b99e9574edfe990393@gt.civo.rbkr.xyz/1
https://gt.civo.rbkr.xyz/api/1/security/?glitchtip_key=6ee24c1a446347b99e9574edfe990393
Now that we have signed up we can disable ENABLE_OPEN_USER_REGISTRATION
by setting it to False
in the docker-compose.yml
, then run docker-compose up -d
.
Optional: Glitchtip is written in Django, so you can also use the following method to manage users and access the admin panel on /admin
:
$ docker-compose run glitchtip-migrate ./manage.py createsuperuser
Creating glitchdip_glitchtip-migrate_run ... done
Email: me@example.com
Password:
Password (again):
Superuser created successfully.
Python Flask App
Now we will create the application that we want to monitor for errors on glitchtip. From the glitchtip-tutorial
directory, create the application code and dockerfile for our python flask app:
mkdir flask-app
touch flask-app/requirements.txt
touch flask-app/app.py
touch flask-app/Dockerfile
First add the requirements in flask-app/requirements.txt
:
flask==1.1.2
sentry-sdk[flask]
gunicorn==20.0.4
Next our dockerfile in flask-app/Dockerfile
:
FROM python:3.8-slim
ADD requirements.txt /src/requirements.txt
ADD run.sh /src/run.sh
RUN chmod +x /src/run.sh
RUN pip install --upgrade -r /src/requirements.txt
ADD app.py /src/app.py
CMD ["/src/run.sh"]
Our boot script that will start flask using gunicorn in flask-app/run.sh
:
#!/bin/sh
gunicorn app:app \
--workers 2 \
--threads 2 \
--bind 0.0.0.0:80 \
--capture-output \
--access-logfile '-' \
--error-logfile '-'
Then our application code in flask-app/app.py
:
import os
import logging
from flask import Flask
import sentry_sdk
from sentry_sdk.integrations.flask import FlaskIntegration
GLITCHTIP_DSN = os.environ['DSN']
sentry_sdk.init(
dsn=GLITCHTIP_DSN,
integrations=[FlaskIntegration()]
)
app = Flask(__name__)
app.config['DEBUG'] = False
@app.before_first_request
def setup_logging():
app.logger.addHandler(logging.StreamHandler())
app.logger.setLevel(logging.INFO)
app.logger.info('logs enabled')
@app.route('/')
def root():
return 'hello, world'
@app.route('/log-error')
def log_error():
app.logger.error('logging error with glitchtip')
return 'logged error'
@app.route('/trigger-error')
def trigger_error():
division_by_zero = 1 / 0
if __name__ == '__main__':
app.logger.info('starting server')
app.run()
Then we add this section to our docker-compose.yml
:
glitchtip-flask-app:
build:
context: flask-app
dockerfile: Dockerfile
container_name: glitchtip-flask-app
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
environment:
DSN: "https://6ee24c1a446347b99e9574edfe990393@gt.civo.rbkr.xyz/1"
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.app.rule=Host(`flask-app.civo.rbkr.xyz`)'
- 'traefik.http.routers.app.entrypoints=https'
- 'traefik.http.routers.app.tls=true'
- 'traefik.http.routers.app.tls.certresolver=letsencrypt'
- 'traefik.http.routers.app.service=app-service'
- 'traefik.http.services.app-service.loadbalancer.server.port=80'
logging: *default-logging
So now our full docker-compose.yml
should look like this more or less:
---
version: '3.8'
x-logging:
&default-logging
driver: "json-file"
options:
max-size: "1m"
services:
glitchtip-traefik:
image: traefik:2.4
container_name: glitchtip-traefik
restart: unless-stopped
volumes:
- ./traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock
networks:
- glitchtip
ports:
- 80:80
- 443:443
command:
- '--api'
- '--providers.docker=true'
- '--providers.docker.exposedByDefault=false'
- '--entrypoints.http=true'
- '--entrypoints.http.address=:80'
- '--entrypoints.http.http.redirections.entrypoint.to=https'
- '--entrypoints.http.http.redirections.entrypoint.scheme=https'
- '--entrypoints.https=true'
- '--entrypoints.https.address=:443'
- '--certificatesResolvers.letsencrypt.acme.email=me@example.com'
- '--certificatesResolvers.letsencrypt.acme.storage=acme.json'
- '--certificatesResolvers.letsencrypt.acme.httpChallenge.entryPoint=http'
- '--log=true'
- '--log.level=INFO'
logging:
driver: "json-file"
options:
max-size: "1m"
glitchtip-postgres:
image: postgres:13
container_name: glitchtip-postgres
restart: unless-stopped
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
- glitchtip
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
retries: 5
logging: *default-logging
glitchtip-redis:
image: redis
container_name: glitchtip-redis
restart: unless-stopped
networks:
- glitchtip
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 30s
retries: 50
logging: *default-logging
glitchtip-web:
image: glitchtip/glitchtip
container_name: glitchtip-web
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
ENABLE_OPEN_USER_REGISTRATION: "False"
GLITCHTIP_MAX_EVENT_LIFE_DAYS: 90
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.glitchtip.rule=Host(`gt.civo.rbkr.xyz`)'
- 'traefik.http.routers.glitchtip.entrypoints=https'
- 'traefik.http.routers.glitchtip.tls=true'
- 'traefik.http.routers.glitchtip.tls.certresolver=letsencrypt'
- 'traefik.http.routers.glitchtip.service=glitchtip-service'
- 'traefik.http.services.glitchtip-service.loadbalancer.server.port=8000'
logging: *default-logging
glitchtip-worker:
image: glitchtip/glitchtip
container_name: glitchtip-worker
restart: unless-stopped
command: celery -A glitchtip worker -B -l INFO
depends_on:
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
networks:
- glitchtip
logging: *default-logging
glitchtip-migrate:
image: glitchtip/glitchtip
container_name: glitchtip-migrate
depends_on:
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
command: "./manage.py migrate"
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
networks:
- glitchtip
logging: *default-logging
glitchtip-flask-app:
build:
context: flask-app
dockerfile: Dockerfile
container_name: glitchtip-flask-app
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
environment:
DSN: "https://6ee24c1a446347b99e9574edfe990393@gt.civo.rbkr.xyz/1"
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.app.rule=Host(`flask-app.civo.rbkr.xyz`)'
- 'traefik.http.routers.app.entrypoints=https'
- 'traefik.http.routers.app.tls=true'
- 'traefik.http.routers.app.tls.certresolver=letsencrypt'
- 'traefik.http.routers.app.service=app-service'
- 'traefik.http.services.app-service.loadbalancer.server.port=80'
logging: *default-logging
networks:
glitchtip:
name: glitchtip
Build the flask-app
container and start the service:
docker-compose up --build -d
Making a test request:
$ curl -IL http://flask-app.civo.rbkr.xyz
HTTP/1.1 308 Permanent Redirect
Location: https://flask-app.civo.rbkr.xyz/
Date: Tue, 28 Sep 2021 06:00:27 GMT
Content-Length: 18
Content-Type: text/plain; charset=utf-8
HTTP/2 200
content-type: text/html; charset=utf-8
date: Tue, 28 Sep 2021 06:00:27 GMT
server: gunicorn/20.0.4
content-length: 12
Logging Exceptions to Glitchtip
Now let's access the endpoints that will cause an exception, let's first make a request to /trigger-error
, then head over to "Issues", or if you have multiple projects, select your organization, then select your project's issues:
From the issues view, we can see we had one issue:
When we select the issue, we can see more information about this exception, such as the useragent info, the request path, where in our application the exception was raised etc:
As you can see, Glitchtip also provide information deeper in the stack where the exception was raised from:
There's a lot of information, but what I also found nice, was that it logs span_id and trace_id, the sdk version etc:
If we have a look at the /log-error
, which will just log an error event, from the issues view, we can see we had one issue:
When we select the issue, we can see more information about this exception, such as the useragent info, the request path, etc:
Alerting
We can setup alerting for every time we receive an exception, to do so, head over to "Settings", "Projects" and you will find "Project Alerts":
When we select "Create New Alert", you will get the alert configuration and by default the alert will be configured to the email address of the team members of the project.
If we "Add Alert Recipient", you will see that we have the option to add a "Webhook URL", so let's go back to our docker-compose.yml
and setup a Python Flask Webhook:
glitchtip-flask-webhook:
build:
context: flask-webhook
dockerfile: Dockerfile
container_name: glitchtip-flask-webhook
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.webhook.rule=Host(`flask-webhook.civo.rbkr.xyz`)'
- 'traefik.http.routers.webhook.entrypoints=https'
- 'traefik.http.routers.webhook.tls=true'
- 'traefik.http.routers.webhook.tls.certresolver=letsencrypt'
- 'traefik.http.routers.webhook.service=webhook-service'
- 'traefik.http.services.webhook-service.loadbalancer.server.port=80'
logging: *default-logging
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 5s
timeout: 3s
retries: 60
Then we create our flask-webhook directory:
mkdir flask-webhook
Create the required files, first our application flask-webhook/app.py
:
import logging
from flask import Flask, request, jsonify
app = Flask(__name__)
app.config['DEBUG'] = False
@app.before_first_request
def setup_logging():
app.logger.addHandler(logging.StreamHandler())
app.logger.setLevel(logging.INFO)
@app.route('/', methods=['POST'])
def webhook():
payload = request.get_json(force=True)
app.logger.info(payload)
return jsonify(payload)
@app.route('/health', methods=['GET'])
def health():
payload = {'status': 'up'}
return jsonify(payload)
if __name__ == '__main__':
app.logger.info('starting server')
app.run()
Then our flask-webhook/Dockerfile
:
FROM python:3.8-slim
RUN apt update && apt install curl -y
WORKDIR /src
ADD requirements.txt /src/requirements.txt
ADD run.sh /src/run.sh
RUN chmod +x /src/run.sh
RUN pip install --upgrade -r /src/requirements.txt
ADD app.py /src/app.py
CMD ["/src/run.sh"]
Then our flask-webhook/requirements.txt
:
flask==1.1.2
gunicorn==20.0.4
Then when everything is in place, build and start the container:
docker-compose up --build -d
Once the application has started, from Settings, Projects, Project Alerts, when we add a new alert recipient, we select the webhook as a recipient type and add our webhook url:
Now we should see:
Select submit and then invoke the /trigger-error
url:
$ curl -I https://flask-app.civo.rbkr.xyz/trigger-error
HTTP/2 500
content-type: text/html; charset=utf-8
date: Tue, 28 Sep 2021 09:36:29 GMT
server: gunicorn/20.0.4
content-length: 290
Now when we look at the logs of our webhook container:
$ docker-compose logs -f glitchtip-flask-webhook
...
glitchtip-flask-webhook | {'alias': 'GlitchTip', 'text': 'GlitchTip Alert', 'attachments': [{'title': 'ZeroDivisionError: division by zero', 'title_link': 'https://gt.civo.rbkr.xyz/my-org/issues/2', 'text': 'trigger_error', 'image_url': None, 'color': '#e52b50'}], 'sections': [{'activityTitle': 'ZeroDivisionError: division by zero', 'activitySubtitle': '[View Issue FLASK-SERVICE-DEV-1](https://gt.civo.rbkr.xyz/my-org/issues/2)'}]}
If we prettify it, you can see we can consume this information and do our own integrations:
>>> print(json.dumps(e, indent=2))
{
"alias": "GlitchTip",
"text": "GlitchTip Alert",
"attachments": [
{
"title": "ZeroDivisionError: division by zero",
"title_link": "https://gt.civo.rbkr.xyz/my-org/issues/2",
"text": "trigger_error",
"image_url": null,
"color": "#e52b50"
}
],
"sections": [
{
"activityTitle": "ZeroDivisionError: division by zero",
"activitySubtitle": "[View Issue FLASK-SERVICE-DEV-1](https://gt.civo.rbkr.xyz/my-org/issues/2)"
}
]
}
And our email notification will look like this:
The Complete Compose
This will be published to my github repository, but the complete docker-compose.yml
:
---
version: '3.8'
x-logging:
&default-logging
driver: "json-file"
options:
max-size: "1m"
services:
glitchtip-traefik:
image: traefik:2.4
container_name: glitchtip-traefik
restart: unless-stopped
volumes:
- ./traefik/acme.json:/acme.json
- /var/run/docker.sock:/var/run/docker.sock
networks:
- glitchtip
ports:
- 80:80
- 443:443
command:
- '--api'
- '--providers.docker=true'
- '--providers.docker.exposedByDefault=false'
- '--entrypoints.http=true'
- '--entrypoints.http.address=:80'
- '--entrypoints.http.http.redirections.entrypoint.to=https'
- '--entrypoints.http.http.redirections.entrypoint.scheme=https'
- '--entrypoints.https=true'
- '--entrypoints.https.address=:443'
- '--certificatesResolvers.letsencrypt.acme.email=email@example.com'
- '--certificatesResolvers.letsencrypt.acme.storage=acme.json'
- '--certificatesResolvers.letsencrypt.acme.httpChallenge.entryPoint=http'
- '--log=true'
- '--log.level=INFO'
logging:
driver: "json-file"
options:
max-size: "1m"
glitchtip-postgres:
image: postgres:13
container_name: glitchtip-postgres
restart: unless-stopped
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
POSTGRES_DB: postgres
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
- glitchtip
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 5s
retries: 5
logging: *default-logging
glitchtip-redis:
image: redis
container_name: glitchtip-redis
restart: unless-stopped
networks:
- glitchtip
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 30s
retries: 50
logging: *default-logging
glitchtip-web:
image: glitchtip/glitchtip
container_name: glitchtip-web
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
ENABLE_OPEN_USER_REGISTRATION: "False"
GLITCHTIP_MAX_EVENT_LIFE_DAYS: 90
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.glitchtip.rule=Host(`gt.civo.rbkr.xyz`)'
- 'traefik.http.routers.glitchtip.entrypoints=https'
- 'traefik.http.routers.glitchtip.tls=true'
- 'traefik.http.routers.glitchtip.tls.certresolver=letsencrypt'
- 'traefik.http.routers.glitchtip.service=glitchtip-service'
- 'traefik.http.services.glitchtip-service.loadbalancer.server.port=8000'
logging: *default-logging
glitchtip-worker:
image: glitchtip/glitchtip
container_name: glitchtip-worker
restart: unless-stopped
command: celery -A glitchtip worker -B -l INFO
depends_on:
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
networks:
- glitchtip
logging: *default-logging
glitchtip-migrate:
image: glitchtip/glitchtip
container_name: glitchtip-migrate
depends_on:
glitchtip-postgres:
condition: service_healthy
glitchtip-redis:
condition: service_healthy
command: "./manage.py migrate"
environment:
DATABASE_URL: postgres://postgres:postgres@glitchtip-postgres:5432/postgres
REDIS_URL: redis://glitchtip-redis:6379/0
SECRET_KEY: jsdf93892309fhufhr
PORT: 8000
EMAIL_URL: "${EMAIL_URL}"
DEFAULT_FROM_EMAIL: ${EMAIL_FROM_ADDRESS}
GLITCHTIP_DOMAIN: "https://gt.civo.rbkr.xyz"
networks:
- glitchtip
logging: *default-logging
glitchtip-flask-app:
build:
context: flask-app
dockerfile: Dockerfile
container_name: glitchtip-flask-app
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
environment:
DSN: "https://6ee24c1a446347b99e9574edfe990393@gt.civo.rbkr.xyz/1"
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.app.rule=Host(`flask-app.civo.rbkr.xyz`)'
- 'traefik.http.routers.app.entrypoints=https'
- 'traefik.http.routers.app.tls=true'
- 'traefik.http.routers.app.tls.certresolver=letsencrypt'
- 'traefik.http.routers.app.service=app-service'
- 'traefik.http.services.app-service.loadbalancer.server.port=80'
logging: *default-logging
glitchtip-flask-webhook:
build:
context: flask-webhook
dockerfile: Dockerfile
container_name: glitchtip-flask-webhook
restart: unless-stopped
depends_on:
glitchtip-traefik:
condition: service_started
networks:
- glitchtip
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.webhook.rule=Host(`flask-webhook.civo.rbkr.xyz`)'
- 'traefik.http.routers.webhook.entrypoints=https'
- 'traefik.http.routers.webhook.tls=true'
- 'traefik.http.routers.webhook.tls.certresolver=letsencrypt'
- 'traefik.http.routers.webhook.service=webhook-service'
- 'traefik.http.services.webhook-service.loadbalancer.server.port=80'
logging: *default-logging
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 5s
timeout: 3s
retries: 60
networks:
glitchtip:
name: glitchtip
I left the domain endpoints and glitchtip application keys in the code intentionally for demonstration purposes, but deleted the stack after the time of writing.
Thank You
I hope this was helpful, I was really impressed with Glitchtip. If you liked this content, please make sure to share or come say hi on my website or twitter:
- Website: ruan.dev
- Twitter: @ruanbekker