我偶尔在MSSQLServer接收器中收到此错误。我看不到这个GUID有什么问题。有任何想法吗?我已经在每个地方都验证过,我可以找到源guid的数据类型是“ Guid”而不是字符串。我只是有些迷惑。
向导应包含32个数字,带4个破折号(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。无法在用户ID列中存储。预期的类型为Guid。
此示例中的向导为:
7526f485-ec2d-4ec8-bd73-12a7d1c49a5d
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
似乎要将模板与我匹配?
更多详细信息:这是一个偶然的问题,但是当它出现时,它会出现很多。它似乎与特定的Guid有关。大多数Guid都很好,但是一小部分有此问题。我们的应用每天记录数千条消息,但是由于问题,这些消息并未记录下来,因此我很难准确地找到导致此错误的特定日志的来源。但是,我们使用集中式日志记录方法,该方法运行如下所示。该测试对我来说是合格的,但它反映了我们通常用于日志记录的设置和代码,通常可以成功。正如我所说的,这是一个间歇性问题:
[Fact]
public void Foobar()
{
// arrange
var columnOptions = new ColumnOptions
{
AdditionalColumns = new Collection<SqlColumn>
{
new SqlColumn {DataType = SqlDbType.UniqueIdentifier, ColumnName = "UserId"},
},
};
columnOptions.Store.Remove(StandardColumn.MessageTemplate);
columnOptions.Store.Remove(StandardColumn.Properties);
columnOptions.Store.Remove(StandardColumn.LogEvent);
columnOptions.Properties.ExcludeAdditionalProperties = true;
var badGuid = new Guid("7526f485-ec2d-4ec8-bd73-12a7d1c49a5d");
var connectionString = "Server=(localdb)\\MSSQLLocalDB;Database=SomeDb;Trusted_Connection=True;MultipleActiveResultSets=true";
var logConfiguration = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.MSSqlServer(connectionString, "Logs",
restrictedToMinimumLevel: LogEventLevel.Information, autoCreateSqlTable: false,
columnOptions: columnOptions)
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information);
Log.Logger = logConfiguration.CreateLogger();
// Suspect the issue is with this line
LogContext.PushProperty("UserId", badGuid);
// Best practice would be to do something like this:
// using (LogContext.PushProperty("UserId", badGuid)
// {
Log.Logger.Information(new FormatException("Foobar"),"This is a test");
// }
Log.CloseAndFlush();
}
自构建此测试代码以来,我注意到的一件事是,没有捕获和处置UserId属性的“ PushProperty”。由于在这种情况下行为为"undefined",所以我还是倾向于对其进行修复,以查看问题是否消失。
完整堆栈:
2020-04-20T08:38:17.5145399Z Exception while emitting periodic batch from Serilog.Sinks.MSSqlServer.MSSqlServerSink: System.ArgumentException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).Couldn't store <"7526f485-ec2d-4ec8-bd73-12a7d1c49a5d"> in UserId Column. Expected type is Guid.
---> System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
at System.Guid.GuidResult.SetFailure(Boolean overflow, String failureMessageID)
at System.Guid.TryParseExactD(ReadOnlySpan`1 guidString, GuidResult& result)
at System.Guid.TryParseGuid(ReadOnlySpan`1 guidString, GuidResult& result)
at System.Guid..ctor(String g)
at System.Data.Common.ObjectStorage.Set(Int32 recordNo, Object value)
at System.Data.DataColumn.set_Item(Int32 record, Object value)
--- End of inner exception stack trace ---
at System.Data.DataColumn.set_Item(Int32 record, Object value)
at System.Data.DataRow.set_Item(DataColumn column, Object value)
at Serilog.Sinks.MSSqlServer.MSSqlServerSink.FillDataTable(IEnumerable`1 events)
at Serilog.Sinks.MSSqlServer.MSSqlServerSink.EmitBatchAsync(IEnumerable`1 events)
at Serilog.Sinks.PeriodicBatching.PeriodicBatchingSink.OnTick()
我在上面的特定代码中看不到任何明显的问题会导致此问题。您将在设置Serilog之前调用PushProperty
的事实会改变(即先设置Serilog,然后再调用PushProperty
),但这似乎并不是您遇到问题的根本原因。
我的猜测是,您有一些代码路径将UserId
记录为string
,而不是Guid
。 Serilog期望使用Guid
值类型,因此,如果为它提供string
的Guid
表示形式,它将不起作用,并且会为您提供这种类型的异常。
也许在代码库中的某个位置,您正在登录之前在.ToString
上调用UserId
?或者也许使用字符串插值Log.Information("User is {UserId}", $"{UserId}");
?
例如:
var badGuid = "7526f485-ec2d- 4ec8-bd73-12a7d1c49a5d";
LogContext.PushProperty("UserId", badGuid);
Log.Information(new FormatException("Foobar"), "This is a test");
或者甚至只是直接使用UserId
属性记录消息:
var badGuid = "7526f485-ec2d-4ec8-bd73-12a7d1c49a5d";
Log.Information("The {UserId} is doing work", badGuid);
上面的两个代码片段都会抛出与您相同的异常,因为它们使用的是
string
值,而不是实际的Guid
值。