Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

JSON target/sample end-point

  • Loading branch information...
commit 2c3394bf72121e717291f6c34fbb9a7c6eafab1c 1 parent 700dc69
Matthew Baxter-Reynolds (@mbrit) authored
Showing with 1,111 additions and 93 deletions.
  1. +60 −0 MetroLog.NetCore.SQLite/LogEventInfoItem.cs
  2. +12 −1 MetroLog.NetCore.SQLite/MetroLog.NetCore.SQLite.csproj
  3. +12 −0 MetroLog.NetCore.SQLite/SQLiteAsync.cs
  4. +95 −0 MetroLog.NetCore.SQLite/SQLiteTarget.cs
  5. +16 −0 MetroLog.NetCore/FileNamingMode.cs
  6. +11 −53 MetroLog.NetCore/FileSnapshotTarget.cs
  7. +18 −3 MetroLog.NetCore/FileStreamingTarget.cs
  8. +132 −0 MetroLog.NetCore/FileTargetBase.cs
  9. +5 −0 MetroLog.NetCore/LazyFlushManager.cs
  10. +41 −0 MetroLog.NetCore/LogManagerFactory.cs
  11. +2 −0  MetroLog.NetCore/MetroLog.NetCore.csproj
  12. +1 −1  MetroLog.NetFx/Targets/TraceTarget.cs
  13. +1 −0  MetroLog.Tests/MetroLog.Tests.csproj
  14. +240 −0 MetroLog.Tests/Tests/FileNamingParametersTests.cs
  15. +2 −0  MetroLog/ILoggingEnvironment.cs
  16. +9 −8 MetroLog/Internal/LogManager.cs
  17. +1 −1  MetroLog/Internal/Logger.cs
  18. +2 −0  MetroLog/Internal/LoggingEnvironmentBase.cs
  19. +137 −0 MetroLog/InternalLogger.cs
  20. +5 −1 MetroLog/Layouts/FileSnapshotLayout.cs
  21. +10 −1 MetroLog/Layouts/Layout.cs
  22. +1 −1  MetroLog/Layouts/NullLayout.cs
  23. +1 −1  MetroLog/Layouts/SingleLineLayout.cs
  24. +6 −1 MetroLog/LogEventInfo.cs
  25. +8 −0 MetroLog/LogWriteContext.cs
  26. +3 −0  MetroLog/MetroLog.csproj
  27. +5 −1 MetroLog/Properties/AssemblyInfo.cs
  28. +2 −2 MetroLog/Targets/BufferedTarget.cs
  29. +1 −1  MetroLog/Targets/DebugTarget.cs
  30. +1 −1  MetroLog/Targets/EtwTarget.cs
  31. +133 −0 MetroLog/Targets/FileNamingParameters.cs
  32. +17 −0 MetroLog/Targets/FileTimestampMoe.cs
  33. +1 −1  MetroLog/Targets/SyncTarget.cs
  34. +43 −0 WebTargetSample/Json/LoggingEnvironmentConverter.cs
  35. +11 −0 WebTargetSample/Model/ExceptionWrapper.cs
  36. +3 −0  WebTargetSample/Model/JsonPostWrapper.cs
  37. +6 −0 WebTargetSample/Model/LogEventInfo.cs
  38. +17 −0 WebTargetSample/Model/LogLevel.cs
  39. +6 −0 WebTargetSample/Model/LoggingEnvironment.cs
  40. +11 −3 WebTargetSample/ReceiveLogEntries.ashx.cs
  41. +3 −0  WebTargetSample/WebTargetSample.csproj
  42. +1 −7 Win8Sample/App.xaml.cs
  43. +1 −0  Win8Sample/LogSamplePage.xaml
  44. +17 −4 Win8Sample/LogSamplePage.xaml.cs
  45. +1 −1  Win8Sample/Win8Sample.csproj
