@@ -571,36 +571,50 @@ async def get_logs(update: Update, context: ContextTypes.DEFAULT_TYPE):
571571
572572 try :
573573 from google .cloud import logging as gcp_logging
574- import html
574+ import json
575+ import io
575576
576577 await update .message .reply_text ("Buscando errores en Google Cloud Logging..." )
577578 client = gcp_logging .Client ()
578579
579580 # Query logs for the cloud_run_revision with severity>=ERROR
580581 filter_str = 'resource.type="cloud_run_revision" AND severity>=ERROR AND resource.labels.service_name="dcubabot"'
581- entries = client .list_entries (filter_ = filter_str , order_by = gcp_logging .DESCENDING , max_results = 10 )
582+ entries = client .list_entries (filter_ = filter_str , order_by = gcp_logging .DESCENDING , max_results = 50 )
582583
583584 log_msgs = []
584585 for entry in entries :
585- # GCP logs can have payload in text_payload or json_payload
586+ # Prepare a structured dictionary for each log entry
587+ log_data = {
588+ "timestamp" : entry .timestamp .isoformat (),
589+ "severity" : entry .severity ,
590+ }
591+
586592 payload = entry .payload
587593 if isinstance (payload , dict ):
588- import json
589- payload = json .dumps (payload )
590- elif payload is None :
591- payload = str (entry .resource )
594+ log_data ["json_payload" ] = payload
595+ elif payload is not None :
596+ log_data ["text_payload" ] = str (payload )
597+ else :
598+ log_data ["resource" ] = str (entry .resource )
592599
593- log_msgs .append (f"[ { entry . timestamp . strftime ( '%Y-%m-%d %H:%M:%S' ) } ] { payload } " )
600+ log_msgs .append (log_data )
594601
595602 if not log_msgs :
596603 await update .message .reply_text ("✅ No se encontraron errores recientes en GCP." )
597604 return
598605
599- msg = "\n \n " .join (log_msgs )
600- # Split message if it's too long for Telegram (4096 chars limit)
601- for i in range (0 , len (msg ), 3800 ):
602- chunk = msg [i :i + 3800 ]
603- await update .message .reply_text (f"Últimos errores:\n <pre>{ html .escape (chunk )} </pre>" , parse_mode = ParseMode .HTML )
606+ # Convert list of dicts to a formatted JSON string
607+ logs_json_str = json .dumps (log_msgs , indent = 2 , ensure_ascii = False )
608+
609+ # Create an in-memory file
610+ file_obj = io .BytesIO (logs_json_str .encode ('utf-8' ))
611+ file_obj .name = f"gcp_error_logs_{ datetime .datetime .now ().strftime ('%Y%m%d_%H%M%S' )} .json"
612+
613+ await context .bot .send_document (
614+ chat_id = update .effective_chat .id ,
615+ document = file_obj ,
616+ caption = "Acá tenés el archivo con los últimos errores registrados en GCP 🕵️♂️"
617+ )
604618 except Exception as e :
605619 await update .message .reply_text (f"Error al leer logs (¿falta permiso roles/logging.viewer en la Service Account?): { e } " )
606620
0 commit comments