Well I'm fully aware that it's very trivial to build some mutable wrappers to provide the ability of writing to those streams, yet this wasn't the main issue why I wanted these. To be fair, I'm asking for default streams that are observable, which is indeed not a very common task. If we could centralize these streams into stdlib then we could provide a little more API then just .write(_:)
from TextOutputStream.
Once I tried to redirect file descriptors so that I was able to observe the data that was written to the whole stream of my current process. It kinda worked for a moment, but then I realized that this solution only worked while the project was running attached to Xcode and stopped emitting any new data otherwise. First I though that maybe print
was preventing it in release mode or when the debugger is not attached, however I couldn't find anything in the source code for that matter.
It was necessary for my project that I was able to redirect not only my own logs, but also logs from a 3rd party library, but this turned out to be not a trivial task at all. In the end I had to fork the third party library and provide a custom hook into their log system. This might worked for me, because that library was open sourced, but there are other modules that may provide useful logs but without a way for us to provide such observable hooks.
For more reference you can have glance over this very old blog post.
I think the reason why the target stream must be passed as inout
is because String
and similar types conform to TextOutputStreamable
.
var storage = ""
print("Swift", to: &storage)
Furthermore the standard library already provides an internal implementation for one of the streams (without observation API).
internal struct _Stdout : TextOutputStream { ... }
That's basically my reasoning why I would want to a two global centrialzed streams to the standard library with a little more API than what TextOutputStream
requires. Then if possible add another parameter to this print function with a default value to the new StandardOutput
stream.
I'm thinking about something like this in the stdlib:
public struct StandardError : TextOutputStream { ... }
public struct StandardOutput : TextOutputStream {
/* API for observation */
internal init() { ... }
}
public standardOutput = StandardOutput()
public standardError = StandardError()