protected virtual void Dispose(bool disposing) { if (disposed) { return; } disposed = true; if (disposing) { if (this.newReportFileTrigger != null) { this.newReportFileTrigger.NewReportFileRequested -= OnNewReportFileRequested; this.newReportFileTrigger = null; } // Mark report collection as complete adding. When the collection is empty, it will dispose the stream writers. this.reportCollection.CompleteAdding(); try { // Make sure that when Dispose() returns, the reporter is fully disposed (streams are closed etc.) this.writingTask?.Wait(DisposalTimeout); } catch { // We are reporting writing task errors from ReportXxx() methods, to no need to pass the task exception up here. } } }
// Constructor for testing purpose. internal CsvHealthReporter( CsvHealthReporterConfiguration configuration, INewReportFileTrigger newReportTrigger = null, int flushPeriodMsec = 5000) { this.flushPeriodMsec = flushPeriodMsec; Initialize(configuration, newReportTrigger); }
// Constructor for testing purpose. internal CsvHealthReporter( CsvHealthReporterConfiguration configuration, INewReportFileTrigger newReportTrigger = null, int flushPeriodMsec = 5000, Func <DateTime> currentTimeProvider = null) { this.flushPeriodMsec = flushPeriodMsec; if (currentTimeProvider != null) { this.getCurrentTime = currentTimeProvider; } Initialize(configuration, newReportTrigger); }
private void Initialize(CsvHealthReporterConfiguration configuration, INewReportFileTrigger newReportTrigger = null) { Requires.NotNull(configuration, nameof(configuration)); this.reportCollection = new BlockingCollection <string>(); this.EnsureOutputCanBeSaved = configuration.EnsureOutputCanBeSaved; this.innerReportWriter = this.ReportText; if (configuration.AssumeSharedLogFolder) { var random = new Random(); const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; this.logFileNameRandomizer = new string(Enumerable.Range(1, 12).Select(i => chars[random.Next(chars.Length)]).ToArray()); } else { this.logFileNameRandomizer = string.Empty; } // Prepare the configuration, set default values, handle invalid values. this.Configuration = configuration; // Create a default throttle. this.throttle = new TimeSpanThrottle(TimeSpan.FromMilliseconds(DefaultThrottlingPeriodMsec)); // Set the file size for csv health report. Minimum is 1MB. Default is 8192MB. this.SingleLogFileMaximumSizeInBytes = (long)(configuration.SingleLogFileMaximumSizeInMBytes > 0 ? configuration.SingleLogFileMaximumSizeInMBytes : 8192) * 1024 * 1024; // Log retention days has a minimum of 1 day. Set to the default value of 30 days. if (configuration.LogRetentionInDays <= 0) { configuration.LogRetentionInDays = 30; } HealthReportLevel logLevel; string logLevelString = this.Configuration.MinReportLevel; if (string.IsNullOrWhiteSpace(logLevelString)) { this.minReportLevel = HealthReportLevel.Error; } else if (Enum.TryParse(logLevelString, out logLevel)) { this.minReportLevel = logLevel; } else { this.minReportLevel = HealthReportLevel.Error; // The severity has to be at least the same as the default level of error. ReportProblem($"Failed to parse log level. Please check the value of: {logLevelString}. Falling back to default value: {this.minReportLevel.ToString()}", TraceTag); } this.Configuration.MinReportLevel = this.minReportLevel.ToString(); if (this.Configuration.ThrottlingPeriodMsec == null || !this.Configuration.ThrottlingPeriodMsec.HasValue) { this.Configuration.ThrottlingPeriodMsec = DefaultThrottlingPeriodMsec; ReportHealthy($"{nameof(this.Configuration.ThrottlingPeriodMsec)} is not specified. Falling back to default value: {this.Configuration.ThrottlingPeriodMsec}.", TraceTag); } else if (this.Configuration.ThrottlingPeriodMsec.Value == DefaultThrottlingPeriodMsec) { // Keep using the default throttle created before. } else if (this.Configuration.ThrottlingPeriodMsec.Value < 0) { ReportWarning($"{nameof(this.Configuration.ThrottlingPeriodMsec)}: {this.Configuration.ThrottlingPeriodMsec.Value} specified in the configuration file is invalid. Falling back to default value: {DefaultThrottlingPeriodMsec}", TraceTag); this.Configuration.ThrottlingPeriodMsec = DefaultThrottlingPeriodMsec; } else if (this.Configuration.ThrottlingPeriodMsec.Value >= 0) { this.throttle = new TimeSpanThrottle(TimeSpan.FromMilliseconds(this.Configuration.ThrottlingPeriodMsec.Value)); } // Set default value for health report file prefix if (string.IsNullOrWhiteSpace(this.Configuration.LogFilePrefix)) { this.Configuration.LogFilePrefix = DefaultLogFilePrefix; ReportHealthy($"{nameof(this.Configuration.LogFilePrefix)} is not specified in configuration file. Falling back to default value: {this.Configuration.LogFilePrefix}", TraceTag); } // Set target folder for health report files. if (string.IsNullOrWhiteSpace(this.Configuration.LogFileFolder)) { this.Configuration.LogFileFolder = "."; ReportHealthy($"{nameof(this.Configuration.LogFileFolder)} is not specified in configuration file. Falling back to default value: {this.Configuration.LogFileFolder}", TraceTag); } ProcessLogFileFolder(); this.newReportFileTrigger = newReportTrigger ?? UtcMidnightNotifier.Instance; this.newReportFileTrigger.NewReportFileRequested += OnNewReportFileRequested; // Clean up existing logging files per retention policy CleanupExistingLogs(); }
private void Initialize(CsvHealthReporterConfiguration configuration, INewReportFileTrigger newReportTrigger = null) { Requires.NotNull(configuration, nameof(configuration)); this.reportCollection = new BlockingCollection <string>(); // Prepare the configuration, set default values, handle invalid values. this.Configuration = configuration; // Create a default throttle this.throttle = new TimeSpanThrottle(TimeSpan.FromMilliseconds(DefaultThrottlingPeriodMsec)); HealthReportLevel logLevel; string logLevelString = this.Configuration.MinReportLevel; if (string.IsNullOrWhiteSpace(logLevelString)) { this.minReportLevel = HealthReportLevel.Error; } else if (Enum.TryParse(logLevelString, out logLevel)) { this.minReportLevel = logLevel; } else { this.minReportLevel = HealthReportLevel.Error; // The severity has to be at least the same as the default level of error. ReportProblem($"Failed to parse log level. Please check the value of: {logLevelString}. Falling back to default value: {this.minReportLevel.ToString()}", TraceTag); } this.Configuration.MinReportLevel = this.minReportLevel.ToString(); if (this.Configuration.ThrottlingPeriodMsec == null || !this.Configuration.ThrottlingPeriodMsec.HasValue) { this.Configuration.ThrottlingPeriodMsec = DefaultThrottlingPeriodMsec; ReportHealthy($"{nameof(this.Configuration.ThrottlingPeriodMsec)} is not specified. Falling back to default value: {this.Configuration.ThrottlingPeriodMsec}.", TraceTag); } else if (this.Configuration.ThrottlingPeriodMsec.Value == DefaultThrottlingPeriodMsec) { // Keep using the default throttle created before. } else if (this.Configuration.ThrottlingPeriodMsec.Value < 0) { ReportWarning($"{nameof(this.Configuration.ThrottlingPeriodMsec)}: {this.Configuration.ThrottlingPeriodMsec.Value} specified in the configuration file is invalid. Falling back to default value: {DefaultThrottlingPeriodMsec}", TraceTag); this.Configuration.ThrottlingPeriodMsec = DefaultThrottlingPeriodMsec; } else if (this.Configuration.ThrottlingPeriodMsec.Value >= 0) { this.throttle = new TimeSpanThrottle(TimeSpan.FromMilliseconds(this.Configuration.ThrottlingPeriodMsec.Value)); } // Set default value for health report file prefix if (string.IsNullOrWhiteSpace(this.Configuration.LogFilePrefix)) { this.Configuration.LogFilePrefix = DefaultLogFilePrefix; ReportHealthy($"{nameof(this.Configuration.LogFilePrefix)} is not specified in configuration file. Falling back to default value: {this.Configuration.LogFilePrefix}", TraceTag); } // Set target folder for health report files. if (string.IsNullOrWhiteSpace(this.Configuration.LogFileFolder)) { this.Configuration.LogFileFolder = "."; ReportHealthy($"{nameof(this.Configuration.LogFileFolder)} is not specified in configuration file. Falling back to default value: {this.Configuration.LogFileFolder}", TraceTag); } ProcessLogFileFolder(); this.newReportFileTrigger = newReportTrigger ?? UtcMidnightNotifier.Instance; this.newReportFileTrigger.NewReportFileRequested += OnNewReportFileRequested; }
public CustomHealthReporter(CsvHealthReporterConfiguration configuration, INewReportFileTrigger newReportTrigger) : base(configuration, newReportTrigger) { }