在.net core6 中使用opentelemetry

1. 引入包

OpenTelemetry.Exporter.Console // 控制台输出

OpenTelemetry.Exporter.OpenTelemetryProtocol // 协议输出,可以对接jaeger、ziplin、seq

OpenTelemetry.Exporter.Prometheus.AspNetCore //普罗米修斯的输出

OpenTelemetry.AutoInstrumentation.AspNetCoreBootstrapper // dotnetcore 自动注入库

OpenTelemetry.Instrumentation.AspNetCore // dotnetcore 的一些功能的遥测实现

OpenTelemetry.Instrumentation.Http // http请求相关的遥测实现

OpenTelemetry.Extensions.Hosting // 扩展

System.Diagnostics.DiagnosticSource // 一些model 要用的话得用这个库

2. 注入service

    public static class OpentelemetryExtension
    {
        /// <summary>
        /// exporter的endpoint
        /// </summary>
        const string OTLP_ENDPOINT_URL = nameof(OTLP_ENDPOINT_URL);
        /// <summary>
        /// 携带的header信息
        /// </summary>
        const string OTEL_EXPORTER_OTLP_HEADERS = nameof(OTEL_EXPORTER_OTLP_HEADERS);
        /// <summary>
        /// 集成opentelemetry 到seq收集trace日志
        /// </summary>
        /// <param name="services">IServiceCollection</param>
        /// <param name="environment">环境</param>
        /// <param name="configuration">configuration</param>
        /// <returns></returns>
        public static IServiceCollection AddOpentelemetryWithTrace(this IServiceCollection services, IWebHostEnvironment environment, IConfiguration configuration)
        {
            var tracingOtlpEndpoint = configuration[OTLP_ENDPOINT_URL];
            var tracingOtlpHeader = configuration[OTEL_EXPORTER_OTLP_HEADERS];
            services.AddOpenTelemetry().WithTracing(tracing =>
            {
                tracing.AddAspNetCoreInstrumentation();
                tracing.AddHttpClientInstrumentation();
                tracing.AddEntityFrameworkCoreInstrumentation();
                tracing.AddSqlClientInstrumentation();
                tracing.AddQuartzInstrumentation();
                tracing.AddSource(environment.ApplicationName);
            });
            services.AddLogging(logging => logging.AddOpenTelemetry(openTelemetryLoggerOptions =>
            {
                openTelemetryLoggerOptions.SetResourceBuilder(
                    ResourceBuilder.CreateEmpty()
                        .AddService($"{environment.ApplicationName}-OpenTelemetry")
                        .AddAttributes(new Dictionary<string, object>
                        {
                            [nameof(environment.EnvironmentName).ToLower()] = environment.EnvironmentName
                        }));
                openTelemetryLoggerOptions.IncludeScopes = true;
                openTelemetryLoggerOptions.IncludeFormattedMessage = true;
                openTelemetryLoggerOptions.AddOtlpExporter(exporter =>
                {
                    exporter.Endpoint = new Uri(tracingOtlpEndpoint);
                    exporter.Protocol = OtlpExportProtocol.HttpProtobuf;
                    exporter.Headers = tracingOtlpHeader;
                });
            }));
            return services;
        }
    }

3. 示例代码如下,在api 中调用了一个服务,该服务手动转发了 Propagator 信息,在跨服务调用时可以考虑该信息放置在header中

using Microsoft.AspNetCore.Mvc;
using OpenTelemetry;
using OpenTelemetry.Context.Propagation;
using System.Diagnostics;

