vim-xcode
vim-xcode copied to clipboard
Tail logs after running
Right now, we're just printing the pid for the app process after running. That's not particularly useful, and I often find myself needing to open Xcode just to use the app in the simulator.
I think there's more we could do here, but for right now, it probably makes sense to at least tail the logs for the simulator wherever we ran the run command. It's at least a more useful default behavior than doing nothing.
Hi @gfontenot,
I noticed that the Swift print("something") does not print anything to the system.log at all. Do you know where we can find the output for this?
override func viewDidLoad() {
super.viewDidLoad()
print("something")
}
Oh, right, I forgot about that. Maybe this isn't what we want to do. I wonder if it'd be a better default to run an lldb session.
I think this PR and https://github.com/gfontenot/vim-xcode/pull/77 are both going to be awesome, but I think we might want to move some of this logic into the vim plugin instead. That way we could have much easier hooks around what to do in these cases. We talked about having this entire integration part in a separate plugin, which I'm not sure makes sense anymore, but I do think it would be nice to be able to customize this the way I wanted to, as far as running them in tmux splits, windows etc.
On the lldb idea here, when launching a process you can pass stdout and stderr file paths:
process launch --stop-at-entry --stdout stdout.log --stderr.log
We would need both of these if for nothing else that Swift's prints end up in stdout and NSLog ends up in stderr
In theory after setting this up we could tail both at once:
tail -f stdout.log stderr.log
I believe this is similar to what Xcode does, as the system.log tailed in this PR has a lot more info than just the specific app's logging.
Also just noticed simctl's --wait-for-debugger/-w flag that might be of some use to us..
So if you change this line:
xcrun simctl launch booted "$app_id"
To
xcrun simctl launch --wait-for-debugger booted "$app_id"
Then the process will launch, seemingly frozen in the foreground of the simulator, and if you then attach a debugger (it seems like there is a timeout for this part too) with something like:
output="$(xcrun simctl launch --wait-for-debugger booted "$app_id")"
pid="$(echo "$output" | cut -d " " -f2)"
lldb -p "$pid"
It launches!
Another possible thing we might able to utilize here is the target.output-path setting. Since we're not explicitly calling process launch we can't inject the file paths for stdout and stderr. It seems like this setting should correspond with those command line arguments
Hmm. So this variable is definitely for this use case, but it seems like setting it after the process is launched, has no effect. Which is kind of our case, since simctl is doing the actual spawning. There must be a way to force a refresh of these file descriptors, but I currently only see that in the python bridge with SetOutputFileHandle (I assuming this would do what we want)
@keith Yeah I did a bunch of experimentation around --wait-for-debugger in #77, but I could never get it to actually attach stdout/stderr to the debugging session, so it didn't seem to solve the problem of seeing print() and NSLog() output.
FWIW, Xcode exhibits this same behaviour when you attach to an app that's already running in the simulator (you don't see stdout/stderr for that process). This makes me think that launching within lldb might be the way to go.
One possible solution to this would be instead to handle the IO redirection at a lower level. As part of the script launched with lldb you could do something like this:
expr --language c -- (int)close(1)
expr --language c -- (int)close(2)
expr --language c -- (int)open("path/to/stdout", 0x201, 0777)
expr --language c -- (int)open("path/to/stderr", 0x201, 0777)
FWIW this is much easier now with os log
have a link with more info?
Hmm. Looks like there's some need for blog posts about this. But a simple example of this is:
$ log stream --predicate "subsystem == 'AppName'"
There are some things with usage about this that you have to handle, like changing the predicate to include more things if you want logs from UIKit and such (you can probably do device to but I haven't looked). But from your app if you log a specific code on launch, you can reset the logs in the terminal, and this command persists across app launches, so you can just run it, and tail logs forever, clearing each relaunch.