Pythonowe logowanie

Coś ostatnio dużo o Pythonie, ale jakoś tak wyszło. Jego siła leży w bibliotece standardowej i jednym z modułów się teraz zajmiemy:

import logging
logging.basicConfig(filename="log.txt", \
     format="%(asctime)s - %(levelname)s - %(message)s, \
     level=logging.DEBUG)

# no to coś zalogujmy
logging.info("piszemy do pliku log")

Konstrukcja %(coś)s odpowiada mniej więcej str(coś) i sporo osób tego używa. Dostajemy teraz plik log.txt z napisem 2016-02-08 18:45:01,622 – INFO – piszemy do pliku log. Proste, czytelne i na temat. Załóżmy teraz, że chcielibyśmy zalogować wyjątek. Utworzyłem plik plik.txt i zabrałem sobie prawa do zapisu. Ciekawe, co Python na to wymyśli:

try:
  plik = open("plik.txt", "w")
except:
  err = sys.exc_info() # zapisujemy komunikat błędu do zmienej
  logging.error("Nie można otworzyć pliku plik.txt do zapisu.")
  logging.error(str(err[1].args[0]) + " " + err[1].args[1])
  sys.exit()

Przedostatnia linijka jest dosyć tajemnicza. Python, jak to ma w zwyczaju, podaje komunikat błędu jako zagnieżdżoną listę. Zerowym elementem jest numer błędu, a pierwszym komunikat. Co teraz znajdzie się w log.txt?

2016-02-08 19:02:28,965 – ERROR – Nie można otworzyć pliku plik.txt do zapisu.
2016-02-08 19:02:28,966 – ERROR – 13 Permission denied

Znowu: proste, czytelne i na temat, czyli dokładnie to, co powinien zawierać log.
Na samym początku skryptu, przy funkcji basicConfig można ustawić szczegółowość logowania na poziomy DEBUG, INFO, WARNING, ERROR oraz CRITICAL. Można tu sprawdzić parametry podane przy uruchamianiu skryptu i ustawić jakąś wartość domyślną. Można zresztą wszystko, ale to już oddzielny temat.