using Serilog; using Serilog.Core; using Serilog.Sinks.Datadog.Logs; using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Security; using System.Text; using System.Threading.Tasks; namespace Sony.Filtr.Utility.Logging { public class DatadogLogger : ILogger { // Note: The actual limit is higher than this, but different Microsoft operating systems actually have // different limits. So just use 30,000 to be safe. //private Logger _log; public DatadogLogger(string url, string port, string key, string service, string host) { var config = new DatadogConfiguration(url: url, port: int.Parse(port), useSSL: true, useTCP: true); Source = GetSource(); Source = CreateEventSource(Source); //_log = new LoggerConfiguration() // .WriteTo.DatadogLogs( // key, // source: Source, // service: service, // host: host, // configuration: config // ) // .CreateLogger(); } private const int MaxEventLogEntryLength = 30000; public string Source { get; private set; } public async Task LogDebug(string message, bool debugLoggingEnabled) { if (debugLoggingEnabled == false) { await Task.CompletedTask; } await Log(message, EventLogEntryType.Information); } public async Task LogInformation(string message) { await Log(message, EventLogEntryType.Information); } public async Task LogWarning(string message) { await Log(message, EventLogEntryType.Warning); } public async Task LogException(string message, Exception ex) { if (ex == null) { throw new ArgumentNullException("ex"); } await Log($"{message}. Details: {ex.ToString()}", EventLogEntryType.Error); } private async Task Log(string message, EventLogEntryType entryType) { // Note: I got an error that the security log was inaccessible. To get around it, I ran the app as administrator // just once, then I could run it from within VS. string possiblyTruncatedMessage = EnsureLogMessageLimit(message); switch (entryType) { case EventLogEntryType.Error: //_log.Error(possiblyTruncatedMessage); break; default: //_log.Information(possiblyTruncatedMessage); break; } EventLog.WriteEntry(Source, possiblyTruncatedMessage, entryType); await Task.CompletedTask; } // Ensures that the log message entry text length does not exceed the event log viewer maximum length of 32766 characters. private static string EnsureLogMessageLimit(string logMessage) { if (logMessage.Length > MaxEventLogEntryLength) { string truncateWarningText = string.Format(CultureInfo.CurrentCulture, "... | Log Message Truncated [ Limit: {0} ]", MaxEventLogEntryLength); // Set the message to the max minus enough room to add the truncate warning. logMessage = logMessage.Substring(0, MaxEventLogEntryLength - truncateWarningText.Length); logMessage = string.Format(CultureInfo.CurrentCulture, "{0}{1}", logMessage, truncateWarningText); } return logMessage; } private string GetSource() { // If the caller has explicitly set a source value, just use it. if (!string.IsNullOrWhiteSpace(Source)) { return Source; } return "Sony.Filtr"; } private string CreateEventSource(string currentAppName) { string eventSource = currentAppName; bool sourceExists; try { // searching the source throws a security exception ONLY if not exists! sourceExists = EventLog.SourceExists(eventSource); if (!sourceExists) { // no exception until yet means the user as admin privilege EventLog.CreateEventSource(eventSource, "Application"); } } catch (SecurityException) { eventSource = "Application"; } return eventSource; } } }