Nombre del servicio directo en el logger
This commit is contained in:
+38
-44
@@ -3,11 +3,13 @@ import json
|
|||||||
import requests
|
import requests
|
||||||
from typing import Optional, Dict, Any
|
from typing import Optional, Dict, Any
|
||||||
|
|
||||||
|
|
||||||
class LokiLogger:
|
class LokiLogger:
|
||||||
"""
|
"""
|
||||||
Logger compatible con Grafana Loki / Alloy.
|
Logger compatible con Grafana Loki / Alloy.
|
||||||
Envía logs en formato JSON a través del endpoint HTTP de Loki.
|
Envía logs en formato JSON a través del endpoint HTTP de Loki.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOWED_LEVELS = (
|
ALLOWED_LEVELS = (
|
||||||
"TRACE",
|
"TRACE",
|
||||||
"DEBUG",
|
"DEBUG",
|
||||||
@@ -24,25 +26,29 @@ class LokiLogger:
|
|||||||
endpoint: str = "http://127.0.0.1:3101/loki/api/v1/push",
|
endpoint: str = "http://127.0.0.1:3101/loki/api/v1/push",
|
||||||
default_labels: Optional[Dict[str, str]] = None,
|
default_labels: Optional[Dict[str, str]] = None,
|
||||||
timeout: float = 5.0,
|
timeout: float = 5.0,
|
||||||
min_level: str = "DEBUG"
|
min_level: str = "DEBUG",
|
||||||
|
service_name: Optional[str] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
:param endpoint: URL completa del endpoint de Loki / Alloy.
|
:param endpoint: URL completa del endpoint de Loki / Alloy.
|
||||||
:param default_labels: etiquetas estáticas por defecto para todos los logs,
|
:param default_labels: etiquetas estáticas comunes (ej: {"env": "dev"})
|
||||||
ej: {"job": "my-service", "env": "prod"}
|
|
||||||
:param timeout: timeout en segundos para la petición HTTP
|
:param timeout: timeout en segundos para la petición HTTP
|
||||||
:param min_level: nivel mínimo para enviar logs. Ej: "INFO" solo enviará INFO o más graves.
|
:param min_level: nivel mínimo para enviar logs
|
||||||
|
:param service_name: nombre del servicio (se usará también como 'job')
|
||||||
"""
|
"""
|
||||||
self.endpoint = endpoint
|
self.endpoint = endpoint
|
||||||
self.default_labels = default_labels or {}
|
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
|
self.service_name = service_name or "unknown-service"
|
||||||
|
|
||||||
min_level = min_level.upper()
|
min_level = min_level.upper()
|
||||||
if min_level not in self.ALLOWED_LEVELS:
|
if min_level not in self.ALLOWED_LEVELS:
|
||||||
raise ValueError(f"min_level debe estar en {self.ALLOWED_LEVELS}")
|
raise ValueError(f"min_level debe estar en {self.ALLOWED_LEVELS}")
|
||||||
self.min_level = min_level
|
self.min_level = min_level
|
||||||
|
|
||||||
# Asigna prioridad (menor valor = más detallado)
|
# Base labels: incluye el job automáticamente
|
||||||
|
self.default_labels = dict(default_labels or {})
|
||||||
|
self.default_labels["job"] = self.service_name
|
||||||
|
|
||||||
self._level_order = {
|
self._level_order = {
|
||||||
"TRACE": 0,
|
"TRACE": 0,
|
||||||
"DEBUG": 1,
|
"DEBUG": 1,
|
||||||
@@ -66,15 +72,11 @@ class LokiLogger:
|
|||||||
self,
|
self,
|
||||||
level: str,
|
level: str,
|
||||||
message: str,
|
message: str,
|
||||||
service: str,
|
|
||||||
labels: Optional[Dict[str, str]] = None,
|
labels: Optional[Dict[str, str]] = None,
|
||||||
metadata: Optional[Dict[str, Any]] = None
|
metadata: Optional[Dict[str, Any]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""Envía un log a Loki con los campos mínimos + metadata opcional."""
|
||||||
Envía un log a Loki con los campos mínimos + metadata opcional.
|
|
||||||
"""
|
|
||||||
level = level.upper()
|
level = level.upper()
|
||||||
# Soporte retroactivo
|
|
||||||
if level == "WARNING":
|
if level == "WARNING":
|
||||||
level = "WARN"
|
level = "WARN"
|
||||||
|
|
||||||
@@ -82,70 +84,62 @@ class LokiLogger:
|
|||||||
raise ValueError(f"Nivel no válido: {level}. Debe estar en {self.ALLOWED_LEVELS}")
|
raise ValueError(f"Nivel no válido: {level}. Debe estar en {self.ALLOWED_LEVELS}")
|
||||||
|
|
||||||
if not self._should_log(level):
|
if not self._should_log(level):
|
||||||
return # No enviar porque está por debajo del umbral
|
return
|
||||||
|
|
||||||
# Combinar etiquetas
|
# Combinar etiquetas
|
||||||
final_labels = dict(self.default_labels)
|
final_labels = dict(self.default_labels)
|
||||||
if labels:
|
if labels:
|
||||||
final_labels.update(labels)
|
final_labels.update(labels)
|
||||||
|
|
||||||
# Payload base
|
|
||||||
payload_metadata = {
|
payload_metadata = {
|
||||||
"service": service,
|
"service": self.service_name,
|
||||||
"level": level
|
"level": level,
|
||||||
}
|
}
|
||||||
if metadata:
|
if metadata:
|
||||||
payload_metadata.update(metadata)
|
payload_metadata.update(metadata)
|
||||||
|
|
||||||
# Construir línea JSON
|
|
||||||
log_line = json.dumps({
|
log_line = json.dumps({
|
||||||
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
||||||
"message": message,
|
"message": message,
|
||||||
**payload_metadata
|
**payload_metadata,
|
||||||
})
|
})
|
||||||
|
|
||||||
body = {
|
body = {
|
||||||
"streams": [
|
"streams": [
|
||||||
{
|
{"stream": final_labels, "values": [[self._current_ns(), log_line]]}
|
||||||
"stream": final_labels,
|
|
||||||
"values": [
|
|
||||||
[self._current_ns(), log_line]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Enviar al endpoint Loki
|
|
||||||
try:
|
try:
|
||||||
resp = requests.post(self.endpoint, json=body, timeout=self.timeout)
|
resp = requests.post(self.endpoint, json=body, timeout=self.timeout)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to send log to Loki: {e}", flush=True)
|
print(f"Failed to send log to Loki: {e}", flush=True)
|
||||||
|
|
||||||
# Métodos por nivel estándar
|
# Métodos estándar por nivel
|
||||||
def trace(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def trace(self, message, labels=None, metadata=None):
|
||||||
self.log("TRACE", message, service, labels, metadata)
|
self.log("TRACE", message, labels, metadata)
|
||||||
|
|
||||||
def debug(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def debug(self, message, labels=None, metadata=None):
|
||||||
self.log("DEBUG", message, service, labels, metadata)
|
self.log("DEBUG", message, labels, metadata)
|
||||||
|
|
||||||
def info(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def info(self, message, labels=None, metadata=None):
|
||||||
self.log("INFO", message, service, labels, metadata)
|
self.log("INFO", message, labels, metadata)
|
||||||
|
|
||||||
def warn(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def warn(self, message, labels=None, metadata=None):
|
||||||
self.log("WARN", message, service, labels, metadata)
|
self.log("WARN", message, labels, metadata)
|
||||||
|
|
||||||
def warning(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def warning(self, message, labels=None, metadata=None):
|
||||||
self.log("WARN", message, service, labels, metadata)
|
self.log("WARN", message, labels, metadata)
|
||||||
|
|
||||||
def error(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def error(self, message, labels=None, metadata=None):
|
||||||
self.log("ERROR", message, service, labels, metadata)
|
self.log("ERROR", message, labels, metadata)
|
||||||
|
|
||||||
def fatal(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def fatal(self, message, labels=None, metadata=None):
|
||||||
self.log("FATAL", message, service, labels, metadata)
|
self.log("FATAL", message, labels, metadata)
|
||||||
|
|
||||||
def critical(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def critical(self, message, labels=None, metadata=None):
|
||||||
self.log("CRITICAL", message, service, labels, metadata)
|
self.log("CRITICAL", message, labels, metadata)
|
||||||
|
|
||||||
def unknown(self, message: str, service: str, labels: Optional[Dict[str, str]] = None, metadata: Optional[Dict[str, Any]] = None):
|
def unknown(self, message, labels=None, metadata=None):
|
||||||
self.log("UNKNOWN", message, service, labels, metadata)
|
self.log("UNKNOWN", message, labels, metadata)
|
||||||
|
|||||||
Reference in New Issue
Block a user