aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api/WebSocket/LogFileWebSocketListener.cs
blob: 7fbea2f4013518770a82613b1d5339f4f625a9b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
{
    /// <summary>
    /// Class ScheduledTasksWebSocketListener
    /// </summary>
    public class LogFileWebSocketListener : BasePeriodicWebSocketListener<IEnumerable<string>, LogFileWebSocketState>
    {
        /// <summary>
        /// Gets the name.
        /// </summary>
        /// <value>The name.</value>
        protected override string Name
        {
            get { return "LogFile"; }
        }

        /// <summary>
        /// The _kernel
        /// </summary>
        private readonly ILogManager _logManager;
        private readonly IFileSystem _fileSystem;

        /// <summary>
        /// Initializes a new instance of the <see cref="LogFileWebSocketListener" /> class.
        /// </summary>
        /// <param name="logger">The logger.</param>
        /// <param name="logManager">The log manager.</param>
        public LogFileWebSocketListener(ILogger logger, ILogManager logManager, IFileSystem fileSystem)
            : base(logger)
        {
            _logManager = logManager;
            _fileSystem = fileSystem;
            _logManager.LoggerLoaded += kernel_LoggerLoaded;
        }

        /// <summary>
        /// Gets the data to send.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>IEnumerable{System.String}.</returns>
        protected override async Task<IEnumerable<string>> 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;
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool dispose)
        {
            if (dispose)
            {
                _logManager.LoggerLoaded -= kernel_LoggerLoaded;
            }
            base.Dispose(dispose);
        }

        /// <summary>
        /// Handles the LoggerLoaded event of the kernel control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
        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;
                }
            }
        }

        /// <summary>
        /// Gets the log lines.
        /// </summary>
        /// <param name="logFilePath">The log file path.</param>
        /// <param name="startLine">The start line.</param>
        /// <returns>Task{IEnumerable{System.String}}.</returns>
        internal static async Task<List<string>> GetLogLines(string logFilePath, int startLine, IFileSystem fileSystem)
        {
            var lines = new List<string>();

            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;
        }
    }

    /// <summary>
    /// Class LogFileWebSocketState
    /// </summary>
    public class LogFileWebSocketState
    {
        /// <summary>
        /// Gets or sets the last log file path.
        /// </summary>
        /// <value>The last log file path.</value>
        public string LastLogFilePath { get; set; }
        /// <summary>
        /// Gets or sets the start line.
        /// </summary>
        /// <value>The start line.</value>
        public int StartLine { get; set; }
    }
}