Skip to content

Logging

struct log_dump_options {
    uint8_t  min_level;
    bool     show_args : 1;
    bool     show_cpu : 1;
    bool     show_tid : 1;
    bool     show_irql : 1;
    bool     show_caller : 1;
    bool     resolve_symbols : 1;
    bool     clear_after_dump : 1;
};
struct log_handle {
    const char        *msg;
    enum log_flags    flags;
    _Atomic uint32_t  seen_internal;
    _Atomic uint64_t  last_ts_internal;
};
struct log_record {
    time_t                   timestamp;
    cpu_id_t                 cpu;
    uint32_t                 tid;
    const struct log_handle  *handle;
    enum log_level           level;
    enum bootstage           boostage;
    uint16_t                 msg_len;
    const char               *fmt;
    uint8_t                  nargs;
    uint64_t                 args[8];
    char                     *caller_fn;
    char                     *caller_file;
    int32_t                  caller_line;
    uintptr_t                caller_pc;
    enum log_record_flags    flags;
    enum irql                logged_at_irql;
};
struct log_ring_slot {
    _Atomic uint64_t   seq;
    struct log_record  rec;
};
struct log_ringbuf {
    struct log_ring_slot  *slots;
    _Atomic uint64_t      head;
    _Atomic uint64_t      tail;
};
struct log_site_options {
    char                     *name;
    enum log_site_flags      flags;
    size_t                   capacity;
    uint32_t                 enabled_mask;
    struct log_dump_options  dump_opts;
};
struct log_site {
    struct list_head         list;
    char                     *name;
    struct log_ringbuf       rb;
    uint32_t                 enabled_mask;
    size_t                   capacity;
    refcount_t               refcount;
    atomic_bool              enabled;
    uint32_t                 dropped;
    enum log_site_flags      flags;
    struct log_dump_options  dump_opts;
};
enum log_flags : uint32_t {
    LOG_PRINT = 1 << 0,
    LOG_IMPORTANT = 1 << 1,
    LOG_RATELIMIT = 1 << 2,
    LOG_ONCE = 1 << 3,
    LOG_PANIC = 1 << 5,
    LOG_NO_NEWLINE = 1 << 6,
    LOG_DEFAULT = 0,
};
enum log_level : uint8_t {
    LOG_TRACE,
    LOG_DEBUG,
    LOG_INFO,
    LOG_WARN,
    LOG_ERROR,
};
enum log_site_flags : uint32_t {
    LOG_SITE_PRINT = 1 << 0,
    LOG_SITE_DROP_OLD = 1 << 1,
    LOG_SITE_NO_IRQ = 1 << 2,
    LOG_SITE_PANIC_VISIBLE = 1 << 3,
    LOG_SITE_NONE = 0,
    LOG_SITE_DEFAULT = LOG_SITE_DROP_OLD,
};
enum log_record_flags : uint16_t {
    LOG_REC_FROM_IRQ = 1 << 0,
    LOG_REC_TRUNCATED = 1 << 1,
};
char log_level_color(enum log_level l);
bool log_handle_should_print(const struct log_handle *h, const struct log_site *s, uint8_t level);
bool log_site_accepts(struct log_site *s);
bool log_site_enabled(const struct log_site *ss, uint8_t level);
void log_emit_internal(struct log_site * *, struct log_handle * *, enum log_level, const char *func, const char *fname, int32_t line, uintptr_t ip, uint8_t nargs, char *fmt);
void log_dump_site_with_opts(struct log_site * *, struct log_dump_options opts);
void log_dump_site(struct log_site *site);
void log_dump_site_default(struct log_site * *);
void log_dump_all(void);
void log_sites_init(void);
void log_site_free(struct log_site *site);
struct log_site * log_site_create(struct log_site_options opts);
bool log_site_get(struct log_site *site);
void log_site_put(struct log_site *site);
size_t log_site_message_count(struct log_site *site);
#define LOG_DUMP_DEFAULT \
    (struct log_dump_options) { \
        .min_level = LOG_TRACE, .show_args = true, .show_cpu = true, \
        .show_tid = true, .show_irql = true, .show_caller = true, \
        .resolve_symbols = true, .clear_after_dump = false, \
    }
#define LOG_DUMP_CONSOLE \
    (struct log_dump_options) { \
        .min_level = LOG_TRACE, .show_args = true, .show_cpu = false, \
        .show_tid = false, .show_irql = false, .show_caller = false, \
        .resolve_symbols = false, .clear_after_dump = false, \
    }
