This repository has been archived by the owner on Nov 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 225
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(sample): Add device reconnection sample project (#124)
- Loading branch information
1 parent
9335a1d
commit 9581df6
Showing
12 changed files
with
806 additions
and
2 deletions.
There are no files selected for viewing
81 changes: 81 additions & 0 deletions
81
iot-hub/Samples/device/DeviceReconnectionSample/ColorConsoleLogger.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Globalization; | ||
using System.Linq; | ||
|
||
namespace Microsoft.Azure.Devices.Client.Samples | ||
{ | ||
/// <summary> | ||
/// The ILogger implementation for writing color log entries to console. | ||
/// </summary> | ||
public class ColorConsoleLogger : ILogger | ||
{ | ||
private readonly string _name; | ||
private readonly ColorConsoleLoggerConfiguration _config; | ||
|
||
/// <summary> | ||
/// Initializes an instance of <see cref="ColorConsoleLogger"/>. | ||
/// </summary> | ||
/// <param name="name">The category name for each <see cref="ILogger"/> instance. This is usually the class name where the logger is initialized.</param> | ||
/// <param name="config">The <see cref="ColorConsoleLoggerConfiguration"/> settings to be used for logging.</param> | ||
public ColorConsoleLogger(string name, ColorConsoleLoggerConfiguration config) | ||
{ | ||
_name = name; | ||
_config = config; | ||
} | ||
|
||
/// <summary> | ||
/// Begin a group of logical operations. | ||
/// </summary> | ||
/// <typeparam name="TState">The type of the state to begin scope for.</typeparam> | ||
/// <param name="state">The identifier for the scope.</param> | ||
/// <returns></returns> | ||
public IDisposable BeginScope<TState>(TState state) | ||
{ | ||
throw new NotImplementedException(); | ||
} | ||
|
||
/// <summary> | ||
/// Checks if the given log level is enabled. | ||
/// </summary> | ||
/// <param name="logLevel">The log level to be checked.</param> | ||
/// <returns></returns> | ||
public bool IsEnabled(LogLevel logLevel) | ||
{ | ||
return logLevel >= _config.MinLogLevel; | ||
} | ||
|
||
/// <summary> | ||
/// Writes the log entry to console output. | ||
/// </summary> | ||
/// <typeparam name="TState">The type of the object to be written.</typeparam> | ||
/// <param name="logLevel">The log level of the log entry to be written.</param> | ||
/// <param name="eventId">The event Id of the log entry to be written.</param> | ||
/// <param name="state">The log entry to be written.</param> | ||
/// <param name="exception">The exception related to the log entry.</param> | ||
/// <param name="formatter">The formatter to be used for formatting the log message.</param> | ||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) | ||
{ | ||
if (!IsEnabled(logLevel)) | ||
{ | ||
return; | ||
} | ||
|
||
var color = _config.LogLevelToColorMapping[logLevel]; | ||
if (_config.EventIds.Contains(ColorConsoleLoggerConfiguration.DefaultEventId) || _config.EventIds.Contains(eventId.Id)) | ||
{ | ||
var initialColor = Console.ForegroundColor; | ||
|
||
Console.ForegroundColor = ConsoleColor.Green; | ||
Console.Write($"{DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffffff", CultureInfo.InvariantCulture)}>> "); | ||
|
||
Console.ForegroundColor = color; | ||
Console.WriteLine($"{logLevel} - {formatter(state, exception)}"); | ||
Console.ForegroundColor = initialColor; | ||
} | ||
} | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
iot-hub/Samples/device/DeviceReconnectionSample/ColorConsoleLoggerConfiguration.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Collections.Generic; | ||
|
||
namespace Microsoft.Azure.Devices.Client.Samples | ||
{ | ||
/// <summary> | ||
/// A color console logger configuration that creates different color console entries per log level, sets the default log level to Information and logs all events. | ||
/// </summary> | ||
public class ColorConsoleLoggerConfiguration | ||
{ | ||
// If the EventId is set to 0, the logger will log all events. | ||
internal const int DefaultEventId = 0; | ||
|
||
private static readonly IReadOnlyDictionary<LogLevel, ConsoleColor> s_defaultColorMapping = new Dictionary<LogLevel, ConsoleColor> | ||
{ | ||
{ LogLevel.Trace, ConsoleColor.Blue }, | ||
{ LogLevel.Debug, ConsoleColor.DarkYellow }, | ||
{ LogLevel.Information, ConsoleColor.Cyan }, | ||
{ LogLevel.Warning, ConsoleColor.DarkMagenta }, | ||
{ LogLevel.Error, ConsoleColor.Red }, | ||
{ LogLevel.Critical, ConsoleColor.DarkRed } | ||
}; | ||
|
||
/// <summary> | ||
/// Initialize an instance of <see cref="ColorConsoleLoggerConfiguration"/> with default color mappings. | ||
/// </summary> | ||
public ColorConsoleLoggerConfiguration() | ||
{ | ||
LogLevelToColorMapping = s_defaultColorMapping; | ||
} | ||
|
||
/// <summary> | ||
/// Initialize an instance of <see cref="ColorConsoleLoggerConfiguration"/> by overriding the default color mappings with the supplied custom mappings. | ||
/// </summary> | ||
/// <param name="customConsoleColorMapping">A dictionary of log level to console color mapping that will be used to override the default color mapping.</param> | ||
public ColorConsoleLoggerConfiguration(IDictionary<LogLevel, ConsoleColor> customConsoleColorMapping) | ||
: this () | ||
{ | ||
var map = (IDictionary<LogLevel, ConsoleColor> )LogLevelToColorMapping; | ||
|
||
// If a custom color mapping is provided, use it to override the default color mapping. | ||
foreach (KeyValuePair<LogLevel, ConsoleColor> entry in customConsoleColorMapping) | ||
{ | ||
if (map.ContainsKey(entry.Key)) | ||
{ | ||
map[entry.Key] = entry.Value; | ||
} | ||
} | ||
LogLevelToColorMapping = (IReadOnlyDictionary<LogLevel, ConsoleColor>)map; | ||
} | ||
|
||
/// <summary> | ||
/// A dictionary containing the log level to console color mappings to be used while writing log entries to the console. | ||
/// </summary> | ||
public IReadOnlyDictionary<LogLevel, ConsoleColor> LogLevelToColorMapping { get; } | ||
|
||
/// <summary> | ||
/// The min log level that will be written to the console, defaults to <see cref="LogLevel.Information"/>. | ||
/// </summary> | ||
public LogLevel MinLogLevel { get; set; } = LogLevel.Information; | ||
|
||
/// <summary> | ||
/// The list of event Ids to be written to the console. By default, all event Ids are written. | ||
/// </summary> | ||
public IEnumerable<int> EventIds { get; set; } = new List<int>() { DefaultEventId }; | ||
} | ||
} |
36 changes: 36 additions & 0 deletions
36
iot-hub/Samples/device/DeviceReconnectionSample/ColorConsoleLoggerExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Microsoft.Azure.Devices.Client.Samples | ||
{ | ||
/// <summary> | ||
/// Extension methods to help simplify creation of a new <see cref="ColorConsoleLoggerProvider"/> instance. | ||
/// </summary> | ||
public static class ColorConsoleLoggerExtensions | ||
{ | ||
/// <summary> | ||
/// Add a new <see cref="ColorConsoleLoggerProvider"/> instance, with the supplied <see cref="ColorConsoleLoggerConfiguration"/> settings. | ||
/// </summary> | ||
/// <param name="loggerFactory">The type for which this extension method is defined.</param> | ||
/// <param name="config">The <see cref="ColorConsoleLoggerConfiguration"/> settings to be used for logging.</param> | ||
/// <returns>The <see cref="ILoggerFactory "/> instance.</returns> | ||
public static ILoggerFactory AddColorConsoleLogger(this ILoggerFactory loggerFactory, ColorConsoleLoggerConfiguration config) | ||
{ | ||
loggerFactory.AddProvider(new ColorConsoleLoggerProvider(config)); | ||
return loggerFactory; | ||
} | ||
|
||
/// <summary> | ||
/// Add a new <see cref="ColorConsoleLoggerProvider"/> instance, with the default <see cref="ColorConsoleLoggerConfiguration"/> settings. | ||
/// </summary> | ||
/// <param name="loggerFactory">The type for which this extension method is defined.</param> | ||
/// <returns>The <see cref="ILoggerFactory "/> instance.</returns> | ||
public static ILoggerFactory AddColorConsoleLogger(this ILoggerFactory loggerFactory) | ||
{ | ||
var config = new ColorConsoleLoggerConfiguration(); | ||
return loggerFactory.AddColorConsoleLogger(config); | ||
} | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
iot-hub/Samples/device/DeviceReconnectionSample/ColorConsoleLoggerProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using Microsoft.Extensions.Logging; | ||
using System.Collections.Concurrent; | ||
|
||
namespace Microsoft.Azure.Devices.Client.Samples | ||
{ | ||
/// <summary> | ||
/// The <see cref="ILoggerProvider"/> implementation that creates the <see cref="ColorConsoleLogger"/> instance. | ||
/// </summary> | ||
public class ColorConsoleLoggerProvider : ILoggerProvider | ||
{ | ||
private readonly ColorConsoleLoggerConfiguration _config; | ||
private readonly ConcurrentDictionary<string, ColorConsoleLogger> _loggers = new ConcurrentDictionary<string, ColorConsoleLogger>(); | ||
|
||
/// <summary> | ||
/// Initialize an instance of <see cref="ColorConsoleLoggerProvider"/> with the supplied <see cref="ColorConsoleLoggerConfiguration"/>. | ||
/// </summary> | ||
/// <param name="config">The <see cref="ColorConsoleLoggerConfiguration"/> settings to be used for logging.</param> | ||
public ColorConsoleLoggerProvider(ColorConsoleLoggerConfiguration config) | ||
{ | ||
_config = config; | ||
} | ||
|
||
/// <summary> | ||
/// Create a new <see cref="ILogger"/> instance. | ||
/// </summary> | ||
/// <param name="categoryName">The category name for the <see cref="ILogger"/> instance. This is usually the class name where the logger is initialized.</param> | ||
/// <returns>The created <see cref="ILogger"/> instance.</returns> | ||
public ILogger CreateLogger(string categoryName) | ||
{ | ||
return _loggers.GetOrAdd(categoryName, name => new ColorConsoleLogger(name, _config)); | ||
} | ||
|
||
/// <summary> | ||
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. | ||
/// </summary> | ||
public void Dispose() | ||
{ | ||
_loggers.Clear(); | ||
} | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
iot-hub/Samples/device/DeviceReconnectionSample/ConsoleEventListener.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using Microsoft.Extensions.Logging; | ||
using System.Linq; | ||
|
||
namespace System.Diagnostics.Tracing | ||
{ | ||
/// <summary> | ||
/// Prints SDK events to Console output - the log level is set to TRACE | ||
/// </summary> | ||
public sealed class ConsoleEventListener : EventListener | ||
{ | ||
private readonly string[] _eventFilters; | ||
private readonly ILogger _logger; | ||
private readonly object _lock = new object(); | ||
|
||
public ConsoleEventListener(string filter, ILogger logger) | ||
{ | ||
_eventFilters = new string[1]; | ||
_eventFilters[0] = filter ?? throw new ArgumentNullException(nameof(filter)); | ||
_logger = logger; | ||
|
||
InitializeEventSources(); | ||
} | ||
|
||
public ConsoleEventListener(string[] filters, ILogger logger) | ||
{ | ||
_eventFilters = filters ?? throw new ArgumentNullException(nameof(filters)); | ||
if (_eventFilters.Length == 0) throw new ArgumentException("Filters cannot be empty", nameof(filters)); | ||
|
||
foreach (string filter in _eventFilters) | ||
{ | ||
if (string.IsNullOrWhiteSpace(filter)) | ||
{ | ||
throw new ArgumentNullException(nameof(filters)); | ||
} | ||
} | ||
_logger = logger; | ||
|
||
InitializeEventSources(); | ||
} | ||
|
||
private void InitializeEventSources() | ||
{ | ||
foreach (EventSource source in EventSource.GetSources()) | ||
{ | ||
EnableEvents(source, EventLevel.LogAlways); | ||
} | ||
} | ||
|
||
protected override void OnEventSourceCreated(EventSource eventSource) | ||
{ | ||
base.OnEventSourceCreated(eventSource); | ||
EnableEvents( | ||
eventSource, | ||
EventLevel.LogAlways | ||
#if !NET451 | ||
, EventKeywords.All | ||
#endif | ||
); | ||
} | ||
|
||
protected override void OnEventWritten(EventWrittenEventArgs eventData) | ||
{ | ||
if (_eventFilters == null) return; | ||
|
||
lock (_lock) | ||
{ | ||
if (_eventFilters.Any(ef => eventData.EventSource.Name.StartsWith(ef, StringComparison.Ordinal))) | ||
{ | ||
string eventIdent; | ||
#if NET451 | ||
// net451 doesn't have EventName, so we'll settle for EventId | ||
eventIdent = eventData.EventId.ToString(CultureInfo.InvariantCulture); | ||
#else | ||
eventIdent = eventData.EventName; | ||
#endif | ||
string text = $"[{eventData.EventSource.Name}-{eventIdent}]{(eventData.Payload != null ? $" ({string.Join(", ", eventData.Payload)})." : "")}"; | ||
_logger.LogTrace(text); | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.