mirror of https://github.com/Squidex/squidex.git
9 changed files with 172 additions and 18 deletions
@ -0,0 +1,34 @@ |
|||||
|
// ==========================================================================
|
||||
|
// FileChannel.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Infrastructure.Log.Internal; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Log |
||||
|
{ |
||||
|
public sealed class FileChannel : ILogChannel, IExternalSystem |
||||
|
{ |
||||
|
private readonly FileLogProcessor processor; |
||||
|
|
||||
|
public FileChannel(string path) |
||||
|
{ |
||||
|
Guard.NotNullOrEmpty(path, nameof(path)); |
||||
|
|
||||
|
processor = new FileLogProcessor(path); |
||||
|
} |
||||
|
|
||||
|
public void Log(SemanticLogLevel logLevel, string message) |
||||
|
{ |
||||
|
processor.EnqueueMessage(new LogMessageEntry { Message = message, Level = logLevel }); |
||||
|
} |
||||
|
|
||||
|
public void Connect() |
||||
|
{ |
||||
|
processor.Connect(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,95 @@ |
|||||
|
// ==========================================================================
|
||||
|
// FileLogChannel.cs
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex Group
|
||||
|
// All rights reserved.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.IO; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Squidex.Infrastructure.Log.Internal |
||||
|
{ |
||||
|
public class FileLogProcessor : IDisposable |
||||
|
{ |
||||
|
private const int MaxQueuedMessages = 1024; |
||||
|
private const int Retries = 10; |
||||
|
private readonly BlockingCollection<LogMessageEntry> messageQueue = new BlockingCollection<LogMessageEntry>(MaxQueuedMessages); |
||||
|
private readonly Task outputTask; |
||||
|
private readonly string path; |
||||
|
|
||||
|
public FileLogProcessor(string path) |
||||
|
{ |
||||
|
this.path = path; |
||||
|
|
||||
|
outputTask = Task.Factory.StartNew(ProcessLogQueue, this, TaskCreationOptions.LongRunning); |
||||
|
} |
||||
|
|
||||
|
public void Connect() |
||||
|
{ |
||||
|
var fileInfo = new FileInfo(path); |
||||
|
|
||||
|
if (!fileInfo.Directory.Exists) |
||||
|
{ |
||||
|
throw new ConfigurationException($"Log directory '{fileInfo.Directory.FullName}' does not exist."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public void EnqueueMessage(LogMessageEntry message) |
||||
|
{ |
||||
|
messageQueue.Add(message); |
||||
|
} |
||||
|
|
||||
|
private async Task ProcessLogQueue() |
||||
|
{ |
||||
|
foreach (var entry in messageQueue.GetConsumingEnumerable()) |
||||
|
{ |
||||
|
for (var i = 1; i <= Retries; i++) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
File.AppendAllText(path, entry.Message + Environment.NewLine, Encoding.UTF8); |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
await Task.Delay(i * 10); |
||||
|
|
||||
|
if (i == Retries) |
||||
|
{ |
||||
|
Console.WriteLine("Failed to write to log file '{0}': {1}", path, ex); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static Task ProcessLogQueue(object state) |
||||
|
{ |
||||
|
var processor = (FileLogProcessor)state; |
||||
|
|
||||
|
return processor.ProcessLogQueue(); |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
messageQueue.CompleteAdding(); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
outputTask.Wait(1500); |
||||
|
} |
||||
|
catch (TaskCanceledException) |
||||
|
{ |
||||
|
} |
||||
|
catch (AggregateException ex) when (ex.InnerExceptions.Count == 1 && ex.InnerExceptions[0] is TaskCanceledException) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue