Problema

En arquitecturas compuestas por Azure Functions, Cosmos DB, Service Bus, LLMs y callbacks externos, la visibilidad de una solicitud completa suele fragmentarse. Cada componente escribe en su propio espacio de logging y, aunque todos comparten un identificador de ejecución (por ejemplo execution_id), los ingenieros deben abrir varios recursos de Application Insights, buscar en tablas de Log Analytics y correlacionar manualmente los eventos. El resultado es:

  • tiempos de diagnóstico de 20‑40 minutos,
  • ejecuciones que quedan “atascadas” en el Change Feed o en colas,
  • fallos de callbacks que no se detectan hasta que el cliente reclama,
  • falta de contexto para determinar si el problema es global, por tenant o por tipo de petición.

Este patrón se repite en cualquier pipeline serverless donde varios servicios Azure interactúan y donde la latencia de los componentes externos (LLM, APIs de terceros) es variable.

Causa

  1. Instrumentación aislada – Cada Function App, cada instancia de Cosmos DB y cada listener de Service Bus envía datos a un recurso de Application Insights distinto. Sin una política de “single source of truth”, los logs no se pueden unir automáticamente.

  2. Ausencia de correlación explícita – El execution_id se pasa como header, pero no se registra como operation_Id ni como customDimensions en todos los puntos de la cadena. Los logs aparecen en diferentes tablas (AppTraces, AzureDiagnostics, ServiceBusLogs) sin una clave común.

  3. Monitoreo reactivo – Las alertas se crean sobre métricas aisladas (p.ej. “queue length > X”) sin considerar el flujo completo. Un mensaje que termina en la dead‑letter se pierde si no hay un alert que lo relacione con la ejecución original.

  4. Costos y retención limitados – En entornos con alto volumen, se reduce la retención de logs para ahorrar dinero, lo que elimina la pista histórica necesaria para investigar incidentes que aparecen horas después.

  5. Dependencias externas no observables – LLM keys, llamadas a Salesforce o a APIs de terceros no exponen métricas de salud en Azure, por lo que cualquier fallo se refleja solo como un error genérico en la Function que los invocó.

Solución

1. Unificar la fuente de datos

  • Crear un único Workspace de Log Analytics y conectar todos los recursos de Application Insights a él (Workspace-based Application Insights).
  • Configurar cada Function App para que use la misma instrumentationKey o, mejor, la misma connectionString del Workspace.
  • En Cosmos DB y Service Bus habilitar la exportación de logs a Log Analytics (Diagnostic Settings → Send to Log Analytics workspace).

2. Propagar y registrar el execution_id

  • En la capa de API que inicia la solicitud, generar un GUID (execution_id) y enviarlo como header x-execution-id.
  • En cada Function, leer el header y asignarlo a:
    telemetry.Context.Operation.Id = executionId;          // para correlación automática
    telemetry.Properties["execution_id"] = executionId;   // para búsquedas ad‑hoc
    
  • En los clientes de Cosmos DB y Service Bus, añadir el mismo execution_id a customProperties de los mensajes o a los requestOptions de las operaciones.

3. Modelar el flujo en Log Analytics

Con los datos centralizados, usar una única consulta Kusto que una todas las tablas por execution_id:

let exec = "INSERT_EXECUTION_ID_AQUI";
union
    (AppTraces | where customDimensions.execution_id == exec),
    (AzureDiagnostics | where properties_s.execution_id == exec),
    (ServiceBusLogs | where customDimensions.execution_id == exec),
    (CosmosDBRequests | where customDimensions.execution_id == exec)
| order by timestamp asc

Esta vista muestra, en orden cronológico, cada paso: entrada HTTP, escritura en Cosmos, evento en Change Feed, mensaje en Service Bus, llamada a LLM, callback a Salesforce y estado final.

4. Dashboards con Azure Workbooks

Crear un Workbook que reciba execution_id como parámetro y renderice:

  • Timeline de eventos (gráfico de líneas con marcas de cada componente).
  • Resumen de salud: número de retries, throttles de Cosmos, tiempo de espera de LLM, estado del callback.
  • Métricas de colas: profundidad, dead‑letter count, edad del mensaje más antiguo.

Los Workbooks pueden exportarse como enlaces compartidos o incrustarse en Teams para acceso rápido.

5. Alertas basadas en el flujo completo

En lugar de alertas aisladas, definir alertas de correlación:

