1using System.Diagnostics;
2using System.Runtime.CompilerServices;
12using System.Threading;
17 internal sealed
class LogService : LoadableService, ILogService
19 private const string startupCrashFileName =
"CrashDump.txt";
20 private const string debugLogFileName =
"Log.txt";
21 private string bareJid =
string.Empty;
22 private bool repairRequested =
false;
25 private TextWriter? debugTextWriter;
26 private FileStream? debugFileStream;
61 public void LogDebug(
string Message,
62 params KeyValuePair<string, object?>[] Tags)
76 public void LogDebug(
string Message,
77 [CallerFilePath]
string FilePath =
"",
78 [CallerLineNumber]
int LineNumber = 0)
80 Log.
Debug($
"{Message} \n (File: {FilePath}, Line: {LineNumber})",
92 public void LogInformational(
string Message, params KeyValuePair<string, object?>[] Tags)
94 Log.
Informational(Message,
string.Empty, this.bareJid, [.. this.GetParameters(Tags)]);
102 public void LogWarning(
string Message, params KeyValuePair<string, object?>[] Tags)
104 Log.
Warning(Message,
string.Empty, this.bareJid, [.. this.GetParameters(Tags)]);
111 public void LogException(Exception ex)
113 this.LogException(ex, []);
121 public void LogException(Exception ex, params KeyValuePair<string, object?>[] extraParameters)
124 if (ex is OperationCanceledException)
127 this.LogInformational(
"Operation canceled.", [.. this.GetParameters(extraParameters)]);
133 Debug.WriteLine(ex.ToString());
134 Log.
Exception(ex,
string.Empty, this.bareJid, [.. this.GetParameters(extraParameters)]);
138 this.repairRequested =
true;
139 Task.Run(RestartForRepair);
148 public void LogAlert(
string Message, params KeyValuePair<string, object?>[] Tags)
150 Log.
Alert(Message,
string.Empty, this.bareJid, [.. this.GetParameters(Tags)]);
153 private static async Task RestartForRepair()
155 ServiceRef.StorageService.FlagForRepair();
163 await ServiceRef.PlatformSpecific.CloseApplication();
176 public void SaveExceptionDump(
string Title,
string StackTrace)
181 string FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), startupCrashFileName);
183 if (File.Exists(FileName))
184 Contents = File.ReadAllText(FileName);
186 Contents =
string.Empty;
188 File.WriteAllText(FileName, Title + Environment.NewLine + StackTrace + Environment.NewLine + Contents);
195 public string LoadExceptionDump()
198 string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), startupCrashFileName);
200 if (File.Exists(fileName))
201 contents = File.ReadAllText(fileName);
203 contents =
string.Empty;
211 public void DeleteExceptionDump()
213 string fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), startupCrashFileName);
215 if (File.Exists(fileName))
216 File.Delete(fileName);
224 public IList<KeyValuePair<string, object?>> GetParameters(params KeyValuePair<string, object?>[] Tags)
226 List<KeyValuePair<string, object?>> Result =
228 new KeyValuePair<string, object?>(
"Platform", DeviceInfo.Platform),
229 new KeyValuePair<string, object?>(
"RuntimeVersion", typeof(LogService).Assembly.ImageRuntimeVersion),
230 new KeyValuePair<string, object?>(
"AppVersion", AppInfo.VersionString),
231 new KeyValuePair<string, object?>(
"Manufacturer", DeviceInfo.Manufacturer),
232 new KeyValuePair<string, object?>(
"Device Model", DeviceInfo.Model),
233 new KeyValuePair<string, object?>(
"Device Name", DeviceInfo.Name),
234 new KeyValuePair<string, object?>(
"OS", DeviceInfo.VersionString),
235 new KeyValuePair<string, object?>(
"Platform", DeviceInfo.Platform.ToString()),
236 new KeyValuePair<string, object?>(
"Device Type", DeviceInfo.DeviceType.ToString()),
239 if (Tags is not
null)
240 Result.AddRange(Tags);
245 public override Task Load(
bool isResuming, CancellationToken cancellationToken)
250 return Task.CompletedTask;
252 public async Task StartDebugLogSessionAsync()
254 string FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), debugLogFileName);
257 if (this.debugSink is not
null)
258 await this.EndDebugLogSessionAsync();
260 if (File.Exists(FileName))
261 File.Delete(FileName);
264 this.debugFileStream =
new FileStream(FileName, FileMode.Create, FileAccess.Write, FileShare.Read);
265 this.debugTextWriter =
new StreamWriter(this.debugFileStream, Encoding.UTF8)
271 this.AddListener(this.debugSink);
274 public async Task EndDebugLogSessionAsync()
276 if (this.debugSink is
null)
280 this.RemoveListener(this.debugSink);
284 this.debugSink =
null;
287 this.debugTextWriter?.Dispose();
288 this.debugTextWriter =
null;
290 this.debugFileStream?.Dispose();
291 this.debugFileStream =
null;
297 public void Dispose()
300 if (this.debugSink is not
null || this.debugTextWriter is not
null || this.debugFileStream is not
null)
303 this.EndDebugLogSessionAsync().GetAwaiter().GetResult();
306 GC.SuppressFinalize(
this);
A strongly-typed resource class, for looking up localized strings, etc.
static string RepairRestart
Looks up a localized string similar to An inconsistency in the internal database has been detected....
static string Ok
Looks up a localized string similar to OK.
static string ErrorTitle
Looks up a localized string similar to An error has occurred.
Outputs events to the console standard output.
Base class for event sinks.
Outputs sniffed data to a text writer.
override Task DisposeAsync()
IDisposableAsync.DisposeAsync
Filters incoming events and passes remaining events to a secondary event sink.
IEventSink SecondarySink
Secondary event sink receiving the events passing the filter.
Static class managing the application event log. Applications and services log events on this static ...
static string CleanStackTrace(string StackTrace)
Cleans a Stack Trace string, removing entries from the asynchronous execution model,...
static IEventSink[] Sinks
Registered sinks.
static void Register(IEventSink EventSink)
Registers an event sink with the event log. Call Unregister(IEventSink) to unregister it,...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
static bool Unregister(IEventSink EventSink)
Unregisters an event sink from the event log.
static void Debug(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a debug event.
static void Alert(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an alert event.
Event sink sending events to a destination over the XMPP network.
XmppClient Client
XMPP Client
Database inconsistency exception. Raised when an inconsistency in the database has been found.
Interface for all event sinks.