dotnet-elastic-apm
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseElasticsearch and Elastic APM Integration
Elasticsearch与Elastic APM集成
Logging and Observability Standards
日志与可观测性标准
- Logging Standard: All logging must be implemented using Serilog with structured logging.
- Centralized Destination: All logs must be centralized in Elasticsearch, using Elastic APM authentication and Data Streams configuration.
- Enriched Information: Logs must be enriched with context properties such as and
app-name.app-type - Bootstrapping: Serilog initialization must be COMPLETELY OMITTED IN and performed through an Extension Method from the Infrastructure layer.
Program.cs
- 日志标准:所有日志必须使用Serilog实现结构化日志记录。
- 集中存储目标:所有日志必须集中存储在Elasticsearch中,采用Elastic APM认证和Data Streams配置。
- 日志内容增强:日志必须包含app-name和app-type等上下文属性以丰富信息。
- 初始化要求:Serilog的初始化必须完全在中省略,转而通过基础设施层的扩展方法完成。
Program.cs
Security and Data Privacy
安全与数据隐私
- Sensitive Information: PII (Personally Identifiable Information), credentials, and tokens must NEVER be logged.
- Sanitize sensitive data before logging.
- Use log filters to exclude sensitive endpoints or data.
- 敏感信息:绝对禁止记录个人可识别信息(PII)、凭证及令牌。
- 记录前需清理敏感数据。
- 使用日志过滤器排除敏感端点或数据。
Serilog Configuration Extension Method
Serilog配置扩展方法
Create an extension method in :
Infrastructure/Extensions/ExtensionLogging.cscsharp
using Serilog;
using Serilog.Events;
using Serilog.Sinks.Elasticsearch;
using Elastic.Ingest.Elasticsearch.DataStreams;
using Elastic.Ingest.Elasticsearch;
using Elastic.Transport;
namespace Infrastructure.Extensions
{
/// <summary>
/// Extension class for configuring Serilog with Elasticsearch and Elastic APM.
/// </summary>
public static class ExtensionLogging
{
/// <summary>
/// Configures Serilog with Elasticsearch using Elastic APM.
/// </summary>
/// <param name="configuration">Application configuration.</param>
public static void AddLog(IConfiguration configuration)
{
string? elasticUrl = configuration.GetValue<string>("Global:Elastic:Url");
string? environment = configuration.GetValue<string>("Global:Elastic:Env");
string? elasticUser = configuration.GetValue<string>("Global:Elastic:User");
string? elasticPass = configuration.GetValue<string>("Global:Elastic:Pass");
string? logLevelEnv = configuration.GetValue<string>("Global:Elastic:LogLevel");
LogEventLevel logEventLevel = (LogEventLevel)int.Parse(logLevelEnv!);
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithProperty("app-name", configuration.GetSection("Elastic").GetValue<string>("app-name"))
.Enrich.WithProperty("app-type", configuration.GetSection("Elastic").GetValue<string>("app-type"))
.WriteTo.Console()
.WriteTo.Elasticsearch([new Uri(elasticUrl!)], opts =>
{
// Use DataStream for Elastic APM compatibility
opts.DataStream = new DataStreamName("app", environment!, "logs");
opts.BootstrapMethod = BootstrapMethod.None;
opts.MinimumLevel = logEventLevel;
}, transport =>
{
// Basic Authentication
transport.Authentication(new BasicAuthentication(elasticUser!, elasticPass!));
// Callback to accept certificates (e.g., in development)
transport.ServerCertificateValidationCallback((a, b, c, d) => true);
})
.CreateLogger();
}
}
}在中创建扩展方法:
Infrastructure/Extensions/ExtensionLogging.cscsharp
using Serilog;
using Serilog.Events;
using Serilog.Sinks.Elasticsearch;
using Elastic.Ingest.Elasticsearch.DataStreams;
using Elastic.Ingest.Elasticsearch;
using Elastic.Transport;
namespace Infrastructure.Extensions
{
/// <summary>
/// Extension class for configuring Serilog with Elasticsearch and Elastic APM.
/// </summary>
public static class ExtensionLogging
{
/// <summary>
/// Configures Serilog with Elasticsearch using Elastic APM.
/// </summary>
/// <param name="configuration">Application configuration.</param>
public static void AddLog(IConfiguration configuration)
{
string? elasticUrl = configuration.GetValue<string>("Global:Elastic:Url");
string? environment = configuration.GetValue<string>("Global:Elastic:Env");
string? elasticUser = configuration.GetValue<string>("Global:Elastic:User");
string? elasticPass = configuration.GetValue<string>("Global:Elastic:Pass");
string? logLevelEnv = configuration.GetValue<string>("Global:Elastic:LogLevel");
LogEventLevel logEventLevel = (LogEventLevel)int.Parse(logLevelEnv!);
Log.Logger = new LoggerConfiguration()
.Enrich.FromLogContext()
.Enrich.WithProperty("app-name", configuration.GetSection("Elastic").GetValue<string>("app-name"))
.Enrich.WithProperty("app-type", configuration.GetSection("Elastic").GetValue<string>("app-type"))
.WriteTo.Console()
.WriteTo.Elasticsearch([new Uri(elasticUrl!)], opts =>
{
// Use DataStream for Elastic APM compatibility
opts.DataStream = new DataStreamName("app", environment!, "logs");
opts.BootstrapMethod = BootstrapMethod.None;
opts.MinimumLevel = logEventLevel;
}, transport =>
{
// Basic Authentication
transport.Authentication(new BasicAuthentication(elasticUser!, elasticPass!));
// Callback to accept certificates (e.g., in development)
transport.ServerCertificateValidationCallback((a, b, c, d) => true);
})
.CreateLogger();
}
}
}Program.cs Configuration
Program.cs配置
Configure Serilog and Elastic APM in only for development:
Program.cscsharp
if (app.Environment.IsDevelopment())
{
builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
ExtensionLogging.AddLog(builder.Configuration);
builder.Services.AddAllElasticApm();
}仅在开发环境下于中配置Serilog和Elastic APM:
Program.cscsharp
if (app.Environment.IsDevelopment())
{
builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
ExtensionLogging.AddLog(builder.Configuration);
builder.Services.AddAllElasticApm();
}Required NuGet Packages
所需NuGet包
- Serilog.AspNetCore
- Serilog.Sinks.Elasticsearch
- Elastic.Apm.NetCoreAll
- Elastic.Ingest.Elasticsearch
- Elastic.Ingest.Elasticsearch.DataStreams
- Elastic.Transport
- Serilog.AspNetCore
- Serilog.Sinks.Elasticsearch
- Elastic.Apm.NetCoreAll
- Elastic.Ingest.Elasticsearch
- Elastic.Ingest.Elasticsearch.DataStreams
- Elastic.Transport
Configuration Settings (appsettings.json)
配置设置(appsettings.json)
json
{
"Elastic": {
"app-name": "your-app-name",
"app-type": "api",
"Url": "https://your-elastic-url:9200",
"Env": "development",
"User": "elastic_user",
"Pass": "elastic_password",
"LogLevel": "2"
}
}json
{
"Elastic": {
"app-name": "your-app-name",
"app-type": "api",
"Url": "https://your-elastic-url:9200",
"Env": "development",
"User": "elastic_user",
"Pass": "elastic_password",
"LogLevel": "2"
}
}Log Level Values
日志级别对应值
- 0 = Verbose
- 1 = Debug
- 2 = Information
- 3 = Warning
- 4 = Error
- 5 = Fatal
- 0 = Verbose(详细)
- 1 = Debug(调试)
- 2 = Information(信息)
- 3 = Warning(警告)
- 4 = Error(错误)
- 5 = Fatal(致命)
Best Practices
最佳实践
- Use structured logging with named properties:
Log.Information("User {UserId} logged in", userId); - Avoid string interpolation in log messages.
- Use log context to enrich logs with request-specific data.
- Configure appropriate log levels for different environments.
- Monitor APM metrics alongside logs for complete observability.
- 使用带命名属性的结构化日志:
Log.Information("User {UserId} logged in", userId); - 避免在日志消息中使用字符串插值。
- 使用日志上下文添加请求特定数据以丰富日志内容。
- 为不同环境配置合适的日志级别。
- 同时监控APM指标与日志,以实现完整的可观测性。