Skip to content
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

Q: streaming output from an execute #395

Open
jrochkind opened this issue Mar 22, 2017 · 11 comments
Open

Q: streaming output from an execute #395

jrochkind opened this issue Mar 22, 2017 · 11 comments
Labels

Comments

@jrochkind
Copy link

Using sshkit 1.11.1 via Capistrano 3.4.0.

I'd like to do an execute, but get streaming output to the console as it appears from the execute. For me, execute seems to have no output. capture can capture output (that you can write out), but only once it's all done, not streaming.

Looking at the sshkit README, I think I could write my own interaction_handler to do this, not because I actually want any interaction, just to capture and write to console the output as it happens.

But it seems like there's probably a built-in way to do this I'm not finding?

@jrochkind
Copy link
Author

Indeed writing my own very simple interaction handler does what I want.

class StreamOutputInteractionHandler

  def initialize(log_level=:info)
    @log_level = log_level
  end

  def on_data(_command, stream_name, data, channel)
    log(data)
  end

  private

  def log(message)
    SSHKit.config.output.send(@log_level, message) unless @log_level.nil?
  end
end

So that's awesoe that sshkit is flexible enough to accomodate it. I think this is a common use case though, I'm wondering if it's built in a way I did not notice?

@leehambley
Copy link
Member

Hey @jrochkind thanks for the quick spike, that's super interesting - perhaps for now, without closing the door on this topic an entry in the EXAMPLES.md would be a welcome addition?

How to stream output of long running commands

And, since it's a totally valid use-case, maybe we could think about renaming the interaction handler class and tightening up some of these APIs to become part of our public spec?

@jrochkind
Copy link
Author

The output I actually wanted to capture was a ruby-progressbar progress bar -- it does something kind of reasonable for non-TTY output, but is still output progress bar markers char-by-char without newlines, which looked weird in the log.

So one further refinement, I made the class so if you set :log_level to :stderr (I know, not really a log level), it uses $stderr.print data instead of log(data). (note print not puts)

Which actually ends up working quite nicely for a ruby-progressbar non-TTY progressbar!

I don't know if I'll do a PR anytime soon, I'm in the middle of some yak-shaving, but at least this GH issue stands as google-able docs for anyone looking for a solution (or who wants to take it further into a PR) -- I've found answers in existing GH Issues all the time!

@jrochkind
Copy link
Author

I did link to this issue and example on the existing StackOverflow i found asking the same thing, that didn't yet have a satisfactory (to me anyway) answer. http://stackoverflow.com/questions/19291438/capistrano-3-x-capture-output-line-by-line/42959611

@jrochkind
Copy link
Author

jrochkind commented Mar 22, 2017

and thanks for the quick response and confirmation that what I'm doing makes some sense! and for sshkit/capistrano!

@leehambley
Copy link
Member

Thanks @jrochkind let's leave this here and see if someone comes back to it. I'll label it appropriately. Good luck with the yak shaving.

yak shaving

@jrochkind
Copy link
Author

Thanks! Fine with me if you close it, it's still here to be googled.

Not this issue, but i'm having trouble figuring out if execute runs on all hosts in current matching set, or just the first one it finds, and if the latter if there's any way to get it to do just the first one it finds. Can't seem to find this in any docs.

@mattbrictson
Copy link
Member

i'm having trouble figuring out if execute runs on all hosts in current matching set, or just the first one it finds

It depends on the :in option passed to on. By default, it uses in: parallel, which means that execute is run on all hosts in the matching set simultaneously. You can also use in: sequence, in which case the first host is executed, then once that finishes, the second host, and so on.

If you'd like to limit the hosts to just a single host, that's up to you to handle before calling on. Capistrano has a way to do this using primary().

@emkookmer
Copy link

Hey @jrochkind thanks for the quick spike, that's super interesting - perhaps for now, without closing the door on this topic an entry in the EXAMPLES.md would be a welcome addition?

This would be a welcome addition, as I have a similar problem with php composer

@jrochkind
Copy link
Author

I'm not certain if that example still works for me, I think it may have stopped working for me since then, I have not gotten to the bottom of what changed. :(

@jrochkind
Copy link
Author

I agree it would be awesome if cap could officially handle this use case somehow and document it; I don't currently have the bandwidth to help provide a solution, sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants