Elastic.Extensions.Logging 8.11.1

前缀已保留
dotnet add package Elastic.Extensions.Logging --version 8.11.1                
NuGet\Install-Package Elastic.Extensions.Logging -Version 8.11.1                
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用 NuGet 模块的 Install-Package 版本。
<PackageReference Include="Elastic.Extensions.Logging" Version="8.11.1" />                
对于支持 PackageReference 的项目,将此 XML 节点复制到项目文件中以引用此包。
paket add Elastic.Extensions.Logging --version 8.11.1                
#r "nuget: Elastic.Extensions.Logging, 8.11.1"                
#r 指令可以在 F# Interactive 和 Polyglot 笔记本中使用。将此内容复制到交互式工具或脚本的源代码中以引用此包。
// Install Elastic.Extensions.Logging as a Cake Addin
#addin nuget:?package=Elastic.Extensions.Logging&version=8.11.1

// Install Elastic.Extensions.Logging as a Cake Tool
#tool nuget:?package=Elastic.Extensions.Logging&version=8.11.1                

Elasticsearch 日志记录器提供者

Elasticsearch-Logstash-Kibana (ELK) 堆栈日志记录器提供者针对 Microsoft.Extensions.Logging。

使用 Elastic Common Schema (ECS) 直接写入 Elasticsearch,对来自消息和范围值的结构化数据进行语义日志记录。可以在 Kibana 控制台中查看和查询结果。

日志记录器使用 Elasticsearch.Net 低级客户端 来管理到 Elasticsearch 的网络连接。

使用方法

添加对 Elastic.Extensions.Logging 包的引用

dotnet add package Elastic.Extensions.Logging

然后,在主机构造期间使用提供的扩展方法将提供者添加到日志Builder中。

using Elastic.Extensions.Logging;

// ...

    .ConfigureLogging((hostContext, loggingBuilder) =>
    {
        loggingBuilder.AddElasticsearch();
    })

默认配置会将日志写入在 https://127.0.0.1:9200/ 运行的本地 Elasticsearch。

