Skip to content

Commit c8da322

Browse files
authored
Merge pull request #43 from MADE-Apps/diagnostics
PR for #7 - Application diagnostics
2 parents 0f94e6e + 221b607 commit c8da322

22 files changed

Lines changed: 1379 additions & 11 deletions
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
// --------------------------------------------------------------------------------------------------------------------
2+
// <copyright file="AppDiagnostics.cs" company="MADE Apps">
3+
// Copyright (c) MADE Apps.
4+
// </copyright>
5+
// <summary>
6+
// Defines a service for managing application wide event logging for exceptions.
7+
// </summary>
8+
// --------------------------------------------------------------------------------------------------------------------
9+
10+
namespace MADE.App.Diagnostics
11+
{
12+
using System.Threading.Tasks;
13+
14+
using MADE.App.Dependency;
15+
using MADE.App.Diagnostics.Logging;
16+
17+
/// <summary>
18+
/// Defines a service for managing application wide event logging for exceptions.
19+
/// </summary>
20+
public class AppDiagnostics : IAppDiagnostics
21+
{
22+
/// <summary>
23+
/// Defines the name of the folder where logs are stored locally in the application.
24+
/// </summary>
25+
public const string LogsFolderName = "Logs";
26+
27+
/// <summary>
28+
/// Defines the format for the name of the file where a log is stored locally in the application.
29+
/// </summary>
30+
public const string LogFileNameFormat = "Log-{0:yyyyMMdd}.txt";
31+
32+
#if WINDOWS_UWP
33+
private StorageFileEventListener listener;
34+
#endif
35+
36+
/// <summary>
37+
/// Initializes a new instance of the <see cref="AppDiagnostics"/> class.
38+
/// </summary>
39+
public AppDiagnostics()
40+
{
41+
if (!SimpleDependencyService.Instance.IsRegistered<IEventLogger>())
42+
{
43+
SimpleDependencyService.Instance.Register<IEventLogger, EventLogger>();
44+
}
45+
46+
this.EventLogger = SimpleDependencyService.Instance.GetInstance<IEventLogger>();
47+
}
48+
49+
/// <summary>
50+
/// Initializes a new instance of the <see cref="AppDiagnostics"/> class.
51+
/// </summary>
52+
/// <param name="eventLogger">
53+
/// The instance of the service for logging application event messages.
54+
/// </param>
55+
public AppDiagnostics(IEventLogger eventLogger)
56+
{
57+
this.EventLogger = eventLogger;
58+
}
59+
60+
/// <summary>
61+
/// Gets the service for logging application event messages.
62+
/// </summary>
63+
public IEventLogger EventLogger { get; }
64+
65+
/// <summary>
66+
/// Gets the string path to the file used for capturing application diagnostic messages.
67+
/// </summary>
68+
public string DiagnosticsFilePath => this.EventLogger?.LogPath;
69+
70+
/// <summary>
71+
/// Gets a value indicating whether application diagnostic messages are being recorded.
72+
/// </summary>
73+
public bool IsRecordingDiagnostics { get; private set; }
74+
75+
/// <summary>
76+
/// Starts tracking and recording the application diagnostic messages.
77+
/// </summary>
78+
/// <returns>
79+
/// An asynchronous operation.
80+
/// </returns>
81+
public async Task StartRecordingDiagnosticsAsync()
82+
{
83+
if (this.IsRecordingDiagnostics)
84+
{
85+
await Task.CompletedTask;
86+
}
87+
88+
this.IsRecordingDiagnostics = true;
89+
90+
#if WINDOWS_UWP
91+
this.listener = new StorageFileEventListener();
92+
this.listener.EnableEvents(this.EventLogger as System.Diagnostics.Tracing.EventSource, System.Diagnostics.Tracing.EventLevel.Verbose);
93+
#endif
94+
95+
this.EventLogger.WriteInfo("Application diagnostics initialized.");
96+
97+
#if WINDOWS_UWP
98+
Windows.UI.Xaml.Application.Current.UnhandledException += this.OnAppUnhandledException;
99+
#else
100+
System.AppDomain.CurrentDomain.UnhandledException += this.OnAppUnhandledException;
101+
#endif
102+
TaskScheduler.UnobservedTaskException += this.OnTaskUnobservedException;
103+
104+
await Task.CompletedTask;
105+
}
106+
107+
/// <summary>
108+
/// Stops tracking and recording the application diagnostic messages.
109+
/// </summary>
110+
public void StopRecordingDiagnostics()
111+
{
112+
if (!this.IsRecordingDiagnostics)
113+
{
114+
return;
115+
}
116+
117+
#if WINDOWS_UWP
118+
Windows.UI.Xaml.Application.Current.UnhandledException -= this.OnAppUnhandledException;
119+
#else
120+
System.AppDomain.CurrentDomain.UnhandledException -= this.OnAppUnhandledException;
121+
#endif
122+
TaskScheduler.UnobservedTaskException -= this.OnTaskUnobservedException;
123+
124+
this.IsRecordingDiagnostics = false;
125+
}
126+
127+
private void OnTaskUnobservedException(object sender, UnobservedTaskExceptionEventArgs args)
128+
{
129+
args.SetObserved();
130+
131+
this.EventLogger.WriteCritical(
132+
args.Exception != null
133+
? $"An unobserved task exception was thrown. Error: {args.Exception}"
134+
: "An unobserved task exception was thrown. Error: No exception information was available.");
135+
}
136+
137+
#if WINDOWS_UWP
138+
private void OnAppUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs args)
139+
{
140+
args.Handled = true;
141+
142+
this.EventLogger.WriteCritical(
143+
args.Exception != null
144+
? $"An unhandled exception was thrown. Error: {args.Exception}"
145+
: "An unhandled exception was thrown. Error: No exception information was available.");
146+
}
147+
#else
148+
private void OnAppUnhandledException(object sender, System.UnhandledExceptionEventArgs args)
149+
{
150+
if (args.IsTerminating)
151+
{
152+
this.EventLogger.WriteCritical("The application is terminating due to an unhandled exception being thrown.");
153+
}
154+
155+
if (!(args.ExceptionObject is System.Exception ex))
156+
{
157+
return;
158+
}
159+
160+
this.EventLogger.WriteCritical($"An unhandled exception was thrown. Error: {ex}");
161+
}
162+
#endif
163+
}
164+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// --------------------------------------------------------------------------------------------------------------------
2+
// <copyright file="IAppDiagnostics.cs" company="MADE Apps">
3+
// Copyright (c) MADE Apps.
4+
// </copyright>
5+
// <summary>
6+
// Defines an interface for handling application diagnostics.
7+
// </summary>
8+
// --------------------------------------------------------------------------------------------------------------------
9+
10+
namespace MADE.App.Diagnostics
11+
{
12+
using System.Threading.Tasks;
13+
14+
using MADE.App.Diagnostics.Logging;
15+
16+
/// <summary>
17+
/// Defines an interface for handling application diagnostics.
18+
/// </summary>
19+
public interface IAppDiagnostics
20+
{
21+
/// <summary>
22+
/// Gets the service for logging application event messages.
23+
/// </summary>
24+
IEventLogger EventLogger { get; }
25+
26+
/// <summary>
27+
/// Gets the string path to the file used for capturing application diagnostic messages.
28+
/// </summary>
29+
string DiagnosticsFilePath { get; }
30+
31+
/// <summary>
32+
/// Gets a value indicating whether application diagnostic messages are being recorded.
33+
/// </summary>
34+
bool IsRecordingDiagnostics { get; }
35+
36+
/// <summary>
37+
/// Starts tracking and recording the application diagnostic messages.
38+
/// </summary>
39+
/// <returns>
40+
/// An asynchronous operation.
41+
/// </returns>
42+
Task StartRecordingDiagnosticsAsync();
43+
44+
/// <summary>
45+
/// Stops tracking and recording the application diagnostic messages.
46+
/// </summary>
47+
void StopRecordingDiagnostics();
48+
}
49+
}

0 commit comments

Comments
 (0)