#define log_msg(lvl, fmt, ...) \
    log_emit_internal(LOG_SITE(global), LOG_HANDLE(global), lvl, __func__, \
                      __FILE__, __LINE__, \
                      (uintptr_t) __builtin_return_address(0), \
                      PP_NARG(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define log_warn_once(fmt, ...) \
    do { \
        static bool done_internal_log = false; \
        if (!done_internal_log) { \
            log_msg(LOG_WARN, fmt, ##__VA_ARGS__); \
            done_internal_log = true; \
        } \
    } while (0)
#define log_global(handle, lvl, fmt, ...) \
    log_emit_internal(LOG_SITE(global), handle, lvl, __func__, __FILE__, \
                      __LINE__, (uintptr_t) __builtin_return_address(0), \
                      PP_NARG(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define log(site, handle, lvl, fmt, ...) \
    log_emit_internal(site, handle, lvl, __func__, __FILE__, __LINE__, \
                      (uintptr_t) __builtin_return_address(0), \
                      PP_NARG(__VA_ARGS__), fmt, ##__VA_ARGS__)
#define log_err(site, handle, fmt, ...) \
    log(site, handle, LOG_ERROR, fmt, ##__VA_ARGS__)
#define log_warn(site, handle, fmt, ...) \
    log(site, handle, LOG_WARN, fmt, ##__VA_ARGS__)
#define log_info(site, handle, fmt, ...) \
    log(site, handle, LOG_INFO, fmt, ##__VA_ARGS__)
#define log_debug(site, handle, fmt, ...) \
    log(site, handle, LOG_DEBUG, fmt, ##__VA_ARGS__)
#define log_trace(site, handle, fmt, ...) \
    log(site, handle, LOG_TRACE, fmt, ##__VA_ARGS__)
#define log_err_global(handle, fmt, ...) \
    log_global(handle, LOG_ERROR, fmt, ##__VA_ARGS__)
#define log_warn_global(handle, fmt, ...) \
    log_global(handle, LOG_WARN, fmt, ##__VA_ARGS__)
#define log_info_global(handle, fmt, ...) \
    log_global(handle, LOG_INFO, fmt, ##__VA_ARGS__)
#define log_debug_global(handle, fmt, ...) \
    log_global(handle, LOG_DEBUG, fmt, ##__VA_ARGS__)
#define log_trace_global(handle, fmt, ...) \
    log_global(handle, LOG_TRACE, fmt, ##__VA_ARGS__)
#define LOG_SITE_CAPACITY_DEFAULT 128 /* good enough for most purposes */
#define LOG_SITE_EXTERN(name) extern struct log_site __log_site_##name
#define LOG_SITE_LEVEL(l) (1u << l)
#define LOG_SITE_ALL UINT32_MAX
#define LOG_SITE_DECLARE(_name, ...) \
    LINKER_SECTION_ATTRIBUTE(log_sites) \
    struct log_site __log_site_##_name = {.name = #_name, __VA_ARGS__}
#define LOG_SITE_DECLARE_DEFAULT(_name, ...) \
    LINKER_SECTION_ATTRIBUTE(log_sites) \
    struct log_site __log_site_##_name = { \
        .name = #_name, \
        .flags = LOG_SITE_DEFAULT, \
        .capacity = LOG_SITE_CAPACITY_DEFAULT, \
        .enabled_mask = LOG_SITE_ALL, \
        .dump_opts = LOG_DUMP_CONSOLE, \
        __VA_ARGS__} /* Rest will get initialized at boot */
#define LOG_SITE(name) &(__log_site_##name)
#define LOG_HANDLE_DEFAULT \
    (struct log_handle){.msg = "", \
                        .flags = LOG_DEFAULT, \
                        .seen_internal = 0, \
                        .last_ts_internal = 0}
#define LOG_HANDLE_SUBSYSTEM_NONE NULL
#define LOG_HANDLE_EXTERN(name) extern struct log_handle __log_handle_##name
#define LOG_HANDLE_DECLARE(_name, ...) \
    struct log_handle __log_handle_##_name = { \
        .msg = #_name, .seen_internal = 0, .last_ts_internal = 0, __VA_ARGS__}
#define LOG_HANDLE_DECLARE_DEFAULT(n, ...) \
    struct log_handle __log_handle_##n = {.msg = #n, \
                                          .flags = LOG_PRINT, \
                                          .seen_internal = 0, \
                                          .last_ts_internal = 0, \
                                          __VA_ARGS__}
#define LOG_HANDLE(name) &(__log_handle_##name)