File: Utils\OutputCollector.cs
Web Access
Project: src\src\Aspire.Cli\Aspire.Cli.csproj (aspire)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Aspire.Cli.Diagnostics;
using Microsoft.Extensions.Logging;
 
namespace Aspire.Cli.Utils;
 
internal enum OutputLineStream
{
    StdOut,
    StdErr
}
 
internal sealed class OutputCollector
{
    private readonly CircularBuffer<(OutputLineStream Stream, string Line)> _lines = new(10000); // 10k lines.
    private readonly object _lock = new object();
    private readonly FileLoggerProvider? _fileLogger;
    private readonly string _category;
 
    /// <summary>
    /// Creates an OutputCollector that only buffers output in memory.
    /// </summary>
    public OutputCollector() : this(null, "AppHost")
    {
    }
 
    /// <summary>
    /// Creates an OutputCollector that buffers output and optionally logs to disk.
    /// </summary>
    /// <param name="fileLogger">Optional file logger for writing output to disk.</param>
    /// <param name="category">Category for log entries (e.g., "Build", "AppHost").</param>
    public OutputCollector(FileLoggerProvider? fileLogger, string category = "AppHost")
    {
        _fileLogger = fileLogger;
        _category = category;
    }
 
    public void AppendOutput(string line)
    {
        AppendLine(OutputLineStream.StdOut, line);
    }
 
    public void AppendError(string line)
    {
        AppendLine(OutputLineStream.StdErr, line);
    }
 
    public IEnumerable<(OutputLineStream Stream, string Line)> GetLines()
    {
        lock (_lock)
        {
            return _lines.ToArray();
        }
    }
 
    private void AppendLine(OutputLineStream stream, string line)
    {
        lock (_lock)
        {
            _lines.Add((stream, line));
            _fileLogger?.WriteLog(DateTimeOffset.UtcNow, stream == OutputLineStream.StdErr ? LogLevel.Error : LogLevel.Information, _category, line);
        }
    }
}