As I’m using a lot Kubernetes to work on my project, I had the need to be able to view the logs produced by the pods.
Actually, you can use the Kubernetes Dashboard to view the logs but it means you have to use the proxy to connect using http://127.0.0.1 and that solution was not perfect for me.

So I decided to play with the Kubernetes C# SDK and it appears that there is a nice method called ReadNamespacedPodLogAsync:

var stream = await this.kubernetesClient.ReadNamespacedPodLogAsync(pod, ns, follow: true, sinceSeconds: 1500, cancellationToken: cancellationToken);

Problem: this method actually returns a Stream, meaning you’ll get data “on the flow”. So you can’t use it (directly) on a WebAPI controller and you need to find a way to send the chunks as soon as you retrieve them.

This is where IAsyncEnumerable (from C# 8) is useful because it was designed for that purpose! So we can easily have a code similar to this one:

public class LogStreamHub : Hub
{   
    private readonly Kubernetes kubernetesClient;

    public LogStreamHub(Kubernetes kubernetesClient)
    {
        this.kubernetesClient = kubernetesClient;
    }

    public async IAsyncEnumerable<string> GetPodLog(string ns, string pod, [EnumeratorCancellation] CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();

        var stream = await this.kubernetesClient.ReadNamespacedPodLogAsync(pod, ns, follow: true, sinceSeconds: 1500, cancellationToken: cancellationToken);

        var buffer = new byte[8192];

        var count = 0;

        do
        {
            count = stream.Read(buffer, 0, buffer.Length);
            if (count != 0)
            {
                var tmpString = Encoding.Default.GetString(buffer, 0, count);

                yield return tmpString
                        .Replace("\u001b[40m\u001b[37mtrce\u001b[39m\u001b[22m\u001b[49m", "trce")
                        .Replace("\u001b[40m\u001b[37mdbug\u001b[39m\u001b[22m\u001b[49m", "dbug")
                        .Replace("\u001b[40m\u001b[32minfo\u001b[39m\u001b[22m\u001b[49m", "info")
                        .Replace("\u001b[40m\u001b[1m\u001b[33mwarn\u001b[39m\u001b[22m\u001b[49m", "warn")
                        .Replace("\u001b[41m\u001b[30mfail\u001b[39m\u001b[22m\u001b[49m", "fail")
                        .Replace("\u001b[41m\u001b[1m\u001b[37mcrit\u001b[39m\u001b[22m\u001b[49m", "crit");
            }
        } while (count > 0);
    }
}

Note that the Replace stuff is not mandatory but it’s useful if you want to display color on your application, as the .NET Core Console does.

On the client side, using the SignalR Javascript library, we can connect to the GetPodLog method:

function registerForStreamNotifications() {
    signalRSubscription = signalRConnection.stream("GetPodLog", $("#namespaces").val(), $("#pods").val()).subscribe({
        next: (content) => {
            var container = $('<div class="logs-element"></div>');

            var line = $('<span class="log-line">' + applyHighlights(content) + '</span>');
            container.append(line);

            $("#logs").append(container);

            // Auto-scroll
            $('#logs').scrollTop($('#logs')[0].scrollHeight);
        }
    });
}

Running the above code, you are now able to display your logs, in real time, in your application:

Happy coding ! 🙂

PS: For those who are interested, here is the code for the applyHighlights method:

function applyHighlights(text) {
    text = text
        .replace("trce:", '<span class="trce">$&amp;</span>:')
        .replace("trce:", 'trce')
        .replace("dbug:", '<span class="dbug">$&amp;</span>:')
        .replace("dbug:", 'dbug')
        .replace("info:", '<span class="info">$&amp;</span>:')
        .replace("info:", 'info')
        .replace("warn:", '<span class="warn">$&amp;</span>:')
        .replace("warn:", 'warn')
        .replace("fail:", '<span class="fail">$&amp;</span>:')
        .replace("fail:", 'fail')
        .replace("crit:", '<span class="crit">$&amp;</span>:')
        .replace("crit:", 'crit');

    return text;
}

d


How to change the pricing tier of my Azure AppService by code? How to write a pull request comment during your Azure DevOps build ?

Leave a Reply

Your email address will not be published. Required fields are marked *