using Microsoft.ApplicationInsights.DataContracts; using System.Text; using System.Text.Json; namespace Core.Telemetry { public record SeqConfiguration(string IngestionEndpoint, string ApiKey, string Environment); public class SeqHttpClient { HttpClient _httpClient; public SeqHttpClient(SeqConfiguration seqConfiguration) { _httpClient = new HttpClient() { BaseAddress = new Uri("http://localhost:5341"), Timeout = TimeSpan.FromSeconds(30) }; _httpClient.DefaultRequestHeaders.Accept.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); if (seqConfiguration.ApiKey != null) _httpClient.DefaultRequestHeaders.Add("X-Seq-ApiKey", seqConfiguration.ApiKey); } public async Task SendAsync(HttpRequestMessage httpRequestMessage, CancellationToken cancellationToken) { return await _httpClient.SendAsync(httpRequestMessage, cancellationToken); } } public class SeqLogger { private readonly SeqHttpClient _httpClient; private readonly string _environmentName; private readonly string _machineName; private readonly SeqConfiguration _configuration; public SeqLogger(SeqHttpClient httpClient, string environmentName, SeqConfiguration configuration) { _httpClient = httpClient; _environmentName = configuration.Environment; _machineName = Environment.MachineName; } public async Task LogTraceTelemetryAsync(TraceTelemetry trace, CancellationToken cancellationToken = default) { var seqEvent = new Dictionary { { "@t", trace.Timestamp.UtcDateTime.ToString("o") }, { "@mt", trace.Message }, { "@l", MapSeverityToLevel(trace.SeverityLevel) }, { "Environment", _environmentName }, { "MachineName", _machineName } }; foreach (var prop in trace.Properties) { seqEvent.Add(prop.Key, prop.Value); } await SendToSeqAsync(seqEvent, cancellationToken); } public async Task LogEventTelemetryAsync(EventTelemetry evt, CancellationToken cancellationToken = default) { var seqEvent = new Dictionary { { "@t", evt.Timestamp.UtcDateTime.ToString("o") }, { "@mt", evt.Name }, { "@l", "Information" }, { "Environment", _environmentName }, { "MachineName", _machineName } }; foreach (var prop in evt.Properties) { seqEvent.Add(prop.Key, prop.Value); } foreach (var metric in evt.Metrics) { seqEvent.Add($"metric_{metric.Key}", metric.Value); } await SendToSeqAsync(seqEvent, cancellationToken); } public async Task LogExceptionTelemetryAsync(ExceptionTelemetry ex, CancellationToken cancellationToken = default) { var seqEvent = new Dictionary { { "@t", ex.Timestamp.UtcDateTime.ToString("o") }, { "@mt", ex.Exception.Message }, { "@l", "Error" }, { "Environment", _environmentName }, { "MachineName", _machineName }, { "ExceptionType", ex.Exception.GetType().Name }, { "StackTrace", ex.Exception.StackTrace } }; foreach (var prop in ex.Properties) { seqEvent.Add(prop.Key, prop.Value); } await SendToSeqAsync(seqEvent, cancellationToken); } public async Task LogDependencyTelemetryAsync(DependencyTelemetry dep, CancellationToken cancellationToken = default) { var seqEvent = new Dictionary { { "@t", dep.Timestamp.UtcDateTime.ToString("o") }, { "@mt", $"Dependency: {dep.Name}" }, { "@l", dep.Success??true ? "Information" : "Error" }, { "Environment", _environmentName }, { "MachineName", _machineName }, { "DependencyType", dep.Type }, { "Target", dep.Target }, { "Duration", dep.Duration.TotalMilliseconds } }; foreach (var prop in dep.Properties) { seqEvent.Add(prop.Key, prop.Value); } await SendToSeqAsync(seqEvent, cancellationToken); } public async Task LogRequestTelemetryAsync(RequestTelemetry req, CancellationToken cancellationToken = default) { var seqEvent = new Dictionary { { "@t", req.Timestamp.UtcDateTime.ToString("o") }, { "@mt", $"Request: {req.Name}" }, { "@l", req.Success??true ? "Information" : "Error" }, { "Environment", _environmentName }, { "MachineName", _machineName }, { "Url", req.Url }, { "ResponseCode", req.ResponseCode }, { "Duration", req.Duration.TotalMilliseconds } }; foreach (var prop in req.Properties) { seqEvent.Add(prop.Key, prop.Value); } await SendToSeqAsync(seqEvent, cancellationToken); } private async Task SendToSeqAsync(Dictionary seqEvent, CancellationToken cancellationToken) { var content = new StringContent( Newtonsoft.Json.JsonConvert.SerializeObject(seqEvent), Encoding.UTF8, "application/vnd.serilog.clef"); var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/ingest/clef") { Content = content }; await _httpClient.SendAsync(requestMessage, cancellationToken); } private string MapSeverityToLevel(SeverityLevel? severity) { return severity switch { SeverityLevel.Verbose => "Verbose", SeverityLevel.Information => "Information", SeverityLevel.Warning => "Warning", SeverityLevel.Error => "Error", SeverityLevel.Critical => "Fatal", _ => "Information" }; } } }