From 7e6f4453ad921a4880d3f1f586cd70dad6b81dc0 Mon Sep 17 00:00:00 2001 From: Jan Eggers Date: Mon, 23 Oct 2017 12:42:31 +0200 Subject: [PATCH] added back MqttTrace consuming api --- Frameworks/MQTTnet.NetStandard/MqttFactory.cs | 7 ++- .../ServiceCollectionExtensions.cs | 9 +++- MQTTnet.Core/Diagnostics/MqttNetLogger.cs | 49 ++++++++++++++++++ MQTTnet.Core/Diagnostics/MqttNetTrace.cs | 33 ++++++++++++ .../MqttNetTraceMessagePublishedEventArgs.cs | 14 +++++ MQTTnet.Core/Diagnostics/MqttTraceMessage.cs | 30 +++++++++++ MQTTnet.Core/MQTTnet.Core.csproj | 1 + .../MqttLoggerProviderTest.cs | 51 +++++++++++++++++++ 8 files changed, 192 insertions(+), 2 deletions(-) create mode 100644 MQTTnet.Core/Diagnostics/MqttNetLogger.cs create mode 100644 MQTTnet.Core/Diagnostics/MqttNetTrace.cs create mode 100644 MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs create mode 100644 MQTTnet.Core/Diagnostics/MqttTraceMessage.cs create mode 100644 Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs diff --git a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs index 3ac03d20..2c18ed96 100644 --- a/Frameworks/MQTTnet.NetStandard/MqttFactory.cs +++ b/Frameworks/MQTTnet.NetStandard/MqttFactory.cs @@ -18,11 +18,16 @@ namespace MQTTnet private static IServiceProvider BuildServiceProvider() { - return new ServiceCollection() + var serviceProvider = new ServiceCollection() .AddMqttClient() .AddMqttServer() .AddLogging() .BuildServiceProvider(); + + serviceProvider.GetRequiredService() + .AddMqttTrace(); + + return serviceProvider; } public MqttFactory() diff --git a/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs b/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs index c0578826..f8f647a9 100644 --- a/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs +++ b/Frameworks/MQTTnet.NetStandard/ServiceCollectionExtensions.cs @@ -6,6 +6,8 @@ using MQTTnet.Core.Serializer; using MQTTnet.Core.Server; using MQTTnet.Implementations; using System; +using Microsoft.Extensions.Logging; +using MQTTnet.Core.Diagnostics; namespace MQTTnet { @@ -27,7 +29,6 @@ namespace MQTTnet services.AddTransient(); services.AddTransient(); - return services; } @@ -51,5 +52,11 @@ namespace MQTTnet return services; } + + public static ILoggerFactory AddMqttTrace(this ILoggerFactory factory) + { + factory.AddProvider(new MqttNetTrace()); + return factory; + } } } diff --git a/MQTTnet.Core/Diagnostics/MqttNetLogger.cs b/MQTTnet.Core/Diagnostics/MqttNetLogger.cs new file mode 100644 index 00000000..54ab6d44 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttNetLogger.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.Extensions.Logging; + +namespace MQTTnet.Core.Diagnostics +{ + public class MqttNetLogger : ILogger + { + private readonly string _categoryName; + private readonly MqttNetTrace _mqttNetTrace; + + public MqttNetLogger(string categoryName, MqttNetTrace mqttNetTrace) + { + _categoryName = categoryName; + _mqttNetTrace = mqttNetTrace; + } + + public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + { + if (formatter == null) + { + throw new ArgumentNullException(nameof(formatter)); + } + + var message = formatter(state, exception); + + var traceMessage = new MqttNetTraceMessage(DateTime.Now, Environment.CurrentManagedThreadId, _categoryName, logLevel, message, exception); + _mqttNetTrace.Publish(traceMessage); + } + + public bool IsEnabled(LogLevel logLevel) + { + return true; + } + + //not supported: async local requires netstandard1.3 + //for implementation see https://github.com/aspnet/Logging/blob/dev/src/Microsoft.Extensions.Logging.Console/ConsoleLogScope.cs + public IDisposable BeginScope(TState state) + { + return new DisposableScope(); + } + + private class DisposableScope : IDisposable + { + public void Dispose() + { + } + } + } +} \ No newline at end of file diff --git a/MQTTnet.Core/Diagnostics/MqttNetTrace.cs b/MQTTnet.Core/Diagnostics/MqttNetTrace.cs new file mode 100644 index 00000000..c14d4931 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttNetTrace.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Concurrent; +using Microsoft.Extensions.Logging; + +namespace MQTTnet.Core.Diagnostics +{ + public class MqttNetTrace : ILoggerProvider + { + private readonly ConcurrentDictionary _loggers = new ConcurrentDictionary(); + + public static event EventHandler TraceMessagePublished; + + public void Publish(MqttNetTraceMessage msg) + { + TraceMessagePublished?.Invoke(this, new MqttNetTraceMessagePublishedEventArgs(msg)); + } + + public void Dispose() + { + TraceMessagePublished = null; + } + + public ILogger CreateLogger(string categoryName) + { + return _loggers.GetOrAdd(categoryName, CreateLoggerImplementation); + } + + private MqttNetLogger CreateLoggerImplementation(string categoryName) + { + return new MqttNetLogger(categoryName, this); + } + } +} diff --git a/MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs b/MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs new file mode 100644 index 00000000..5b8f796d --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttNetTraceMessagePublishedEventArgs.cs @@ -0,0 +1,14 @@ +using System; + +namespace MQTTnet.Core.Diagnostics +{ + public sealed class MqttNetTraceMessagePublishedEventArgs : EventArgs + { + public MqttNetTraceMessagePublishedEventArgs(MqttNetTraceMessage traceMessage) + { + TraceMessage = traceMessage ?? throw new ArgumentNullException(nameof(traceMessage)); + } + + public MqttNetTraceMessage TraceMessage { get; } + } +} diff --git a/MQTTnet.Core/Diagnostics/MqttTraceMessage.cs b/MQTTnet.Core/Diagnostics/MqttTraceMessage.cs new file mode 100644 index 00000000..852aae45 --- /dev/null +++ b/MQTTnet.Core/Diagnostics/MqttTraceMessage.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.Extensions.Logging; + +namespace MQTTnet.Core.Diagnostics +{ + public sealed class MqttNetTraceMessage + { + public MqttNetTraceMessage(DateTime timestamp, int threadId, string source, LogLevel level, string message, Exception exception) + { + Timestamp = timestamp; + ThreadId = threadId; + Source = source; + Level = level; + Message = message; + Exception = exception; + } + + public DateTime Timestamp { get; } + + public int ThreadId { get; } + + public string Source { get; } + + public LogLevel Level { get; } + + public string Message { get; } + + public Exception Exception { get; } + } +} diff --git a/MQTTnet.Core/MQTTnet.Core.csproj b/MQTTnet.Core/MQTTnet.Core.csproj index 3e877421..71a518d5 100644 --- a/MQTTnet.Core/MQTTnet.Core.csproj +++ b/MQTTnet.Core/MQTTnet.Core.csproj @@ -25,6 +25,7 @@ + \ No newline at end of file diff --git a/Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs b/Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs new file mode 100644 index 00000000..bda3195e --- /dev/null +++ b/Tests/MQTTnet.Core.Tests/MqttLoggerProviderTest.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MQTTnet.Core.Diagnostics; + +namespace MQTTnet.Core.Tests +{ + [TestClass] + public class MqttLoggerProviderTest + { + [TestMethod] + public void TestLoggerCallback() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddLogging(); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + using ((IDisposable)serviceProvider) + { + var loggerFactory = serviceProvider.GetRequiredService(); + + loggerFactory.AddMqttTrace(); + + var expectedMsg = "Hello World!"; + MqttNetTraceMessage msg = null; + + MqttNetTrace.TraceMessagePublished += (sender, args) => + { + msg = args.TraceMessage; + }; + + var logger = loggerFactory.CreateLogger(); + + logger.LogInformation(expectedMsg); + + Assert.AreEqual(expectedMsg, msg.Message); + + var expectedException = new Exception("bad stuff"); + + logger.LogError(new EventId(), expectedException, expectedException.Message); + + Assert.AreEqual(expectedException, msg.Exception); + Assert.AreEqual(expectedException.Message, msg.Message); + } + } + } +}