Skip to content

Commit

Permalink
Added example projects. Added documentation. Minor tweaks and renamings.
Browse files Browse the repository at this point in the history
  • Loading branch information
markolbert committed Jun 28, 2020
1 parent ae33644 commit 6b8bd9e
Show file tree
Hide file tree
Showing 42 changed files with 692 additions and 143 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
*.user
*.userosscache
*.sln.docstates
J4JLoggingTest/TwilioTestConfig.cs
J4JLoggingTests/TwilioTestConfig.cs
**/TwilioTestConfig.cs

# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
Expand Down
70 changes: 49 additions & 21 deletions AutoFacJ4JLogging/AutoFacExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Autofac;
using J4JSoftware.Logging;
Expand All @@ -13,6 +14,13 @@ namespace AutoFacJ4JLogging
{
public static class AutofacExtensions
{
// Configures the J4JLogging system based on a JSON configuration file whose structure either
// matches or is derived from J4JLoggerConfiguration.
//
// channelTypes is a collection of Types implementing ILogChannel and decorated with a ChannelAttribute
// defining the name/ID of the channel. Channel names/IDs should be unique. Type not fulfilling
// the ILogChannel/ChannelAttribute constraints will be ignored. If duplicate Channel names/IDs are
// specified only the last instance will be retained and used by the library.
public static ContainerBuilder AddJ4JLogging<TConfig>(
this ContainerBuilder builder,
string configFilePath,
Expand Down Expand Up @@ -40,11 +48,23 @@ public static ContainerBuilder AddJ4JLogging<TConfig>(
.AsImplementedInterfaces()
.SingleInstance();

builder.AddJ4JLogging();
//builder.AddJ4JLogging();

return builder;
}

// Configures the J4JLogging system based on an IConfigurationRoot object. This is targeted at
// supporting configuration files where the logging configuration is embedded within a larger
// configuration file.
//
// loggerSection is the key of the key/value pair exposed by IConfigurationRoot which contains
// the embedded logging configuration information. That embedded information must match the structure
// defined by TConfig.
//
// channelTypes is a collection of Types implementing ILogChannel and decorated with a ChannelAttribute
// defining the name/ID of the channel. Channel names/IDs should be unique. Type not fulfilling
// the ILogChannel/ChannelAttribute constraints will be ignored. If duplicate Channel names/IDs are
// specified only the last instance will be retained and used by the library.
public static ContainerBuilder AddJ4JLogging<TConfig>(
this ContainerBuilder builder,
IConfigurationRoot configRoot,
Expand All @@ -66,14 +86,34 @@ public static ContainerBuilder AddJ4JLogging<TConfig>(
.As<IJ4JLoggerConfiguration>()
.SingleInstance();

builder.AddJ4JLogging();
builder.RegisterLogger();

return builder;
}

public static ContainerBuilder AddJ4JLogging(this ContainerBuilder builder)
//// utility method for creating and registering the underlying Serilog logger used by
//// J4JLogger.
//public static ContainerBuilder AddJ4JLogging(this ContainerBuilder builder)
//{
// builder.Register(c => c.Resolve<IJ4JLoggerConfiguration>().CreateLogger())
// .As<ILogger>()
// .SingleInstance();

// builder.RegisterType<J4JLogger>()
// .As<IJ4JLogger>();

// return builder;
//}

// utility method for creating and registering the underlying Serilog logger used by
// J4JLogger.
public static ContainerBuilder RegisterLogger(this ContainerBuilder builder)
{
builder.Register(c => c.Resolve<IJ4JLoggerConfiguration>().CreateLogger())
builder.Register(c =>
{
var loggerConfig = c.Resolve<IJ4JLoggerConfiguration>();
return loggerConfig.CreateLogger();
})
.As<ILogger>()
.SingleInstance();

Expand All @@ -83,7 +123,8 @@ public static ContainerBuilder AddJ4JLogging(this ContainerBuilder builder)
return builder;
}

private static ContainerBuilder RegisterChannels( this ContainerBuilder builder, Dictionary<string, Type> channels )
// registers valid ILogChannel Types
private static ContainerBuilder RegisterChannels(this ContainerBuilder builder, Dictionary<string, Type> channels)
{
foreach (var kvp in channels)
{
Expand All @@ -95,22 +136,9 @@ private static ContainerBuilder RegisterChannels( this ContainerBuilder builder,
return builder;
}

public static ContainerBuilder RegisterLogger( this ContainerBuilder builder )
{
builder.Register( c =>
{
var loggerConfig = c.Resolve<IJ4JLoggerConfiguration>();
return loggerConfig.CreateLogger();
} )
.As<ILogger>()
.SingleInstance();

builder.RegisterType<J4JLogger>()
.As<IJ4JLogger>();

return builder;
}

// validates Types as ILogChannel Types decorated with a ChannelAttribute. Types not meeting those constraints
// are ignored. If duplicate channel names/IDs are specified (they should be unique) only the last
// Type with the duplicate name/ID is retained.
private static Dictionary<string, Type> GetChannels( Type[] channelTypes )
{
var retVal = new Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
Expand Down
86 changes: 86 additions & 0 deletions FileChannel/FileChannel.Static.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Microsoft.Extensions.Configuration;
using Serilog;
using Serilog.Configuration;
using Serilog.Events;

namespace J4JSoftware.Logging
{
public partial class FileChannel : LogChannel
{
public static string DefineLocalAppDataLogPath( string fileStub, string folder = null )
{
fileStub = IsFileNameValid( fileStub ) ? fileStub : "log.txt";

if( string.IsNullOrEmpty( folder ) )
folder = GetProgramName();

DirectoryInfo logDir = null;

if( ( logDir = CreateLogFileDirectory( folder ) ) == null )
{
if( ( logDir = CreateLogFileDirectory( "LogFiles" ) ) == null )
throw new ApplicationException(
$"Couldn't create log file directory {folder} or the backup/default directory 'LogFiles'" );
}

return Path.Combine( logDir.FullName, fileStub );
}

public static string DefineExeLogPath( string fileStub, string folder = null )
{
fileStub = IsFileNameValid( fileStub ) ? fileStub : "log.txt";

if( folder != null && !IsFileNameValid( folder ) )
folder = null;

return string.IsNullOrEmpty( folder )
? Path.Combine( Environment.CurrentDirectory, fileStub )
: Path.Combine( Environment.CurrentDirectory, folder, fileStub );
}

private static bool IsFileNameValid( string fileName )
{
return !string.IsNullOrEmpty( fileName )
&& fileName.IndexOfAny( Path.GetInvalidFileNameChars() ) >= 0
&& fileName.IndexOfAny( Path.GetInvalidPathChars() ) >= 0;
}

private static DirectoryInfo CreateLogFileDirectory( string folder )
{
var appDataFolder = Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData );
var fullPath = Path.Combine( appDataFolder, folder );

try
{
return Directory.CreateDirectory( fullPath );
}
#pragma warning disable 168
catch( IOException ioException )
#pragma warning restore 168
{
return null;
}
}

private static string GetProgramName()
{
var defaultName =
Path.GetFileNameWithoutExtension( Assembly.GetExecutingAssembly().GetType().Assembly.Location );

var trace = new StackTrace();

// we want the last frame
return trace.GetFrame( trace.FrameCount - 1 )?
.GetMethod()?
.DeclaringType?
.Assembly?
.GetName()?
.Name
?? defaultName;
}
}
}
72 changes: 1 addition & 71 deletions FileChannel/FileChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace J4JSoftware.Logging
{
[Channel("File")]
public class FileChannel : LogChannel
public partial class FileChannel : LogChannel
{
public FileChannel()
{
Expand Down Expand Up @@ -53,75 +53,5 @@ public override LoggerConfiguration Configure( LoggerSinkConfiguration sinkConfi
: sinkConfig.File( path : path, restrictedToMinimumLevel : MinimumLevel,
rollingInterval : RollingInterval, outputTemplate : outputTemplate );
}

public static string DefineLocalAppDataLogPath( string fileStub, string folder = null )
{
fileStub = IsFileNameValid( fileStub ) ? fileStub : "log.txt";

if( string.IsNullOrEmpty( folder ) )
folder = GetProgramName();

DirectoryInfo logDir = null;

if( ( logDir = CreateLogFileDirectory( folder ) ) == null )
{
if( ( logDir = CreateLogFileDirectory( "LogFiles" ) ) == null )
throw new ApplicationException(
$"Couldn't create log file directory {folder} or the backup/default directory 'LogFiles'" );
}

return Path.Combine( logDir.FullName, fileStub );
}

public static string DefineExeLogPath( string fileStub, string folder = null )
{
fileStub = IsFileNameValid( fileStub ) ? fileStub : "log.txt";

if( folder != null && !IsFileNameValid( folder ) )
folder = null;

return string.IsNullOrEmpty( folder )
? Path.Combine( Environment.CurrentDirectory, fileStub )
: Path.Combine( Environment.CurrentDirectory, folder, fileStub );
}

private static bool IsFileNameValid( string fileName )
{
return !string.IsNullOrEmpty( fileName )
&& fileName.IndexOfAny( Path.GetInvalidFileNameChars() ) >= 0
&& fileName.IndexOfAny( Path.GetInvalidPathChars() ) >= 0;
}

private static DirectoryInfo CreateLogFileDirectory( string folder )
{
var appDataFolder = Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData );
var fullPath = Path.Combine( appDataFolder, folder );

try
{
return Directory.CreateDirectory( fullPath );
}
catch( IOException ioException )
{
return null;
}
}

private static string GetProgramName()
{
var defaultName =
Path.GetFileNameWithoutExtension( Assembly.GetExecutingAssembly().GetType().Assembly.Location );

var trace = new StackTrace();

// we want the last frame
return trace.GetFrame( trace.FrameCount - 1 )?
.GetMethod()?
.DeclaringType?
.Assembly?
.GetName()?
.Name
?? defaultName;
}
}
}
4 changes: 4 additions & 0 deletions FileChannel/LogFileLocation.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
namespace J4JSoftware.Logging
{
// distinguishes between allowable locations for log files
public enum LogFileLocation
{
// store the log file in the user's AppData folder
AppData,

// store the log file in the application's exe folder
ExeFolder
}
}
2 changes: 2 additions & 0 deletions FileChannel/LogFileLocationConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace J4JSoftware.Logging
{
// converts between string values and LogFileLocation enum values. Any text other than
// "appdata" (case insensitive) translates to LogFileLocation.ExeFolder.
public class LogFileLocationConverter : JsonConverter<LogFileLocation>
{
public override LogFileLocation Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options )
Expand Down
2 changes: 2 additions & 0 deletions FileChannel/RollingIntervalConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace J4JSoftware.Logging
{
// converts between string values and RollingInterval values. Any text other than day, hour, minute,
// month or year (case insensitive) maps to RollingInterval.Infinite.
public class RollingIntervalConverter : JsonConverter<RollingInterval>
{
public override RollingInterval Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options )
Expand Down
27 changes: 26 additions & 1 deletion J4JLogging.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwilioChannel", "TwilioChan
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutofacJ4JLogging", "AutoFacJ4JLogging\AutofacJ4JLogging.csproj", "{004FDDE3-3E6C-4BBA-AD47-D5744FC12204}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "J4JLoggingTests", "J4JLoggingTests\J4JLoggingTests.csproj", "{A4168158-D34D-4BD3-A539-257B3A19402C}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "J4JLoggingTests", "J4JLoggingTests\J4JLoggingTests.csproj", "{A4168158-D34D-4BD3-A539-257B3A19402C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{39A87B0A-7DBC-4F49-B619-6E9D8A6CE3F4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleFileExample", "examples\SimpleFileExample\SimpleFileExample.csproj", "{2E5BC340-78B0-4DED-A42D-2A54B36B0F33}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DerivedFileExample", "examples\DerivedFileExample\DerivedFileExample.csproj", "{6F18D9CB-028A-4C7D-8F9E-915141F7F743}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EmbeddedFileExample", "examples\EmbeddedFileExample\EmbeddedFileExample.csproj", "{6C11B3D1-4508-493C-BA79-147F501721B7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -63,10 +71,27 @@ Global
{A4168158-D34D-4BD3-A539-257B3A19402C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4168158-D34D-4BD3-A539-257B3A19402C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4168158-D34D-4BD3-A539-257B3A19402C}.Release|Any CPU.Build.0 = Release|Any CPU
{2E5BC340-78B0-4DED-A42D-2A54B36B0F33}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2E5BC340-78B0-4DED-A42D-2A54B36B0F33}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2E5BC340-78B0-4DED-A42D-2A54B36B0F33}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2E5BC340-78B0-4DED-A42D-2A54B36B0F33}.Release|Any CPU.Build.0 = Release|Any CPU
{6F18D9CB-028A-4C7D-8F9E-915141F7F743}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F18D9CB-028A-4C7D-8F9E-915141F7F743}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F18D9CB-028A-4C7D-8F9E-915141F7F743}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F18D9CB-028A-4C7D-8F9E-915141F7F743}.Release|Any CPU.Build.0 = Release|Any CPU
{6C11B3D1-4508-493C-BA79-147F501721B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C11B3D1-4508-493C-BA79-147F501721B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C11B3D1-4508-493C-BA79-147F501721B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6C11B3D1-4508-493C-BA79-147F501721B7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{2E5BC340-78B0-4DED-A42D-2A54B36B0F33} = {39A87B0A-7DBC-4F49-B619-6E9D8A6CE3F4}
{6F18D9CB-028A-4C7D-8F9E-915141F7F743} = {39A87B0A-7DBC-4F49-B619-6E9D8A6CE3F4}
{6C11B3D1-4508-493C-BA79-147F501721B7} = {39A87B0A-7DBC-4F49-B619-6E9D8A6CE3F4}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {747AE797-C094-4597-9FA9-0DAD20A77C44}
EndGlobalSection
Expand Down
5 changes: 5 additions & 0 deletions J4JLogging/DummyAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ namespace J4JSoftware.Logging
[AttributeUsage( validOn: AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = true )]
public class DummyAttribute : Attribute
{
#pragma warning disable 67
// ReSharper disable once EventNeverSubscribedTo.Global
public event EventHandler<int> Ralph;
#pragma warning restore 67

#pragma warning disable 8618
public DummyAttribute( string arg1, Type arg2 )
#pragma warning restore 8618
{
}

Expand Down
Loading

0 comments on commit 6b8bd9e

Please sign in to comment.