Skip to content

Commit 231c3c1

Browse files
authored
Merge pull request mouredev#4785 from isilanes/reto-025
#25 - Python
2 parents f5b992f + 3b54426 commit 231c3c1

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import logging
2+
import os
3+
import re
4+
from datetime import datetime
5+
6+
LOGFILE = "isilanes.log"
7+
8+
9+
def get_logger(name: str) -> logging.Logger:
10+
logger = logging.getLogger(name)
11+
12+
# Fijamos el nivel mínimo de logs a DEBUG:
13+
logger.setLevel(logging.DEBUG)
14+
15+
# Console handler (salida a pantalla):
16+
handler = logging.StreamHandler()
17+
handler.setLevel(logging.DEBUG)
18+
19+
# Formateador para consola:
20+
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
21+
handler.setFormatter(formatter)
22+
23+
# Añadir el console handler al logger:
24+
logger.addHandler(handler)
25+
26+
# File handler (salida a fichero):
27+
handler = logging.FileHandler(filename=LOGFILE)
28+
handler.setLevel(logging.WARNING)
29+
30+
# Formateador para fichero:
31+
formatter = logging.Formatter('%(asctime)s:%(name)s:%(levelname)s:%(message)s')
32+
handler.setFormatter(formatter)
33+
34+
# Añadir el console handler al logger:
35+
logger.addHandler(handler)
36+
37+
return logger
38+
39+
40+
def get_logger_extra(filename: str) -> logging.Logger:
41+
logger = logging.getLogger("TaskManager")
42+
43+
logger.setLevel(logging.DEBUG)
44+
handler = logging.FileHandler(filename=filename)
45+
formatter = logging.Formatter('%(asctime)s|%(name)s|%(levelname)s|%(message)s')
46+
handler.setFormatter(formatter)
47+
logger.addHandler(handler)
48+
49+
return logger
50+
51+
52+
log = get_logger(__name__)
53+
54+
55+
class TaskManager:
56+
log_filename = "task_manager.log"
57+
log = get_logger_extra(log_filename)
58+
59+
def __init__(self):
60+
self.tasks = {}
61+
62+
def contains(self, name: str) -> bool:
63+
return name in self.tasks
64+
65+
def add(self, name: str, description: str) -> None:
66+
if self.contains(name):
67+
self.log.warning(
68+
"Pasamos de añadir la tarea '%s', porque ya existe en TaskManager.",
69+
name,
70+
)
71+
return
72+
73+
self.tasks[name] = description
74+
self.log.info("La tarea '%s' fue añadida al TaskManager", name)
75+
76+
def remove(self, name: str) -> None:
77+
if not self.contains(name):
78+
self.log.warning("No podemos eliminar la tarea '%s', puesto que no existe.", name)
79+
return
80+
81+
del self.tasks[name]
82+
self.log.info("La tarea '%s' fue eliminada del TaskManager", name)
83+
84+
def list(self) -> None:
85+
print("Lista de tareas pendientes:")
86+
for i, (task, desc) in enumerate(self.tasks.items()):
87+
print(f" {i+1:2d} - {task}: {desc}")
88+
89+
def summary(self) -> None:
90+
"""
91+
Nótese que parsear el log de esta manera es frágil, y podría ser buena
92+
idea usar algún tipo de log estructurado.
93+
"""
94+
tasks = {}
95+
if not os.path.exists(self.log_filename):
96+
self.log.info("No hay log disponible.")
97+
return
98+
99+
with open(self.log_filename, "r", encoding="utf-8") as f:
100+
for line in f:
101+
fields = line.split("|")
102+
if len(fields) != 4:
103+
continue
104+
105+
ts = fields[0]
106+
try:
107+
t = datetime.strptime(ts, "%Y-%m-%d %H:%M:%S,%f")
108+
except ValueError:
109+
continue
110+
111+
msg = fields[-1]
112+
patt = re.compile(r"'(?P<task>\w+)'")
113+
match = patt.search(msg)
114+
115+
if not match:
116+
continue
117+
118+
task = match.group("task")
119+
120+
if task not in tasks:
121+
tasks[task] = {"start": None, "end": None}
122+
123+
if "fue añadida" in line:
124+
tasks[task]["start"] = t
125+
elif "fue eliminada" in line:
126+
tasks[task]["end"] = t
127+
else:
128+
continue
129+
130+
now = datetime.now()
131+
for i, (task, data) in enumerate(tasks.items()):
132+
start: datetime = data.get("start")
133+
if not start:
134+
continue
135+
136+
end = data.get("end")
137+
if end:
138+
dt_ms = (end - start).total_seconds() * 1000 # noqa
139+
print(f" {i:2d} - {task}: ha durado {dt_ms:.2f} ms.")
140+
else:
141+
dt_ms = (now - start).total_seconds() * 1000 # noqa
142+
print(f" {i:2d} - {task}: aún no ha terminado. Lleva {dt_ms:.2f} ms desde que se añadió.")
143+
144+
145+
def main():
146+
print("===== MAIN =====")
147+
who = "Iñaki"
148+
log.debug(
149+
"Hemos configurado el logger para usar loguear por pantalla todo, y por fichero todo"
150+
" lo que sea WARNING o más grave."
151+
)
152+
log.debug(
153+
"Mencionar que los formatos del mensaje en fichero y por pantalla pueden configurarse"
154+
" por separado (y lo hemos hecho)."
155+
)
156+
log.debug("%s, un mensaje de nivel DEBUG sólo saldrá por pantalla", who)
157+
log.info("%s, un mensaje de nivel INFO sólo saldrá por pantalla", who)
158+
log.warning(
159+
"%s, un mensaje de nivel WARNING saldrá por pantalla y también irá a fichero (%s)",
160+
who,
161+
LOGFILE,
162+
)
163+
log.error(
164+
"%s, un mensaje de nivel ERORR saldrá por pantalla y también irá a fichero (%s)",
165+
who,
166+
LOGFILE,
167+
)
168+
log.critical(
169+
"%s, un mensaje de nivel ERROR saldrá por pantalla y también irá a fichero (%s)",
170+
who,
171+
LOGFILE,
172+
)
173+
174+
175+
def extra():
176+
print("\n===== EXTRA =====")
177+
print("Inicializamos el gestor de tareas:")
178+
print('>>> tm = TaskManager()')
179+
tm = TaskManager()
180+
181+
print("\nAñadimos tareas:")
182+
print('>>> tm.add(name="fregar", description="Fregar los platos")')
183+
print('>>> tm.add(name="leer", description="Dedicar un rato a leer un libro")')
184+
tm.add(name="fregar", description="Fregar los platos")
185+
tm.add(name="leer", description="Dedicar un rato a leer un libro")
186+
187+
print("\nHemos configurado TaskManager para que esas acciones sólo guarden log a fichero.")
188+
print("Podemos listar las tareas activas (esto no guarda log, y sólo imprime por pantalla):")
189+
print('>>> tm.list()')
190+
tm.list()
191+
192+
print("\nSi intentamos añadir una tarea repetida, será ignorada (y un aviso añadido al log):")
193+
print('>>> tm.add(name="fregar", description="Quiero fregar más")')
194+
tm.add(name="fregar", description="Quiero fregar más")
195+
print('>>> tm.list()')
196+
tm.list()
197+
198+
print("\nPodemos eliminar una tarea:")
199+
print('>>> tm.remove(name="fregar")')
200+
tm.remove(name="fregar")
201+
print('>>> tm.list()')
202+
tm.list()
203+
204+
print("\nIntentar eliminar una tarea no existente no hará nada (y guardará aviso en log):")
205+
print('>>> tm.remove(name="bailar")')
206+
tm.remove(name="bailar")
207+
print('>>> tm.list()')
208+
tm.list()
209+
210+
print("\nImprimimos un resumen de las tareas añadidas:")
211+
print('>>> tm.summary()')
212+
tm.summary()
213+
214+
215+
if __name__ == "__main__":
216+
main()
217+
extra()

0 commit comments

Comments
 (0)