mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-29 06:13:20 +00:00
Add async-safe flog support
This allows using flog in a limited way after calling fork, or from signal handlers.
This commit is contained in:
parent
727934c6b6
commit
28bf44d698
2 changed files with 75 additions and 1 deletions
56
src/flog.cpp
56
src/flog.cpp
|
@ -20,6 +20,10 @@ namespace flog_details {
|
||||||
/// This is not modified after initialization.
|
/// This is not modified after initialization.
|
||||||
static std::vector<category_t *> s_all_categories;
|
static std::vector<category_t *> s_all_categories;
|
||||||
|
|
||||||
|
/// The fd underlying the flog output file.
|
||||||
|
/// This is separated out for flogf_async_safe.
|
||||||
|
static int s_flog_file_fd{STDERR_FILENO};
|
||||||
|
|
||||||
/// When a category is instantiated it adds itself to the 'all' list.
|
/// When a category is instantiated it adds itself to the 'all' list.
|
||||||
category_t::category_t(const wchar_t *name, const wchar_t *desc, bool enabled)
|
category_t::category_t(const wchar_t *name, const wchar_t *desc, bool enabled)
|
||||||
: name(name), description(desc), enabled(enabled) {
|
: name(name), description(desc), enabled(enabled) {
|
||||||
|
@ -85,6 +89,52 @@ void logger_t::log_fmt(const category_t &cat, const char *fmt, ...) {
|
||||||
log_fmt(cat, L"%s", buff.get());
|
log_fmt(cat, L"%s", buff.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void async_safe_write_str(const char *s, size_t len = std::string::npos) {
|
||||||
|
if (s_flog_file_fd < 0) return;
|
||||||
|
if (len == std::string::npos) len = std::strlen(s);
|
||||||
|
ignore_result(write(s_flog_file_fd, s, len));
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
void logger_t::flogf_async_safe(const char *category, const char *fmt, const char *param1,
|
||||||
|
const char *param2, const char *param3, const char *param4,
|
||||||
|
const char *param5, const char *param6, const char *param7,
|
||||||
|
const char *param8, const char *param9, const char *param10,
|
||||||
|
const char *param11, const char *param12) {
|
||||||
|
const char *const params[] = {param1, param2, param3, param4, param5, param6,
|
||||||
|
param7, param8, param9, param10, param11, param12};
|
||||||
|
const size_t max_params = sizeof params / sizeof *params;
|
||||||
|
|
||||||
|
// Can't call fwprintf, that may allocate memory.
|
||||||
|
// Just call write() over and over.
|
||||||
|
async_safe_write_str(category);
|
||||||
|
async_safe_write_str(": ");
|
||||||
|
|
||||||
|
size_t param_idx = 0;
|
||||||
|
const char *cursor = fmt;
|
||||||
|
while (*cursor != '\0') {
|
||||||
|
const char *end = std::strchr(cursor, '%');
|
||||||
|
if (end == nullptr) end = cursor + std::strlen(cursor);
|
||||||
|
if (end > cursor) async_safe_write_str(cursor, end - cursor);
|
||||||
|
if (end[0] == '%' && end[1] == 's') {
|
||||||
|
// Handle a format string.
|
||||||
|
const char *param = (param_idx < max_params ? params[param_idx++] : nullptr);
|
||||||
|
if (!param) param = "(null)";
|
||||||
|
async_safe_write_str(param);
|
||||||
|
cursor = end + 2;
|
||||||
|
} else if (end[0] == '\0') {
|
||||||
|
// Must be at the end of the string.
|
||||||
|
cursor = end;
|
||||||
|
} else {
|
||||||
|
// Some other format specifier, just skip it.
|
||||||
|
cursor = end + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We always append a newline.
|
||||||
|
async_safe_write_str("\n");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace flog_details
|
} // namespace flog_details
|
||||||
|
|
||||||
using namespace flog_details;
|
using namespace flog_details;
|
||||||
|
@ -117,7 +167,11 @@ void activate_flog_categories_by_pattern(const wcstring &inwc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_flog_output_file(FILE *f) { g_logger.acquire()->set_file(f); }
|
void set_flog_output_file(FILE *f) {
|
||||||
|
assert(f && "Null file");
|
||||||
|
g_logger.acquire()->set_file(f);
|
||||||
|
s_flog_file_fd = fileno(f);
|
||||||
|
}
|
||||||
|
|
||||||
void log_extra_to_flog_file(const wcstring &s) { g_logger.acquire()->log_extra(s.c_str()); }
|
void log_extra_to_flog_file(const wcstring &s) { g_logger.acquire()->log_extra(s.c_str()); }
|
||||||
|
|
||||||
|
|
20
src/flog.h
20
src/flog.h
|
@ -164,6 +164,15 @@ class logger_t {
|
||||||
|
|
||||||
// Log outside of the usual flog usage.
|
// Log outside of the usual flog usage.
|
||||||
void log_extra(const wchar_t *s) { log1(s); }
|
void log_extra(const wchar_t *s) { log1(s); }
|
||||||
|
|
||||||
|
// Variant of flogf which is async safe. This is intended to be used after fork().
|
||||||
|
static void flogf_async_safe(const char *category, const char *fmt,
|
||||||
|
const char *param1 = nullptr, const char *param2 = nullptr,
|
||||||
|
const char *param3 = nullptr, const char *param4 = nullptr,
|
||||||
|
const char *param5 = nullptr, const char *param6 = nullptr,
|
||||||
|
const char *param7 = nullptr, const char *param8 = nullptr,
|
||||||
|
const char *param9 = nullptr, const char *param10 = nullptr,
|
||||||
|
const char *param11 = nullptr, const char *param12 = nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern owning_lock<logger_t> g_logger;
|
extern owning_lock<logger_t> g_logger;
|
||||||
|
@ -207,6 +216,17 @@ void log_extra_to_flog_file(const wcstring &s);
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
/// Variant of FLOG which is safe to use after fork().
|
||||||
|
/// Only %s specifiers are supported.
|
||||||
|
#define FLOGF_SAFE(wht, ...) \
|
||||||
|
do { \
|
||||||
|
if (flog_details::category_list_t::g_instance->wht.enabled) { \
|
||||||
|
auto old_errno = errno; \
|
||||||
|
flog_details::logger_t::flogf_async_safe(#wht, __VA_ARGS__); \
|
||||||
|
errno = old_errno; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define should_flog(wht) (flog_details::category_list_t::g_instance->wht.enabled)
|
#define should_flog(wht) (flog_details::category_list_t::g_instance->wht.enabled)
|
||||||
|
|
Loading…
Reference in a new issue