using MediaBrowser.Common.IO; using MediaBrowser.Common.Net; using MediaBrowser.Controller.IO; using MediaBrowser.Model.Logging; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Api.WebSocket { /// /// Class ScheduledTasksWebSocketListener /// public class LogFileWebSocketListener : BasePeriodicWebSocketListener, LogFileWebSocketState> { /// /// Gets the name. /// /// The name. protected override string Name { get { return "LogFile"; } } /// /// The _kernel /// private readonly ILogManager _logManager; private readonly IFileSystem _fileSystem; /// /// Initializes a new instance of the class. /// /// The logger. /// The log manager. public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem) : base(logger) { _logManager = logManager; _fileSystem = fileSystem; _logManager.LoggerLoaded += kernel_LoggerLoaded; } /// /// Gets the data to send. /// /// The state. /// IEnumerable{System.String}. protected override async Task> GetDataToSend(LogFileWebSocketState state) { if (!string.Equals(_logManager.LogFilePath, state.LastLogFilePath)) { state.LastLogFilePath = _logManager.LogFilePath; state.StartLine = 0; } var lines = await GetLogLines(state.LastLogFilePath, state.StartLine, _fileSystem).ConfigureAwait(false); state.StartLine += lines.Count; return lines; } /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool dispose) { if (dispose) { _logManager.LoggerLoaded -= kernel_LoggerLoaded; } base.Dispose(dispose); } /// /// Handles the LoggerLoaded event of the kernel control. /// /// The source of the event. /// The instance containing the event data. void kernel_LoggerLoaded(object sender, EventArgs e) { // Reset the startline for each connection whenever the logger reloads lock (ActiveConnections) { foreach (var connection in ActiveConnections) { connection.Item4.StartLine = 0; } } } /// /// Gets the log lines. /// /// The log file path. /// The start line. /// Task{IEnumerable{System.String}}. internal static async Task> GetLogLines(string logFilePath, int startLine, IFileSystem fileSystem) { var lines = new List(); using (var fs = fileSystem.GetFileStream(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, true)) { using (var reader = new StreamReader(fs)) { while (!reader.EndOfStream) { var line = await reader.ReadLineAsync().ConfigureAwait(false); if (line.IndexOf(", Info,", StringComparison.OrdinalIgnoreCase) != -1 || line.IndexOf(", Warn,", StringComparison.OrdinalIgnoreCase) != -1 || line.IndexOf(", Error,", StringComparison.OrdinalIgnoreCase) != -1) { lines.Add(line); } } } } if (startLine > 0) { lines = lines.Skip(startLine).ToList(); } return lines; } } /// /// Class LogFileWebSocketState /// public class LogFileWebSocketState { /// /// Gets or sets the last log file path. /// /// The last log file path. public string LastLogFilePath { get; set; } /// /// Gets or sets the start line. /// /// The start line. public int StartLine { get; set; } } }