Utilizar Bugsink con Sentry en un docker compose para registrar errores

Tiempo de lectura: 6 minutos

Hoy vamos a implementar Bugsink un sistema autoalojado que nos permitirá registrar errores de nuestras aplicaciones y servidores de forma remota y con avisos. Para ello utilizaremos un docker compose.

Bugsink logo

Lo primero es entender qué es Bugsink.

BugSink es una herramienta o plataforma diseñada para gestionar errores o bugs en aplicaciones de software de manera centralizada. Su propósito es identificar, rastrear, priorizar y resolver problemas de software con mayor eficacia. Aunque no es un término ampliamente conocido como marca o software específico, en general, un sistema como BugSink podría funcionar como:

  1. Un sistema de gestión de errores: Recopila y centraliza reportes de errores provenientes de aplicaciones en producción, pruebas o desarrollo.
  2. Monitorización de excepciones: Detecta errores en tiempo real mientras los usuarios interactúan con la aplicación, registrando detalles técnicos como trazas de pila (stack trace), entornos de ejecución, o el estado del sistema cuando ocurrió el problema.
  3. Integración con flujos de trabajo: Muchas herramientas similares ofrecen integraciones con sistemas de gestión de proyectos como Jira, Trello, o Asana, lo que permite asignar y priorizar la resolución de errores directamente.
  4. Análisis y priorización: Proporciona métricas y visualizaciones para identificar cuáles errores son más críticos según su frecuencia, impacto en los usuarios, o gravedad.
  5. Facilidad para desarrolladores: Ofrece una interfaz amigable para rastrear los errores hasta su causa raíz, facilitando la depuración.

Ahora vamos a crear el entorno:

  • Creamos un docker-compose con esta estructura.
services:
    bugsink:
        image: bugsink/bugsink:latest
        container_name: bugsink
        restart: always
        ports:
            - '8000:8000'
        environment:
            - PORT=8000
            - CREATE_SUPERUSER=${CREATE_SUPERUSER}
            - SECRET_KEY=${SECRET_KEY}
            - BEHIND_HTTPS_PROXY=${USAR_PROXY_INVERSO}
            - SINGLE_USER=False
            - EMAIL_HOST=${EMAIL_HOST}
            - EMAIL_HOST_USER=${EMAIL_HOST_USER}
            - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD}
            - EMAIL_PORT=${EMAIL_PORT}
            - EMAIL_USE_TLS=${EMAIL_USE_TLS}
            - DEFAULT_FROM_EMAIL=${DEFAULT_FROM_EMAIL}
            - DATABASE_URL=${DATABASE_URL}
            - SITE_TITLE=${SITE_TITLE}
            - BASE_URL=${BASE_URL}
        links:
            - mysql_bugsink:db
        depends_on:
            - mysql_bugsink

    mysql_bugsink:
        image: mariadb
        container_name: mysql_bugsink
        restart: always
        environment:
            MYSQL_DATABASE: ${MYSQL_DATABASE} 
            MYSQL_USER: ${MYSQL_USER} 
            MYSQL_PASSWORD: ${MYSQL_PASSWORD}
            MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
        volumes:
            - ./config/mariadb:/var/lib/mysql

    phpmyadmin_mysql_bugsink:
        image: phpmyadmin
        restart: unless-stopped
        container_name: phpmyadmin_mysql_bugsink
        ports:
            - 8080:80
        environment:
            - PMA_ARBITRARY=1
            - MAX_EXECUTION_TIME=99999
            - PHP_UPLOAD_MAX_FILESIZE=10000M
            - PHP_POST_MAX_SIZE=10000M
            - PHP_MEMORY_LIMIT=10000M
        links:
            - mysql_bugsink:db

He creado el servicio de bugsink configurando las variables para:

  • Crear un super usuario
  • El secret key (debemos generarlo aleatoriamente)
  • Indicar si tiene o no un proxy por delante
  • Indicar si va a utilizar un unico usuario (en este caso permito múltiples usuarios)
  • Los datos del email SMTP. Esto se necesita para crear nuevos usuarios, ya que envía invitación utilizando el email.
  • Database URL, necesario para utilizar MYSQL en vez de SQLite.
  • Y podemos indicar el título del sitio.

Por otro lado, he desplegado un contenedor mariadb y phpmyadmin para poder utilizarlo como base de datos.

