using Google.Protobuf; using Grpc.Core.Interceptors; using Microsoft.Extensions.Logging; using CMSMicroservice.Application.Common.Interfaces; using System.Text.RegularExpressions; namespace CMSMicroservice.WebApi.Common.Behaviours; public partial class LoggingBehaviour : Interceptor { private readonly ILogger _logger; private readonly ICurrentUserService _currentUserService; // فیلدهایی که نباید لاگ شوند (بایت‌های تصویر / فایل) [GeneratedRegex(@"""(File|ImageFile|image_file|file)"":\s*\{[^}]*\}", RegexOptions.Singleline)] private static partial Regex BinaryFieldPattern(); public LoggingBehaviour(ILogger logger, ICurrentUserService currentUserService) { _logger = logger; _currentUserService = currentUserService; } public override async Task UnaryServerHandler( TRequest request, ServerCallContext context, UnaryServerMethod continuation) { var requestName = typeof(TRequest).Name; var userId = _currentUserService.UserId ?? string.Empty; // لاگ بدون بایت‌های فایل var safeLog = SanitizeForLog(request); _logger.LogInformation("gRPC Starting receiving call. Type/Method: {Type} / {Method} Request: {Name} {UserId} {Request}", MethodType.Unary, context.Method, requestName, userId, safeLog); try { return await continuation(request, context); } catch (Exception ex) { _logger.LogError(ex, "gRPC Request: Unhandled Exception for Request {Name} {Request}", requestName, safeLog); throw; } } /// /// حذف بایت‌های فایل از لاگ — جایگزینی با [BINARY DATA] /// private static string SanitizeForLog(T request) { if (request is IMessage protoMessage) { var json = JsonFormatter.Default.Format(protoMessage); // حذف محتوای فیلدهای باینری json = BinaryFieldPattern().Replace(json, "\"$1\": \"[BINARY DATA]\""); // اگر هنوز رشته‌های base64 طولانی هست، خلاصه کن if (json.Length > 2000) return json[..2000] + "... [TRUNCATED]"; return json; } return request?.ToString() ?? ""; } }