天天看點

5_02_GLib庫入門與實踐_日志和調試

簡介

GLib提供了一套日志輸出接口,包括不同日志級别的輸出以及與systemd日志系統的對接。

資料結構

日志輸出最主要的資料結構是日志級别。

GLib提供了debug、info、message、warning、critical和error這六種日志輸出級别。

其中,error預設是FATAL級别日志輸出,輸出該級别日志會調用abort()導緻程式退出。

enum GLogLevelFlags
           

函數清單

void 	g_log ()
void 	g_logv ()
#define 	g_message()
#define 	g_warning()
#define 	g_critical()
#define 	g_error()
#define 	g_info()
#define 	g_debug()
guint 	g_log_set_handler ()
guint 	g_log_set_handler_full ()
void 	g_log_remove_handler ()
GLogLevelFlags 	g_log_set_always_fatal ()
GLogLevelFlags 	g_log_set_fatal_mask ()
void 	g_log_default_handler ()
GLogFunc 	g_log_set_default_handler ()
void 	g_log_structured ()
void 	g_log_variant ()
void 	g_log_structured_array ()
#define 	G_DEBUG_HERE
GLogWriterOutput 	(*GLogWriterFunc) ()
void 	g_log_set_writer_func ()
gboolean 	g_log_writer_supports_color ()
gboolean 	g_log_writer_is_journald ()
gchar * 	g_log_writer_format_fields ()
GLogWriterOutput 	g_log_writer_journald ()
GLogWriterOutput 	g_log_writer_standard_streams ()
GLogWriterOutput 	g_log_writer_default ()
           

函數功能分類

// 日志輸出函數,g_logv接受valist變量
void 	g_log ()
void 	g_logv ()

// 不同的調試輸出日志函數
// 按級别排序:debug<info<message<warning<critical<error
#define 	g_message()
#define 	g_warning()
#define 	g_critical()
#define 	g_error()
#define 	g_info()
#define 	g_debug()

// 設定和取消自定義日志函數
guint 	g_log_set_handler ()
guint 	g_log_set_handler_full ()
void 	g_log_remove_handler ()

// 給參數中指定的輸出日志級别設定一個全局的fatal
// 如果設定了fatal,則在運作時,該日志輸出之後會調用到abort()繼而出現段錯誤。
// 預設情況下,隻有error級别的輸出,會導緻段錯誤
GLogLevelFlags 	g_log_set_always_fatal ()

// 與g_log_set_always_fatal相似,但隻對某一domain設定fatal,而非全局
GLogLevelFlags 	g_log_set_fatal_mask ()

// 設定預設輸出函數
void 	g_log_default_handler ()
GLogFunc 	g_log_set_default_handler ()

// 與systemd日志相關的結構化日志輸出函數
void 	g_log_structured ()
// 參數為泛型的結構化日志輸出函數
void 	g_log_variant ()
// 參數為數組的結構化日志輸出函數
void 	g_log_structured_array ()

// 設定寫函數
void 	g_log_set_writer_func ()
// 是否支援ANSI顔色轉義序列
gboolean 	g_log_writer_supports_color ()
// 判斷給定的檔案描述符是否與systemd日志檔案有關
gboolean 	g_log_writer_is_journald ()

// 将結構化日志輸出到systemd日志系統
GLogWriterOutput 	g_log_writer_journald ()
// 将結構化日志輸出到标準輸出stdout或标準錯誤輸出stderr
GLogWriterOutput 	g_log_writer_standard_streams ()
// 将結構化日志輸出到系統預設日志系統(一般是systemd),如果從終端運作或被重定向到檔案,則會輸出到标準輸出
GLogWriterOutput 	g_log_writer_default ()
           

函數功能說明及綜合示範

g_log函數用法示範

示例代碼如下:

源碼見

glib_examples\glib_log\glib_log_g_log

#include <glib.h>

static void my_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
    g_print("[%s]my_log_handler : %s \n",user_data,message);

}

