Skip to content

Commit

Permalink
broken wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jevinskie committed Mar 29, 2024
1 parent 623c8fd commit 7a04a30
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 16 deletions.
11 changes: 10 additions & 1 deletion include/redirect-to-os-log/redirect-to-os-log.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@

namespace redirect_to_os_log {

struct log_args {
const char *const __nonnull subsystem;
const bool is_injected;
const bool echo;
};

[[gnu::visibility("default")]]
extern int exit_pipe[2];

[[gnu::visibility("default")]]
extern bool should_echo_from_env_var();

[[gnu::visibility("default")]]
extern ssize_t safe_write(int fd, const void *__nonnull buf, ssize_t count);

[[gnu::visibility("default")]]
void *__nullable io_loop(void *__nonnull arg);
extern void *__nullable io_loop(void *__nonnull arg);

} // namespace redirect_to_os_log
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <redirect-to-os-log/redirect-to-os-log.hpp>

#include <cstdio>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>

Expand All @@ -14,9 +15,11 @@ static pthread_t io_loop_thread;
[[gnu::constructor]]
static void redirect_to_os_log_injector_ctor() {
// Spawn the I/O loop thread
bool is_injected = true;
redirect_to_os_log::log_args args = {.is_injected = true,
.echo = redirect_to_os_log::should_echo_from_env_var(),
.subsystem = getprogname()};
assert(!pthread_create(&io_loop_thread, nullptr, redirect_to_os_log::io_loop,
reinterpret_cast<void *>(&is_injected)));
reinterpret_cast<void *>(&args)));
}

[[gnu::destructor]]
Expand Down
53 changes: 40 additions & 13 deletions lib/redirect-to-os-log/redirect-to-os-log-lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ static int stderr_pipe[2];
int exit_pipe[2];
static int original_stdout;
static int original_stderr;
static os_log_t logger_stdout;
static os_log_t logger_stderr;

bool should_echo_from_env_var() {
const auto do_echo = getenv("REDIRECT_TO_OS_LOG");
if (do_echo) {
if (!strcmp(do_echo, "1") || !strcmp(do_echo, "YES") || !strcmp(do_echo, "ON")) {
return true;
}
}
return false;
}

ssize_t safe_write(int fd, const void *__nonnull buf, ssize_t count) {
assert(count >= 0);
Expand All @@ -46,20 +58,36 @@ ssize_t safe_write(int fd, const void *__nonnull buf, ssize_t count) {
return written;
}

void log_output(int fd, os_log_t logger, bool echo) {
static void write_and_log(int fd, const std::string &line, bool echo) {
const size_t max_log_length = 1024;

if (echo) {
write(fd == STDOUT_FILENO ? STDOUT_FILENO : STDERR_FILENO, line.c_str(), line.length());
write(fd == STDOUT_FILENO ? STDOUT_FILENO : STDERR_FILENO, "\n", 1);
}

for (size_t pos = 0; pos < line.length(); pos += max_log_length) {
std::string chunk = line.substr(pos, max_log_length);
os_log_with_type(logger, fd == STDOUT_FILENO ? OS_LOG_TYPE_DEFAULT : OS_LOG_TYPE_ERROR,
"%{public}s", chunk.c_str());
}
}

static void log_output(int fd, os_log_t logger, bool echo) {
char buffer[1024];
ssize_t bytes_read;

while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
if (echo) {
safe_write(fd, buffer, bytes_read);
}
os_log_with_type(logger, fd == STDOUT_FILENO ? OS_LOG_TYPE_DEFAULT : OS_LOG_TYPE_ERROR,
"%{public}s", buffer);
os_log_with_type(fd == STDOUT_FILENO ? logger_stdout : logger_stderr,
fd == STDOUT_FILENO ? OS_LOG_TYPE_DEFAULT : OS_LOG_TYPE_ERROR,
"%{public}.*s", static_cast<int>(bytes_read), buffer);
}
}

static void setup_io_redirection(const bool is_injected) {
static void setup_io_redirection(const char *const __nonnull subsystem, const bool is_injected) {
// Create pipes for stdout and stderr
assert(!pipe(stdout_pipe));
assert(!pipe(stderr_pipe));
Expand All @@ -80,11 +108,16 @@ static void setup_io_redirection(const bool is_injected) {
// Close the original write ends of the pipes
assert(!close(stdout_pipe[1]));
assert(!close(stderr_pipe[1]));

logger_stdout = os_log_create(subsystem, "stdout");
logger_stderr = os_log_create(subsystem, "stderr");
}

void *__nullable io_loop(void *__nonnull arg) {
const auto is_injected = *reinterpret_cast<const bool *>(arg);
setup_io_redirection(is_injected);
const auto args = reinterpret_cast<const log_args *>(arg);
const auto is_injected = args->is_injected;
const auto echo = args->echo;
setup_io_redirection(args->subsystem, is_injected);

struct kevent kev[3];
int kq = kqueue();
Expand All @@ -107,13 +140,7 @@ void *__nullable io_loop(void *__nonnull arg) {
for (int i = 0; i < nev; ++i) {
int fd = static_cast<int>(event_list[i].ident);
if (fd == stdout_pipe[0] || fd == stderr_pipe[0]) {
// Data is available to read, echo it to the original stdout or stderr
char buffer[1024];
ssize_t bytes_read = read(fd, buffer, sizeof(buffer));
if (bytes_read > 0) {
int output_fd = (fd == stdout_pipe[0]) ? original_stdout : original_stderr;
safe_write(output_fd, buffer, bytes_read);
}
log_output(fd, echo);
}
if (is_injected && fd == exit_pipe[0]) {
do_exit = true;
Expand Down

0 comments on commit 7a04a30

Please sign in to comment.