Skip to content

Commit 693d6ff

Browse files
committed
Wired up the fallback loggers through the dispatcher and into the config.
1 parent f82c715 commit 693d6ff

15 files changed

Lines changed: 289 additions & 20 deletions

Take2/NuLog.Tests/Unit/Configuration/XmlConfigurationProviderTests/XmlConfigProviderTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,5 +172,21 @@ public void Should_ReadIncludeStackFrameFlag()
172172
// Validate
173173
Assert.True(config.IncludeStackFrame);
174174
}
175+
176+
/// <summary>
177+
/// The config provider should read the fallback log path.
178+
/// </summary>
179+
[Fact(DisplayName = "Should_ReadFallbackLogPath")]
180+
public void Should_ReadFallbackLogPath()
181+
{
182+
// Setup
183+
var provider = GetConfigurationProvider("<nulog fallbackLog=\"fallbacklog.txt\"></nulog>");
184+
185+
// Execute
186+
var config = provider.GetConfiguration();
187+
188+
// Validate
189+
Assert.Equal("fallbacklog.txt", config.FallbackLogPath);
190+
}
175191
}
176192
}

Take2/NuLog.Tests/Unit/Dispatchers/StandardDispatcherTests.cs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,6 @@ public void Should_FallbackLoggingNow()
233233
.MustHaveHappened();
234234
}
235235

236-
/// <summary>
237-
/// The dispatcher should write the fallback message to trace, if no fallback logger is set
238-
/// on the dispatcher.
239-
/// </summary>
240-
[Fact(DisplayName = "Should_FallbackToTraceIfNoFallbackSetLater", Skip = "Not implemented yet.")]
241-
public void Should_FallbackToTraceIfNoFallbackSetLater()
242-
{
243-
throw new NotImplementedException();
244-
}
245-
246236
/// <summary>
247237
/// Setup a fake target.
248238
/// </summary>
@@ -266,7 +256,7 @@ protected static ITagRouter FakeTagRouter()
266256
/// </summary>
267257
protected static IDispatcher GetDispatcher(IEnumerable<ITarget> targets, ITagRouter tagRouter, IFallbackLogger fallbackLogger = null)
268258
{
269-
return new StandardDispatcher(targets, tagRouter, fallbackLogger);
259+
return new StandardDispatcher(targets, tagRouter, fallbackLogger ?? A.Fake<IFallbackLogger>());
270260
}
271261
}
272262

Take2/NuLog.Tests/Unit/Factories/StandardLoggerFactoryUnitTests.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Source on GitHub: https://github.com/ivanpointer/NuLog */
44

55
using NuLog.Configuration;
6+
using NuLog.FallbackLoggers;
67
using NuLog.Targets;
78
using System.Collections.Generic;
89
using System.Linq;
@@ -392,5 +393,42 @@ public void Should_SetStackFrameFlagOnLogger()
392393
// Verify
393394
Assert.True(logger.IncludeStackFrame);
394395
}
396+
397+
/// <summary>
398+
/// The factory should build a trace fallback logger when a fallback log (file path) isn't configured.
399+
/// </summary>
400+
[Fact(DisplayName = "Should_BuildTraceFallbackLoggerDefault")]
401+
public void Should_BuildTraceFallbackLoggerDefault()
402+
{
403+
// Setup
404+
var factory = GetLogFactory(new Config());
405+
406+
// Execute
407+
var fallbackLogger = factory.GetFallbackLogger();
408+
409+
// Verify
410+
Assert.NotNull(fallbackLogger);
411+
Assert.True(typeof(StandardTraceFallbackLogger).IsAssignableFrom(fallbackLogger.GetType()));
412+
}
413+
414+
/// <summary>
415+
/// When a fallback path is configured, the factory should build the file fallback logger.
416+
/// </summary>
417+
[Fact(DisplayName = "Should_BuildFileFallbackLoggerWhenConfigured")]
418+
public void Should_BuildFileFallbackLoggerWhenConfigured()
419+
{
420+
// Setup
421+
var factory = GetLogFactory(new Config
422+
{
423+
FallbackLogPath = "fallbacklog.txt"
424+
});
425+
426+
// Execute
427+
var fallbackLogger = factory.GetFallbackLogger();
428+
429+
// Verify
430+
Assert.NotNull(fallbackLogger);
431+
Assert.True(typeof(StandardFileFallbackLogger).IsAssignableFrom(fallbackLogger.GetType()));
432+
}
395433
}
396434
}

Take2/NuLog.Tests/Unit/FallbackLoggers/StandardFallbackLoggerBaseTests.cs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,72 @@ public void Should_IncludeLogEventExceptionMessage()
184184
Assert.Contains("LogEvent Exception: \"Log Event Exception Message!\"", text);
185185
}
186186

