1

ASP.NET Core 9 MVC controller reads Debian 12 journal using:

  public async Task<IActionResult> Syslog(string param = "-r -u eevatest.service --since \"2 days ago\""
    )
  {
    var p = new Process
    {
      StartInfo = { CreateNoWindow = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    RedirectStandardInput = true,
                    UseShellExecute = false,
                    FileName = "/usr/bin/journalctl"
                }
    };

    p.StartInfo.Arguments = param;

    if (!p.Start())
      throw new Exception("journalctl not started");

    var buffer = new byte[32768];
    byte[] file;

    using (var ms = new MemoryStream())
    {
      while (true)
      {
        Thread.Sleep(10 * 1000);
        var read = await p.StandardOutput.BaseStream.ReadAsync(buffer.AsMemory(0, buffer.Length));
        if (read <= 0)
          break;
        await ms.WriteAsync(buffer.AsMemory(0, read));
      }
      file = ms.ToArray();
    }

    if (!p.WaitForExit(60000))
      throw new Exception("journalctl not exited");

    var returnCode = p.ExitCode;
    p.Close();

    if (returnCode != 0) {
//Reading standard error throws
// System.InvalidOperationException: StandardError has not been redirected.
// var log = await p.StandardError.ReadToEndAsync();

      throw new Exception(returnCode  +" journalctl exit error, length "+ file.Length );
}

    return new ContentResult() { Content = Encoding.UTF8.GetString(file) };
  }

This code throws exception:

journalctl exit code is 1 and file.Length is 0

I tried to read standard error as shown in comment using:

var log = await p.StandardError.ReadToEndAsync();

but this throws

System.InvalidOperationException: StandardError has not been redirected.

How to read Linux journal in Debian 12 in an ASP.NET Core 9 MVC controller?

6
  • Not an answer to your question, but it seems you're just trying to read a file, there are better ways to do that than process. Commented Feb 2 at 22:21
  • journal is in binary file or in multiple files. journalctl extracts readable text from those files. There are no packages in .NET which can directly read journal files. syslog-ng can create text files from it but those files are rotated, gzipped and each log has different file. I'm looking for a way to query journal directly without creating text files from it. Commented Feb 2 at 22:36
  • Not sure if it's a duplicate because you're on Linux, but here is a similar question with lots of answers, maybe it can help: stackoverflow.com/q/4291912/1220550 Commented Feb 2 at 23:08
  • Maybe p is closed after WaitForExit(), causing p.StandardError to be inaccessible. Commented Feb 3 at 3:02
  • 1
    Please try to modify the code like this gist link, it works for me. Please let me know if it works for you. Commented Feb 3 at 3:03

1 Answer 1

1

p is closed after WaitForExit(), causing p.StandardError to be inaccessible.

So we can modify the code like below.

public async Task<IActionResult> Syslog(string param = "-r -u eevatest.service --since \"2 days ago\"")
{
    var p = new Process
    {
        StartInfo = {
            FileName = "/usr/bin/journalctl",
            Arguments = param,
            RedirectStandardOutput = true,
            RedirectStandardError = true,  
            UseShellExecute = false,
            CreateNoWindow = true
        }
    };

    try
    {
        p.Start(); 

        Task<string> errorTask = p.StandardError.ReadToEndAsync();
        Task<byte[]> outputTask = ReadStreamAsync(p.StandardOutput.BaseStream);

        bool exited = await Task.Run(() => p.WaitForExit(60000));
        if (!exited)
            throw new Exception("journalctl did not exit in time");

        string errorOutput = await errorTask;
        byte[] output = await outputTask;

        if (p.ExitCode != 0)
            throw new Exception($"journalctl exited with code {p.ExitCode}, error: {errorOutput}");

        return new ContentResult { Content = Encoding.UTF8.GetString(output) };
    }
    finally
    {
        p.Dispose(); 
    }
}

private static async Task<byte[]> ReadStreamAsync(Stream stream)
{
    using var ms = new MemoryStream();
    await stream.CopyToAsync(ms);
    return ms.ToArray();
}

It works for me.

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

Another related question is in stackoverflow.com/questions/79434420/…

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.