• 引入Jaeger——扩展


      Jaeger是收集全链路跟踪的信息,在Jaeger收集的信息中,有请求的url信息,有每个请求的时间间隔,借助这些信息可以进行报警,比如一次较长的请求,或者是某些请求的次数和先后等。不管报警的业务规则是什么,首先得收集Jaeger中的信息。

      Jaeger有api可以提供这些信息,比如

      /api/services,获取所有服务

      /api/traces?service={servicename}获取该服务下的所有跟踪

      /api/traces/{traceid}获取某个跟踪的信息等

      /api/traces?end={endtime}&limit={20}&lookback={1h}&service={servicename}&start={starttime}按条件查询跟踪信息等api

    下面代码定义Jaeger中的实体类,类中的属性可以根据自己的型业务规则收集,这里定义不完整

     

    using System.Collections.Generic;
    
    namespace JaegerAlert
    {
        /// <summary>
        /// 服务报警
        /// </summary>
        public class AlertList
        {
            public string ServiceName { get; set; }
            public List<AlertItem> Alerts { get; set; }
        }
        /// <summary>
        /// 报警条目
        /// </summary>
        public class AlertItem
        {
            public string TraceID { get; set; }
            public long StartTime { get; set; }
    
            public long Duration { get; set; }
    
            public string Method { get; set; }
    
            public string Operation { get; set; }
        }
    
        /// <summary>
        /// 服务数据
        /// </summary>
        public class ServicesData
        {
            public string[] Data { get; set; }
            public int Total { get; set; }
            public int Limit { get; set; }
            public int Offset { get; set; }
        }
    
        /// <summary>
        /// 跟踪数据
        /// </summary>
        public class TracesData
        {
            public TracesItem[] Data { get; set; }
            public int Total { get; set; }
            public int Limit { get; set; }
            public int Offset { get; set; }
        }
        /// <summary>
        /// 跟踪条目
        /// </summary>
        public class TracesItem
        {
            public string TraceID { get; set; }
    
            public Span[] Spans { get; set; }
        }
        /// <summary>
        /// Span
        /// </summary>
        public class Span
        {
            public string TraceID { get; set; }
            public string SpanID { get; set; }
            public bool IsAlertMark => TraceID == SpanID;
            public int Flags { get; set; }
            public string OperationName { get; set; }
            public long StartTime { get; set; }
    
            public long Duration { get; set; }
            public Tag[] Tags { get; set; }
        }
        /// <summary>
        /// Tag
        /// </summary>
        public class Tag
        {
            public string Key { get; set; }
            public string Type { get; set; }
    
            public string Value { get; set; }
        }
    }

    这里简单进行了收集,转换成了自己的数据集合,方便对接自己的报警平台:

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Logging;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Http;
    using System.Threading.Tasks;
    
    namespace JaegerAlert.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class HomeController : ControllerBase
        {
            private readonly IHttpClientFactory _clientFactory;
            private readonly ILogger<HomeController> _logger;
    
            public HomeController(ILogger<HomeController> logger, IHttpClientFactory clientFactory)
            {
                _clientFactory = clientFactory;
                _logger = logger;
            }
    
            [HttpGet]
            public async Task<IEnumerable<AlertList>> Get()
            {
                _logger.LogInformation("获取警报列表");
                return await GetServices();
            }
            /// <summary>
            /// 获取所有服务
            /// </summary>
            /// <returns></returns>
            async Task<IEnumerable<AlertList>> GetServices()
            {
                var service = await GetJaegerServices();
                var services = new List<AlertList>();
                foreach (var serviceName in service.Data)
                {
                    if (serviceName == "jaeger-query")
                    {
                        continue;
                    }
                    var alerts = new List<AlertItem>();
                    var tracesModels = await GetJaegerTraces(serviceName);
                    foreach (var traces in tracesModels.Data)
                    {
                        foreach (var span in traces.Spans)
                        {
                            if (span.IsAlertMark)
                            {
                                var method = span.Tags.SingleOrDefault(s => s.Key == "http.method")?.Value;
                                var operation = span.Tags.SingleOrDefault(s => s.Key == "http.url")?.Value;
                                alerts.Add(new AlertItem { TraceID = traces.TraceID, Duration = span.Duration, Method = method, Operation = operation, StartTime = span.StartTime });
                            }
                        }
                    }
                    services.Add(new AlertList() { ServiceName = serviceName, Alerts = alerts });
                }
                return services;
            }
    
            /// <summary>
            /// 获取服务下的跟踪条目
            /// </summary>
            /// <param name="serviceName"></param>
            /// <returns></returns>
            async Task<TracesData> GetJaegerTraces(string serviceName)
            {
                using var client = _clientFactory.CreateClient("Jaeger");
                var request = new HttpRequestMessage(HttpMethod.Get, $"/api/traces?service={serviceName}");
    
                using var response = await client.SendAsync(request);
                if (response.IsSuccessStatusCode)
                {
                    var jsonString = await response.Content.ReadAsStringAsync();
                    var traces = Newtonsoft.Json.JsonConvert.DeserializeObject<TracesData>(jsonString);
                    return traces;
                }
                else
                {
                    return new TracesData();
                }
            }
            /// <summary>
            /// 获取服务
            /// </summary>
            /// <returns></returns>
            async Task<ServicesData> GetJaegerServices()
            {
                using var client = _clientFactory.CreateClient("Jaeger");
                var request = new HttpRequestMessage(HttpMethod.Get, "/api/services");
                using var response = await client.SendAsync(request);
                if (response.IsSuccessStatusCode)
                {
                    var jsonString = await response.Content.ReadAsStringAsync();
                    var service = Newtonsoft.Json.JsonConvert.DeserializeObject<ServicesData>(jsonString);
                    return service;
                }
                else
                {
                    return new ServicesData();
                }
            }
        }   
    }

    请求结果:

      收集到数据后,就可以应用到报警平台上,如果报警平台有api,可以进行调用处理;还可以把这些数据推送到时序数据库中,如InfluxDB,再通过Grafana展示出来,进行实时展时跟踪,关于跟踪的细节和业务规则有关系,如果以后工作中遇到这类处理,到时再追加一篇博文进行细说。

      想要更快更方便的了解相关知识,可以关注微信公众号 
     

     

  • 相关阅读:
    Jenkins构建.NetFramework项目
    【转】linux docker 中实现某些程序段开机自启动
    SQL SERVER之查询 未创建索引的外键 和 所有外键及索引
    进入蓝牙协议开发领域外加ELink电子标签开发
    WPF DevExpress中GridControl动态修改行背景颜色 借用的
    新中新身份证阅读器 无法加载 DLL“SynIDCardAPI.dll”: 找不到指定的程序。 (异常来自 HRESULT:0x8007007F)。
    VS项目删除Git、不想用Git、
    Android 生成二维码
    [WPF 学习] 20. 增量更新续——用阿里云对象存储OSS
    RabbitMQ安装
  • 原文地址:https://www.cnblogs.com/axzxs2001/p/15860685.html
Copyright © 2020-2023  润新知