Closed KINGGUOKUN closed 2 years ago
My code is like this:
public class XXHostService : IHostedService, IDisposable
{
#region Private Fields
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<XXHostService > _logger;
private Timer _timer;
#endregion
#region Constructors
public XXHostService (IServiceProvider serviceProvider,
ILogger<XXHostService > logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
}
#endregion
public void Dispose()
{
_timer?.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("start...");
_timer= new Timer(async (state) =>
{
await DoXXX(state);
},
null, TimeSpan.Zero, TimeSpan.FromMinutes(1);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("stop...");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
private async Task DoXXX(object state)
{
if (!Elastic.Apm.Agent.IsConfigured)
{
return;
}
using (var scope = _serviceProvider.CreateScope())
{
var myService = scope.ServiceProvider.GetService<IMyService>();
await Elastic.Apm.Agent.Tracer.CaptureTransaction("XXXX", "backgroundjob", async () =>
{
// DoSomeThing with db query, http request, etc
await myService .DoSomeThing();
});
}
}
}
Hi @KINGGUOKUN
tldr: I think it's because of the if (!Elastic.Apm.Agent.IsConfigured) return
check - that returns false and you always return from the DoXXX
method.
How do you enable the agent?
With a hosted service, the best is to not use the static API. Instead you can enable the agent in your program.cs
this way:
private static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) => { services.AddHostedService<HostedService>(); })
.UseAllElasticApm();
this will register the agent with DI and it'll also configure the agent, so with the UseAllElasticApm()
line you are ready to go.
Then you could dependency inject an ITracer
into your XXHostService
:
public XXHostService (IServiceProvider serviceProvider,
ILogger<XXHostService > logger, ITracer tracer)
{
_serviceProvider = serviceProvider;
_logger = logger;
_tracer = tracer; // use this tracer instead of the static Elastic.Apm.Agent.Tracer.
}
We have a similar sample here.
Does this help?
I enable it in Starup.Configure, like this: public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedHost | ForwardedHeaders.XForwardedProto });
app.UseElasticApm(Configuration,
new HttpDiagnosticsSubscriber(),
new EfCoreDiagnosticsSubscriber(),
new SqlClientDiagnosticSubscriber());
if (env.IsDevelopment())
{
System.Net.Http.HttpClient.DefaultProxy = new System.Net.WebProxy("http://proxy.zte.com.cn:80");
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
}
And before I post the issue, I do use it as you suggest, the result is: HostService traced success fully, but other traces lose, eg, my normal http request!
The check if (!Elastic.Apm.Agent.IsConfigured) return; is to avoid double initialize the agent. Without it, Elastic.Apm.Agent will be initialized with something like http://localhost:8200 and never load the apmserver configuration.
Ok, I see.
In this setup, I'd still avoid the static API and enable the agent with the UseElasticApm
method.
HostService traced success fully, but other traces lose, eg, my normal http request!
We should look into this. Could you maybe turn on trace logs and show agent logs when this happened? Also.. where did those HTTP request happened? An HTTP request is captured as a span and it needs to be in a transaction - so make sure there is an active transaction. Btw. we also have a UseAllElasticApm
method which turns on all the listeners for you in this package - of course you can also enable listeners one by one, so this is just an info that may help you.
The check if (!Elastic.Apm.Agent.IsConfigured) return; is to avoid double initialize the agent.
Yes, that's the typical use case for it. So in this sense you use it correctly, but somewhere the agent must be initialized
Without it, Elastic.Apm.Agent will be initialized with something like http://localhost:8200/ and never load the apmserver configuration.
Correct, and that will read configs from environment variables in this case. You can still configure the agent, but in this case you can't use e.g. appsettings.json
(because you don't pass the IConfiguration
instance to the agent), instead you need to set configs via environment variables. Environment variable names can be found in the docs. An example is here. (spot the ELASTIC_APM_SERVER_URL
).
Nevertheless I'd still look into the UseElasticApm
way of adding the agent and figure out why that didn't work.
OK, I will turn on trace logs and look details into it later.
Since this issue is fairly old and I think most questions are answered I'm closing this now. Feel free to comment if anything is left.
Bellow is my code in the Timer callback of my custom HostService,but Elastic.Apm.Agent.Tracer.CaptureTransaction does't trace any thing.