Philip Withnall
philip.withnall@collabora.co.uk 2015

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.

Jako zvláštní výjimka se vám držitelem autorských práv uděluje svolení kopírovat, upravovat a šířit ukázkový kód obsažený v tomto dokumentu za podmínek, které si zvolíte, bez dalších omezení.

Ladicí záznamy a informační výstup z knihoven a programů

# Záznamy (log)

#

        Shrnutí

        Záznam ladicího a informačního výstupu z knihoven a programů je stále otevřený problém a existuje řada metod pro převod více datových proudů s výstupními záznamy do vlastních datových proudů stdout a stderr. Níže jsou uvedena některá doporučení, jak zaznamenávání implementovat. Nejdůležitější věcí ale je zajistit, aby záznamy byly konzistentní, takže k nim bude jednoduchý přístup a půjde v nich snadno vyhledávat, protože to je přesně to, k čemu slouží. Používat odlišné mechanizmy záznamu a odlišné formáty u různých projektů není ten pravý přístup.

          Místo záznamů přímo do stderr a stdout používejte framework GLib pro záznamy. ()
          Když může být projekt závislý na systemd, zvažte přímé použití záznamů v žurnálu. ()
          Neimplementujte rotaci a mazání záznamů. Ponechte to na systémových službách. ()

# Framework GLib pro záznamy

GLib poskytuje framework pro zaznamenávání, který je postavený na funkci `g_log()` spolu s obalujícími funkcemi `g_debug()`, `g_message()`, `g_warning()` a `g_error()` pro větší pohodlí. Tento framework má pár užitečných vlastností:

Programové přesměrování záznamu zpráv pomocí `g_log_set_handler()`.

Více domén záznamů, které mohou být zpracovány odděleně.

Více úrovní záznamů, které mohou být zpracovány odděleně. Například to umožňuje za běhu zapnout a vypnout ladicí zprávy.

Podpora pro automatické přerušení programu u „kritických“ zpráv.

Uvedeným postupům byste měli dát přednost před funkcemi jako jsou `printf()`, `g_print()` a `g_printerr()`, protože je to daleko flexibilnější. Funkce pro zaznamenávání umožňují provádět zaznamenávání přímo z kódu, namísto pomocí externích shellových skriptů, čímž se vše zjednoduší.

Klíčovým důvodem pro používání frameworku pro záznamy je, že jej používá GLib a ostatní související knihovny. Když jej budete používat i vy, půjdou všechny zprávy skrz ten samý systém a mohou být zpracovány podobně.

Když chcete používat framework GLib pro záznamy, definujte pro projekt jedinečnou `G_LOG_DOMAIN`, lišící se od ostatních projektů. Ladicí zprávu zaznamenáte zavoláním `g_debug("Zpráva")`.

V případě, že výchozí obsluha záznamů v GLib není dostačující, například když potřebujete zaznamenávané zprávy ve vlastním formátu nebo potřebujete integraci s journald, nastavte obsluhu záznamů pomocí následujícího kódu:

static const gchar * log_level_to_string (GLogLevelFlags level) { switch (level) { case G_LOG_LEVEL_ERROR: return "ERROR"; case G_LOG_LEVEL_CRITICAL: return "CRITICAL"; case G_LOG_LEVEL_WARNING: return "WARNING"; case G_LOG_LEVEL_MESSAGE: return "MESSAGE"; case G_LOG_LEVEL_INFO: return "INFO"; case G_LOG_LEVEL_DEBUG: return "DEBUG"; default: return "UNKNOWN"; } }

static void log_handler_cb (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data) { const gchar *log_level_str;

/* Když je vypnuto ladění, ignorovat ladicí zprávy. */ if (!debug_enabled && (log_level & G_LOG_LEVEL_DEBUG)) { return; }

log_level_str = log_level_to_string (log_level & G_LOG_LEVEL_MASK);

/* Použít g_printerr() pro varování a g_print() v ostatních případech. */ if (flags <= G_LOG_LEVEL_WARNING) { g_printerr ("%s: %s: %s\n", log_domain, log_level_str, message); } else { g_print ("%s: %s: %s\n", log_domain, log_level_str, message); } }

g_log_set_handler ("log-domain", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, log_handler_cb, NULL);

## Výjimky

Nepoužívejte `g_message()` v normálním kódu k výpisům. Výpisy by se měly dělat jen v nejvyšší úrovni aplikace pomocí `g_print()` a měly by být jen zřídkavé, tj. prováděné jen v aplikacích pro příkazový řádek.

Nepoužívejte `g_warning()` v programovém kódu knihoven. Místo toho použijte `GError`.

Obdobně, nenastavujte obsluhu záznamů v kódu knihovny. Zprávy do záznamu by měly být propagovány z kódu knihovny ven a obslouženy v obsluze záznamu v nejvyšší úrovni aplikace.

# Integrace journald

Ve srovnání s tradičními záznamy ve stylu syslog, journald podporuje ukládání záznamů ve strukturované podobě, co usnadňuje následnou analýzu záznamů. Můžete přidat `systemd-journal` jako závislost do svého projektu a jako funkce pro obsluhu záznamů pak můžete použít `sd_journal_print()` a `sd_journal_send()`, na místo `g_print()` a `g_printerr()`.

Další informace najdete v tomto článku o záznamu do žurnálu.

# Rotování záznamů

Rotování záznamů je jedna z funkcí, která jde mimo rozsah systému záznamů v GLib. Mělo by být obsluhováno normálním mechanizmem systému záznamů, jako je logrotate nebo systemd-journald.