Loggning¶
Se även
loggning - hur man gör
Python-programmerare använder ofta print()
i sin kod som ett snabbt och bekvämt felsökningsverktyg. Att använda loggningsramverket är bara lite mer ansträngande än så, men det är mycket mer elegant och flexibelt. Förutom att vara användbart för felsökning kan loggning också ge dig mer - och bättre strukturerad - information om tillståndet och hälsan i din applikation.
Översikt¶
Django använder och utökar Pythons inbyggda modul logging
för att utföra systemloggning. Denna modul diskuteras i detalj i Pythons egen dokumentation; detta avsnitt ger en snabb överblick.
De medverkande spelarna¶
En Python-loggningskonfiguration består av fyra delar:
ämne-loggning-delar-loggare
topic-logging-parts-filter
Loggers¶
En logger är ingångspunkten till loggningssystemet. Varje logger är en namngiven hink till vilken meddelanden kan skrivas för bearbetning.
En logger är konfigurerad att ha en loggnivå. Denna loggnivå beskriver allvarlighetsgraden i de meddelanden som loggern kommer att hantera. Python definierar följande loggnivåer:
DEBUG
: Systeminformation på låg nivå för felsökningsändamålINFO
: Allmän systeminformationVARNING
: Information som beskriver ett mindre problem som har uppstått.ERROR
: Information som beskriver ett större problem som har uppstått.KRITISK
: Information som beskriver ett kritiskt problem som har uppstått.
Varje meddelande som skrivs till loggaren är en loggpost. Varje loggpost har också en loggnivå som anger allvarlighetsgraden för det specifika meddelandet. En loggpost kan också innehålla användbara metadata som beskriver den händelse som loggas. Det kan t.ex. vara en stackspårning eller en felkod.
När ett meddelande skickas till loggern jämförs loggnivån för meddelandet med loggnivån för loggern. Om meddelandets loggnivå är lika med eller högre än loggnivån för loggern själv, kommer meddelandet att behandlas vidare. Om den inte gör det ignoreras meddelandet.
När en logger har bestämt att ett meddelande behöver behandlas skickas det till en Handler.
Handläggare¶
Handlaren är den motor som avgör vad som händer med varje meddelande i en logger. Den beskriver ett visst loggningsbeteende, t.ex. att skriva ett meddelande till skärmen, till en fil eller till ett nätverkssocket.
Precis som loggar har även hanterare en loggnivå. Om loggnivån för en loggpost inte uppfyller eller överstiger nivån för hanteraren, ignorerar hanteraren meddelandet.
En logger kan ha flera hanterare och varje hanterare kan ha olika loggnivåer. På så sätt är det möjligt att tillhandahålla olika former av meddelanden beroende på hur viktigt ett meddelande är. Du kan t.ex. installera en hanterare som vidarebefordrar ERROR
- och CRITICAL
-meddelanden till en personsökningstjänst, medan en andra hanterare loggar alla meddelanden (inklusive ERROR
- och CRITICAL
-meddelanden) till en fil för senare analys.
Filter¶
Ett filter används för att ge ytterligare kontroll över vilka loggposter som skickas från logger till hanterare.
Som standard hanteras alla loggmeddelanden som uppfyller kraven för loggnivå. Genom att installera ett filter kan du dock lägga till ytterligare kriterier för loggningsprocessen. Du kan t.ex. installera ett filter som bara tillåter att ERROR
-meddelanden från en viss källa skickas ut.
Filter kan också användas för att ändra loggposten innan den sänds ut. Du kan t.ex. skriva ett filter som nedgraderar loggposter av typen ERROR
till WARNING
om en viss uppsättning kriterier uppfylls.
Filter kan installeras på loggrar eller på hanterare; flera filter kan användas i en kedja för att utföra flera filtreringsåtgärder.
Formatterare¶
I slutändan måste en loggpost återges som text. Formaterare beskriver det exakta formatet för den texten. En formaterare består vanligtvis av en Python-formateringssträng som innehåller LogRecord attributes; men du kan också skriva anpassade formaterare för att implementera ett specifikt formateringsbeteende.
Konsekvenser för säkerheten¶
Loggningssystemet hanterar potentiellt känslig information. Loggposten kan t.ex. innehålla information om en webbförfrågan eller ett stackspår, och en del av de data som du samlar in i dina egna loggar kan också ha säkerhetsimplikationer. Du måste vara säker på att du vet:
vilken information som samlas in
var den därefter kommer att förvaras
hur det kommer att överföras
som kan ha tillgång till den.
För att kontrollera insamlingen av känslig information kan du uttryckligen ange att viss känslig information ska filtreras bort från felrapporter – läs mer om hur du filtrerar felrapporter.
AdminEmailHandler
¶
Den inbyggda AdminEmailHandler
förtjänar ett omnämnande i säkerhetssammanhang. Om dess alternativ include_html
är aktiverat kommer e-postmeddelandet som skickas att innehålla en fullständig spårning, med namn och värden på lokala variabler på varje nivå i stacken, plus värdena på dina Django-inställningar (med andra ord samma detaljnivå som exponeras på en webbsida när DEBUG
är True
).
Det anses i allmänhet inte vara en bra idé att skicka sådan potentiellt känslig information via e-post. Överväg istället att använda en av de många tredjepartstjänster som detaljerade loggar kan skickas till för att få det bästa av flera världar - den rika informationen från fullständiga spårningar, tydlig hantering av vem som meddelas och har tillgång till informationen, och så vidare.
Konfigurera loggning¶
Pythons loggningsbibliotek tillhandahåller flera tekniker för att konfigurera loggning, allt från ett programmatiskt gränssnitt till konfigurationsfiler. Som standard använder Django dictConfig-formatet.
För att konfigurera loggning använder du LOGGING
för att definiera en ordlista med loggningsinställningar. Dessa inställningar beskriver de loggar, hanterare, filter och formatterare som du vill ha i din loggningskonfiguration, samt de loggnivåer och andra egenskaper som du vill att dessa komponenter ska ha.
Som standard slås inställningen LOGGING
samman med Djangos standardkonfiguration för loggning enligt följande schema.
Om nyckeln disable_existing_loggers
i dictConfig för LOGGING
är inställd på True
(vilket är standardvärdet för dictConfig
om nyckeln saknas) kommer alla loggar från standardkonfigurationen att inaktiveras. Inaktiverade loggrar är inte samma sak som borttagna; loggern kommer fortfarande att existera, men kommer i tysthet att kasta allt som loggas till den, inte ens sprida poster till en överordnad logger. Du bör därför vara mycket försiktig med att använda 'disable_existing_loggers': True
; det är förmodligen inte vad du vill. Istället kan du sätta disable_existing_loggers
till False
och omdefiniera några eller alla standardloggare; eller så kan du sätta LOGGING_CONFIG
till None
och :ref:``handle logging config yourself <disabling-logging-configuration>`.
Loggning konfigureras som en del av den allmänna Django setup()
-funktionen. Därför kan du vara säker på att loggar alltid är redo att användas i din projektkod.
Exempel¶
Den fullständiga dokumentationen för dictConfig format är den bästa källan till information om loggningskonfigurationsordböcker. Men för att ge dig en försmak av vad som är möjligt följer här några exempel.
Till att börja med följer här en liten konfiguration som gör att du kan mata ut alla loggmeddelanden till konsolen:
`ettings.py`
¶import os
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "WARNING",
},
}
Detta konfigurerar den överordnade root
-loggaren att skicka meddelanden med nivån WARNING
och högre till konsolhanteraren. Genom att justera nivån till INFO
eller DEBUG
kan du visa fler meddelanden. Detta kan vara användbart under utveckling.
Därefter kan vi lägga till mer finkornig loggning. Här är ett exempel på hur man får loggningssystemet att skriva ut fler meddelanden från bara den django som heter logger:
`ettings.py`
¶import os
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "WARNING",
},
"loggers": {
"django": {
"handlers": ["console"],
"level": os.getenv("DJANGO_LOG_LEVEL", "INFO"),
"propagate": False,
},
},
}
Som standard skickar den här konfigurationen meddelanden från django
-loggen på nivå INFO
eller högre till konsolen. Detta är samma nivå som Djangos standardkonfiguration för loggning, förutom att standardkonfigurationen endast visar loggposter när DEBUG=True
. Django loggar inte många sådana meddelanden på INFO
-nivå. Med denna konfiguration kan du dock också ställa in miljövariabeln DJANGO_LOG_LEVEL=DEBUG
för att se all Djangos felsökningsloggning som är mycket utförlig eftersom den inkluderar alla databasfrågor.
Du behöver inte logga till konsolen. Här är en konfiguration som skriver all loggning från django med namnet logger till en lokal fil:
`ettings.py`
¶LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"file": {
"level": "DEBUG",
"class": "logging.FileHandler",
"filename": "/path/to/django/debug.log",
},
},
"loggers": {
"django": {
"handlers": ["file"],
"level": "DEBUG",
"propagate": True,
},
},
}
Om du använder det här exemplet måste du ändra sökvägen för 'filnamn
till en plats som är skrivbar för den användare som kör Django-applikationen.
Slutligen, här är ett exempel på en ganska komplex loggningskonfiguration:
`ettings.py`
¶LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"verbose": {
"format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
"filters": {
"special": {
"()": "project.logging.SpecialFilter",
"foo": "bar",
},
"require_debug_true": {
"()": "django.utils.log.RequireDebugTrue",
},
},
"handlers": {
"console": {
"level": "INFO",
"filters": ["require_debug_true"],
"class": "logging.StreamHandler",
"formatter": "simple",
},
"mail_admins": {
"level": "ERROR",
"class": "django.utils.log.AdminEmailHandler",
"filters": ["special"],
},
},
"loggers": {
"django": {
"handlers": ["console"],
"propagate": True,
},
"django.request": {
"handlers": ["mail_admins"],
"level": "ERROR",
"propagate": False,
},
"myproject.custom": {
"handlers": ["console", "mail_admins"],
"level": "INFO",
"filters": ["special"],
},
},
}
Den här loggningskonfigurationen gör följande:
Identifierar konfigurationen som att den är i formatet ”dictConfig version 1”. För närvarande är detta den enda versionen av dictConfig-formatet.
Definierar två formatterare:
simple
, som matar ut namnet på loggnivån (t.ex.DEBUG
) och loggmeddelandet.Strängen
format
är en vanlig Python-formateringssträng som beskriver de detaljer som ska skrivas ut på varje loggningsrad. Den fullständiga listan över detaljer som kan matas ut finns i Formatter Objects.verbose
, som ger ut namnet på loggnivån, loggmeddelandet samt tid, process, tråd och modul som genererar loggmeddelandet.
Definierar två filter:
project.logging.SpecialFilter
, med aliasetspecial
. Om det här filtret kräver ytterligare argument kan de anges som ytterligare nycklar i filterkonfigurationsordlistan. I det här fallet kommer argumentetfoo
att ges värdetbar
närSpecialFilter
instansieras.django.utils.log.RequireDebugTrue
, som vidarebefordrar poster närDEBUG
ärTrue
.
Definierar två handläggare:
console
, enStreamHandler`
, som skriver ut valfrittINFO
(eller högre) meddelande tillsys.stderr
. Denna hanterare använder utdataformatetsimple
.mail_admins
, enAdminEmailHandler
, som e-postar allaERROR
(eller högre) meddelanden till webbplatsensADMINS
. Denna hanterare använder filtretspecial
.
Konfigurerar tre loggrar:
django
, som skickar alla meddelanden tillconsole
-hanteraren.django.request
, som skickar allaERROR
-meddelanden tillmail_admins
-hanteraren. Dessutom är denna logger markerad för att inte sprida meddelanden. Detta innebär att loggmeddelanden som skrivs tilldjango.request
inte kommer att hanteras av loggerndjango
.myproject.custom
, som skickar alla meddelanden påINFO
eller högre som också passerarspecial
-filtret till två hanterare –konsolen
ochmail_admins
. Detta innebär att alla meddelanden påINFO
-nivå (eller högre) skrivs ut till konsolen;ERROR
- ochCRITICAL
-meddelanden skickas också ut via e-post.
Anpassad konfiguration av loggning¶
Om du inte vill använda Pythons dictConfig-format för att konfigurera din logger kan du ange ditt eget konfigurationsschema.
Inställningen LOGGING_CONFIG
definierar den callable som ska användas för att konfigurera Djangos loggar. Som standard pekar den på Pythons funktion logging.config.dictConfig()
. Men om du vill använda en annan konfigurationsprocess kan du använda någon annan callable som tar ett enda argument. Innehållet i LOGGING
kommer att anges som värdet på det argumentet när loggning konfigureras.
Inaktivering av loggningskonfiguration¶
Om du inte vill konfigurera loggning alls (eller om du vill konfigurera loggning manuellt med din egen metod) kan du ställa in LOGGING_CONFIG
till None
. Detta kommer att inaktivera konfigurationsprocessen för Djangos standardloggning.
Om du ställer in LOGGING_CONFIG
till None
betyder det bara att den automatiska konfigurationsprocessen inaktiveras, inte själva loggningen. Om du inaktiverar konfigurationsprocessen kommer Django fortfarande att göra loggningsanrop och falla tillbaka till det standardloggningsbeteende som har definierats.
Här är ett exempel som inaktiverar Djangos loggningskonfiguration och sedan konfigurerar loggning manuellt:
`ettings.py`
¶LOGGING_CONFIG = None
import logging.config
logging.config.dictConfig(...)
Observera att standardkonfigurationsprocessen anropar LOGGING_CONFIG
först när inställningarna är helt laddade. Om du däremot konfigurerar loggningen manuellt i din inställningsfil laddas din loggningskonfiguration omedelbart. Därför måste din loggningskonfiguration visas efter alla inställningar som den är beroende av.