-
Notifications
You must be signed in to change notification settings - Fork 23
Forward native standard streams to platform diagnostics #233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bkaradzic-microsoft
wants to merge
7
commits into
BabylonJS:main
Choose a base branch
from
bkaradzic-microsoft:jsruntime-console-logger
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
76ef338
Add cross-platform standard stream forwarding
bkaradzic f8b8619
Fix StandardStreamLogger UWP and iOS CI failures
bkaradzic 227d45a
Mark both POSIX pipe ends CLOEXEC in StandardStreamLogger
bkaradzic e29f716
Address Copilot follow-ups on StandardStreamLogger
bkaradzic ac36b14
Split StandardStreamLogger into platform TUs
bkaradzic 1c4519a
Share StandardStreamLogger tee body across platforms
bkaradzic 60c6b53
Clarify StandardStreamLogger .inl CMake listing
bkaradzic File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| #pragma once | ||
|
|
||
| #include "Api.h" | ||
|
|
||
| namespace Babylon::StandardStreamLogger | ||
| { | ||
| /** | ||
| * Starts process-wide standard-stream forwarding. | ||
| * | ||
| * Android forwards to logcat, Apple platforms forward to os_log, and Windows | ||
| * forwards to OutputDebugString while preserving the original stream destination. | ||
| * Other Unix platforms already expose standard streams and leave them unchanged. | ||
| * | ||
| * Returns false if a platform stream could not be redirected. Repeated calls are | ||
| * idempotent. | ||
| */ | ||
| bool BABYLON_API Start(); | ||
|
|
||
| /** | ||
| * Flushes pending output, restores the original streams, and stops forwarding. | ||
| * | ||
| * Returns false if an original stream could not be restored or pending output | ||
| * could not be drained before the shutdown timeout. Repeated calls are idempotent. | ||
| */ | ||
| bool BABYLON_API Stop(); | ||
|
|
||
| /** | ||
| * Returns whether Start() has successfully begun process-wide forwarding and | ||
| * Stop() has not yet completed. | ||
| * | ||
| * This is the logical started flag, not a live probe of the underlying file | ||
| * descriptors. On platforms that leave stdout/stderr unchanged (plain Linux | ||
| * and other non-Android Unix hosts), Start() still succeeds and IsStarted() | ||
| * reports true even though no redirection was installed. | ||
| */ | ||
| bool BABYLON_API IsStarted(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| #include "StandardStreamLogger.h" | ||
| #include "StandardStreamLoggerPlatform.h" | ||
|
|
||
| #include <cstdlib> | ||
| #include <mutex> | ||
|
|
||
| namespace | ||
| { | ||
| std::mutex g_mutex{}; | ||
| bool g_started{}; | ||
| bool g_exitHandlerRegistered{}; | ||
| } | ||
|
|
||
| namespace Babylon::StandardStreamLogger | ||
| { | ||
| bool Start() | ||
| { | ||
| std::lock_guard<std::mutex> lock{g_mutex}; | ||
| if (g_started) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| if (!Platform::Start()) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| if (!g_exitHandlerRegistered) | ||
| { | ||
| if (std::atexit([] { | ||
| (void)Babylon::StandardStreamLogger::Stop(); | ||
| }) != 0) | ||
| { | ||
| (void)Platform::Stop(); | ||
| return false; | ||
| } | ||
| g_exitHandlerRegistered = true; | ||
| } | ||
|
|
||
| g_started = true; | ||
| return true; | ||
| } | ||
|
|
||
| bool Stop() | ||
| { | ||
| std::lock_guard<std::mutex> lock{g_mutex}; | ||
| if (!g_started) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| const bool stopped = Platform::Stop(); | ||
| g_started = false; | ||
| return stopped; | ||
| } | ||
|
|
||
| bool IsStarted() | ||
| { | ||
| std::lock_guard<std::mutex> lock{g_mutex}; | ||
| return g_started; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| #pragma once | ||
|
|
||
| // Internal platform hooks for StandardStreamLogger. | ||
| // Each JSRUNTIMEHOST_PLATFORM TU implements these; the shared API TU owns the | ||
| // process-wide mutex / started flag and is the only public entry point. | ||
|
|
||
| namespace Babylon::StandardStreamLogger::Platform | ||
| { | ||
| // Install stdout/stderr redirection and drain threads. | ||
| // Not synchronized — the shared API holds the process-wide mutex. | ||
| bool Start(); | ||
|
|
||
| // Flush, restore original streams, and join (or timeout-detach) drains. | ||
| // Not synchronized — the shared API holds the process-wide mutex. | ||
| bool Stop(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #include "StandardStreamLoggerPlatform.h" | ||
|
|
||
| #include <android/log.h> | ||
| #include <cerrno> | ||
| #include <cstdint> | ||
| #include <string> | ||
|
|
||
| #include <fcntl.h> | ||
| #include <unistd.h> | ||
|
|
||
| namespace | ||
| { | ||
| // POSIX fd helpers (dup/pipe/CLOEXEC/devnull); sink is OsWritePlatform below. | ||
| #include "StandardStreamLogger_PosixOps.inl" | ||
|
|
||
| void OsWritePlatform(bool isError, const std::string& line) | ||
| { | ||
| const int priority = isError ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO; | ||
| __android_log_write(priority, "JsRuntimeHost", line.c_str()); | ||
| } | ||
| } | ||
|
|
||
| #include "StandardStreamLogger_Shared.inl" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| #include "StandardStreamLoggerPlatform.h" | ||
|
|
||
| #include <os/log.h> | ||
| #include <cerrno> | ||
| #include <cstdint> | ||
| #include <string> | ||
|
|
||
| #include <fcntl.h> | ||
| #include <unistd.h> | ||
|
|
||
| namespace | ||
| { | ||
| // POSIX fd helpers (dup/pipe/CLOEXEC/devnull); sink is OsWritePlatform below. | ||
| #include "StandardStreamLogger_PosixOps.inl" | ||
|
|
||
| void OsWritePlatform(bool isError, const std::string& line) | ||
| { | ||
| const os_log_type_t type = isError ? OS_LOG_TYPE_ERROR : OS_LOG_TYPE_DEFAULT; | ||
| os_log_with_type(OS_LOG_DEFAULT, type, "%{public}s", line.c_str()); | ||
| } | ||
| } | ||
|
|
||
| #include "StandardStreamLogger_Shared.inl" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // POSIX fd primitives shared by Android and Apple. Included inside an anonymous | ||
| // namespace that already provides OsWritePlatform. | ||
|
|
||
| struct ChannelPlatformState | ||
| { | ||
| }; | ||
|
|
||
| int OsDuplicate(int fd) | ||
| { | ||
| return ::dup(fd); | ||
| } | ||
|
|
||
| int OsDuplicateTo(int source, int target) | ||
| { | ||
| return ::dup2(source, target) < 0 ? -1 : 0; | ||
| } | ||
|
|
||
| int OsClose(int fd) | ||
| { | ||
| return ::close(fd); | ||
| } | ||
|
|
||
| int64_t OsRead(int fd, void* data, size_t size) | ||
| { | ||
| return ::read(fd, data, size); | ||
| } | ||
|
|
||
| int64_t OsWrite(int fd, const void* data, size_t size) | ||
| { | ||
| return ::write(fd, data, size); | ||
| } | ||
|
|
||
| int OsCreatePipe(int fds[2]) | ||
| { | ||
| if (::pipe(fds) != 0) | ||
| { | ||
| return -1; | ||
| } | ||
| // Mark both ends CLOEXEC. Leaving the write end inheritable would let a | ||
| // concurrent exec keep the pipe open and delay Drain()'s EOF on Stop(). | ||
| if (::fcntl(fds[0], F_SETFD, FD_CLOEXEC) != 0 || | ||
| ::fcntl(fds[1], F_SETFD, FD_CLOEXEC) != 0) | ||
| { | ||
| const int error = errno; | ||
| (void)::close(fds[0]); | ||
| (void)::close(fds[1]); | ||
| errno = error; | ||
| return -1; | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| bool OsOccupyTarget(int target) | ||
| { | ||
| const int nullFd = ::open("/dev/null", O_WRONLY); | ||
| if (nullFd < 0) | ||
| { | ||
| return false; | ||
| } | ||
| if (nullFd == target) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| const bool duplicated = OsDuplicateTo(nullFd, target) == 0; | ||
| (void)OsClose(nullFd); | ||
| return duplicated; | ||
| } | ||
|
|
||
| bool OsOnStartChannel(ChannelPlatformState&, int, bool) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| bool OsOnRedirected(ChannelPlatformState&, int) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| bool OsOnRestore(ChannelPlatformState&, int) | ||
| { | ||
| return true; | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.