Open Tracing instrumentation for running process
Open tracing allows you to trace calls between (micro)services . It has also calls for HTTP and Sql. For a ASP.NET Core application the code is at follows ( for exporting at Jaeger, for example):
services.AddOpenTelemetryTracing(b => { string nameAssemblyEntry = Assembly.GetEntryAssembly().GetName().Name; var rb = ResourceBuilder.CreateDefault(); rb.AddService(nameAssemblyEntry); var data = new Dictionary<string, object>() { { "PC", Environment.MachineName } }; data.Add("Exe", nameAssemblyEntry); rb.AddAttributes(data); _ = b .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddSqlClientInstrumentation() .AddSource("MySource") .SetResourceBuilder(rb) .AddJaegerExporter(c => { var s = Configuration.GetSection("Jaeger"); s.Bind(c); }); }) ;
This code was made with
<PackageReference Include=”OpenTelemetry” Version=”1.1.0-beta1″ />
<PackageReference Include=”OpenTelemetry.Instrumentation.AspNetCore” Version=”1.0.0-rc3″ />
<PackageReference Include=”OpenTelemetry.Exporter.Jaeger” Version=”1.1.0-beta1″ />
<PackageReference Include=”OpenTelemetry.Extensions.Hosting” Version=”1.0.0-rc3″ />
<PackageReference Include=”OpenTelemetry.Instrumentation.Http” Version=”1.0.0-rc3″ />
<PackageReference Include=”OpenTelemetry.Instrumentation.SqlClient” Version=”1.0.0-rc3″ />
For a .NET Core console, the code is :
string nameAssemblyEntry = Assembly.GetEntryAssembly().GetName().Name; var rb = ResourceBuilder.CreateDefault(); rb.AddService(nameAssemblyEntry); var data = new Dictionary<string, object>() { { "PC", Environment.MachineName } }; data.Add("Exe", nameAssemblyEntry); rb.AddAttributes(data); openTelemetry = Sdk.CreateTracerProviderBuilder() .AddSource("MySource") .AddHttpClientInstrumentation() .AddSqlClientInstrumentation() .SetResourceBuilder(rb) .AddJaegerExporter(o => { var s = config.GetSection("Jaeger"); s.Bind(o); }) .Build();
But how to transmit data for a Web that calls a process and not modify the command line ? Simple : via environment variable
The code for running the process is :
var pi = new ProcessStartInfo(); pi.FileName = ...; pi.WorkingDirectory = ...; var act = Activity.Current; if (act != null) { pi.EnvironmentVariables.Add(nameof(act.TraceId), act.TraceId.ToHexString()); pi.EnvironmentVariables.Add(nameof(act.SpanId), act.SpanId.ToHexString()); } var p = Process.Start(pi);
For the console, the code is:
using (var act = MyActivitySource.StartActivity("StartProcess", ActivityKind.Producer)) { act.SetTag("proc", "main"); var traceStr = (Environment.GetEnvironmentVariable(nameof(act.TraceId))); if (!string.IsNullOrWhiteSpace(traceStr)) { var trace = ActivityTraceId.CreateFromString(traceStr); var span = ActivitySpanId.CreateFromString(Environment.GetEnvironmentVariable(nameof(act.SpanId))); act.SetParentId(trace, span, ActivityTraceFlags.Recorded); } try { //executing code act.SetStatus(Status.Ok); } catch (Exception ex) { act.SetStatus(Status.Error); throw; } }