public void Should_compress_deleting_log_files_in_place() { var archiveWrapper = new ArchiveHooks(); using (var temp = TempFolder.ForCaller()) { var path = temp.AllocateFilename("log"); // Write events, such that we end up with 2 deleted files and 1 retained file WriteLogEvents(path, archiveWrapper, LogEvents); // Get all the files in the test directory var files = Directory.GetFiles(temp.Path) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should have a single log file, and 2 gz files files.Count(x => x.EndsWith("log")).ShouldBe(1); files.Count(x => x.EndsWith("gz")).ShouldBe(2); // Ensure the data was GZip compressed, by decompressing and comparing against what we wrote int i = 0; foreach (var gzipFile in files.Where(x => x.EndsWith("gz"))) { var lines = Utils.DecompressLines(gzipFile); lines.Count.ShouldBe(1); lines[0].ShouldEndWith(LogEvents[i].MessageTemplate.Text); i++; } } }
/// <summary> /// Write log events to Serilog, using a rolling log file configuration with a 1-byte size limit, so we roll /// after each log event, and with a retained count of 1 so 2 files will be deleted and 1 retained /// </summary> private static void WriteLogEvents(string path, ArchiveHooks hooks, LogEvent[] logEvents) { using (var log = new LoggerConfiguration() .WriteTo.File(path, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1, retainedFileCountLimit: 1, hooks: hooks) .CreateLogger()) { foreach (var logEvent in logEvents) { log.Write(logEvent); } } }
public SerilogHooks(long limitBytes, int retainedFileCountLimit, string pathArchive = null, CompressionLevel compression = CompressionLevel.Fastest) { _limitBytes = limitBytes; _pathArchive = pathArchive; _retainedFileCountLimit = retainedFileCountLimit; if (string.IsNullOrEmpty(_pathArchive)) { _pathArchive = null; } MyArchiveHooks = new ArchiveHooks(CompressionLevel.Fastest, _pathArchive); }
public void Should_expand_tokens_in_target_path() { using (var temp = TempFolder.ForCaller()) { var subfolder = temp.AllocateFolderName(); var targetDirPath = Path.Combine(subfolder, "{Date:yyyy}"); var path = temp.AllocateFilename("log"); var archiveWrapper = new ArchiveHooks(CompressionLevel.NoCompression, targetDirPath); // Write events, such that we end up with 2 deleted files and 1 retained file WriteLogEvents(path, archiveWrapper, LogEvents); // Get the final, expanded target directory var targetDirs = Directory.GetDirectories(subfolder); targetDirs.Length.ShouldBe(1); // Ensure the directory name contains the expanded date token targetDirs[0].ShouldEndWith(DateTime.Now.ToString("yyyy")); } }
public void Should_copy_deleting_log_files() { using (var temp = TempFolder.ForCaller()) { var targetDirPath = temp.AllocateFolderName(); var path = temp.AllocateFilename("log"); var archiveWrapper = new ArchiveHooks(CompressionLevel.NoCompression, targetDirPath); // Write events, such that we end up with 2 deleted files and 1 retained file WriteLogEvents(path, archiveWrapper, LogEvents); // Get all the files in the test directory var files = Directory.GetFiles(temp.Path) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should only have a single log file files.Length.ShouldBe(1); // Get all the files in the target directory var targetFiles = Directory.GetFiles(targetDirPath) .OrderBy(p => p, StringComparer.OrdinalIgnoreCase) .ToArray(); // We should have 2 log files in the target directory targetFiles.Length.ShouldBe(2); targetFiles.ShouldAllBe(x => x.EndsWith(".log")); // Ensure the content matches what we wrote for (var i = 0; i < targetFiles.Length; i++) { var lines = System.IO.File.ReadAllLines(targetFiles[i]); lines.Length.ShouldBe(1); lines[0].ShouldEndWith(LogEvents[i].MessageTemplate.Text); } } }
private static LoggerConfiguration configFromWebApiConfig(LoggerConfiguration loggerConfiguration, WebApiConfig apiConfig) { apiConfig = apiConfig ?? new WebApiConfig(); loggerConfiguration.MinimumLevel.ControlledBy(apiConfig.InnerSerilogLevels.AppLogLevel) .MinimumLevel.Override("Microsoft", apiConfig.InnerSerilogLevels.SystemLogLevel) .MinimumLevel.Override("System", apiConfig.InnerSerilogLevels.SystemLogLevel) .MinimumLevel.Override("Microsoft.AspNetCore", apiConfig.InnerSerilogLevels.AppLogLevel) .MinimumLevel.Override("Microsoft.Hosting", apiConfig.InnerSerilogLevels.AppLogLevel) .MinimumLevel.Override("Microsoft.EntityFrameworkCore.Database.Command", apiConfig.InnerSerilogLevels.EFCoreCommandLevel) .MinimumLevel.Override("System.Net.Http.HttpClient", apiConfig.InnerSerilogLevels.AppLogLevel) .MinimumLevel.Override("ServerRequest.Logger", apiConfig.InnerSerilogLevels.ServerRequestLevel) .MinimumLevel.Override("ClientRequest.Logger", apiConfig.InnerSerilogLevels.ClientRequestLevel) .Destructure.ToMaximumStringLength(apiConfig.MaxLogLength); loggerConfiguration = loggerConfiguration.Enrich.FromLogContext(); if (apiConfig.ConsoleJsonLog) { loggerConfiguration = loggerConfiguration.WriteTo.Console(new CompactJsonFormatter(apiConfig)); } else if (apiConfig.ConsoleLog) { loggerConfiguration = loggerConfiguration.WriteTo.Console(); } else { loggerConfiguration = loggerConfiguration.WriteTo.Console(Serilog.Events.LogEventLevel.Warning); } if (apiConfig.FileLog || apiConfig.FileJsonLog) { string path = apiConfig.GetLogPath(); string pathTemplate = apiConfig.LogPathTemplate; if (string.IsNullOrEmpty(pathTemplate)) { pathTemplate = LogPathTemplates.DayFolderAndLoggerNameFile; } Serilog.Formatting.Display.MessageTemplateTextFormatter pathFormatter = new Serilog.Formatting.Display.MessageTemplateTextFormatter(pathTemplate); ArchiveHooks archiveHooks = new ArchiveHooks(CompressionLevel.Fastest); string template = apiConfig.LogTemplate; if (string.IsNullOrEmpty(template)) { template = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{NewLine}{Exception}"; } bool keySelector(Serilog.Events.LogEvent logEvent, out LogPathAndTimeKey key) { StringWriter sw = new StringWriter(); StringBuilder sb = new StringBuilder(); pathFormatter.Format(logEvent, sw); sw.Flush(); string dp = sw.GetStringBuilder().ToString(); string p = Path.Combine(path, dp); key = new LogPathAndTimeKey() { Path = p, Time = logEvent.Timestamp.Date }; return(true); }; if (apiConfig.FileJsonLog) { var formatter = new CompactJsonFormatter(apiConfig); loggerConfiguration = loggerConfiguration .WriteTo.MapCondition <LogPathAndTimeKey>(keySelector, (path, lc) => { lc.Async(lc => lc.File( formatter, path.Path, rollingInterval: RollingInterval.Infinite, rollOnFileSizeLimit: true, fileSizeLimitBytes: apiConfig.MaxLogFileSize, retainedFileCountLimit: apiConfig.RetainedFileCount, hooks: archiveHooks)); }, key => { // 自动Dispose前一天的日志 DateTimeOffset now = DateTimeOffset.Now.Date; if (now > key.Time.Date) { return(true); } return(false); }); } else { loggerConfiguration = loggerConfiguration .WriteTo.MapCondition <LogPathAndTimeKey>(keySelector, (path, lc) => { lc.Async(lc => lc.File( path.Path, rollingInterval: RollingInterval.Infinite, rollOnFileSizeLimit: true, fileSizeLimitBytes: apiConfig.MaxLogFileSize, retainedFileCountLimit: apiConfig.RetainedFileCount, hooks: archiveHooks, outputTemplate: template)); }, key => { // 自动Dispose前一天的日志 DateTimeOffset now = DateTimeOffset.Now.Date; if (now > key.Time.Date) { return(true); } return(false); }); } } return(loggerConfiguration); }