# Where does the happy-path output (stdout?) from a prebuild plugin tool using an external binary go? How do I see it?

**URL:** <https://forums.swift.org/t/where-does-the-happy-path-output-stdout-from-a-prebuild-plugin-tool-using-an-external-binary-go-how-do-i-see-it/69520>\
**Category:** Using Swift\
**Tags:** packagemanager, plugins\
**Created:** [January 18, 2024, 9:15pm UTC](https://forums.swift.org/t/where-does-the-happy-path-output-stdout-from-a-prebuild-plugin-tool-using-an-external-binary-go-how-do-i-see-it/69520 "2024-01-18T21:15:15Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![carlynorama](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/carlynorama/32/27072_2.png) [@carlynorama](https://forums.swift.org/u/carlynorama)\
**Post date:** [January 18, 2024, 9:15pm UTC](https://forums.swift.org/t/where-does-the-happy-path-output-stdout-from-a-prebuild-plugin-tool-using-an-external-binary-go-how-do-i-see-it/69520/1 "2024-01-18T21:15:15Z")

</div>

I have a prebuild plugin that runs `ls` and one that runs `echo`. If I purposefully pass them bad input I see the error message in both Xcode and in the command line. If I pass them something valid, my expectation would be to see output messages in the build log as well but I don't. Where does it go? How do I see it? And is this related to why \> and \>\> can't be passed as arguments?

FWIW when I put print statements in my own custom local executable they do show up in the build log. Print statements from the plugin code also show up in the build log. It's just the output from the executable when it's an external binary so far. I have not yet tried a non-system binary.

```swift
    func logDirectoryContents(toLog:Path, output:Path) -> PackagePlugin.Command {
        .prebuildCommand(
            displayName: "Test prebuild",
            executable: .init("/bin/ls"),
            arguments: ["-1t", toLog.string],
             //known can't be done... a shame.  
            //arguments: ["-1", toLog.string, ">>", output.string], 
            //environment: T##[String : CustomStringConvertible],
            outputFilesDirectory: output.removingLastComponent()
        )
    }

```

```swift
    func echoTest(toEcho:some StringProtocol, outputDir:Path) -> PackagePlugin.Command {
        .prebuildCommand(
            displayName: "Results from echo",
            executable: .init("/bin/zsh"),
            arguments: ["-c", "echo \(toEcho)"],
            outputFilesDirectory: outputDir
        )
    }

```

I understand that to make this work I can [build my own tool that opens a Process](https://forums.swift.org/t/how-do-i-capture-output-of-a-swiftlint-buildtoolplugin-and-save-it-to-a-file/59224). In the mean time I'm curious though about how the plugin system works.

The `invocationDelegate` has a `handleOutput` function which the comment says handles both `stderr` and `stdout`?

```swift
/// Invoked when the plugin emits arbtirary data on its stdout/stderr. There is no guarantee that the data is split on UTF-8 character encoding boundaries etc. The script runner delegate just passes it on to the invocation delegate.
func handleOutput(data: Data) {
   invocationDelegate.pluginEmittedOutput(data)
}

```

[code link](https://github.com/apple/swift-package-manager/blob/3ef830dddff459e569d6e49c186c3ded33c39bcc/Sources/SPMBuildCore/Plugins/PluginInvocation.swift#L215)

But looking in the code base it appear to [only be called for stderr](https://github.com/apple/swift-package-manager/blob/3ef830dddff459e569d6e49c186c3ded33c39bcc/Sources/Workspace/DefaultPluginScriptRunner.swift#L531) not for stdout ever. From handleOutput the stderr infor can be easily traced through the code to where it ends up in the Diagnostics in [BuildOperation](https://github.com/apple/swift-package-manager/blob/3ef830dddff459e569d6e49c186c3ded33c39bcc/Sources/Build/BuildOperation.swift#L500)

`stdout` appears instead to be handled by a [`FileHandle.writePluginMessage`](https://github.com/apple/swift-package-manager/blob/cdceff5c64861dc7635fc353c3dd8c5f6214878e/Sources/Workspace/DefaultPluginScriptRunner.swift#L500) and the file handle eventually winds up at

```swift
            if let handler = handle.readabilityHandler {
                handler(handle)
            }

```

[link to code](https://github.com/apple/swift-package-manager/blob/cdceff5c64861dc7635fc353c3dd8c5f6214878e/Sources/Workspace/DefaultPluginScriptRunner.swift#L562)

info on [readabilityHandler](https://developer.apple.com/documentation/foundation/nsfilehandle/1412413-readabilityhandler)

But then it I can't tell what actually gets DONE with it? Who gets the contents of stdout? Why do the print statements in my local executable show up but output from `ls` and `echo` don't? Are they not all `stdout`?

Related?

- [[SR-15692] Output currently printed to stdout stream should go through the same system as diagnostics (with a new `output` severity) · Issue #4364 · apple/swift-package-manager · GitHub](https://github.com/apple/swift-package-manager/issues/4364)
- [Handling stdout/stderr/terminationStatus from .prebuildCommand · Issue #6469 · apple/swift-package-manager · GitHub](https://github.com/apple/swift-package-manager/issues/6469)

---

<div class="post-metadata">

**Author:** ![carlynorama](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/carlynorama/32/27072_2.png) [@carlynorama](https://forums.swift.org/u/carlynorama)\
**Post date:** [January 20, 2024, 7:45pm UTC](https://forums.swift.org/t/where-does-the-happy-path-output-stdout-from-a-prebuild-plugin-tool-using-an-external-binary-go-how-do-i-see-it/69520/2 "2024-01-20T19:45:31Z")

</div>

Thank you Ed & Ray for pointing me in the right direction.

In Xcode each line in the build log has a hamburger menu on the right had side when it is selected that I had failed to notice. I hadn't realized those were a thing 🤯

 ![Screenshot 2024-01-20 at 11.36.04 AM](https://global.discourse-cdn.com/swift/original/3X/d/7/d78cab3caf562b41db92f13347a1ebedec4ba0e7.png)

Clicking on it reveals script and its output.

In the command line you won't see them with verbose, but will see them with very verbose

```bash
# Does not contain script output
swift run -v plugin-tester fruit_list
# Does contain script output
swift run --vv plugin-tester fruit_list

```

Very verbose contains a lot of other stuff as well so its not ideal for just scanning for a result, but at least it's parse-able!

Still would personally prefer to have them hit the Diagnostic level/behave the same as prints from the same script but at least I can find them now!