Ahora hay que configurar el .env de la siguiente forma:

SECRET_KEY=X534wALv1bEsJDmDnagsm19pPkYohZu5x3rORQenntylm3oxm5
USAR_PROXY_INVERSO=True

CREATE_SUPERUSER=admin:admin

SITE_TITLE=Bugsink - Control de errores

BASE_URL=https://dominio.com

#SMTP Email
EMAIL_HOST=ssl.dominio.com
EMAIL_HOST_USER=user@dominio.com
EMAIL_HOST_PASSWORD=pass_email
EMAIL_PORT=587
EMAIL_USE_TLS=True
DEFAULT_FROM_EMAIL=Test <user@dominio.com>

#Base de datos
DATABASE_URL="mysql://user:password@db:3306/database_name"
MYSQL_DATABASE="database_name"
MYSQL_USER="user"
MYSQL_PASSWORD="password"
MYSQL_ROOT_PASSWORD="root_password"

Aquí tenemos que indicar las variables de entorno, primero indicaremos el SECRET_KEY, este debemos generarlo de forma aleatoría, he incluido el de defecto.

CREATE_SUPERUSER, debemos indicar el usuario:password del usuario administrador.

El resto de datos es para configurar el SMTP y la conexión a la base de datos.

Ahora podremos entrar al panel de control desde: http://localhost:8000/

E introducir los datos de usuario.

Para añadir un usuario tenemos que crear un nuevo equipo, vamos a Teams y pulsamos en New Team.

New Team Bugsink

Ahora podremos invitar a un nuevo usuario pulsando en Invite Member:

Invite Member bugsink

Ahora crearemos un nuevo projecto, pulsamos en Projects > New Project

Elegiremos el nombre y el Team al que pertenece.

Ahora nos aparecerá la información de conexión con Python, JavaScript o PHP.

Instalar el cliente con JavaScript en React:

Utiliza el SDK de Sentry por lo que primero instalaremos Sentry:

npm install @sentry/react @sentry/tracing

Si utilizamos Next.js pondremos:

npm install @sentry/nextjs @sentry/tracing

Esto incluye:

  1. Sentry para React: Maneja errores y eventos en tus componentes React.
  2. Sentry para Next.js: Captura errores y excepciones en el servidor y cliente, e incluye soporte para API Routes y páginas dinámicas.

Configurar Sentry en JavaScript (React o Next.js)

Next.js tiene soporte para configurar Sentry fácilmente con un archivo de configuración dedicado.

Creamos un archivo dentro de utils por ejemplo, lo llamamos Bugsink.tsx o js según nuestro entorno

import * as Sentry from '@sentry/nextjs';

export function iniciarlizarBugsink() {
   Sentry.init({
     dsn: 'https://<YOUR_DSN>@sentry.io/<PROJECT_ID>',
     tracesSampleRate: 1.0, // Captura el 100% de las solicitudes para debugging. Reduce en producción.
   });
}

*DSN es la URL que viene directamente en el proyecto creado.

Y ahora debemos importar el archivo en un context o nuestra web principal por ejemplo index.tsx

useEffect(() => {
        iniciarlizarBugsink();
  }, []);

Puedes añadir otro tipo de configuración, por ejemplo los IDs de usuario:

import * as Sentry from '@sentry/nextjs';

Sentry.configureScope((scope) => {
  scope.setUser({ id: '123', email: 'user@example.com' });
  scope.setTag('environment', 'production');
});

Y puedes capturar errores manualmente:

try {
  // Código que puede fallar
  throw new Error('Test error');
} catch (err) {
  Sentry.captureException(err);
}

Ahora para probarlo generaremos un error:

throw new Error("Error Thrown on purpose to send it to Bugsink");

Y si todo va bien, aparecerá el error capturado en la web:

Error en BugsInk

En el caso de Next.js

Ahora tenemos que generar los archivos .map para mostrar el source code en Bugsink.

Para ello vamos a next.config.js y añadimos esta línea dentro de nextConfig

