Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Commit

Permalink
feat(sample): Add device reconnection sample project (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
abhipsaMisra authored Aug 12, 2020
1 parent 9335a1d commit 9581df6
Show file tree
Hide file tree
Showing 12 changed files with 806 additions and 2 deletions.
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;
}
}
}
}
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 };
}
}
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);
}
}
}
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();
}
}
}
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);
}
}
}
}
}
Loading

0 comments on commit 9581df6

Please sign in to comment.