gint main(gint argc, gchar **argv)
{
    g_log_set_default_handler(my_log_handler, "User_Data");

    g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);

    g_log ("foo", G_LOG_LEVEL_DEBUG, "6");
    g_log ("bar", G_LOG_LEVEL_DEBUG, "6");
    g_log ("baz", G_LOG_LEVEL_DEBUG, "6");

    return 0;
}
           

運作結果:

[[email protected]_6 build]# ./glib_log_g_log
[User_Data]my_log_handler : 6
[User_Data]my_log_handler : 6
[User_Data]my_log_handler : 6
           

不同級别的日志輸出

示例代碼如下:

源碼見

glib_examples\glib_log\glib_log_handler

#include <glib.h>

static void my_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
    g_print("[%s]my_log_handler : %s \n",user_data,message);

}
gint main(gint argc, gchar **argv)
{
    guint handler_id = 0;

    g_print("set handler: G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION \n");
    handler_id = g_log_set_handler(NULL, 
        G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION, my_log_handler, "APP_TAG");

    g_debug("debug");
    g_info("info");
    g_message("message");
    g_warning("warning");
    g_critical("critical");
    //g_error("error");

    g_log_remove_handler(NULL, handler_id);

    g_print("set handler: G_LOG_LEVEL_INFO|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION \n");

    handler_id = g_log_set_handler(NULL, 
        G_LOG_LEVEL_INFO|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION, my_log_handler, "APP_TAG");
    g_debug("debug");
    g_info("info");
    g_message("message");
    g_warning("warning");
    g_critical("critical");

    g_log_remove_handler(NULL, handler_id);

    g_print("set handler: G_LOG_LEVEL_INFO|G_LOG_LEVEL_WARNING|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION \n");
    handler_id = g_log_set_handler(NULL, 
        G_LOG_LEVEL_INFO|G_LOG_LEVEL_WARNING|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION, my_log_handler, "APP_TAG");

    g_debug("debug");
    g_info("info");
    g_message("message");
    g_warning("warning");
    g_critical("critical");

    
    g_log_remove_handler(NULL, handler_id);

    g_print("set handler: G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION \n");
    handler_id = g_log_set_handler(NULL, 
        G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION, my_log_handler, "APP_TAG");

    g_log_set_always_fatal(G_LOG_LEVEL_MESSAGE);
    g_debug("debug");
    g_info("info");
    g_message("message");
    g_warning("warning");
    g_critical("critical");

    return 0;
}
           

運作結果:

[[email protected]_6 build]# ./glib_log_handler
set handler: G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION
[APP_TAG]my_log_handler : debug
[APP_TAG]my_log_handler : info
[APP_TAG]my_log_handler : message
[APP_TAG]my_log_handler : warning
[APP_TAG]my_log_handler : critical
set handler: G_LOG_LEVEL_INFO|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION
[APP_TAG]my_log_handler : info
** Message: 15:10:31.479: message

** (process:6101): WARNING **: 15:10:31.479: warning

** (process:6101): CRITICAL **: 15:10:31.479: critical
set handler: G_LOG_LEVEL_INFO|G_LOG_LEVEL_WARNING|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION
[APP_TAG]my_log_handler : info
** Message: 15:10:31.479: message
[APP_TAG]my_log_handler : warning

** (process:6101): CRITICAL **: 15:10:31.479: critical
set handler: G_LOG_LEVEL_MASK|G_LOG_FLAG_FATAL|G_LOG_FLAG_RECURSION
[APP_TAG]my_log_handler : debug
[APP_TAG]my_log_handler : info
[APP_TAG]my_log_handler : message
Trace/breakpoint trap(吐核)
           

在上述例子中,對日志輸出的handler進行了多次設定和取消設定,G_LOG_LEVEL_MASK會将所有的日志輸出都重定向到hander設定的輸出函數,也可以單獨設定某一項或某幾項。

注意:設定低級别時,進階别的日志也會輸出,但不會走設定的輸出函數,而是走預設輸出函數。例如,如果設定的是info級别,則debug不會輸出,但message會輸出日志,因為debug的級别比info低,但message的級别比info要高。

設定全局或域FATAL錯誤

