Skip to content

Logging

struct log_dump_options {
    uint8_t  min_level;
    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 {
    void                   (*print)(const struct log_site *site, const struct log_record *rec, void (*print)(const char *fmt, ...));
    enum log_handle_flags  flags;
    _Atomic uint32_t       seen_internal;
    _Atomic uint64_t       last_ts_internal;
};
struct log_record {
    time_ms_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;
    char               *shadow_buf;
};
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;
    size_t                   msg_max_len;
    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;
    size_t                   msg_max_len;
    uint32_t                 dropped;
    enum log_site_flags      flags;
    struct log_dump_options  dump_opts;
};
enum log_handle_flags : uint32_t {
    LOG_HANDLE_PRINT = 1 << 0,
    LOG_HANDLE_IMPORTANT = 1 << 1,
    LOG_HANDLE_RATELIMIT = 1 << 2,
    LOG_HANDLE_ONCE = 1 << 3,
    LOG_HANDLE_PANIC = 1 << 4,
    LOG_HANDLE_NO_NEWLINE = 1 << 5,
    LOG_HANDLE_FLAGS_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_DUP_MESSAGES = 1 << 4,
    LOG_SITE_NDJSON = 1 << 5,
    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_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_dump_panic(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);
void log_handle_init(struct log_handle *h, enum log_handle_flags f);
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_HANDLE_DEFAULT \
    (struct log_handle){.flags = LOG_HANDLE_FLAGS_DEFAULT, \
                        .seen_internal = 0, \
                        .last_ts_internal = 0}
#define LOG_DUMP_DEFAULT \
    (struct log_dump_options) { \
        .min_level = LOG_TRACE, .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_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 = {.capacity = \
                                              LOG_SITE_CAPACITY_DEFAULT, \
                                          .enabled_mask = LOG_SITE_ALL, \
                                          .dump_opts = LOG_DUMP_CONSOLE, \
                                          .name = #_name, \
                                          __VA_ARGS__}
#define LOG_SITE_DECLARE_PRINT(_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_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 = { \
        .seen_internal = 0, .last_ts_internal = 0, __VA_ARGS__}
#define LOG_HANDLE_DECLARE_PRINT(n, ...) \
    struct log_handle __log_handle_##n = {.flags = LOG_HANDLE_PRINT, \
                                          .seen_internal = 0, \
                                          .last_ts_internal = 0, \
                                          __VA_ARGS__}
#define LOG_HANDLE(name) &(__log_handle_##name)