View
60 MetroLog.NetCore.SQLite/LogEventInfoItem.cs
@@ -0,0 +1,60 @@
+using SQLite;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MetroLog.Targets
+{
+ /// <summary>
+ /// Defines the class uses for serializing log entries to the database.
+ /// </summary>
+ public class LogEventInfoItem
+ {
+ [PrimaryKey, AutoIncrement]
+ public int ItemId { get; set; }
+
+ public DateTime DateTimeUtc { get; set; }
+ public string SessionId { get; set; }
+ public long SequenceId { get; set; }
+ public LogLevel Level { get; set; }
+ public string Logger { get; set; }
+ public string Message { get; set; }
+
+ public bool HasException { get; set; }
+ public string Exception { get; set; }
+ public int ExceptionHresult { get; set; }
+
+ public LogEventInfoItem()
+ {
+ }
+
+ internal static LogEventInfoItem GetForInsert(LogWriteContext context, LogEventInfo info)
+ {
+ var item = new LogEventInfoItem()
+ {
+ SessionId = context.Manager.LoggingEnvironment.SessionId.ToString(),
+ DateTimeUtc = info.TimeStamp.UtcDateTime,
+ SequenceId = info.SequenceID,
+ Level = info.Level,
+ Logger = info.Logger,
+ Message = info.Message
+ };
+
+ // if...
+ if (info.Exception != null)
+ item.SetException(info.Exception);
+
+ // return...
+ return item;
+ }
+
+ private void SetException(Exception ex)
+ {
+ this.HasException = true;
+ this.Exception = ex.ToString();
+ this.ExceptionHresult = ex.HResult;
+ }
+ }
+}
View
13 MetroLog.NetCore.SQLite/MetroLog.NetCore.SQLite.csproj
@@ -111,7 +111,8 @@
</SDKReference>
</ItemGroup>
<ItemGroup>
- <Compile Include="Class1.cs" />
+ <Compile Include="LogEventInfoItem.cs" />
+ <Compile Include="SQLiteTarget.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SQLite.cs" />
<Compile Include="SQLiteAsync.cs" />
@@ -119,6 +120,16 @@
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\MetroLog.NetCore\MetroLog.NetCore.csproj">
+ <Project>{429ee5fc-46fe-4249-bb40-8dc6d9023a04}</Project>
+ <Name>MetroLog.NetCore</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\MetroLog\MetroLog.csproj">
+ <Project>{65e2062e-aac2-4054-aae6-d6764040c769}</Project>
+ <Name>MetroLog</Name>
+ </ProjectReference>
+ </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '11.0' ">
<VisualStudioVersion>11.0</VisualStudioVersion>
</PropertyGroup>
View
12 MetroLog.NetCore.SQLite/SQLiteAsync.cs
@@ -27,6 +27,7 @@
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
+using Windows.UI.Xaml;
namespace SQLite
{
@@ -403,6 +404,17 @@ public void OnApplicationSuspended ()
static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool ();
+ private SQLiteConnectionPool()
+ {
+ // mbr - 2012-09-14 - this needs to find its way into the main sqlite-net branch.
+ Application.Current.Suspending += Current_Suspending;
+ }
+
+ void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
+ {
+ this.ApplicationSuspended();
+ }
+
/// <summary>
/// Gets the singleton instance of the connection tool.
/// </summary>
View
95 MetroLog.NetCore.SQLite/SQLiteTarget.cs
@@ -0,0 +1,95 @@
+using MetroLog.Layouts;
+using SQLite;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MetroLog.Targets
+{
+ /// <summary>
+ /// Defines a target that is able to write to a SQLite database.
+ /// </summary>
+ public class SQLiteTarget : AsyncTarget
+ {
+ /// <summary>
+ /// Gets or sets the numbers of days that log entries should be retained for.
+ /// </summary>
+ public int RetainDays { get; set; }
+
+ /// <summary>
+ /// Holds the next cleanup time.
+ /// </summary>
+ private DateTime NextCleanupUtc { get; set; }
+
+ /// <summary>
+ /// Gets or sets the database path.
+ /// </summary>
+ public string DatabasePath { get; set; }
+
+ /// <summary>
+ /// Holds whether the target has been initialized.
+ /// </summary>
+ private bool IsInitialized { get; set; }
+
+ public SQLiteTarget()
+ : this(new NullLayout())
+ {
+ }
+
+ public SQLiteTarget(Layout layout)
+ : base(layout)
+ {
+ // defaults...
+ this.RetainDays = 30;
+ this.DatabasePath = "MetroLogs/MetroLog.db";
+ }
+
+ protected override async Task<LogWriteOperation> WriteAsync(LogWriteContext context, LogEventInfo entry)
+ {
+ await EnsureInitialize();
+
+ // cleanup
+ await CheckCleanup();
+
+ // ok...
+ var conn = GetConnection();
+ await conn.InsertAsync(LogEventInfoItem.GetForInsert(context, entry));
+
+ // return...
+ return new LogWriteOperation(this, entry, true);
+ }
+
+ private async Task CheckCleanup()
+ {
+ if (DateTime.UtcNow > this.NextCleanupUtc && this.RetainDays > 0)
+ {
+ // delete out...
+ try
+ {
+ var threshold = DateTime.UtcNow.AddDays(0 - this.RetainDays);
+
+ // delete...
+ var conn = GetConnection();
+ await conn.ExecuteAsync("delete from LogEventInfoItem where datetimeutc <= ?", threshold);
+ }
+ catch (Exception ex)
+ {
+ InternalLogger.Current.Error("Failed to run cleanup operation.", ex);
+ }
+ }
+ }
+
+ private async Task EnsureInitialize()
+ {
+ var conn = GetConnection();
+ await conn.CreateTableAsync<LogEventInfoItem>();
+ }
+
+ private SQLiteAsyncConnection GetConnection()
+ {
+ return new SQLiteAsyncConnection(this.DatabasePath);
+ }
+ }
+}
View
16 MetroLog.NetCore/FileNamingMode.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MetroLog
+{
+ public enum FileNamingMode
+ {
+ SingleFile = 0,
+ FilePerDate = 1,
+ FilePerSession = 2,
+ FilePerDateAndSession = 3
+ }
+}
View
64 MetroLog.NetCore/FileSnapshotTarget.cs
@@ -10,12 +10,8 @@
namespace MetroLog.Targets
{
- public class FileSnapshotTarget : AsyncTarget
+ public class FileSnapshotTarget : FileTargetBase
{
- public static StorageFolder _logFolder = null;
-
- private const string LogFolderName = "MetroLogs";
-
public FileSnapshotTarget()
: this(new FileSnapshotLayout())
{
@@ -24,51 +20,11 @@ public FileSnapshotTarget()
public FileSnapshotTarget(Layout layout)
: base(layout)
{
- }
-
- public static async Task<StorageFolder> EnsureInitializedAsync()
- {
- var folder = _logFolder;
- if(folder == null)
- {
- StorageFolder logFolder = null;
- var root = ApplicationData.Current.LocalFolder;
- try
- {
- logFolder = await root.GetFolderAsync(LogFolderName);
- }
- catch (FileNotFoundException ex)
- {
- SinkException(ex);
- }
-
- // if...
- if (logFolder == null)
- {
- try
- {
- logFolder = await root.CreateFolderAsync(LogFolderName, CreationCollisionOption.OpenIfExists);
- }
- catch (Exception ex)
- {
- SinkException(ex);
- }
-
- // if we get into trouble here, try and load it again... (something else should have created it)...
- if (logFolder == null)
- logFolder = await root.GetFolderAsync(LogFolderName);
- }
-
- // store it - but only if we have one...
- if(logFolder != null)
- Interlocked.CompareExchange<StorageFolder>(ref _logFolder, logFolder, null);
- }
- return _logFolder;
- }
-
- private static void SinkException(Exception ex)
- {
- // no-op - just preventing compile warnings...
+ this.FileNamingParameters.IncludeLevel = true;
+ this.FileNamingParameters.IncludeLogger = true;
+ this.FileNamingParameters.IncludeSession = false;
+ this.FileNamingParameters.IncludeSequence = true;
+ this.FileNamingParameters.IncludeTimestamp = FileTimestampMode.DateTime;
}
protected override async Task<LogWriteOperation> WriteAsync(LogWriteContext context, LogEventInfo entry)
@@ -77,13 +33,15 @@ private static void SinkException(Exception ex)
if (folder == null)
return new LogWriteOperation(this, entry, false);
+ // cleanup...
+ await this.CheckCleanupAsync(folder);
+
// create the file...
- var filename = string.Format("Log - {0} - {1} - {2} - {3}.log", entry.Logger, entry.Level,
- entry.TimeStamp.ToString("yyyyMMdd HHmmss"), entry.SequenceID);
+ var filename = this.FileNamingParameters.GetFilename(context, entry);
var file = await folder.CreateFileAsync(filename).AsTask();
// write...
- string buf = this.Layout.GetFormattedString(entry);
+ string buf = this.Layout.GetFormattedString(context, entry);
await FileIO.WriteTextAsync(file, buf);
// return...
View
21 MetroLog.NetCore/FileStreamingTarget.cs
@@ -9,7 +9,10 @@
namespace MetroLog.Targets
{
- public class FileStreamingTarget : AsyncTarget
+ /// <summary>
+ /// Defines a target that will append messages to a single file.
+ /// </summary>
+ public class FileStreamingTarget : FileTargetBase
{
public FileStreamingTarget()
: this(new SingleLineLayout())
@@ -19,16 +22,28 @@ public FileStreamingTarget()
public FileStreamingTarget(Layout layout)
: base(layout)
{
+ this.FileNamingParameters.IncludeLevel = false;
+ this.FileNamingParameters.IncludeLogger = false;
+ this.FileNamingParameters.IncludeSequence = false;
+ this.FileNamingParameters.IncludeSession = false;
+ this.FileNamingParameters.IncludeTimestamp = FileTimestampMode.Date;
}
protected override async Task<LogWriteOperation> WriteAsync(LogWriteContext context, LogEventInfo entry)
{
var folder = await FileSnapshotTarget.EnsureInitializedAsync();
+ // cleanup...
+ await this.CheckCleanupAsync(folder);
+
// write...
- var filename = string.Format("Log - {0}.log", entry.TimeStamp.ToString("yyyyMMdd"));
+ var filename = this.FileNamingParameters.GetFilename(context, entry);
var file = await folder.CreateFileAsync(filename, CreationCollisionOption.OpenIfExists);
- await FileIO.AppendTextAsync(file, this.Layout.GetFormattedString(entry) + "\r\n");
+
+ // need to append a session header...
+
+ // append...
+ await FileIO.AppendTextAsync(file, this.Layout.GetFormattedString(context, entry) + "\r\n");
// return...
return new LogWriteOperation(this, entry, true);
View
132 MetroLog.NetCore/FileTargetBase.cs
@@ -0,0 +1,132 @@
+using MetroLog.Layouts;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Windows.Storage;
+
+namespace MetroLog.Targets
+{
+ /// <summary>
+ /// Base class for file targets.
+ /// </summary>
+ public abstract class FileTargetBase : AsyncTarget
+ {
+ /// <summary>
+ /// Gets an object that defines the file naming parameters.
+ /// </summary>
+ public FileNamingParameters FileNamingParameters { get; private set; }
+
+ /// <summary>
+ /// Gets or sets the number of days to retain log files for.
+ /// </summary>
+ public int RetainDays { get; set; }
+
+ public static StorageFolder _logFolder = null;
+ private const string LogFolderName = "MetroLogs";
+
+ /// <summary>
+ /// Holds the next cleanup time.
+ /// </summary>
+ private DateTime NextCleanupUtc { get; set; }
+
+ protected FileTargetBase(Layout layout)
+ : base(layout)
+ {
+ this.FileNamingParameters = new FileNamingParameters();
+ this.RetainDays = 30;
+ }
+
+ public static async Task<StorageFolder> EnsureInitializedAsync()
+ {
+ var folder = _logFolder;
+ if (folder == null)
+ {
+ StorageFolder logFolder = null;
+ var root = ApplicationData.Current.LocalFolder;
+ try
+ {
+ logFolder = await root.GetFolderAsync(LogFolderName);
+ }
+ catch (FileNotFoundException ex)
+ {
+ SinkException(ex);
+ }
+
+ // if...
+ if (logFolder == null)
+ {
+ try
+ {
+ logFolder = await root.CreateFolderAsync(LogFolderName, CreationCollisionOption.OpenIfExists);
+ }
+ catch (Exception ex)
+ {
+ SinkException(ex);
+ }
+
+ // if we get into trouble here, try and load it again... (something else should have created it)...
+ if (logFolder == null)
+ logFolder = await root.GetFolderAsync(LogFolderName);
+ }
+
+ // store it - but only if we have one...
+ if (logFolder != null)
+ Interlocked.CompareExchange<StorageFolder>(ref _logFolder, logFolder, null);
+ }
+ return _logFolder;
+ }
+
+ private static void SinkException(Exception ex)
+ {
+ // no-op - just preventing compile warnings...
+ }
+
+ /// <summary>
+ /// Cleans up any old log files.
+ /// </summary>
+ /// <returns></returns>
+ protected async Task CheckCleanupAsync(StorageFolder folder)
+ {
+ var now = DateTime.UtcNow;
+ if (now < this.NextCleanupUtc || this.RetainDays < 1)
+ return;
+
+ try
+ {
+ // threshold...
+ var threshold = now.AddDays(0 - this.RetainDays);
+
+ // walk...
+ var regex = this.FileNamingParameters.GetRegex();
+ var toDelete = new List<StorageFile>();
+ foreach (var file in await folder.GetFilesAsync())
+ {
+ if (regex.Match(file.Name).Success && file.DateCreated <= threshold)
+ toDelete.Add(file);
+ }
+
+ // walk...
+ foreach (var file in toDelete)
+ {
+ try
+ {
+ await file.DeleteAsync();
+ }
+ catch (Exception ex)
+ {
+ InternalLogger.Current.Warn(string.Format("Failed to delete '{0}'.", file.Path), ex);
+ }
+ }
+ }
+ finally
+ {
+ // reset...
+ this.NextCleanupUtc = DateTime.UtcNow.AddHours(1);
+ }
+ }
+ }
+}
View
5 MetroLog.NetCore/LazyFlushManager.cs
@@ -60,6 +60,11 @@ static LazyFlushManager()
private static async void Current_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
+ await FlushAllAsync();
+ }
+
+ internal static async Task FlushAllAsync()
+ {
var tasks = new List<Task>();
foreach (var manager in Owners.Values)
tasks.Add(manager.LazyFlushAsync());
View
41 MetroLog.NetCore/LogManagerFactory.cs
@@ -9,6 +9,9 @@
namespace MetroLog
{
+ /// <summary>
+ /// Defines a class that allows the log manager to be configured for Windows Store apps.
+ /// </summary>
public class LogManagerFactory : LogManagerFactoryBase
{
protected LogManagerFactory()
@@ -16,6 +19,10 @@ protected LogManagerFactory()
}
+ /// <summary>
+ /// Initializes the log manager.
+ /// </summary>
+ /// <param name="config">The (optional) logging configuration to make as the default.</param>
public static void Initialize(LoggingConfiguration config = null)
{
var factory = new LogManagerFactory();
@@ -28,6 +35,10 @@ public static void Initialize(LoggingConfiguration config = null)
LazyFlushManager.Initialize(instance);
}
+ /// <summary>
+ /// Gets the default settings for Windows Store apps.
+ /// </summary>
+ /// <returns></returns>
protected override LoggingConfiguration CreateDefaultSettings()
{
var def = base.CreateDefaultSettings();
@@ -35,5 +46,35 @@ protected override LoggingConfiguration CreateDefaultSettings()
return def;
}
+
+ /// <summary>
+ /// Configures a global exception handler.
+ /// </summary>
+ /// <remarks>This method will bind a global handler that will write the exception information to FATAL.
+ /// It will then throw another exception which will stop the application (as per MS's Windows Store
+ /// UX guidelines).</remarks>
+ public static void ConfigureGlobalHandler()
+ {
+ Application.Current.UnhandledException += App_UnhandledException;
+ }
+
+ private static async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+ {
+ // unbind we're going to re-enter and don't want to loop...
+ Application.Current.UnhandledException -= App_UnhandledException;
+
+ // say we've handled this one. this allows our FATAL write to complete.
+ e.Handled = true;
+
+ // go...
+ var log = (ILoggerAsync)DefaultLogManager.GetLogger<LogManagerFactory>();
+ await log.FatalAsync("The application crashed: " + e.Message, e.Exception);
+
+ // if we're aborting, fake a suspend to flush the targets...
+ await LazyFlushManager.FlushAllAsync();
+
+ // abort the app here...
+ Application.Current.Exit();
+ }
}
}
View
2  MetroLog.NetCore/MetroLog.NetCore.csproj
@@ -112,7 +112,9 @@
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="FileSnapshotTarget.cs" />
+ <Compile Include="FileNamingMode.cs" />
<Compile Include="FileStreamingTarget.cs" />
+ <Compile Include="FileTargetBase.cs" />
<Compile Include="LoggingEnvironment.cs" />
<Compile Include="LogManagerFactory.cs" />
<Compile Include="LogZcf.cs" />
View
2  MetroLog.NetFx/Targets/TraceTarget.cs
@@ -22,7 +22,7 @@ public TraceTarget(Layout layout)
protected override void Write(LogWriteContext context, LogEventInfo entry)
{
- var message = Layout.GetFormattedString(entry);
+ var message = Layout.GetFormattedString(context, entry);
Trace.WriteLine(message);
}
}
View
1  MetroLog.Tests/MetroLog.Tests.csproj
@@ -96,6 +96,7 @@
<Compile Include="Objects\BrokenTarget.cs" />
<Compile Include="Objects\TestTarget.cs" />
<Compile Include="Tests\BrokenTargetTests.cs" />
+ <Compile Include="Tests\FileNamingParametersTests.cs" />
<Compile Include="Tests\JsonTests.cs" />
<Compile Include="Tests\LevelTests.cs" />
<Compile Include="Tests\LoggerTests.cs" />
View
240 MetroLog.Tests/Tests/FileNamingParametersTests.cs
@@ -0,0 +1,240 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit;
+using MetroLog.Targets;
+using MetroLog.Internal;
+
+namespace MetroLog.Tests
+{
+ public class FileNamingParametersTests
+ {
+ private LogEventInfo GetLogEventInfo()
+ {
+ return new LogEventInfo(LogLevel.Info, "foobar", "barfoo", null);
+ }
+
+ [Fact]
+ public void TestEverythingOff()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = false,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.None
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal("Log.log", filename);
+ }
+
+ [Fact]
+ public void TestLevelOn()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = true,
+ IncludeLogger = false,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.None
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal("Log - INFO.log", filename);
+ }
+
+ [Fact]
+ public void TestLoggerOn()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = true,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.None
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal("Log - foobar.log", filename);
+ }
+
+ [Fact]
+ public void TestSequenceOn()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = false,
+ IncludeSequence = true,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.None
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal(string.Format("Log - {0}.log", info.SequenceID), filename);
+ }
+
+ [Fact]
+ public void TestTimestampDate()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = false,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.Date
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal(string.Format("Log - {0}.log", LogManager.GetDateTime().ToString("yyyyMMdd")), filename);
+ }
+
+ [Fact]
+ public void TestTimestampTime()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = false,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.Time
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal(string.Format("Log - {0}.log", LogManager.GetDateTime().ToString("HHmmss")), filename);
+ }
+
+ [Fact]
+ public void TestTimestampBoth()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = false,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.DateTime
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var filename = naming.GetFilename(new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration())),
+ info);
+ Assert.Equal(string.Format("Log - {0}.log", LogManager.GetDateTime().ToString("yyyyMMdd HHmmss")), filename);
+ }
+
+ [Fact]
+ public void TestEverythingOn()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = true,
+ IncludeLogger = true,
+ IncludeSequence = true,
+ IncludeSession = true,
+ IncludeTimestamp = FileTimestampMode.DateTime
+ };
+
+ // ok...
+ var info = GetLogEventInfo();
+
+ // check...
+ var context = new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration()));
+ var filename = naming.GetFilename(context, info);
+ Assert.Equal(string.Format("Log - INFO - foobar - {0} - {1} - {2}.log", LogManager.GetDateTime().ToString("yyyyMMdd HHmmss"),
+ context.Environment.SessionId, info.SequenceID), filename);
+ }
+
+ [Fact]
+ public void TestRegexEverythingOff()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = false,
+ IncludeLogger = false,
+ IncludeSequence = false,
+ IncludeSession = false,
+ IncludeTimestamp = FileTimestampMode.None
+ };
+
+ // get...
+ var regex = naming.GetRegex();
+
+ // create...
+ var info = GetLogEventInfo();
+
+ // check...
+ var context = new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration()));
+ var filename = naming.GetFilename(context, info);
+
+ // check...
+ Assert.True(regex.Match(filename).Success);
+ }
+
+ [Fact]
+ public void TestRegexEverythingOn()
+ {
+ var naming = new FileNamingParameters()
+ {
+ IncludeLevel = true,
+ IncludeLogger = true,
+ IncludeSequence = true,
+ IncludeSession = true,
+ IncludeTimestamp = FileTimestampMode.DateTime
+ };
+
+ // get...
+ var regex = naming.GetRegex();
+
+ // create...
+ var info = GetLogEventInfo();
+
+ // check...
+ var context = new LogWriteContext(new LogManager(new LoggingEnvironment(), new LoggingConfiguration()));
+ var filename = naming.GetFilename(context, info);
+
+ // check...
+ Assert.True(regex.Match(filename).Success);
+ }
+ }
+}
View
2  MetroLog/ILoggingEnvironment.cs
@@ -8,6 +8,8 @@ namespace MetroLog
{
public interface ILoggingEnvironment
{
+ Guid SessionId { get; }
+
string ToJson();
}
}
View
17 MetroLog/Internal/LogManager.cs
@@ -67,7 +67,7 @@ private void OnLoggerCreatedSafe(ILoggerEventArgs args)
}
catch (Exception ex)
{
- LogInternal("Failed to handle OnLoggerCreated event.", ex);
+ InternalLogger.Current.Error("Failed to handle OnLoggerCreated event.", ex);
}
}
@@ -78,13 +78,14 @@ protected virtual void OnLoggerCreated(ILoggerEventArgs args)
}
// logs problems with the framework to Debug...
- internal static void LogInternal(string message, Exception ex)
- {
- if(ex != null)
- Debug.WriteLine("{0}|INTERNAL|(null)|{1} --> {2}", GetDateTime().ToString(DateTimeFormat), message, ex);
- else
- Debug.WriteLine("{0}|INTERNAL|(null)|{1}", GetDateTime().ToString(DateTimeFormat), message);
- }
+ // mbr - 2012-09-14 - moves to InternalLogger...
+ //internal static void LogInternal(string message, Exception ex)
+ //{
+ // if(ex != null)
+ // Debug.WriteLine("{0}|INTERNAL|(null)|{1} --> {2}", GetDateTime().ToString(DateTimeFormat), message, ex);
+ // else
+ // Debug.WriteLine("{0}|INTERNAL|(null)|{1}", GetDateTime().ToString(DateTimeFormat), message);
+ //}
internal static DateTimeOffset GetDateTime()
{
View
2  MetroLog/Internal/Logger.cs
@@ -120,7 +120,7 @@ private Task<LogWriteOperation[]> LogInternal(LogLevel level, string message, ob
}
catch (Exception logEx)
{
- LogManager.LogInternal("Logging operation failed.", logEx);
+ InternalLogger.Current.Error("Logging operation failed.", logEx);
return Task.FromResult(new LogWriteOperation[] {});
}
}
View
2  MetroLog/Internal/LoggingEnvironmentBase.cs
@@ -12,6 +12,7 @@ namespace MetroLog.Internal
{
public abstract class LoggingEnvironmentBase : ILoggingEnvironment
{
+ public Guid SessionId { get; private set; }
public string FxProfile { get; private set; }
public bool IsDebugging { get; private set; }
@@ -21,6 +22,7 @@ public abstract class LoggingEnvironmentBase : ILoggingEnvironment
protected LoggingEnvironmentBase(string fxProfile)
{
// common...
+ this.SessionId = Guid.NewGuid();
this.FxProfile = fxProfile;
this.IsDebugging = Debugger.IsAttached;
this.MetroLogVersion = typeof(ILogger).GetTypeInfo().Assembly.GetName().Version;
View
137 MetroLog/InternalLogger.cs
@@ -0,0 +1,137 @@
+using MetroLog.Internal;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MetroLog
+{
+ public class InternalLogger : ILogger
+ {
+ private static InternalLogger _current;
+
+ private InternalLogger()
+ {
+ }
+
+ static InternalLogger()
+ {
+ _current = new InternalLogger();
+ }
+
+ public static ILogger Current
+ {
+ get
+ {
+ return _current;
+ }
+ }
+
+ public string Name
+ {
+ get
+ {
+ return "(Internal)";
+ }
+ }
+
+ public bool IsTraceEnabled { get { return true; } }
+ public bool IsDebugEnabled { get { return true; } }
+ public bool IsInfoEnabled { get { return true; } }
+ public bool IsWarnEnabled { get { return true; } }
+ public bool IsErrorEnabled { get { return true; } }
+ public bool IsFatalEnabled { get { return true; } }
+
+ public void Trace(string message, Exception ex = null)
+ {
+ this.Log(LogLevel.Trace, message, ex);
+ }
+
+ public void Trace(string message, params object[] ps)
+ {
+ this.Log(LogLevel.Trace, message, ps);
+ }
+
+ public void Debug(string message, Exception ex = null)
+ {
+ this.Log(LogLevel.Trace, message, ex);
+ }
+
+ public void Debug(string message, params object[] ps)
+ {
+ this.Log(LogLevel.Trace, message, ps);
+ }
+
+ public void Info(string message, Exception ex = null)
+ {
+ this.Log(LogLevel.Trace, message, ex);
+ }
+
+ public void Info(string message, params object[] ps)
+ {
+ this.Log(LogLevel.Trace, message, ps);
+ }
+
+ public void Warn(string message, Exception ex = null)
+ {
+ this.Log(LogLevel.Trace, message, ex);
+ }
+
+ public void Warn(string message, params object[] ps)
+ {
+ this.Log(LogLevel.Trace, message, ps);
+ }
+
+ public void Error(string message, Exception ex = null)
+ {
+ this.Log(LogLevel.Trace, message, ex);
+ }
+
+ public void Error(string message, params object[] ps)
+ {
+ this.Log(LogLevel.Trace, message, ps);
+ }
+
+ public void Fatal(string message, Exception ex = null)
+ {
+ this.Log(LogLevel.Trace, message, ex);
+ }
+
+ public void Fatal(string message, params object[] ps)
+ {
+ this.Log(LogLevel.Trace, message, ps);
+ }
+
+ public void Log(LogLevel logLevel, string message, Exception ex)
+ {
+ string formatted = null;
+ long sequence = LogEventInfo.GetNextSequenceId();
+ string dt = LogManager.GetDateTime().ToString(LogManager.DateTimeFormat);
+ string asString = logLevel.ToString().ToUpper();
+ int thread = Environment.CurrentManagedThreadId;
+ if (ex != null)
+ formatted = string.Format("{0}|{1}|{2}|{3}|{4} --> {5}", sequence, dt, asString, thread, message, ex);
+ else
+ formatted = string.Format("{0}|{1}|{2}|{3}|{4}", sequence, dt, asString, thread, message);
+
+ // debug...
+ System.Diagnostics.Debug.WriteLine(formatted);
+
+ // TODO: EWT
+ }
+
+ public void Log(LogLevel logLevel, string message, params object[] ps)
+ {
+ if(ps.Any())
+ this.Log(logLevel, string.Format(message, ps), (Exception)null);
+ else
+ this.Log(logLevel, message, (Exception)null);
+ }
+
+ public bool IsEnabled(LogLevel level)
+ {
+ return true;
+ }
+ }
+}
View
6 MetroLog/Layouts/FileSnapshotLayout.cs
@@ -9,7 +9,7 @@ namespace MetroLog.Layouts
{
public class FileSnapshotLayout : Layout
{
- public override string GetFormattedString(LogEventInfo info)
+ public override string GetFormattedString(LogWriteContext context, LogEventInfo info)
{
StringBuilder builder = new StringBuilder();
builder.Append("Sequence: ");
@@ -31,6 +31,10 @@ public override string GetFormattedString(LogEventInfo info)
builder.Append(info.Exception);
}
+ builder.Append("\r\n------------------------\r\n");
+ builder.Append("Session: ");
+ builder.Append(context.Environment.ToJson());
+
return builder.ToString();
}
}
View
11 MetroLog/Layouts/Layout.cs
@@ -6,12 +6,21 @@
namespace MetroLog.Layouts
{
+ /// <summary>
+ /// Defines the base class for string-based layouts.
+ /// </summary>
public abstract class Layout
{
protected Layout()
{
}
- public abstract string GetFormattedString(LogEventInfo info);
+ /// <summary>
+ /// Returns the formatted log event.
+ /// </summary>
+ /// <param name="context">The logging context.</param>
+ /// <param name="info">The log event for format.</param>
+ /// <returns>The foramtted string.</returns>
+ public abstract string GetFormattedString(LogWriteContext context, LogEventInfo info);
}
}
View
2  MetroLog/Layouts/NullLayout.cs
@@ -12,7 +12,7 @@ public NullLayout()
{
}
- public override string GetFormattedString(LogEventInfo info)
+ public override string GetFormattedString(LogWriteContext context, LogEventInfo info)
{
return string.Empty;
}
View
2  MetroLog/Layouts/SingleLineLayout.cs
@@ -9,7 +9,7 @@ namespace MetroLog.Layouts
{
public class SingleLineLayout : Layout
{
- public override string GetFormattedString(LogEventInfo info)
+ public override string GetFormattedString(LogWriteContext context, LogEventInfo info)
{
StringBuilder builder = new StringBuilder();
builder.Append(info.SequenceID);
View
7 MetroLog/LogEventInfo.cs
@@ -29,7 +29,12 @@ internal LogEventInfo(LogLevel level, string logger, string message, Exception e
Message = message;
Exception = ex;
TimeStamp = LogManager.GetDateTime();
- SequenceID = Interlocked.Increment(ref _globalSequenceId);
+ SequenceID = GetNextSequenceId();
+ }
+
+ internal static long GetNextSequenceId()
+ {
+ return Interlocked.Increment(ref _globalSequenceId);
}
public string ToJson()
View
8 MetroLog/LogWriteContext.cs
@@ -14,5 +14,13 @@ internal LogWriteContext(ILogManager manager)
{
this.Manager = manager;
}
+
+ public ILoggingEnvironment Environment
+ {
+ get
+ {
+ return Manager.LoggingEnvironment;
+ }
+ }
}
}
View
3  MetroLog/MetroLog.csproj
@@ -110,6 +110,7 @@
<Compile Include="ILoggerEventArgs.cs" />
<Compile Include="ILoggerQuery.cs" />
<Compile Include="ILoggingEnvironment.cs" />
+ <Compile Include="InternalLogger.cs" />
<Compile Include="Internal\LoggingEnvironmentBase.cs" />
<Compile Include="ILoggerAsync.cs" />
<Compile Include="ILazyFlushable.cs" />
@@ -131,6 +132,8 @@
<Compile Include="Targets\AsyncTarget.cs" />
<Compile Include="Targets\BufferedTarget.cs" />
<Compile Include="Targets\EtwTarget.cs" />
+ <Compile Include="Targets\FileNamingParameters.cs" />
+ <Compile Include="Targets\FileTimestampMoe.cs" />
<Compile Include="Targets\HttpClientEventHandler.cs" />
<Compile Include="Targets\JsonPostTarget.cs" />
<Compile Include="Targets\JsonPostWrapper.cs" />
View
6 MetroLog/Properties/AssemblyInfo.cs
@@ -1,4 +1,5 @@
using System.Reflection;
+using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
@@ -20,4 +21,7 @@
// "ed95a703d3ffc367837e047f6fbdba8fae1d1295a5c031a108aa452c62f14b7a12766f86a0f94f" +
// "28dae83980e5b69e97985899ae9299dd6951b0933d13416c564b3997d8ed784208afa2e18f0389" +
// "9da14d209054ce3002e47e9ae1bd811baa2a20899c5f6c8211b886be9284541d58476fbabc7323" +
-// "90a0f7c9")]
+// "90a0f7c9")]
+
+// mbr - 2012-09-15 - added at the suggestion of @davkean...
+[assembly: NeutralResourcesLanguage("en-US")]
View
4 MetroLog/Targets/BufferedTarget.cs
@@ -50,7 +50,7 @@ protected internal override sealed Task<LogWriteOperation> WriteAsync(LogWriteCo
}
catch (Exception ex)
{
- LogManager.LogInternal(string.Format("Failed to write to target '{0}'.", this), ex);
+ InternalLogger.Current.Error(string.Format("Failed to write to target '{0}'.", this), ex);
return Task.FromResult(new LogWriteOperation(this, entry, false));
}
}
@@ -67,7 +67,7 @@ protected internal override sealed Task<LogWriteOperation> WriteAsync(LogWriteCo
}
catch (Exception ex)
{
- LogManager.LogInternal(string.Format("Failed to flush for target '{0}'.", this), ex);
+ InternalLogger.Current.Error(string.Format("Failed to flush for target '{0}'.", this), ex);
return new LogWriteOperation(this, toFlush, false);
}
}
View
2  MetroLog/Targets/DebugTarget.cs
@@ -22,7 +22,7 @@ public DebugTarget(Layout layout)
protected override void Write(LogWriteContext context, LogEventInfo entry)
{
- var message = Layout.GetFormattedString(entry);
+ var message = Layout.GetFormattedString(context, entry);
Debug.WriteLine(message);
}
}
View
2  MetroLog/Targets/EtwTarget.cs
@@ -22,7 +22,7 @@ public EtwTarget(Layout layout)
protected override void Write(LogWriteContext context, LogEventInfo entry)
{
- var message = Layout.GetFormattedString(entry);
+ var message = Layout.GetFormattedString(context, entry);
switch(entry.Level)
{
View
133 MetroLog/Targets/FileNamingParameters.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+
+namespace MetroLog.Targets
+{
+ /// <summary>
+ /// Defines a class that allows the user to configure file naming.
+ /// </summary>
+ public class FileNamingParameters
+ {
+ public bool IncludeLevel { get; set; }
+ public FileTimestampMode IncludeTimestamp { get; set; }
+ public bool IncludeLogger { get; set; }
+ public bool IncludeSession { get; set; }
+ public bool IncludeSequence { get; set; }
+
+ public FileNamingParameters()
+ {
+ this.IncludeLevel = false;
+ this.IncludeTimestamp = FileTimestampMode.Date;
+ this.IncludeLogger = false;
+ this.IncludeSession = true;
+ this.IncludeSequence = false;
+ }
+
+ public string GetFilename(LogWriteContext context, LogEventInfo entry)
+ {
+ var builder = new StringBuilder();
+ builder.Append("Log");
+ if (this.IncludeLevel)
+ {
+ builder.Append(" - ");
+ builder.Append(entry.Level.ToString().ToUpper());
+ }
+ if (this.IncludeLogger)
+ {
+ builder.Append(" - ");
+ builder.Append(entry.Logger);
+ }
+ if (this.IncludeTimestamp != FileTimestampMode.None)
+ {
+ bool date = ((int)this.IncludeTimestamp & (int)FileTimestampMode.Date) != 0;
+ if (date)
+ {
+ builder.Append(" - ");
+ builder.Append(entry.TimeStamp.ToString("yyyyMMdd"));
+ }
+
+ bool time = ((int)this.IncludeTimestamp & (int)FileTimestampMode.Time) != 0;
+ if(time)
+ {
+ if(date)
+ builder.Append(" ");
+ else
+ builder.Append(" - ");
+ builder.Append(entry.TimeStamp.ToString("HHmmss"));
+ }
+ }
+ if (this.IncludeSession)
+ {
+ builder.Append(" - ");
+ builder.Append(context.Environment.SessionId);
+ }
+ if (this.IncludeSequence)
+ {
+ builder.Append(" - ");
+ builder.Append(entry.SequenceID);
+ }
+
+ // return...
+ builder.Append(".log");
+ return builder.ToString();
+ }
+
+ public Regex GetRegex()
+ {
+ var builder = new StringBuilder();
+ builder.Append("^Log");
+
+ // stuff...
+ if (this.IncludeLevel)
+ {
+ builder.Append(@"\s*-\s*");
+ builder.Append(@"\w+");
+ }
+ if (this.IncludeLogger)
+ {
+ builder.Append(@"\s*-\s*");
+ builder.Append(@"[\w\s]+");
+ }
+ if (this.IncludeTimestamp != FileTimestampMode.None)
+ {
+ bool date = ((int)this.IncludeTimestamp & (int)FileTimestampMode.Date) != 0;
+ if (date)
+ {
+ builder.Append(@"\s*-\s*");
+ builder.Append("[0-9]{8}");
+ }
+
+ bool time = ((int)this.IncludeTimestamp & (int)FileTimestampMode.Time) != 0;
+ if (time)
+ {
+ if (date)
+ builder.Append(@"\s+");
+ else
+ builder.Append(@"\s*-\s*");
+ builder.Append("[0-9]{6}");
+ }
+ }
+ if (this.IncludeSession)
+ {
+ builder.Append(@"\s*-\s*");
+ builder.Append(@"[a-fA-F0-9\-]+");
+ }
+ if (this.IncludeSequence)
+ {
+ builder.Append(@"\s*-\s*");
+ builder.Append("[0-9]+");
+ }
+
+ // log...
+ builder.Append(".log$");
+
+ // go...
+ var regex = new Regex(builder.ToString(), RegexOptions.Singleline | RegexOptions.IgnoreCase);
+ return regex;
+ }
+ }
+}
View
17 MetroLog/Targets/FileTimestampMoe.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MetroLog.Targets
+{
+ [Flags]
+ public enum FileTimestampMode
+ {
+ None = 0,
+ Date = 1,
+ Time = 2,
+ DateTime = Date | Time
+ }
+}
View
2  MetroLog/Targets/SyncTarget.cs
@@ -24,7 +24,7 @@ protected internal override sealed Task<LogWriteOperation> WriteAsync(LogWriteCo
}
catch (Exception ex)
{
- LogManager.LogInternal(string.Format("Failed to write to target '{0}'.", this), ex);
+ InternalLogger.Current.Error(string.Format("Failed to write to target '{0}'.", this), ex);
return Task.FromResult(new LogWriteOperation(this, entry, false));
}
}
View
43 WebTargetSample/Json/LoggingEnvironmentConverter.cs
@@ -0,0 +1,43 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+using WebTargetSample.Model;
+
+namespace WebTargetSample.Json
+{
+ public class LoggingEnvironmentConverter : JsonConverter
+ {
+ public override bool CanConvert(Type objectType)
+ {
+ return typeof(LoggingEnvironment).IsAssignableFrom(objectType);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ var env = new LoggingEnvironment();
+
+ // walk...
+ string prop = null;
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonToken.PropertyName)
+ prop = Convert.ToString(reader.Value);
+ else if (reader.TokenType == JsonToken.EndObject)
+ break;
+
+ // set...
+ env.Values[prop] = reader.Value;
+ }
+
+ // return...
+ return env;
+ }
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
View
11 WebTargetSample/Model/ExceptionWrapper.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace WebTargetSample.Model
+{
+ public class ExceptionWrapper
+ {
+ }
+}
View
3  WebTargetSample/Model/JsonPostWrapper.cs
@@ -3,12 +3,15 @@
using System.Collections.Generic;
using System.Linq;
using System.Web;
+using WebTargetSample.Json;
namespace WebTargetSample.Model
{
public class JsonPostWrapper
{
+ [JsonConverter(typeof(LoggingEnvironmentConverter))]
public LoggingEnvironment Environment { get; set; }
+
public LogEventInfo[] Events { get; set; }
public JsonPostWrapper()
View
6 WebTargetSample/Model/LogEventInfo.cs
@@ -7,5 +7,11 @@ namespace WebTargetSample.Model
{
public class LogEventInfo
{
+ public long SequenceID { get; set; }
+ public LogLevel Level { get; set; }
+ public string Logger { get; set; }
+ public string Message { get; set; }
+ public DateTimeOffset TimeStamp { get; set; }
+ public ExceptionWrapper Exception { get; set; }
}
}
View
17 WebTargetSample/Model/LogLevel.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Web;
+
+namespace WebTargetSample.Model
+{
+ public enum LogLevel
+ {
+ Trace = 0,
+ Debug = 1,
+ Info = 2,
+ Warn = 3,
+ Error = 4,
+ Fatal = 5
+ }
+}
View
6 WebTargetSample/Model/LoggingEnvironment.cs
@@ -7,5 +7,11 @@ namespace WebTargetSample.Model
{
public class LoggingEnvironment
{
+ public Dictionary<string, object> Values { get; private set; }
+
+ public LoggingEnvironment()
+ {
+ this.Values = new Dictionary<string, object>();
+ }
}
}
View
14 WebTargetSample/ReceiveLogEntries.ashx.cs
@@ -1,7 +1,11 @@
-using System;
+using Newtonsoft.Json;
+using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
using System.Linq;
using System.Web;
+using WebTargetSample.Model;
namespace WebTargetSample
{
@@ -13,11 +17,15 @@ public class ReceiveLogEntries : IHttpHandler
public void ProcessRequest(HttpContext context)
{
// get the json out...
+ string json = null;
+ using (var reader = new StreamReader(context.Request.InputStream))
+ json = reader.ReadToEnd();
// deserialize...
+ var wrapper = JsonConvert.DeserializeObject<JsonPostWrapper>(json);
- // dump to the event log...
-
+ //Console.WriteLine(info);
+ Debug.WriteLine(wrapper);
}
public bool IsReusable
View
3  WebTargetSample/WebTargetSample.csproj
@@ -68,9 +68,12 @@
<Compile Include="Default.aspx.designer.cs">
<DependentUpon>Default.aspx</DependentUpon>
</Compile>
+ <Compile Include="Json\LoggingEnvironmentConverter.cs" />
+ <Compile Include="Model\ExceptionWrapper.cs" />
<Compile Include="Model\JsonPostWrapper.cs" />
<Compile Include="Model\LogEventInfo.cs" />
<Compile Include="Model\LoggingEnvironment.cs" />
+ <Compile Include="Model\LogLevel.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ReceiveLogEntries.ashx.cs">
<DependentUpon>ReceiveLogEntries.ashx</DependentUpon>
View
8 Win8Sample/App.xaml.cs
@@ -35,13 +35,7 @@ public App()
// start logging here...
LogManagerFactory.Initialize();
- this.UnhandledException += App_UnhandledException;
- }
-
- async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- var log = (ILoggerAsync)LogManagerFactory.DefaultLogManager.GetLogger<App>();
- await log.FatalAsync("The application crashed: " + e.Message, e.Exception);
+ LogManagerFactory.ConfigureGlobalHandler();
}
/// <summary>
View
1  Win8Sample/LogSamplePage.xaml
@@ -48,6 +48,7 @@
<Button Content="Crash/Fatal" Margin="0,30,0,0" Click="HandleFatal"></Button>
<Button Content="Register FileStreamingTarget" Margin="0,30,0,0" Click="HandleRegisterStreamingTarget" x:Name="buttonFileStreaming"></Button>
<Button Content="Register JsonPostTarget" Click="HandleRegisterJsonPostTarget" x:Name="buttonJsonPost"/>
+ <Button Content="Register SQLiteTarget" Click="HandleRegisterSQLiteTarget" x:Name="buttonSQLite"/>
</StackPanel>
<VisualStateManager.VisualStateGroups>
View
21 Win8Sample/LogSamplePage.xaml.cs
@@ -64,7 +64,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
private void HandleTrace(object sender, RoutedEventArgs e)
{
- this.Log.Debug("This is a trace message.");
+ this.Log.Trace("This is a trace message.");
}
private void HandleDebug(object sender, RoutedEventArgs e)
@@ -103,12 +103,12 @@ private void DoMagic()
private void HandleFatal(object sender, RoutedEventArgs e)
{
// the idea here is to invoke the global error handler...
- throw new NotImplementedException("Bang.");
+ throw new InvalidOperationException("Bang.");
}
private void HandleRegisterStreamingTarget(object sender, RoutedEventArgs e)
{
- LogManagerFactory.DefaultLogManager.DefaultConfiguration.AddTarget(LogLevel.Debug, LogLevel.Fatal,
+ LogManagerFactory.DefaultLogManager.DefaultConfiguration.AddTarget(LogLevel.Trace, LogLevel.Fatal,
new FileStreamingTarget());
// reset...
@@ -121,7 +121,7 @@ private void HandleRegisterStreamingTarget(object sender, RoutedEventArgs e)
private void HandleRegisterJsonPostTarget(object sender, RoutedEventArgs e)
{
- LogManagerFactory.DefaultLogManager.DefaultConfiguration.AddTarget(LogLevel.Debug, LogLevel.Fatal,
+ LogManagerFactory.DefaultLogManager.DefaultConfiguration.AddTarget(LogLevel.Trace, LogLevel.Fatal,
new JsonPostTarget(5, new Uri("http://localhost/metrologweb/receivelogentries.ashx")));
// reset...
@@ -131,5 +131,18 @@ private void HandleRegisterJsonPostTarget(object sender, RoutedEventArgs e)
// set...
this.buttonJsonPost.IsEnabled = false;
}
+
+ private void HandleRegisterSQLiteTarget(object sender, RoutedEventArgs e)
+ {
+ LogManagerFactory.DefaultLogManager.DefaultConfiguration.AddTarget(LogLevel.Trace, LogLevel.Fatal,
+ new SQLiteTarget());
+
+ // reset...
+ LogManagerFactory.DefaultLogManager.ResetCache();
+ this.Log = LogManagerFactory.DefaultLogManager.GetLogger<LogSamplePage>();
+
+ // set...
+ this.buttonSQLite.IsEnabled = false;
+ }
}
}
View
2  Win8Sample/Win8Sample.csproj
@@ -22,7 +22,7 @@
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE;NETFX_CORE</DefineConstants>
+ <DefineConstants>TRACE;DEBUG;NETFX_CORE, DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
Please sign in to comment.
Something went wrong with that request. Please try again.