问题描述
我有一个应用程序,可以使用 serilog 将日志写入 elasticsearch。我使用 docker-compose 配置了 APM 服务器。一旦我启动应用程序并执行操作(浏览浏览器中的页面),然后关闭应用程序。然后将这些日志记录到elasticsearch。我遇到了这个 article,它谈到了将日志与 APM 相关联。我选择了几个要遵循的步骤,因为我在这个应用程序中没有使用 python,并注意到 APM 内部有事务。
通过这些事务,我如何能够将日志相互关联。换句话说,我如何将这些日志联系在一起,是否有一个唯一的变量/ID/键可以将所有记录在单个事务中的日志联系起来(当我启动应用程序,执行操作,然后关闭应用程序时)?
当我查看每个事务时,我注意到它们有一个 transcation_id 和一个 trace_id。但是,它们会随着我执行的每个操作而变化。 我想知道是否可行,如果可行,我如何收集与该单个事务相关的所有日志?例如,如果我通过单个 ID 进行查询,那么所有这些日志日志将被返回。
docker-compose.yml
version: '2.2'
services:
apm-server:
image: docker.elastic.co/apm/apm-server:7.13.0
depends_on:
elasticsearch:
condition: service_healthy
kibana:
condition: service_healthy
cap_add: ["CHOWN","DAC_OVERRIDE","SETGID","SETUID"]
cap_drop: ["ALL"]
ports:
- 8200:8200
networks:
- elastic
command: >
apm-server -e
-E apm-server.rum.enabled=true
-E setup.kibana.host=kibana:5601
-E setup.template.settings.index.number_of_replicas=0
-E apm-server.kibana.enabled=true
-E apm-server.kibana.host=kibana:5601
-E output.elasticsearch.hosts=["elasticsearch:9200"]
healthcheck:
interval: 10s
retries: 12
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:8200/
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.13.0
environment:
- bootstrap.memory_lock=true
- cluster.name=docker-cluster
- cluster.routing.allocation.disk.threshold_enabled=false
- discovery.type=single-node
- ES_JAVA_OPTS=-XX:UseAVX=2 -xms1g -Xmx1g
ulimits:
memlock:
hard: -1
soft: -1
volumes:
- esdata:/usr/share/elasticsearch/data
ports:
- 9200:9200
networks:
- elastic
healthcheck:
interval: 20s
retries: 10
test: curl -s http://localhost:9200/_cluster/health | grep -vq '"status":"red"'
kibana:
image: docker.elastic.co/kibana/kibana:7.13.0
depends_on:
elasticsearch:
condition: service_healthy
environment:
ELASTICSEARCH_URL: http://elasticsearch:9200
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
ports:
- 5601:5601
networks:
- elastic
healthcheck:
interval: 10s
retries: 20
test: curl --write-out 'HTTP %{http_code}' --fail --silent --output /dev/null http://localhost:5601/api/status
volumes:
esdata:
driver: local
networks:
elastic:
driver: bridge
更新
在查看 Elastic.Apm.SerilogEnricher
的 documentation 之后,我继续将它包含到我的 Startup.cs
文件和我的 Program.cs
文件中。只是想仔细检查一下我是否正确地合并了它。
Startup.cs
:
namespace CustomerSimulatorApp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
var logger = new LoggerConfiguration()
.Enrich.WithElasticApmCorrelationInfo()
.Writeto.Console(outputTemplate: "[{ElasticApmTraceId} {ElasticApmTransactionId} {Message:lj} {NewLine}{Exception}")
.CreateLogger();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// create a new node instance
var node = new Uri("http://localhost:9200");
// settings instance for the node
var settings = new ConnectionSettings(node);
settings.DefaultFieldNameInferrer(p => p);
services.AddSingleton<IElasticclient>(new Elasticclient(settings));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
{
app.UseAllElasticApm(Configuration);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios,see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Program.cs
namespace CustomerSimulatorApp
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog((context,configuration) =>
{
configuration.Enrich.FromLogContext()
.Enrich.WithElasticApmCorrelationInfo()
.Enrich.WithMachineName()
.Writeto.Console()
.Writeto.Elasticsearch(new ElasticsearchSinkOptions(new Uri(context.Configuration["ElasticConfiguration:Uri"]))
{
IndexFormat = $"{context.Configuration["ApplicationName"]}-logs-{context.HostingEnvironment.EnvironmentName?.ToLower().Replace(".","-")}-{DateTime.UtcNow:yyyy-MM}",AutoRegisterTemplate = true
})
.Enrich.WithProperty("Environment",context.HostingEnvironment.EnvironmentName)
.ReadFrom.Configuration(context.Configuration);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
})
.UseAllElasticApm();
}
}
我注意到当我运行程序并在浏览器上执行操作然后检查 APM 时,trace.id 和 transaction.id 仍在更改,因此我无法将我在浏览器上执行的单个事务与日志相关联.我是否错误地实现了上面的 Elastic.Apm.SerilogEnricher
?
不同的ID(有更多的不同,但不想用截图展开)
它们每页重定向都会发生变化,因此我无法从单个 ID 收集日志。
这是我在控制台上看到的以及更新的 startup.cs 和 program.cs 文件:
我最终关闭了程序:
解决方法
如果您使用 Serilog 将日志发送到 Elasticsearch,并且还在您的应用程序中使用 Elastic APM .NET 代理来捕获跟踪,您可以参考 Elastic.Apm.SerilogEnricher
以使用 APM 跟踪 ID 和事务 ID(以及在即将发布的 1.6 版本中,span ids) 如果在登录时有活动事务
var logger = new LoggerConfiguration()
.Enrich.WithElasticApmCorrelationInfo()
.WriteTo.Console(outputTemplate: "[{ElasticApmTraceId} {ElasticApmTransactionId} {Message:lj} {NewLine}{Exception}")
.CreateLogger();
查看 documentation,了解更多信息。