【发布时间】:2021-01-18 02:21:12
【问题描述】:
我在 ASP.NET Core 3.1 中使用 Serilog elasticsearch sink(版本 8.4.1,elastic 7.8.0),配置如下:
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Serilog.AspNetCore": "Information"
}
},
"Enrich": [ "FromLogContext" ],
"WriteTo": [
{
"Name": "Logger",
"Args": {
"configureLogger": {
"Filter": [
{
"Name": "ByIncludingOnly",
"Args": {
"expression": "SourceContext = 'Serilog.AspNetCore.RequestLoggingMiddleware'"
}
}
],
"WriteTo": [
{
"Name": "Elasticsearch",
"Args": {
"nodeUris": "http://localhost:9200",
"indexFormat": "request-logs-{0:yyyy.MM.dd}",
"period": 1,
"connectionTimeout": 5,
"typeName": "_doc",
"inlineFields": true,
"restrictToMinimumLevel": "Information"
}
}
]
}
}
}
]
}
}
我正在使用 Serilog.AspNetCore 的 RequestLogging
app.UseSerilogRequestLogging();
并使用需要对 GeoSpatial 和 IP 属性进行特殊映射的对象来丰富自定义中间件中的 IDiagnosticContext。
HttpDiagnostics diagnostics = new HttpDiagnostics
{
Host = host.ToString(),
IsHttps = isHttps,
LocalIp = localIpAddress,
LocalPort = localPort,
Protocol = protocol,
RemoteIp = remoteIpAddress,
RemotePort = remotePort,
RequestContentLength = requestContentLength,
RequestContentType = requestContentType,
Scheme = scheme,
UserAgent = userAgent,
ResponseContentLength = responseContentLength,
ResponseContentType = responseContentType
};
this.diagnosticContext.Set("Http", diagnostics, true);
我最终在 logevent 中正确映射字段的方法是:使用我的自定义 Object 重新建模 LogEvent 类型,并使用 NEST 客户端为索引模板创建映射。
ElasticClient client = new ElasticClient(new Uri(settings.Uri));
PutIndexTemplateResponse response = client.Indices.PutTemplate(
settings.Name,
p => p.IndexPatterns(settings.IndexPattern)
.Settings(s => s.DefaultPipeline("geoip"))
.Map<SerilogDiagnosticsLogEvent>(m => m.AutoMap()));
索引模板映射创建正确
{
"_doc": {
"properties": {
"traceId": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"level": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"requestMethod": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"message": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"sourceContext": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"parentId": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"elapsed": {
"type": "double"
},
"spanId": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"@timestamp": {
"type": "date"
},
"requestId": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"http": {
"type": "object",
"properties": {
"responseContentLength": {
"type": "long"
},
"requestContentLength": {
"type": "long"
},
"geoIp": {
"type": "object",
"properties": {
"cityName": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"countryIsoCode": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"regionName": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"location": {
"type": "geo_point"
},
"continentName": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
}
}
},
"remoteIp": {
"type": "ip"
},
"localPort": {
"type": "integer"
},
"scheme": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"remotePort": {
"type": "integer"
},
"userAgent": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"protocol": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"responseContentType": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"host": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"isHttps": {
"type": "boolean"
},
"localIp": {
"type": "ip"
},
"requestContentType": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
}
}
},
"connectionId": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"messageTemplate": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"requestPath": {
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
},
"type": "text"
},
"statusCode": {
"type": "integer"
}
}
}
}
所以现在我期望 Serilog 索引的文档使用我创建的索引模板的映射。但实际发生的是,创建的索引没有使用模板中的正确映射。因此 IP 字段被索引为字符串,这导致 GeoIp 管道无法处理这些字段。
现在我问自己:我的配置有问题吗? Serilog 是否总是使用他们的映射索引日志事件?如何将正确的映射应用到日志事件中的自定义属性?
【问题讨论】: