123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using MediaBrowser.Model.Logging;
- namespace Emby.Server.Implementations.Logging
- {
- public class SimpleLogManager : ILogManager, IDisposable
- {
- public LogSeverity LogSeverity { get; set; }
- public string ExceptionMessagePrefix { get; set; }
- private FileLogger _fileLogger;
- private readonly string LogDirectory;
- private readonly string LogFilePrefix;
- public string DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
- public SimpleLogManager(string logDirectory, string logFileNamePrefix)
- {
- LogDirectory = logDirectory;
- LogFilePrefix = logFileNamePrefix;
- }
- public ILogger GetLogger(string name)
- {
- return new NamedLogger(name, this);
- }
- public async Task ReloadLogger(LogSeverity severity, CancellationToken cancellationToken)
- {
- LogSeverity = severity;
- var logger = _fileLogger;
- if (logger != null)
- {
- logger.Dispose();
- await TryMoveToArchive(logger.Path, cancellationToken).ConfigureAwait(false);
- }
- var newPath = Path.Combine(LogDirectory, LogFilePrefix + ".txt");
- if (File.Exists(newPath))
- {
- newPath = await TryMoveToArchive(newPath, cancellationToken).ConfigureAwait(false);
- }
- _fileLogger = new FileLogger(newPath);
- if (LoggerLoaded != null)
- {
- try
- {
- LoggerLoaded(this, EventArgs.Empty);
- }
- catch (Exception ex)
- {
- GetLogger("Logger").ErrorException("Error in LoggerLoaded event", ex);
- }
- }
- }
- private async Task<string> TryMoveToArchive(string file, CancellationToken cancellationToken, int retryCount = 0)
- {
- var archivePath = GetArchiveFilePath();
- try
- {
- File.Move(file, archivePath);
- return file;
- }
- catch (FileNotFoundException)
- {
- return file;
- }
- catch (DirectoryNotFoundException)
- {
- return file;
- }
- catch
- {
- if (retryCount >= 50)
- {
- return GetArchiveFilePath();
- }
- await Task.Delay(100, cancellationToken).ConfigureAwait(false);
- return await TryMoveToArchive(file, cancellationToken, retryCount + 1).ConfigureAwait(false);
- }
- }
- private string GetArchiveFilePath()
- {
- return Path.Combine(LogDirectory, LogFilePrefix + "-" + decimal.Floor(DateTime.Now.Ticks / 10000000) + ".txt");
- }
- public event EventHandler LoggerLoaded;
- public void Flush()
- {
- var logger = _fileLogger;
- if (logger != null)
- {
- logger.Flush();
- }
- }
- private bool _console = true;
- public void AddConsoleOutput()
- {
- _console = true;
- }
- public void RemoveConsoleOutput()
- {
- _console = false;
- }
- public void Log(string message)
- {
- if (_console)
- {
- Console.WriteLine(message);
- }
- var logger = _fileLogger;
- if (logger != null)
- {
- message = DateTime.Now.ToString(DateTimeFormat) + " " + message;
- logger.Log(message);
- }
- }
- public void Dispose()
- {
- var logger = _fileLogger;
- if (logger != null)
- {
- logger.Dispose();
- var task = TryMoveToArchive(logger.Path, CancellationToken.None);
- Task.WaitAll(task);
- }
- _fileLogger = null;
- }
- }
- public class FileLogger : IDisposable
- {
- private readonly FileStream _fileStream;
- private bool _disposed;
- private readonly CancellationTokenSource _cancellationTokenSource;
- private readonly BlockingCollection<string> _queue = new BlockingCollection<string>();
- public string Path { get; set; }
- public FileLogger(string path)
- {
- Path = path;
- Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
- _fileStream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read, 32768);
- _cancellationTokenSource = new CancellationTokenSource();
- Task.Factory.StartNew(LogInternal, _cancellationTokenSource.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
- }
- private void LogInternal()
- {
- while (!_cancellationTokenSource.IsCancellationRequested && !_disposed)
- {
- try
- {
- foreach (var message in _queue.GetConsumingEnumerable())
- {
- var bytes = Encoding.UTF8.GetBytes(message + Environment.NewLine);
- if (_disposed)
- {
- return;
- }
- _fileStream.Write(bytes, 0, bytes.Length);
- if (_disposed)
- {
- return;
- }
- _fileStream.Flush(true);
- }
- }
- catch
- {
- }
- }
- }
- public void Log(string message)
- {
- if (_disposed)
- {
- return;
- }
- _queue.Add(message);
- }
- public void Flush()
- {
- if (_disposed)
- {
- return;
- }
- _fileStream.Flush(true);
- }
- public void Dispose()
- {
- if (_disposed)
- {
- return;
- }
- _disposed = true;
- _cancellationTokenSource.Cancel();
- var stream = _fileStream;
- if (stream != null)
- {
- using (stream)
- {
- stream.Flush(true);
- }
- }
- }
- }
- public class NamedLogger : ILogger
- {
- public string Name { get; private set; }
- private readonly SimpleLogManager _logManager;
- public NamedLogger(string name, SimpleLogManager logManager)
- {
- Name = name;
- _logManager = logManager;
- }
- public void Info(string message, params object[] paramList)
- {
- Log(LogSeverity.Info, message, paramList);
- }
- public void Error(string message, params object[] paramList)
- {
- Log(LogSeverity.Error, message, paramList);
- }
- public void Warn(string message, params object[] paramList)
- {
- Log(LogSeverity.Warn, message, paramList);
- }
- public void Debug(string message, params object[] paramList)
- {
- if (_logManager.LogSeverity == LogSeverity.Info)
- {
- return;
- }
- Log(LogSeverity.Debug, message, paramList);
- }
- public void Fatal(string message, params object[] paramList)
- {
- Log(LogSeverity.Fatal, message, paramList);
- }
- public void FatalException(string message, Exception exception, params object[] paramList)
- {
- ErrorException(message, exception, paramList);
- }
- public void ErrorException(string message, Exception exception, params object[] paramList)
- {
- LogException(LogSeverity.Error, message, exception, paramList);
- }
- private void LogException(LogSeverity level, string message, Exception exception, params object[] paramList)
- {
- message = FormatMessage(message, paramList).Replace(Environment.NewLine, ". ");
- var messageText = LogHelper.GetLogMessage(exception);
- var prefix = _logManager.ExceptionMessagePrefix;
- if (!string.IsNullOrWhiteSpace(prefix))
- {
- messageText.Insert(0, prefix);
- }
- LogMultiline(message, level, messageText);
- }
- private static string FormatMessage(string message, params object[] paramList)
- {
- if (paramList != null)
- {
- for (var i = 0; i < paramList.Length; i++)
- {
- var obj = paramList[i];
- message = message.Replace("{" + i + "}", (obj == null ? "null" : obj.ToString()));
- }
- }
- return message;
- }
- public void LogMultiline(string message, LogSeverity severity, StringBuilder additionalContent)
- {
- if (severity == LogSeverity.Debug && _logManager.LogSeverity == LogSeverity.Info)
- {
- return;
- }
- additionalContent.Insert(0, message + Environment.NewLine);
- const char tabChar = '\t';
- var text = additionalContent.ToString()
- .Replace(Environment.NewLine, Environment.NewLine + tabChar)
- .TrimEnd(tabChar);
- if (text.EndsWith(Environment.NewLine))
- {
- text = text.Substring(0, text.LastIndexOf(Environment.NewLine, StringComparison.OrdinalIgnoreCase));
- }
- Log(severity, text);
- }
- public void Log(LogSeverity severity, string message, params object[] paramList)
- {
- message = severity + " " + Name + ": " + FormatMessage(message, paramList);
- _logManager.Log(message);
- }
- }
- }
|