diff --git a/AMT.Extensions.Logging/IP/Internal/NullExternalScopeProvider.cs b/AMT.Extensions.Logging/IP/Internal/NullExternalScopeProvider.cs
index 9163a4d..6aac5ba 100644
--- a/AMT.Extensions.Logging/IP/Internal/NullExternalScopeProvider.cs
+++ b/AMT.Extensions.Logging/IP/Internal/NullExternalScopeProvider.cs
@@ -6,13 +6,15 @@
using Microsoft.Extensions.Logging;
using System;
+using System.Diagnostics.CodeAnalysis;
namespace AMT.Extensions.Logging.IP
{
///
/// Scope provider that does nothing.
///
- internal class NullExternalScopeProvider : IExternalScopeProvider
+ [ExcludeFromCodeCoverage]
+ public class NullExternalScopeProvider : IExternalScopeProvider
{
private NullExternalScopeProvider()
{
diff --git a/AMT.Extensions.Logging/IP/Internal/NullScope.cs b/AMT.Extensions.Logging/IP/Internal/NullScope.cs
index 43525b5..ecefa1b 100644
--- a/AMT.Extensions.Logging/IP/Internal/NullScope.cs
+++ b/AMT.Extensions.Logging/IP/Internal/NullScope.cs
@@ -5,12 +5,14 @@
// due to it being internal access there.
using System;
+using System.Diagnostics.CodeAnalysis;
namespace AMT.Extensions.Logging.IP
{
///
/// An empty scope without any logic
///
+ [ExcludeFromCodeCoverage]
internal class NullScope : IDisposable
{
public static NullScope Instance { get; } = new NullScope();
diff --git a/AMT.Extensions.Logging/IP/UdpLoggerProcessor.cs b/AMT.Extensions.Logging/IP/UdpLoggerProcessor.cs
index 335a490..0f0d7db 100644
--- a/AMT.Extensions.Logging/IP/UdpLoggerProcessor.cs
+++ b/AMT.Extensions.Logging/IP/UdpLoggerProcessor.cs
@@ -49,11 +49,7 @@ public virtual void EnqueueMessage(LogMessageEntry message)
}
// Adding is completed so just log the message
- try
- {
- WriteMessage(message);
- }
- catch (Exception) { }
+ WriteMessage(message);
}
internal virtual void WriteMessage(LogMessageEntry entry)
@@ -96,13 +92,17 @@ public void Dispose()
_messageQueue.CompleteAdding();
_shutdown = true;
+ // Give the sender time to complete its tasks
try
{
+ // TODO: use a config value for timeout
_outputThread.Join(1500); // with timeout in-case Console is locked by user input
}
catch (ThreadStateException) { }
_udpSender.Dispose();
+ // Clear any messages
+ _messageQueue.Dispose();
}
#endregion IDisposable impl
diff --git a/AMT.Extensions.Logging/IP/UdpLoggerProvider.cs b/AMT.Extensions.Logging/IP/UdpLoggerProvider.cs
index 64e44c7..4c9019a 100644
--- a/AMT.Extensions.Logging/IP/UdpLoggerProvider.cs
+++ b/AMT.Extensions.Logging/IP/UdpLoggerProvider.cs
@@ -37,7 +37,13 @@ public ILogger CreateLogger(string category)
public void SetScopeProvider(IExternalScopeProvider scopeProvider)
{
- _scopeProvider = scopeProvider;
+ if (null == scopeProvider)
+ {
+ _scopeProvider = NullExternalScopeProvider.Instance;
+ } else
+ {
+ _scopeProvider = scopeProvider;
+ }
}
#endregion ISupportExternalScope impl
diff --git a/Test.AMT.Extensions.Logging/IP/UdpLoggerProcessorTests.cs b/Test.AMT.Extensions.Logging/IP/UdpLoggerProcessorTests.cs
new file mode 100644
index 0000000..1b084a1
--- /dev/null
+++ b/Test.AMT.Extensions.Logging/IP/UdpLoggerProcessorTests.cs
@@ -0,0 +1,44 @@
+// Copyright (c) AltaModa Technologies. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Ext = AMT.Extensions.Logging.IP;
+using FluentAssertions;
+using System;
+using System.Diagnostics.CodeAnalysis;
+using Xunit;
+using AMT.Extensions.Logging.IP;
+
+
+namespace Test.AMT.Extensions.Logging.IP
+{
+ [ExcludeFromCodeCoverage]
+ public class UdpLoggerProcessorTests
+ {
+
+ [Fact]
+ public void excp_on_null_options()
+ {
+ Action act = () => new Ext.UdpLoggerProcessor(null);
+ act.Should().Throw();
+ }
+
+
+ #region IDisposable tests
+
+ [Fact]
+ public void verify_disposable()
+ {
+ using (var proc = new Ext.UdpLoggerProcessor(_opts))
+ {
+ var udpProv = new Ext.UdpLoggerProvider(_opts);
+ }
+
+ }
+
+ #endregion IDisposable tests
+
+
+ private static readonly UdpLoggerOptions _opts = new UdpLoggerOptions();
+ }
+
+}
diff --git a/Test.AMT.Extensions.Logging/IP/UdpLoggerProviderTests.cs b/Test.AMT.Extensions.Logging/IP/UdpLoggerProviderTests.cs
index 7042e72..4460966 100644
--- a/Test.AMT.Extensions.Logging/IP/UdpLoggerProviderTests.cs
+++ b/Test.AMT.Extensions.Logging/IP/UdpLoggerProviderTests.cs
@@ -8,7 +8,6 @@
using Xunit;
using AMT.Extensions.Logging.IP;
using Microsoft.Extensions.Logging;
-using System.Configuration.Provider;
namespace Test.AMT.Extensions.Logging.IP
@@ -17,6 +16,16 @@ namespace Test.AMT.Extensions.Logging.IP
public class UdpLoggerProviderTests
{
+ [Fact]
+ public void excp_on_null_category()
+ {
+ var provider = new Ext.UdpLoggerProvider(_opts);
+ Action act = () => provider.CreateLogger(null);
+
+ act.Should().Throw();
+ }
+
+
[Fact]
public void excp_on_null_options()
{
@@ -28,21 +37,48 @@ public void excp_on_null_options()
#region ILoggerProvider tests
[Fact]
- public void foo()
+ public void can_log_to_category()
{
- var udpProv = new Ext.UdpLoggerProvider(_opts);
+ using (var udpProv = new Ext.UdpLoggerProvider(_opts))
+ {
+ ILoggerProvider prov = udpProv as ILoggerProvider;
+ Assert.NotNull(prov);
+
+ ILogger l = prov.CreateLogger("randomCategory");
+ Assert.NotNull(l);
+
+ l.LogInformation("using ILogger.LogInformation...");
+ }
+ }
+
+ #endregion ILoggerProvider tests
- ILoggerProvider prov = udpProv as ILoggerProvider;
- Assert.NotNull(prov);
- ILogger l = prov.CreateLogger("randomCategory");
- Assert.NotNull(l);
+ #region ISupportExternalScope tests
- l.LogInformation("using ILogger.LogInformation...");
+ [Fact]
+ public void can_set_scope_provider()
+ {
+ var testEsps = new IExternalScopeProvider[] {
+ null,
+ NullExternalScopeProvider.Instance
+ };
+ // TODO: consider disabling null
+ foreach (IExternalScopeProvider esp in testEsps ) {
+ using (var udpProv = new Ext.UdpLoggerProvider(_opts))
+ {
+ udpProv.SetScopeProvider(esp);
+ ILogger l = udpProv.CreateLogger("randomCategory");
+ Assert.NotNull(l);
+
+ l.LogInformation("using ILogger.LogInformation...");
+ }
+ }
}
- #endregion ILoggerProvider tests
+ #endregion ISupportExternalScope tests
+
private static readonly UdpLoggerOptions _opts = new UdpLoggerOptions();
diff --git a/Test.AMT.Extensions.Logging/IP/UdpLoggerTests.cs b/Test.AMT.Extensions.Logging/IP/UdpLoggerTests.cs
index 6ddd528..19266f2 100644
--- a/Test.AMT.Extensions.Logging/IP/UdpLoggerTests.cs
+++ b/Test.AMT.Extensions.Logging/IP/UdpLoggerTests.cs
@@ -8,6 +8,8 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Xunit;
+using System.Net;
+using System.Runtime.CompilerServices;
namespace Test.AMT.Extensions.Logging.IP
@@ -19,30 +21,31 @@ public class UdpLoggerTests
[Fact]
public void verify_each_loglevel()
{
- // Prepare listener to receive messages
- var opts = new Ext.UdpLoggerOptions();
+ // Prepare listener to receive messages; isolate port for message count
+ var opts = new Ext.UdpLoggerOptions(new IPEndPoint(IPAddress.Loopback, 17460));
using (_receiver = new UdpReceiver())
{
_receiver.Start(opts);
// Add options to provider before create logger
- _provider = new Ext.UdpLoggerProvider(opts);
- var logger = _provider.CreateLogger("test") as Ext.UdpLogger;
-
- // Log a message of each LogLevel
- foreach (int level in _logLevels)
- {
- logger.Log((LogLevel)level, DEFAULT_EVENTID, DEFAULT_STATE, DEFAULT_EXCEPTION, setStringFormatter);
+ using (_provider = new Ext.UdpLoggerProvider(opts)) {
+ _logger = _provider.CreateLogger("test") as Ext.UdpLogger;
+
+ // Log a message of each LogLevel
+ foreach (int level in _logLevels)
+ {
+ _logger.Log((LogLevel)level, DEFAULT_EVENTID, DEFAULT_STATE, DEFAULT_EXCEPTION, setStringFormatter);
+ }
+
+ // Brief wait, then stop listener
+ System.Threading.Thread.Sleep(100);
+ _receiver.Stop();
+
+ // NOTE: RetrieveMessages returns a _consuming_ enumerator, so it can only be used once.
+ // LogLevel.None filtered, so reduce by 1.
+ _receiver.RetrieveMessages().Count().Should().Be(_logLevels.Length - 1);
}
-
- // Brief wait, then stop listener
- System.Threading.Thread.Sleep(100);
- _receiver.Stop();
-
- // NOTE: RetrieveMessages returns a _consuming_ enumerator, so it can only be used once.
- // 2024.09.17, JB: previously None was filtered, but it seems that changed in logging fx.
- _receiver.RetrieveMessages().Count().Should().Be(_logLevels.Length);
}
}
@@ -119,6 +122,36 @@ public void verify_few_log_messages()
}
+ [Fact]
+ public void verify_begin_scope()
+ {
+ // Prepare listener to receive messages
+ var opts = new Ext.UdpLoggerOptions();
+
+ using (_receiver = new UdpReceiver())
+ {
+ _receiver.Start(opts);
+
+ // Add options to provider before create logger
+ using (_provider = new Ext.UdpLoggerProvider(opts)) {
+ _logger = _provider.CreateLogger("test") as Ext.UdpLogger;
+
+ using (_logger.BeginScope("SCOPE L1: ", null))
+ {
+ _logger.Log(LogLevel.Trace, "some log message");
+ using (_logger.BeginScope("SCOPE L2: ", null))
+ {
+ _logger.Log(LogLevel.Trace, "some log message");
+ }
+
+ // TODO: confirm scope messages?
+ }
+
+ }
+ }
+ }
+
+
private LogLevel GetRandomLogLevel(bool excludeNone = true)
{
return (LogLevel)_randomizer.Next(0, excludeNone ? _logLevels.Length - 1 : _logLevels.Length);
@@ -139,6 +172,7 @@ public UdpLoggerTests(Xunit.Abstractions.ITestOutputHelper outputHelper)
private ILoggerProvider _provider;
+ private ILogger _logger;
private UdpReceiver _receiver;
private readonly object DEFAULT_STATE = "### Default state for testing ###";
private readonly object NULL_STATE = "[null-state]"; // TODO: use null;
diff --git a/Test.AMT.Extensions.Logging/IP/Utils/UdpReceiver.cs b/Test.AMT.Extensions.Logging/IP/Utils/UdpReceiver.cs
index 783a245..cd5e06f 100644
--- a/Test.AMT.Extensions.Logging/IP/Utils/UdpReceiver.cs
+++ b/Test.AMT.Extensions.Logging/IP/Utils/UdpReceiver.cs
@@ -17,7 +17,7 @@ namespace Test.AMT.Extensions.Logging.IP
internal class UdpReceiver : IDisposable
{
private static int _maxQueuedMessages = 1024;
- private readonly BlockingCollection _messageQueue = new BlockingCollection(_maxQueuedMessages);
+ private BlockingCollection _messageQueue = new BlockingCollection(_maxQueuedMessages);
private bool _stopListener = false;
private UdpClient _client;
@@ -54,14 +54,27 @@ public void Stop()
}
+ private static IEnumerable emptyList = new List();
public IEnumerable RetrieveMessages()
{
- return _messageQueue.GetConsumingEnumerable();
+ if (_messageQueue.Count > 0)
+ {
+ return _messageQueue.GetConsumingEnumerable();
+ } else
+ {
+ return emptyList;
+ }
}
#region IDisposable impl
public void Dispose()
{
+ // Drain the queue
+ if (_messageQueue != null)
+ {
+ _messageQueue = null;
+ }
+
if (null != _client)
{
_client.Close();
@@ -71,6 +84,5 @@ public void Dispose()
}
#endregion IDisposable impl
-
}
}
\ No newline at end of file
diff --git a/Test.AMT.Extensions.System/ConvertTests.cs b/Test.AMT.Extensions.System/ConvertTests.cs
index 5753b26..7c06c31 100644
--- a/Test.AMT.Extensions.System/ConvertTests.cs
+++ b/Test.AMT.Extensions.System/ConvertTests.cs
@@ -67,6 +67,14 @@ public void excp_on_null()
};
act.Should().Throw();
+
+
+ // Verify proper exception when encoded is null
+ act = () => {
+ Ext.Convert.FromBase64UrlString(null);
+ };
+
+ act.Should().Throw();
}
@@ -79,6 +87,14 @@ public void excp_on_empty_string()
};
act.Should().Throw();
+
+
+ // Verify proper exception when encoded is empty
+ act = () => {
+ Ext.Convert.FromBase64UrlString(string.Empty);
+ };
+
+ act.Should().Throw();
}