En un proyecto personal, el problema no suele ser que algo falle: es enterarse tres días después por un usuario. En este capítulo monto lo mínimo para ver qué pasa en la aplicación y recibir un aviso cuando algo se tuerce.
Para quién es y qué necesitas
Para quien ya tiene la aplicación desplegada y quiere enterarse de los errores antes que sus usuarios.
Antes de empezar:
- La aplicación desplegada.
- Saber que el plan gratuito sirve para empezar; el de pago guarda más días y más eventos.
- Un correo o un canal (Slack, Discord) donde quieras recibir las alertas.
Al terminar tendrás logs estructurados que se pueden consultar, errores agrupados, métricas propias, visitas sin cookies y alertas de errores y de facturación.
Qué mirar y con qué herramienta
flowchart LR
W[Worker] -->|console.log| L[Workers Logs]
W -->|automático| T[Traces]
W -->|writeDataPoint| AE[(Analytics Engine)]
N[Navegador] -->|script sin cookies| WA[Web Analytics]
L & T --> IS[Issues<br/>errores agrupados]
L & AE --> M[Monitors<br/>alertas con SQL]
IS & M --> A[Email · Webhook]
| Pregunta | Herramienta |
|---|---|
| ¿Qué ha fallado y por qué? | Workers Logs + Issues |
| ¿Qué parte de la petición es lenta? | Traces |
| ¿Cuántas notas se crean al día? ¿Qué función de IA se usa más? | Analytics Engine |
| ¿Cuántas visitas tengo y de dónde? | Web Analytics |
| ¿Me entero si algo se rompe? | Monitors y Platform Notifications |
Activar logs y trazas
{ "observability": { "enabled": true, "head_sampling_rate": 1, "traces": { "enabled": true, "head_sampling_rate": 0.1 } }}head_sampling_rate es la proporción de peticiones que se registran (1 = todas). Las trazas cubren automáticamente las llamadas a fetch y a los bindings (D1, KV, R2, Durable Objects) sin cambiar el código.
Logs que se pueden consultar
Un log en JSON se puede filtrar y agrupar por cualquier campo en el Query Builder del panel. Uso un pequeño ayudante:
type Level = "info" | "warn" | "error";
export function log( level: Level, event: string, data: Record<string, unknown> = {},) { const line = { level, event, ...data }; if (level === "error") console.error(line); else if (level === "warn") console.warn(line); else console.log(line);}log("info", "note_created", { userId, noteId: note.id });log("error", "ai_failure", { userId, model, message: String(err) });| Workers Logs | Gratuito | Pago |
|---|---|---|
| Eventos | 200.000 al día | 20 M al mes incluidos; 0,60 $ por millón más |
| Retención | 3 días | 7 días |
| Tamaño máximo por log | 256 KB | 256 KB |
Issues: errores agrupados
Issues detecta errores que se repiten en tus Workers, los agrupa (un error que pasa 500 veces es una sola incidencia) y puede enviarlos a un webhook, a un chat o a una herramienta de incidencias. Es lo más parecido a un Sentry integrado y es lo primero que miro cada mañana.
Más allá: Tail Workers, Logpush y OpenTelemetry
| Necesidad | Opción |
|---|---|
| Filtrar o transformar logs con tu código (quitar datos, enviar solo errores) | Tail Worker: un Worker que recibe los eventos de otro |
| Guardar logs más de 7 días, en R2 o S3 | Logpush (plan de pago) |
| Usar Grafana, Honeycomb, Datadog… | Exportación OpenTelemetry de logs y trazas |
Métricas propias con Analytics Engine
Para métricas de negocio (“notas creadas por día”, “preguntas a la IA por usuario”) uso Workers Analytics Engine: escribir un punto no bloquea la respuesta y admite muchísimos valores distintos (alta cardinalidad), algo que en D1 sería caro.
{ "analytics_engine_datasets": [ { "binding": "METRICS", "dataset": "notes_events" } ]}export function track( env: Env, event: string, userId: string, value = 1,) { env.METRICS.writeDataPoint({ indexes: [userId], // sampling key blobs: [event], doubles: [value], });}Se consulta con SQL a través de la API (con un token de solo lectura de Analytics):
SELECT toStartOfDay(timestamp) AS day, SUM(_sample_interval * double1) AS totalFROM notes_eventsWHERE blob1 = 'note_created' AND timestamp > NOW() - INTERVAL '30' DAYGROUP BY dayORDER BY dayVisitas sin cookies: Web Analytics
Web Analytics cuenta visitas, páginas, países y rendimiento real (Core Web Vitals) con un script pequeño y sin cookies, así que no necesitas banner de consentimiento. Se activa en Analytics & Logs › Web Analytics y se pega el script con su token en el layout. Es lo que uso en este blog.
Alertas: enterarte antes que tus usuarios
En Observability › Alerts hay dos tipos:
| Tipo | Qué es | Ejemplos |
|---|---|---|
| Monitors | Una consulta SQL que se ejecuta con un horario y avisa por umbral, anomalía o SLO | “Más de 50 errores en 5 minutos”, “La latencia p95 de /api supera 800 ms” |
| Platform Notifications | Avisos ya hechos de cada producto | Facturación, certificados SSL, ataques DDoS, health checks |
Los avisos llegan por email o webhook en todos los planes (PagerDuty requiere un plan Business). Mi mínimo en cada proyecto:
- Un monitor de tasa de errores del Worker.
- Las notificaciones de facturación, para enterarme si el uso se dispara.
- Las de certificados del dominio.
- Un monitor externo de disponibilidad (un servicio gratuito que haga
GET /api/healthcada minuto) que no dependa de Cloudflare.
Así quedan conectados en mis proyectos:
flowchart LR
E[Monitor de tasa de errores] --> A[Alerta]
F[Notificación de facturación] --> A
C[Notificación de certificados] --> A
X[Monitor externo<br/>de disponibilidad] --> A
A -->|correo o webhook| T[Tú]
Cuánto cuesta
Cuánto cuesta al mes
Supuestos: 5 M de peticiones al mes con logs al 100 % (unos 10 M de eventos), trazas al 10 % y Web Analytics
| Concepto | Importe |
|---|---|
| Workers Logs10 M de eventos: dentro de los 20 M incluidos (tarifa hasta el 30/11/2026) | 0,00 $ |
| Web AnalyticsGratis | 0,00 $ |
| Alertas por email y webhookTodos los planes | 0,00 $ |
| Total al mes | 0,00 $ |
Precios consultados el 3 de noviembre de 2026. Pueden cambiar.
Resumen
observability.enableddesde el primer despliegue; logs en JSON.- Issues para los errores, Analytics Engine para las métricas, Web Analytics para las visitas.
- Monitores de errores y avisos de facturación desde el día uno.
- Siguiente capítulo: costes y escalado.