namespace OpenTelemetryDemo.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

        private readonly ILogger<WeatherForecastController> _logger;
        private readonly ServiceA serviceA;
        private readonly IWebHostEnvironment webHostEnvironment;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, ServiceA serviceA, IWebHostEnvironment webHostEnvironment)
        {
            _logger = logger;
            this.serviceA = serviceA;
            this.webHostEnvironment = webHostEnvironment;
        }
        private static readonly ActivitySource RegisteredActivity = new ActivitySource("Examples.ManualInstrumentations.Registered");

        [HttpGet(Name = "GetWeatherForecast")]
        public IEnumerable<WeatherForecast> Get()
        {
            var name = Guid.NewGuid();
            _logger.LogInformation($"{name}");
            // A span
            using var activity = ServiceA.ActivitySource.StartActivity("Call to Service B");
            activity?.AddTag("Path","GetApi");

            serviceA.GetName(name.ToString());
            activity?.Stop();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();
        }
    }

    public class ServiceA
    {
        private readonly ILogger logger;

        public ServiceA(ILogger<ServiceA> logger)
        {
            this.logger = logger;
        }
        public static readonly ActivitySource ActivitySource = new ActivitySource("AAAA");

        private static readonly TextMapPropagator Propagator = new OpenTelemetry.Extensions.Propagators.B3Propagator();
        public string GetName(string name)
        {

            // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/semantic_conventions/messaging.md#span-name
            var activityName = $"send";

            using var activity = Activity.Current ?? ActivitySource.StartActivity(activityName, ActivityKind.Producer);

            ActivityContext contextToInject = default;
            if (activity != null)
            {
                contextToInject = activity.Context;
            }
            else if (Activity.Current != null)
            {
                contextToInject = Activity.Current.Context;
            }
            Propagator.Inject(new PropagationContext(contextToInject, Baggage.Current), new Dictionary<string, string>() { { "X-B3-Flags", "1" }, { "X-B3-TraceId", Guid.NewGuid().ToString() }, { "X-B3-SpanId", Guid.NewGuid().ToString() } }, InjectTraceContextIntoBasicProperties);

            var parentContext = Propagator.Extract(new PropagationContext(contextToInject, Baggage.Current), new Dictionary<string, string>() { { "X-B3-Flags", "1" }, { "X-B3-TraceId", Guid.NewGuid().ToString() }, { "X-B3-SpanId", Guid.NewGuid().ToString() } }, this.ExtractTraceContextFromBasicProperties);

            Baggage.Current = parentContext.Baggage;

            var activityName1 = $"receive";
            using var activity1 = ActivitySource.StartActivity(activityName1, ActivityKind.Consumer, parentContext.ActivityContext);
            activity1?.AddTag("Path", "GetName function");
            logger.LogWarning($"参数是{name}");
            activity1?.Stop();
            return name;
        }

        private void InjectTraceContextIntoBasicProperties(Dictionary<string, string> headers, string key, string value)
        {
            try
            {
                if (headers == null)
                {
                    headers = new Dictionary<string, string>();
                }

                headers[key] = value;
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "Failed to inject trace context.");
            }
        }

        private IEnumerable<string> ExtractTraceContextFromBasicProperties(Dictionary<string, string> headers, string key)
        {
            try
            {
                if (headers.TryGetValue(key, out var value))
                {
                    return new[] { value };
                }
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "Failed to extract trace context.");
            }

            return Enumerable.Empty<string>();
        }
    }
}

源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
依赖注入(Dependency Injection,DI)是一种设计模式,其目的是实现对象之间的解耦,提高代码的可测试性和可维护性。在 .NET Core ,依赖注入是一个内置的功能,可以通过 ASP.NET Core 的内置容器或第三方容器库来实现。以下是在 .NET Core 使用依赖注入的步骤: 1. 定义接口和实现类 首先,定义需要注入的接口和实现类。例如: ```csharp public interface IMyService { void DoSomething(); } public class MyService : IMyService { public void DoSomething() { // 实现具体逻辑 } } ``` 2. 注册依赖关系 然后,在应用程序的启动代码,注册接口和实现类之间的依赖关系。例如: ```csharp public void ConfigureServices(IServiceCollection services) { services.AddScoped<IMyService, MyService>(); } ``` 上述代码使用 `AddScoped` 方法将 `IMyService` 接口与 `MyService` 实现类进行了注册。`AddScoped` 方法表示每个请求范围内都会创建一个新的实例。 3. 使用依赖注入 现在,可以在需要使用 `IMyService` 的地方进行依赖注入。例如: ```csharp public class MyController : Controller { private readonly IMyService _myService; public MyController(IMyService myService) { _myService = myService; } public IActionResult Index() { _myService.DoSomething(); return View(); } } ``` 上述代码,`MyController` 类在构造函数注入了 `IMyService` 接口,并在 `Index` 方法使用它。 通过以上步骤,就可以在 .NET Core 使用依赖注入了。值得注意的是,ASP.NET Core 的内置容器支持多种生命周期选项,如 `AddSingleton`、`AddTransient` 和 `AddScoped` 等,可以根据实际需求来选择不同的生命周期选项。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值