const nextConfig = {
  productionBrowserSourceMaps: true,

Y en la configuración de webpack añadimos lo siguiente:

 webpack(config, options) {
    config.devtool = options.dev ? 'eval-source-map' : 'source-map';

Configuración en React Native:

Instalamos las dependencias:

npm install @sentry/react-native

O si utilizas expo (https://docs.expo.dev/guides/using-sentry/)

npx expo install @sentry/react-native

Y ahora creamos el inicializador en un archivo llamado Bugsink qué podemos añadir en utils:

import * as Sentry from '@sentry/react';

export function iniciarlizarBugsink() {
    Sentry.init({
        dsn: '<url proyecto>',
        tracesSampleRate: 1.0, // Captura el 100% de las solicitudes para debugging. Reduce en producción.
    });
}

Enviamos un mensaje de prueba de error:

Sentry.captureMessage('Mensaje de prueba desde Expo');

O generando una excepcion:

throw new Error('Hello, again, Sentry!'); 

Añadir en Python:

Para añadirlo en python tendremos que instalar la libreria:

pip install sentry-sdk

Y ahora debemos inicializarla en el main de nuestra aplicación:

import sentry_sdk

sentry_sdk.init(
    '<url proyecto>',

    send_default_pii=True,
    max_request_body_size="always",

    # Setting up the release is highly recommended. The SDK will try to
    # infer it, but explicitly setting it is more reliable:
    # release=...,

    traces_sample_rate=1.0,
)

*Indica la URL del proyecto que viene en el panel de control.

Extra: Utilizarlo debajo de Nginx Proxy Manager

Para configurar Bugsink con HTTPS detrás de un Nginx Proxy Manager, puedes usar los pasos a continuación. Esto asegura que Bugsink reconozca que está detrás de un proxy y maneja correctamente las solicitudes HTTPS.


1. Configuración del Proxy en Nginx Proxy Manager

Configura un host en tu Nginx Proxy Manager que redirija el tráfico al contenedor de Bugsink.

  1. Añadir un Proxy Host:
    • En Nginx Proxy Manager, crea un nuevo Proxy Host.
    • Domain Name: Introduce el dominio (por ejemplo, bugsink.example.com).
    • Forward Hostname/IP: La dirección interna del contenedor de Bugsink, como bugsink (nombre del servicio en Docker Compose).
    • Forward Port: El puerto que usa Bugsink (por defecto, suele ser 8000 para Gunicorn).
    • Enable Websockets: Marca esta opción.
  2. Configurar HTTPS:
    • En la pestaña SSL, selecciona “Request a new SSL certificate”.
    • Habilita las opciones:
      • “Force SSL” para que todas las solicitudes sean redirigidas a HTTPS.
      • “HTTP/2 Support” para mejorar el rendimiento.
  3. Guarda los cambios.

2. Configurar Bugsink para HTTPS y Proxy

En tu configuración de Bugsink, debes asegurarte de que la aplicación reconozca que está detrás de un proxy y que el proxy maneja HTTPS.

Opción 1: Usar la variable de entorno BEHIND_HTTPS_PROXY

En tu archivo docker-compose.yml, añade esta variable de entorno al servicio de Bugsink:

services:
  bugsink:
    image: bugsink:latest
    environment:
      - BEHIND_HTTPS_PROXY=True
    ports:
      - "8000:8000"
    depends_on:
      - db

Esto configura automáticamente las siguientes opciones en Bugsink:

  • SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
  • SESSION_COOKIE_SECURE = True
  • CSRF_COOKIE_SECURE = True
  • USE_X_REAL_IP = True

Opción 2: Configurar manualmente en bugsink_conf.py

Si prefieres personalizar los ajustes, edita el archivo bugsink_conf.py (o el archivo equivalente de configuración):

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
USE_X_REAL_IP = True

En Nginx Proxy Manager, asegúrate de que las cabeceras necesarias estén configuradas:

  • X-Forwarded-Proto: Debe ser https.
  • X-Real-IP: Debe ser la dirección IP real del cliente.

3. Verificar las Cabeceras en Nginx Proxy Manager

Nginx Proxy Manager ya maneja correctamente las cabeceras como X-Forwarded-Proto y X-Real-IP, pero puedes personalizar las reglas si es necesario:

  1. Ve al Advanced Tab del Proxy Host.
  2. Asegúrate de añadir las siguientes cabeceras personalizadas si no están presentes:
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Esto asegurará que Bugsink reciba las cabeceras necesarias.


4. Reiniciar los Servicios

Después de hacer los cambios, reinicia tanto el contenedor de Bugsink como el Nginx Proxy Manager:

docker-compose restart

Deja un comentario