如何在ASP.NET Core 9 MVC控制器中读取Debian 12系统日志?
ASP.NET Core 9 MVC读取Debian 12系统日志的修复方案
问题回顾
调用journalctl读取系统日志时遇到两个问题:
- 进程退出码为1,输出内容为空
- 尝试读取标准错误时提示
StandardError has not been redirected,尽管代码中已设置RedirectStandardError = true
原代码:
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) }; }
修复步骤
1. 修正标准错误读取逻辑
错误根源是读取时机错误:你在调用p.Close()后才尝试读取标准错误,此时流已被释放。需要提前启动异步读取任务,在进程退出后再获取结果。
2. 优化进程异步处理逻辑
- 移除
Thread.Sleep,改用异步读取避免不必要的等待 - 使用
WaitForExitAsync替代同步的WaitForExit,符合ASP.NET Core异步编程规范 - 同时读取标准输出和错误,防止因输出缓冲区满导致进程挂起
3. 权限检查
ASP.NET Core默认运行用户(通常是www-data)可能没有读取系统日志的权限,执行以下命令添加权限:
sudo usermod -aG systemd-journal www-data
执行后重启ASP.NET Core服务生效。
4. 修正参数传递(可选)
避免嵌套转义带来的参数解析问题,推荐用ArgumentList传递参数:
p.StartInfo.ArgumentList.AddRange(new[] { "-r", "-u", "eevatest.service", "--since", "2 days ago" });
完整修复代码
public async Task<IActionResult> Syslog(string param = "-r -u eevatest.service --since \"2 days ago\"") { using var process = new Process { StartInfo = { CreateNoWindow = true, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, UseShellExecute = false, FileName = "/usr/bin/journalctl", Arguments = param } }; // 提前启动异步读取任务,避免进程阻塞 var outputTask = process.StandardOutput.ReadToEndAsync(); var errorTask = process.StandardError.ReadToEndAsync(); if (!process.Start()) throw new Exception("journalctl 启动失败"); // 异步等待进程退出,超时时间60秒 if (!await process.WaitForExitAsync(TimeSpan.FromSeconds(60))) throw new Exception("journalctl 未按时退出"); // 获取读取结果 var logContent = await outputTask; var errorContent = await errorTask; var exitCode = process.ExitCode; if (exitCode != 0) { throw new Exception($"journalctl 退出错误,代码:{exitCode},错误信息:{errorContent}"); } return new ContentResult { Content = logContent, ContentType = "text/plain; charset=utf-8" }; }
内容的提问来源于stack exchange,提问作者Andrus
相关产品推荐
相关产品推荐