Condición Acción
ServiceBusDeadLetterMessages > 0 y customDimensions.execution_id presente Enviar notificación a Action Group con link al Workbook filtrado por ese execution_id.
CosmosDBThrottledRequests > 0 durante 5 min Crear ticket automático y adjuntar query de logs.
LLMKeyCooldown = true y failureRate > 5 % Desactivar key mediante Azure Automation runbook.
CallbackStatus = Failed y retryCount = 0 Reintentar vía runbook o escalar a soporte.

Las alertas se configuran en Azure Monitor → Alerts → New alert rule → Log query con la misma unión Kusto anterior, filtrando por los criterios específicos.

6. Runbooks para respuesta rápida

Implementar Azure Automation o Azure Functions “runbooks” que:

  • Re‑procesen mensajes en dead‑letter (az servicebus queue deadletter receive).
  • Re‑inicien el Change Feed listener (az functionapp restart).
  • Roten la clave LLM cuando se detecte cooldown (az openai key rotate).
  • Re‑envíen callbacks fallidos mediante una llamada HTTP con el payload original.

Los runbooks deben recibir como parámetro el execution_id y registrar su propia traza en Application Insights para cerrar el ciclo.

7. Opcional: Grafana para vistas ejecutivas

Si el equipo necesita dashboards de alta estética o integración con otras fuentes (Prometheus, Grafana Cloud), conectar Grafana a Azure Monitor mediante el plugin oficial. Mantener la lógica de correlación en Azure (queries Kusto) y usar Grafana solo para visualización.

Cuándo aplicar esta solución

  • Síntomas: diagnóstico > 15 min, mensajes en dead‑letter sin explicación, ejecuciones “stuck” en Change Feed, callbacks que fallan sin registro visible.
  • Entorno: pipelines serverless con al menos dos Azure Functions, Cosmos DB, Service Bus y llamadas a servicios externos (LLM, APIs).
  • No aplica: sistemas monolíticos donde todos los logs ya están en un único archivo, o entornos con requerimientos de compliance que impiden centralizar logs fuera de la suscripción.

Código

# Crear Workspace único
az monitor log-analytics workspace create \
  --resource-group rg-observability \
  --workspace-name obs-workspace \
  --location eastus

# Vincular Application Insights existente al Workspace
az monitor app-insights component update \
  --app insights-name \
  --resource-group rg-observability \
  --workspace-id $(az monitor log-analytics workspace show \
    --resource-group rg-observability \
    --workspace-name obs-workspace \
    --query id -o tsv)

# Configurar diagnóstico de Service Bus
az monitor diagnostic-settings create \
  --name sb-diag \
  --resource /subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-observability/providers/Microsoft.ServiceBus/namespaces/sb-namespace \
  --workspace $(az monitor log-analytics workspace show \
    --resource-group rg-observability \
    --workspace-name obs-workspace \
    --query id -o tsv) \
  --logs '[{"category":"OperationalLogs","enabled":true}]'

Verificación

  1. Ejecutar una solicitud de prueba que incluya un execution_id único.
  2. En Log Analytics, lanzar la query de unión con ese execution_id. Deben aparecer registros de:
    • HTTP trigger,
    • escritura en Cosmos,
    • mensaje en Service Bus,
    • respuesta de LLM,
    • callback a Salesforce.
  3. Simular un fallo (p.ej. desconectar temporalmente el endpoint de Salesforce) y confirmar que la alerta de “Callback failure” se dispara y que el Workbook muestra el estado Failed.
  4. Ejecutar el runbook de re‑envío y validar que el mismo execution_id vuelve a aparecer con estado Success.

Notas adicionales

  • Retención: al menos 30 días en Log Analytics para poder investigar incidentes tardíos; ajusta el costo mediante políticas de archivado a Blob Storage.
  • Ingestión: habilitar sampling en Application Insights solo si el volumen supera varios cientos de miles de eventos por minuto; de lo contrario, registrar todo para evitar huecos de correlación.
  • Latencia: los logs de Service Bus pueden tardar hasta 2 min en aparecer; las alertas deben considerar este retardo para evitar falsos positivos.
  • Seguridad: el execution_id puede contener datos sensibles del cliente; marcarlo como PII en la política de retención si corresponde.
  • Escalabilidad: si la carga crece, dividir el Workspace por entorno (dev, prod) y usar Azure Monitor Cross‑Workspace queries para consolidar vistas sin mezclar datos.