发送一些日志事件后,打开 Kibana(例如 https://127.0.0.1:5601/),为 "dotnet-*" 定义一个包含时间过滤器 "@timestamp" 的索引模式。

然后可以查看索引的日志事件。一些有用的列包括 log.levellog.loggerevent.codemessagetagsprocess.thread.id

如果您正在运行多个应用程序或多个服务器,您可能希望包括 service.typeservice.versionhost.hostname

以下定义了其他字段,所有单个消息和作用域值都记录为 labels.* 自定义键/值对,例如 labels.CustomerId

基本配置

对于部署,您通常希望用您实际的服务器位置覆盖配置。其他有用的配置值是环境标签,例如 开发/测试/生产。

{
  "Logging": {
    "Elasticsearch": {
      "NodeUris": [ "https://elastic-staging.example.com:9200" ],
      "Tags": [ "Staging" ]
    }
  }
}

注意:仅使用本地 Elasticsearch 实例时,无需任何配置,默认为 https://127.0.0.1:9200/。

示例程序

Example - Elasticsearch

配置设置

日志提供程序将自动配置带有别名 Elasticsearch 下的任何日志设置。

以下使用默认设置:

{
  "Logging": {
    "Elasticsearch": {
      "IncludeHost": true,
      "IncludeProcess": true,
      "IncludeScopes": true,
      "IncludeUser": true,
      "Index": "dotnet-{0:yyyy.MM.dd}",
      "IndexOffset": null,
      "IsEnabled": true,
      "ListSeparator": ", ",
      "MapCorrelationValues": true,
      "Tags": [],
      "ShipTo": {
        "NodePoolType": "SingleNode",
        "NodeUris": [ "https://127.0.0.1:9200" ]
      }
    }
  }
}
设置 类型 描述
IncludeHost 布尔值 默认 true;将 false 设置为禁用主机值记录。
IncludeProcess 布尔值 默认 true;将 false 设置为禁用进程值记录。
IncludeScopes 布尔值 默认 true;将 false 设置为禁用作用域值记录。
IncludeUser 布尔值 默认 true;将 false 设置为禁用用户详情记录。
Index 格式 用于生成 Elasticsearch index 的格式字符串,使用当前时间戳。默认为 dotnet-{0:yyyy.MM.dd}
IndexOffset 时间 span 覆盖以设置用于生成 index 的偏移量。默认值是 null,使用系统本地偏移量;使用 "00:00" 表示 UTC。
IsEnabled 布尔值 默认 true;将 false 设置为禁用日志记录器。
ListSeparator 字符串 用于 labels.* 值中的 IEnumerable 的分隔符。默认是 ", "
Tags 数组 要包含在消息中的其他标签。用于指定环境或其他详细信息,例如 [ "Staging", "Priority" ]

根据连接池类型,ShipTo 设置可以具有以下属性:

设置 类型 描述
ApiKey 字符串 API 键,当连接池类型为 Cloud 并通过 API 键验证时。
CloudId 字符串 Cloud ID,当连接池类型为 Cloud。
NodePoolType 枚举 默认为 Singlenode,对于多个节点为 Sniffing,如果提供 CloudId 则为 Cloud。其他支持的值是 StaticSticky
NodeUris 数组 要连接的 Elasticsearch 节点的 URI(s)。默认为一个节点 [ "https://127.0.0.1:9200" ]
Password 字符串 密码,当连接池类型为 Cloud 并通过用户名/密码验证时。
Username 字符串 用户名,当连接池类型为 Cloud 并通过用户名/密码验证时。

如果您想从不同的部分进行配置,可以手动配置

    .ConfigureLogging((hostContext, loggingBuilder) =>
    {
        loggingBuilder.AddElasticsearch(options =>
            hostContext.Configuration.Bind("Logging:CustomElasticsearch", options));
    })

当然,也可以在代码中进行配置,例如将环境作为标签添加。

Elastic Cloud 配置

如果提供了 CloudId,则 ConnectionPoolType 默认为 Cloud

{
  "Logging": {
    "Elasticsearch": {
      "ShipTo": {
        "CloudId": "12345",
        "ApiKey": "abcdef"
      }
    }
  }
}

输出 - Elastic Common Schema (ECS)

发送到 Elasticsearch 的日志消息遵循 Elastic Common Schema (ECS)

示例文档

_source 字段是从 LoggerProvider 发送的消息,包括 _index_id(一个 GUID)。

{
  "_index": "dotnet-2020.04.12",
  "_type": "_doc",
  "_id": "563503a8-9d10-46ff-a09f-c6ccbf124db9",
  "_version": 1,
  "_score": null,
  "_source": {
    "MessageTemplate": "Unexpected error processing customer {CustomerId}.",
    "Scopes": [
      "IP address 2001:db8:85a3::8a2e:370:7334",
      "PlainScope"
    ],
    "agent": {
      "version": "1.0.0+bd3ad6",
      "type": "Elastic.Extensions.Logging.LoggerProvider"
    },
    "ecs": {
      "version": "1.5.0"
    },
    "error": {
      "message": "Calculation error",
      "type": "System.Exception",
      "stack_trace": "System.Exception: Calculation error\n ---> System.DivideByZeroException: Attempted to divide by zero.\n   at HelloElasticsearch.Worker.ExecuteAsync(CancellationToken stoppingToken) in /home/sly/Code/essential-logging/examples/HelloElasticsearch/Worker.cs:line 80\n   --- End of inner exception stack trace ---\n   at HelloElasticsearch.Worker.ExecuteAsync(CancellationToken stoppingToken) in /home/sly/Code/essential-logging/examples/HelloElasticsearch/Worker.cs:line 84"
    },
    "event": {
      "code": "5000",
      "action": "ErrorProcessingCustomer",
      "severity": 3
    },
    "host": {
      "os": {
        "platform": "Unix",
        "full": "Linux 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020",
        "version": "4.15.0.91"
      },
      "hostname": "VUB1804",
      "architecture": "X64"
    },
    "log": {
      "level": "Error",
      "logger": "HelloElasticsearch.Worker"
    },
    "process": {
      "thread": {
        "id": 10
      },
      "pid": 25982,
      "name": "HelloElasticsearch"
    },
    "service": {
      "type": "HelloElasticsearch",
      "version": "1.0.0"
    },
    "user": {
      "id": "[email protected]",
      "name": "sly",
      "domain": "VUB1804"
    },
    "@timestamp": "2020-04-13T21:25:22.3352989+10:00",
    "tags": [
      "Development"
    ],
    "labels": {
      "ip": "2001:db8:85a3::8a2e:370:7334",
      "CustomerId": "12345"
    },
    "message": "Unexpected error processing customer 12345.",
    "trace": {
      "id": "c20bde1071f7cf4e9a6f368c824e05f7"
    },
    "transaction": {
      "id": "92ba5ee64d963746"
    }
  },
  "fields": {
    "@timestamp": [
      "2020-04-13T11:25:22.335Z"
    ]
  },
  "sort": [
    1586777122335
  ]
}

标准字段

字段 类型 描述
@timestamp 日期 记录消息的 DateTimeOffset,包括本地偏移量。
message 字符串 格式化日志消息和参数。
tags 数组 来自配置的自定义标签,例如 [ "Staging", "Priority" ]。可以有多个值。
event.action 字符串 记录的事件的 EventId 名称,例如 ErrorProcessingCustomer
event.code 字符串 EventId 的数值(作为字符串),例如 5000
event.severity long 与日志级别对应的 syslog 严重性,2 = 危急,3 = 错误,4 = 警告,6 = 信息,7 = 调试和跟踪。(也用于 ConsoleLoggerProvider 的 Systemd 格式)
log.level 字符串 日志级别:CriticalErrorWarningInformationDebugTrace
log.logger 字符串 记录器的类别名称(命名空间和类),例如 HelloElasticsearch.Worker

event.severity 字段是数值,可以用来按级别排序事件,例如 Kibana 查询 event.severity <= 4 将获取所有日志级别为 Warning 或更严重的信息。

错误字段

如果日志消息包含异常,详细信息将在错误字段中报告。

字段 类型 描述
error.message 字符串 任何异常的 Message 属性。
error.stack_trace 字符串 异常的完整详细信息,包括堆栈跟踪和内部异常的堆栈跟踪,例如 Exception.ToString()
error.type 字符串 错误消息的类型,例如 System.DivideByZeroException
自定义字段

根据 ECS 规范,这些使用交替的大写字母,以识别它们为非标准字段。

字段 类型 描述
MessageTemplate 字符串 原始消息模板,例如 "处理客户时出现意外错误 {CustomerId}."
Scopes 数组 字符串格式的作用域值数组,按添加顺序排列。
标签值
字段 类型 描述
labels.* 字符串 所有命名参数值和命名作用域值的自定义键/值对。所有值都是字符串(没有嵌套对象)。

标签值可以通过其键访问,例如如果消息或作用域包括一个参数 CustomerId,则值将记录为 labels.CustomerId 可在 Kibana 中使用 "labels.CustomerId: 12345" 进行搜索。

示例

以下将生成两个标签,labels.EndTime 来自消息,labels.CustomerId 来自作用域

using (_logger.BeginScope("{CustomerId}", customerId))
{
  _logger.LogWarning("End of processing reached at {EndTime}.", end);
}

标签从消息(状态)和任何作用域值中获取(可能通过配置选项禁用)。在 Microsoft.Extensions.Logging 中,内部 FormattedLogValues 在 ILogger 过载的日志级别和作用域中使用;它实现了 IEnumerable<KeyValuePair<string, object>> 接口,用于提取单个参数值。

在 ECS 中的 labels 属性不应包含嵌套对象,因此值被转换为关键字字符串。对于大多数对象,这只需调用 ToString(),对于某些类型的特定格式,例如在列表上调用字符串通常不是很有用,因此记录列表的内容。

标签值格式化

类型 格式化
byte 十六进制,例如 "9A"。
byte[] 前缀十六进制,例如 "0x12789AF0"。
DateTimeOffset ISO 格式,例如 "2020-01-02T03:04:05.000000+06:00"。
DateTime 大多数情况下应使用 DateTimeOffset(1)。当 DateTime 用于仅日期而没有时间组件时,格式化为日期,例如 "2020-01-02"。如果它具有时间组件,则使用往返 ("o") 格式。
IEnumerable 逗号空格分隔的值(可配置)
IDictionary<string, object> 包含键值对的字符串,例如 token="0x12789AF0" count="5"
其他值 ToString() 的结果,包括标量值,例如数字 5.3 被记录为字符串 "5.3"。

(1)请参阅 https://docs.microsoft.com/en-us/dotnet/standard/datetime/choosing-between-datetime

代理字段

这些标识正在使用的记录器提供器的版本。

字段 类型 描述
agent.type 字符串 记录器提供器程序集的名称,例如 Elastic.Extensions.Logging.LoggerProvider
agent.version 字符串 记录器程序集的信息性版本号,例如 1.1.1+bd3ad63
ecs.version 字符串 使用的 ECS 标准版本,目前为 1.5

服务字段

这标识了正在运行并生成日志的应用程序/服务。

获取值的方式是从入口装配中抽取的,使用Assembly.GetEntryAssembly(),根据NameAssemblyInformationalVersionAttribute的值(如果有设置为信息版本,否则使用装配的Version)。

字段 类型 描述
service.type 字符串 入口汇编的名字,HelloElasticsearch
service.version 字符串 入口汇编的信息版本号,例如:1.2.0-beta.1+79d095a

注意:您应该使用正确设置装配信息版本的构建过程。例如,如果您使用git的dotnet项目,可以安装本地工具GitVersion.Tool,并使用它自动从git分支信息生成语义版本号。

安装工具

dotnet new tool-manifest
dotnet tool install GitVersion.Tool

然后使用该工具创建在构建过程中可以使用的语义版本号

dotnet tool restore
dotnet gitversion

您可以使用本仓库中的build.ps1脚本作为示例。

跟踪字段

字段 类型 描述
trace.id 字符串 跨服务跟踪关联识别符。从System.Diagnostics中的Activity.Current.RootId获取,如果有回退到CorrelationManager.ActivityId。可以由消息或范围值trace.id覆盖。
transaction.id 字符串 此服务的交易,例如,单个请求标识符。如果在W3C格式中,从System.Diagnostics中的Activity.Current.Id解析出SpanId,否则直接使用完整的Activity.Current.Id(例如,如果是分层结构)。可以由消息或范围值transaction.id覆盖。

ASP.NET会自动在层之间传递关联标识符;从3.0起,它还支持W3C跟踪上下文标准(https://www.w3.org/TR/trace-context/)。

Activity.Current.RootId的值用作跨服务标识符(在W3C格式中这是跟踪ID),如果在W3C格式中,则使用Activity.Current.Id中Span ID部分作为交易的值,否则使用完整值(这与ASP.NET的工作方式一致)。

建议启用W3C格式,以提高与其他系统的兼容性

Activity.DefaultIdFormat = ActivityIdFormat.W3C;

宿主字段

注意:可以通过配置禁用。

字段 类型 描述
host.architecture 字符串 处理器架构,例如X64。值为RuntimeInformation.OSArchitecture
host.hostname 字符串 计算机名称。值为Environment.MachineName
host.os.full 字符串 操作系统完整描述。值为RuntimeInformation.OSDescription
host.os.platform 字符串 操作系统平台。值为Environment.OSVersion.Platform
host.os.version 字符串 操作系统版本。值为Environment.OSVersion.Version

进程字段

注意:可以通过配置禁用。

字段 类型 描述
process.name 字符串 当前进程名称。从Process.GetCurrentProcess()获取。
process.pid long 当前进程ID。从Process.GetCurrentProcess()获取。
process.thread.id long 当前线程ID。值为Thread.CurrentThread.ManagedThreadId
process.thread.name 字符串 线程名称。从Thread.CurrentThread.Name获取。

用户字段

注意:可以通过配置禁用。

字段 类型 描述
user.domain 字符串 当前域,无论是计算机名称还是Windows域。值为Environment.UserDomainName
user.id 字符串 当前用户主体名称,如果已设置。值为Thread.CurrentPrincipal.Identity.Name
user.name 字符串 当前用户。值为Environment.UserName
产品 兼容和附加计算的目标框架版本。
.NET net5.0 已计算。 net5.0-windows 已计算。 net6.0 已计算。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 已计算。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 已计算。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
.NET Core netcoreapp2.0 已计算。 netcoreapp2.1 已计算。 netcoreapp2.2 已计算。 netcoreapp3.0 已计算。 netcoreapp3.1 已计算。
.NET 标准化 netstandard2.0 兼容。 netstandard2.1 兼容。
.NET 框架 net461 已计算。 net462 已计算。 net463 已计算。 net47 已计算。 net471 已计算。 net472 已计算。 net48 已计算。 net481 已计算。
MonoAndroid monoandroid 已计算。
MonoMac monomac 已计算。
MonoTouch monotouch 已计算。
Tizen tizen40 已计算。 tizen60 已计算。
Xamarin.iOS xamarinios 已计算。
Xamarin.Mac xamarinmac 已计算。
Xamarin.TVOS xamarintvos 已计算。
Xamarin.WatchOS xamarinwatchos 已计算。
兼容的目标框架
包含的目标框架(在包中)
了解更多关于目标框架.NET Standard的信息。

NuGet包 (2)

显示依赖于Elastic.Extensions.Logging的前两个NuGet包

下载
BitzArt.OpenTelemetry.BoilerPlate

OpenTelemetry的一些模板代码

Gench.Logging

包描述

GitHub仓库

此包未被任何流行GitHub仓库使用。

版本 下载 最后更新
8.11.1 2,798 6/10/2024
8.11.0 9,216 4/10/2024
8.6.1 53,979 8/3/2023
8.6.0 11,254 5/9/2023