187+
/// <summary>
188+
/// The fallback logger should write the current date/time stamp at the start of the log message.
189+
/// </summary>
190+
[Fact(DisplayName = "Should_SimpleMessageStartWithDateTimeStamp")]
191+
public void Should_SimpleMessageStartWithDateTimeStamp()
192+
{
193+
// Setup
194+
var fallbackLogger = GetFallbackLogger();
195+
var target = A.Fake<ITarget>();
196+
197+
// Execute
198+
fallbackLogger.Log("Simple message!");
199+
200+
// Verify
201+
var text = fallbackLogger.LoggedMessages.Single();
202+
var pattern = new Regex(@"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} | .*$");
203+
var now = DateTime.Now;
204+
var midDateText = now.ToString("yyyy-MM-dd hh:mm");
205+
var maxDateText = now.AddSeconds(1).ToString("yyyy-MM-dd hh:mm");
206+
207+
Assert.True(pattern.IsMatch(text), "Text loaded from file doesn't match regular expression for starting with a date time string.");
208+
Assert.True(text.StartsWith(midDateText) || text.StartsWith(maxDateText), "Text loaded from file doesn't appear to be prefixed with the current time.");
209+
}
210+
211+
/// <summary>
212+
/// The fallback logger should write the current date/time stamp at the start of the log message.
213+
/// </summary>
214+
[Fact(DisplayName = "Should_FormattedMessageStartWithDateTimeStamp")]
215+
public void Should_FormattedMessageStartWithDateTimeStamp()
216+
{
217+
// Setup
218+
var fallbackLogger = GetFallbackLogger();
219+
var target = A.Fake<ITarget>();
220+
221+
// Execute
222+
fallbackLogger.Log("Formatted {0}!", "message");
223+
224+
// Verify
225+
var text = fallbackLogger.LoggedMessages.Single();
226+
var pattern = new Regex(@"^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3} | .*$");
227+
var now = DateTime.Now;
228+
var midDateText = now.ToString("yyyy-MM-dd hh:mm");
229+
var maxDateText = now.AddSeconds(1).ToString("yyyy-MM-dd hh:mm");
230+
231+
Assert.True(pattern.IsMatch(text), "Text loaded from file doesn't match regular expression for starting with a date time string.");
232+
Assert.True(text.StartsWith(midDateText) || text.StartsWith(maxDateText), "Text loaded from file doesn't appear to be prefixed with the current time.");
233+
}
234+
235+
/// <summary>
236+
/// The fallback logger should format a simple message, with arguments.
237+
/// </summary>
238+
[Fact(DisplayName = "Should_FormatSimpleMessage")]
239+
public void Should_FormatSimpleMessage()
240+
{
241+
// Setup
242+
var fallbackLogger = GetFallbackLogger();
243+
var target = A.Fake<ITarget>();
244+
245+
// Execute
246+
fallbackLogger.Log("Formatted {0}!", "message");
247+
248+
// Verify
249+
var text = fallbackLogger.LoggedMessages.Single();
250+
Assert.Contains("Formatted message!", text);
251+
}
252+
187253
/// <summary>
188254
/// Gets the fallback logger under test.
189255
/// </summary>
@@ -207,8 +273,14 @@ public DummyStandardFallbackLogger()
207273

208274
public override void Log(Exception exception, ITarget target, ILogEvent logEvent)
209275
{
210-
var message = FormatMessage(exception, target, logEvent);
211-
LoggedMessages.Add(message);
276+
var formatted = FormatMessage(exception, target, logEvent);
277+
LoggedMessages.Add(formatted);
278+
}
279+
280+
public override void Log(string message, params object[] args)
281+
{
282+
var formatted = FormatMessage(message, args);
283+
LoggedMessages.Add(formatted);
212284
}
213285
}
214286
}

Take2/NuLog.Tests/Unit/FallbackLoggers/StandardFileFallbackLoggerTests.cs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,61 @@ public void Should_WriteToFile()
4545
}
4646
}
4747
}
48+
49+
/// <summary>
50+
/// The standard file fallback logger should write a simple message to file.
51+
/// </summary>
52+
[Fact(DisplayName = "Should_WriteSimpleMessageToFile")]
53+
public void Should_WriteSimpleMessageToFile()
54+
{
55+
try
56+
{
57+
// Setup
58+
var fallbackLogger = new StandardFileFallbackLogger("Should_WriteSimpleMessageToFile.txt");
59+
var target = A.Fake<ITarget>();
60+
61+
// Execute
62+
fallbackLogger.Log("Hello, simple message");
63+
64+
// Verify
65+
var text = File.ReadAllText("Should_WriteSimpleMessageToFile.txt");
66+
Assert.Contains("Hello, simple message", text);
67+
}
68+
finally
69+
{
70+
if (File.Exists("Should_WriteSimpleMessageToFile.txt"))
71+
{
72+
File.Delete("Should_WriteSimpleMessageToFile.txt");
73+
}
74+
}
75+
}
76+
77+
/// <summary>
78+
/// The standard file fallback logger should write a formatted message to file.
79+
/// </summary>
80+
[Fact(DisplayName = "Should_WriteFormattedMessageToFile")]
81+
public void Should_WriteFormattedMessageToFile()
82+
{
83+
try
84+
{
85+
// Setup
86+
var fallbackLogger = new StandardFileFallbackLogger("Should_WriteFormattedMessageToFile.txt");
87+
var target = A.Fake<ITarget>();
88+
89+
// Execute
90+
fallbackLogger.Log("Hello, simple {0}!", "message");
91+
92+
// Verify
93+
var text = File.ReadAllText("Should_WriteFormattedMessageToFile.txt");
94+
Assert.Contains("Hello, simple message!", text);
95+
}
96+
finally
97+
{
98+
if (File.Exists("Should_WriteFormattedMessageToFile.txt"))
99+
{
100+
File.Delete("Should_WriteFormattedMessageToFile.txt");
101+
}
102+
}
103+
}
48104
}
49105
}