FATAL錯誤是一種無法恢複的錯誤,當出現FATAL時,需要退出程式,GLib通過調用abort()使程式退出。預設情況下,隻有error輸出為FATAL級别,會導緻段錯誤使程式退出,但可以使用g_log_set_always_fatal或者g_log_set_fatal_mask為某一域設定FATAL錯誤。

示例代碼如下:

源碼見

glib_examples\glib_log_fatal\glib_log_fatal

#include <glib.h>

static void my_log_handler(const gchar *log_domain, GLogLevelFlags log_level, const gchar *message, gpointer user_data)
{
    g_print("[domain:%s][LEVEL:%3d][%s]my_log_handler : %s \n",log_domain,log_level,user_data,message);
}

gint main(gint argc, gchar **argv)
{
    g_log_set_default_handler(my_log_handler, "User_Data");

    g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);

    g_log ("foo", G_LOG_LEVEL_DEBUG, "foo debug");
    g_log ("foo", G_LOG_LEVEL_INFO, "foo info");
    g_log ("bar", G_LOG_LEVEL_MESSAGE, "bar message");
    g_log ("bar", G_LOG_LEVEL_WARNING, "bar warning");
    g_log ("baz", G_LOG_LEVEL_CRITICAL, "bar critical");

    g_print("set fatal mask: baz G_LOG_LEVEL_MESSAGE \n");
    g_log_set_fatal_mask("baz", G_LOG_LEVEL_MESSAGE);

    g_log ("foo", G_LOG_LEVEL_DEBUG, "foo debug");
    g_log ("foo", G_LOG_LEVEL_INFO, "foo info");
    g_log ("foo", G_LOG_LEVEL_MESSAGE, "foo message");
    g_log ("bar", G_LOG_LEVEL_MESSAGE, "bar message");
    g_log ("bar", G_LOG_LEVEL_WARNING, "bar warning");
    g_log ("baz", G_LOG_LEVEL_INFO, "baz info");
    g_log ("baz", G_LOG_LEVEL_CRITICAL, "baz critical");

    g_print("set always fatal: G_LOG_LEVEL_MESSAGE \n");
    g_log_set_always_fatal(G_LOG_LEVEL_MESSAGE);

    g_log ("foo", G_LOG_LEVEL_DEBUG, "foo debug");
    g_log ("foo", G_LOG_LEVEL_INFO, "foo info");
    g_log ("bar", G_LOG_LEVEL_MESSAGE, "bar message");
    g_log ("bar", G_LOG_LEVEL_WARNING, "bar warning");
    g_log ("baz", G_LOG_LEVEL_CRITICAL, "baz critical");

    return 0;
}
           

運作結果:

[[email protected]_6 build]# ./glib_log_fatal
[domain:foo][LEVEL:128][User_Data]my_log_handler : foo debug
[domain:foo][LEVEL: 64][User_Data]my_log_handler : foo info
[domain:bar][LEVEL: 32][User_Data]my_log_handler : bar message
[domain:bar][LEVEL: 16][User_Data]my_log_handler : bar warning
[domain:baz][LEVEL:  8][User_Data]my_log_handler : bar critical
set fatal mask: baz G_LOG_LEVEL_MESSAGE
[domain:foo][LEVEL:128][User_Data]my_log_handler : foo debug
[domain:foo][LEVEL: 64][User_Data]my_log_handler : foo info
[domain:foo][LEVEL: 32][User_Data]my_log_handler : foo message
[domain:bar][LEVEL: 32][User_Data]my_log_handler : bar message
[domain:bar][LEVEL: 16][User_Data]my_log_handler : bar warning
[domain:baz][LEVEL: 64][User_Data]my_log_handler : baz info
[domain:baz][LEVEL:  8][User_Data]my_log_handler : baz critical
set always fatal: G_LOG_LEVEL_MESSAGE
[domain:foo][LEVEL:128][User_Data]my_log_handler : foo debug
[domain:foo][LEVEL: 64][User_Data]my_log_handler : foo info
[domain:bar][LEVEL: 34][User_Data]my_log_handler : bar message
Trace/breakpoint trap(吐核)
           

繼續閱讀