// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Diagnostics; using Microsoft.Extensions.Logging; namespace EpicGames.Core { /// /// Manages a status message for a long running operation, which can be updated with progress. Typically transient on consoles, and written to the same line. /// public interface ILoggerProgress : IDisposable { /// /// Prefix message for the status /// string Message { get; } /// /// The current /// string Progress { get; set; } } /// /// Extension methods for status objects /// public static class LoggerProgressExtensions { /// /// Concrete implementation of /// class LoggerProgress : ILoggerProgress { /// /// The logger to output to /// private readonly ILogger _logger; /// /// Prefix message for the status /// public string Message { get; } /// /// The current /// public string Progress { get => _progressInternal; set { _progressInternal = value; if (_timer.Elapsed > TimeSpan.FromSeconds(3.0)) { _lastOutput = String.Empty; Flush(); _timer.Restart(); } } } /// /// The last string that was output /// string _lastOutput = String.Empty; /// /// Backing storage for the Progress string /// string _progressInternal = String.Empty; /// /// Timer since the last update /// readonly Stopwatch _timer = Stopwatch.StartNew(); /// /// Constructor /// /// The logger to write to /// The base message to display public LoggerProgress(ILogger logger, string message) { _logger = logger; Message = message; _progressInternal = String.Empty; logger.LogInformation("{Progress}", message); } /// /// Dispose of this object /// public void Dispose() { Flush(); } /// /// Flushes the current output to the log /// void Flush() { string output = Message; if (!String.IsNullOrEmpty(Progress)) { output += $" {Progress}"; } if (!String.Equals(output, _lastOutput, StringComparison.Ordinal)) { _logger.LogInformation("{Progress}", output); _lastOutput = output; } } } /// /// Begins a new progress scope /// /// The logger being written to /// The message prefix /// Scope object, which should be disposed when finished public static ILoggerProgress BeginProgressScope(this ILogger logger, string message) { return new LoggerProgress(logger, message); } } }