dotnet-elastic-apm

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Elasticsearch 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
    app-name
    and
    app-type
    .
  • Bootstrapping: Serilog initialization must be COMPLETELY OMITTED IN
    Program.cs
    and performed through an Extension Method from the Infrastructure layer.
  • 日志标准:所有日志必须使用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.cs
:
csharp
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.cs
中创建扩展方法:
csharp
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
Program.cs
only for development:
csharp
if (app.Environment.IsDevelopment())
{
    builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
    ExtensionLogging.AddLog(builder.Configuration);
    builder.Services.AddAllElasticApm();
}
仅在开发环境下于
Program.cs
中配置Serilog和Elastic APM:
csharp
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指标与日志,以实现完整的可观测性。