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展示出来,进行实时展时跟踪,关于跟踪的细节和业务规则有关系,如果以后工作中遇到这类处理,到时再追加一篇博文进行细说。