Take2/NuLog.Tests/Unit/FallbackLoggers/StandardTraceFallbackLoggerTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,39 @@ public void Should_WriteToTrace()
5050
Assert.True(this.traceListener.Messages.Any(m => m.Contains("Hello, StandardTraceFallbackLogger!")));
5151
Assert.True(this.traceListener.Messages.Any(m => m.Contains("Hello, StandardTraceFallbackLogger Line Two!")));
5252
}
53+
54+
/// <summary>
55+
/// A simple message should be written to trace.
56+
/// </summary>
57+
[Fact(DisplayName = "Should_WriteSimpleMessageToTrace")]
58+
public void Should_WriteSimpleMessageToTrace()
59+
{
60+
// Setup
61+
var fallbackLogger = new StandardTraceFallbackLogger();
62+
var target = A.Fake<ITarget>();
63+
64+
// Execute
65+
fallbackLogger.Log("Hello, Simple Message!");
66+
67+
// Verify
68+
Assert.True(this.traceListener.Messages.Any(m => m.Contains("Hello, Simple Message!")));
69+
}
70+
71+
/// <summary>
72+
/// A formatted message should be written to trace.
73+
/// </summary>
74+
[Fact(DisplayName = "Should_WriteFormattedMessageToTrace")]
75+
public void Should_WriteFormattedMessageToTrace()
76+
{
77+
// Setup
78+
var fallbackLogger = new StandardTraceFallbackLogger();
79+
var target = A.Fake<ITarget>();
80+
81+
// Execute
82+
fallbackLogger.Log("Hello, Formatted {0}!", "Message");
83+
84+
// Verify
85+
Assert.True(this.traceListener.Messages.Any(m => m.Contains("Hello, Formatted Message!")));
86+
}
5387
}
5488
}

Take2/NuLog.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ EndProject
1010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuLog.CLI.PerfTune", "NuLog.CLI.PerfTune\NuLog.CLI.PerfTune.csproj", "{40A62D51-DE30-4C8A-BD5F-157189E0C8B5}"
1111
EndProject
1212
Global
13+
GlobalSection(Performance) = preSolution
14+
HasPerformanceSessions = true
15+
EndGlobalSection
1316
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1417
Debug|Any CPU = Debug|Any CPU
1518
Release|Any CPU = Release|Any CPU

Take2/NuLog/Configuration/Config.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,12 @@ public class Config
3636
/// the logger to include the stack frame in created log events.
3737
/// </summary>
3838
public bool IncludeStackFrame { get; set; }
39+
40+
/// <summary>
41+
/// The (optional) path to a fallback log, which is used when failure occurs when logging a
42+
/// log event. Can be useful when there are problems with the logging system, such as
43+
/// programming errors in components, or configuration issues.
44+
/// </summary>
45+
public string FallbackLogPath { get; set; }
3946
}
4047
}

Take2/NuLog/Configuration/XmlConfigurationProvider.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public Config GetConfiguration()
3838
// Get the "includeStackFrame" flag
3939
config.IncludeStackFrame = GetBooleanAttribute(xmlElement, "includeStackFrame");
4040

41+
// Get the fallback log path
42+
config.FallbackLogPath = GetStringAttribute(xmlElement, "fallbackLog");
43+
4144
// Return the built config
4245
return config;
4346
}

Take2/NuLog/Dispatchers/IFallbackLogger.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,11 @@ public interface IFallbackLogger
1717
/// Logs an exception that occurred while writing to the given target.
1818
/// </summary>
1919
void Log(Exception exception, ITarget target, ILogEvent logEvent);
20+
21+
/// <summary>
22+
/// Logs an arbitrary message. Will format the message, if arguments are given, otherwise,
23+
/// will just write it direct.
24+
/// </summary>
25+
void Log(string message, params object[] args);
2026
}
2127
}

0 commit comments

Comments
 (0)