
1. 问题现象与初步排查最近在调试一个C#项目时遇到了个诡异现象日志面板显示的所有时间都是当天日期明明前几天生成的日志文件打开后时间戳却全部变成了今天的日期。这直接导致日志完全无法用于问题追踪因为所有事件看起来都发生在同一天。使用Serilog作为日志框架的项目突然出现这种时间错乱首先检查了日志配置部分。在Program.cs中找到的初始化代码是这样的Log.Logger new LoggerConfiguration() .WriteTo.Console() .WriteTo.File(logs/log-.txt, rollingInterval: RollingInterval.Day, outputTemplate: {Timestamp:yyyy-MM-dd HH:mm:ss} [{Level}] {Message}{NewLine}{Exception}) .CreateLogger();表面看配置没有问题指定了按天滚动日志文件且时间格式包含年月日时分秒。但实际生成的日志文件内容却是2023-08-20 14:25:38 [INF] Application starting... 2023-08-20 14:25:39 [INF] Loading configuration... 2023-08-20 14:25:40 [ERR] Database connection failed!而实际上这些日志是三天前2023-08-17生成的。更奇怪的是用记事本打开日志文件时显示的修改日期是正确的只有文件内容里的时间戳有问题。2. 时区与时间格式深度分析2.1 系统时钟与日志时间戳首先用以下代码验证系统时间获取是否正常Console.WriteLine(DateTime.Now); Console.WriteLine(DateTime.UtcNow); Console.WriteLine(TimeZoneInfo.Local.DisplayName);输出显示系统时间和时区设置都正确。进一步检查发现如果在日志模板中使用{Timestamp:O}ISO 8601格式输出的时间会包含时区信息2023-08-20T14:25:38.123456708:00 [INF] Application starting...这说明时间数据本身是正确的问题出在格式化输出环节。2.2 Serilog的时间处理机制Serilog的Timestamp属性默认使用DateTimeOffset.UtcNow作为时间源。关键点在于当使用{Timestamp:yyyy-MM-dd HH:mm:ss}格式化时时区信息会被丢弃如果系统时区设置被意外修改或者运行环境如Docker容器的时区配置不正确会导致时间显示异常通过添加时区信息验证outputTemplate: {Timestamp:yyyy-MM-dd HH:mm:ss zzz} [{Level}] {Message}{NewLine}{Exception}发现输出时区显示为00:00而我们的服务器实际位于东八区。这表明时区配置确实存在问题。3. 时区配置问题解决方案3.1 容器环境时区设置如果应用运行在Docker容器中需要在Dockerfile中明确设置时区ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone3.2 Windows服务器时区验证对于Windows服务器检查以下注册表项HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation确保TimeZoneKeyName值为正确的时区如China Standard Time。3.3 代码强制指定时区可以在日志配置中强制使用时区Log.Logger new LoggerConfiguration() .Destructure.WithUtcTimestampDestructuringPolicy() .WriteTo.File(new CompactJsonFormatter(), logs/log-.json) .CreateLogger(); public class UtcTimestampDestructuringPolicy : IDestructuringPolicy { public bool TryDestructure(object value, ILogEventPropertyValueFactory propertyValueFactory, out LogEventPropertyValue result) { if (value is DateTime dateTime) { result new ScalarValue(dateTime.ToUniversalTime()); return true; } result null; return false; } }4. 日志系统最佳实践4.1 推荐的时间格式建议使用ISO 8601格式记录日志时间outputTemplate: {Timestamp:O} [{Level}] {Message}{NewLine}{Exception}这会输出包含时区信息的完整时间戳如2023-08-17T14:25:38.123456708:00 [INF] Application starting...4.2 日志文件命名策略结合日期和小时进行日志滚动避免大文件.WriteTo.File(logs/log-.txt, rollingInterval: RollingInterval.Hour, outputTemplate: {Timestamp:O} [{Level}] {Message}{NewLine}{Exception})4.3 集中式日志管理考虑使用Seq等日志服务器避免本地时间问题.WriteTo.Seq(http://localhost:5341, apiKey: your-api-key, controlLevelSwitch: new LoggingLevelSwitch(LogEventLevel.Verbose))5. 常见问题排查指南5.1 时间不一致检查清单系统时区设置Docker容器时区环境变量应用程序池的Identity时区权限第三方服务如数据库的时间设置日志框架的默认时间处理行为5.2 Serilog特定问题使用Enrich.WithProperty(MachineTime, DateTime.Now)添加本地时间作为对比启用自诊断日志检查内部时间处理Serilog.Debugging.SelfLog.Enable(msg Debug.WriteLine(msg));5.3 生产环境建议所有服务器使用NTP时间同步容器镜像中显式设置TZ环境变量日志中同时记录UTC和本地时间关键操作添加额外的时间戳验证我在实际项目中遇到过类似问题最终发现是CI/CD流水线中的构建容器没有正确设置时区导致所有部署的应用都使用了UTC时间。建议在应用启动时输出完整的时区信息到日志中var timeZones TimeZoneInfo.GetSystemTimeZones(); Log.Information(Current timezone: {Timezone}, TimeZoneInfo.Local); Log.Information(Available timezones: {TimezoneList}, string.Join(, , timeZones.Select(t t.Id)));