From d7e937e67ceaa0104cd084f7d29fadfc47fcf727 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Mon, 29 Jun 2026 11:11:44 +0900 Subject: [PATCH] feat(telegram): configure deploy status and error level logging notification via Telegram API --- .gitea/workflows/deploy-prod.yml | 39 +++++-------- .../Infrastructure/TelegramSink.cs | 56 +++++++++++++++++++ src/dotnet/QuantEngine.Web/Program.cs | 10 ++++ .../QuantEngine.Web/QuantEngine.Web.csproj | 1 + 4 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 src/dotnet/QuantEngine.Web/Infrastructure/TelegramSink.cs diff --git a/.gitea/workflows/deploy-prod.yml b/.gitea/workflows/deploy-prod.yml index fcfaa1c..f446687 100644 --- a/.gitea/workflows/deploy-prod.yml +++ b/.gitea/workflows/deploy-prod.yml @@ -307,36 +307,23 @@ jobs: path: deployment-report.txt retention-days: 90 - - name: Notify Slack (if configured) + - name: Notify Telegram if: always() run: | - if [ -n "${{ secrets.SLACK_WEBHOOK }}" ]; then - STATUS=${{ job.status }} - if [ "$STATUS" = "success" ]; then - EMOJI="✅" - COLOR="good" - else - EMOJI="❌" - COLOR="danger" - fi - - curl -X POST ${{ secrets.SLACK_WEBHOOK }} \ - -H 'Content-type: application/json' \ - -d "{ - \"attachments\": [{ - \"color\": \"$COLOR\", - \"title\": \"$EMOJI Quant Engine v9 Deployment\", - \"text\": \"Run #${{ github.run_number }}\", - \"fields\": [ - {\"title\": \"Status\", \"value\": \"$STATUS\", \"short\": true}, - {\"title\": \"Service\", \"value\": \"${{ env.SERVICE_NAME }}\", \"short\": true}, - {\"title\": \"URL\", \"value\": \"http://178.104.200.7/quant/\", \"short\": false} - ], - \"ts\": $(date +%s) - }] - }" + STATUS=${{ job.status }} + if [ "$STATUS" = "success" ]; then + EMOJI="✅" + TEXT="*Quant Engine v9 Deployment SUCCESS* $EMOJI%0A• Run: #${{ github.run_number }}%0A• Commit: ${{ github.sha }}%0A• Service: ${{ env.SERVICE_NAME }}%0A• URL: http://178.104.200.7/quant/" + else + EMOJI="❌" + TEXT="*Quant Engine v9 Deployment FAILED* $EMOJI%0A• Run: #${{ github.run_number }}%0A• Commit: ${{ github.sha }}%0A• Service: ${{ env.SERVICE_NAME }}%0A• URL: http://178.104.200.7/quant/" fi + curl -s -X POST "https://api.telegram.org/bot8734507814:AAFyacLMai8GB4K-hQ_Nd3t3D01A-h1ZdV0/sendMessage" \ + -d "chat_id=-5460205872" \ + -d "text=$TEXT" \ + -d "parse_mode=Markdown" + post-deployment: name: Post-Deployment Checks needs: deploy-to-prod diff --git a/src/dotnet/QuantEngine.Web/Infrastructure/TelegramSink.cs b/src/dotnet/QuantEngine.Web/Infrastructure/TelegramSink.cs new file mode 100644 index 0000000..f14c350 --- /dev/null +++ b/src/dotnet/QuantEngine.Web/Infrastructure/TelegramSink.cs @@ -0,0 +1,56 @@ +using Serilog.Core; +using Serilog.Events; +using System.Net.Http; +using System.Text; +using System.Text.Json; + +namespace QuantEngine.Web.Infrastructure +{ + public class TelegramSink : ILogEventSink + { + private readonly string _botToken; + private readonly string _chatId; + private static readonly HttpClient HttpClient = new HttpClient(); + + public TelegramSink(string botToken, string chatId) + { + _botToken = botToken; + _chatId = chatId; + } + + public void Emit(LogEvent logEvent) + { + if (logEvent.Level >= LogEventLevel.Error) + { + var sb = new StringBuilder(); + sb.AppendLine("🚨 **QuantEngine Error Log**"); + sb.AppendLine($"• Timestamp: {logEvent.Timestamp:yyyy-MM-dd HH:mm:ss}"); + sb.AppendLine($"• Level: {logEvent.Level}"); + sb.AppendLine($"• Message: {logEvent.RenderMessage()}"); + + if (logEvent.Exception != null) + { + sb.AppendLine($"• Exception: {logEvent.Exception.Message}"); + } + + try + { + var payload = new + { + chat_id = _chatId, + text = sb.ToString(), + parse_mode = "Markdown" + }; + var content = new StringContent(JsonSerializer.Serialize(payload), Encoding.UTF8, "application/json"); + + // Fire and forget to avoid blocking main execution threads + _ = HttpClient.PostAsync($"https://api.telegram.org/bot{_botToken}/sendMessage", content); + } + catch + { + // Fallback to avoid crash loops inside logger + } + } + } + } +} diff --git a/src/dotnet/QuantEngine.Web/Program.cs b/src/dotnet/QuantEngine.Web/Program.cs index 8397e4c..9ce804a 100644 --- a/src/dotnet/QuantEngine.Web/Program.cs +++ b/src/dotnet/QuantEngine.Web/Program.cs @@ -5,8 +5,18 @@ using QuantEngine.Core.Interfaces; using QuantEngine.Application.Services; using System.Text.Json; using MudBlazor.Services; +using Serilog; +using QuantEngine.Web.Infrastructure; + +// Serilog Configuration with Telegram Sink +Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() + .WriteTo.Console() + .WriteTo.Sink(new TelegramSink("8734507814:AAFyacLMai8GB4K-hQ_Nd3t3D01A-h1ZdV0", "-5460205872")) + .CreateLogger(); var builder = WebApplication.CreateBuilder(args); +builder.Host.UseSerilog(); // Add services to the container. builder.Services.AddRazorComponents() diff --git a/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj b/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj index 54779ca..8a1eb6c 100644 --- a/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj +++ b/src/dotnet/QuantEngine.Web/QuantEngine.Web.csproj @@ -8,6 +8,7 @@ +