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展示出來,進行實時展時跟蹤,關於跟蹤的細節和業務規則有關係,如果以後工作中遇到這類處理,到時再追加一篇博文進行細說。