sshnet / SSH.NET

SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism.
http://sshnet.github.io/SSH.NET/
MIT License
3.88k stars 917 forks source link

add optional execution timestamp #1365

Closed michaelSant0s closed 2 months ago

michaelSant0s commented 3 months ago

When executing a command that outputs many lines of text its not possible to know when there was which output. In situations where you want to know how much time it took between outputs it would be helpful to see the exact time when the output occured.

This is why i want to add an optional timestamp before the output of a command.

Rob-Hague commented 2 months ago

Thanks for the PR @michaelSant0s. I understand the use case but I'm not sure this is something worth building in to the library.

You might already be able to achieve the desired behaviour by wrapping SshCommand.OutputStream with a System.IO.StreamReader?

michaelSant0s commented 2 months ago

Thanks for the PR @michaelSant0s. I understand the use case but I'm not sure this is something worth building in to the library.

You might already be able to achieve the desired behaviour by wrapping SshCommand.OutputStream with a System.IO.StreamReader?

Thank you for helping me out! This works exactly like i need it to work.

michaelSant0s commented 2 months ago

If somebody wants to have the same feature, here is an extension function i created with the help of @Rob-Hague 's informations.

namespace Renci.SshNet
{
    public static class SshNetExtension
    {
        public static async Task<string> ExecuteWithTimestamp(this SshClient sshClient, string command)
        {
            using SshCommand sshCommand = sshClient.CreateCommand(command);
            IAsyncResult async = sshCommand.BeginExecute();

            Stream stream = sshCommand.OutputStream;
            StreamReader streamReader = new StreamReader(stream);

            string result = "";

            bool completed = false;
            Task streamReaderTask = Task.Run(() =>
            {
                while (!completed)
                {
                    if (streamReader.Peek() > 0)
                    {
                        result += $"[{DateTime.Now}]: {streamReader.ReadLine()}\n";
                    }
                    else
                    {
                        Thread.Sleep(5);
                    }
                }
            });

            string lastLine = sshCommand.EndExecute(async);
            result += $"[{DateTime.Now}]: {lastLine}\n";

            completed = true;
            await streamReaderTask;

            // using StreamReader will dispose it too early
            streamReader.Dispose();
            return result;
        }
    }
}
zybexXL commented 2 months ago

You should use BeginRead with a callback instead of waking up the thread 200 times per second to poll the reader: https://stackoverflow.com/questions/2784878/continuously-reading-from-a-stream