環境:Core:3.1的專案
說明:由於該方案為個人測試專案,重啟時佇列中的部分資料很可能會丟失,
對資料有要求的該方案不適用,不能照搬需要持久化處理,
另外發布到Linux Docker中通常不會自動回收,但是釋出到IIS中需要簡單設定不回收即可!!! 如下截圖:
在IIS中找到這個站點所用的程式池,點選 高階設定。。。
回收——固定時間間隔 修改為 0
回收——虛擬/專用記憶體限制 修改為 0
程序模型——閒置超時 修改為 0
1:先來看效果
1.1:操作紀錄檔資料到表
1.2:操作紀錄檔資料到檔案
2:過濾器
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Filters; using System.Text; using System.Diagnostics; using QzjcService.Models.Dto.LogModels; using QzjcService.Controllers; using SqlSugar.IOC; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using QzjcService.Helper; using Microsoft.AspNetCore.Mvc; using QzjcService.Models; namespace QzjcService.Filters { public class ActionNewLogFilter : ActionFilterAttribute { private static Stopwatch _watting = new Stopwatch(); public static double? longtime = 0; private ActionLogModel log = new ActionLogModel(); private readonly ILogger<ActionNewLogFilter> _logger; public ActionNewLogFilter(ILogger<ActionNewLogFilter> logger) { _logger = logger; } public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { _watting.Start(); string controllerName = context.ActionDescriptor.RouteValues["controller"]; string actionName = context.ActionDescriptor.RouteValues["action"]; string method = context.HttpContext.Request.Method;//請求方式 string queryString = context.HttpContext.Request.QueryString.Value;//地址引數 string argments = JsonConvert.SerializeObject(context.ActionArguments); string url = context.HttpContext.Request.Host + context.HttpContext.Request.Path;//介面地址 var logStr = string.Format("\r\n【介面地址】:{0} \r\n【請求方式】:{1} \r\n【地址引數】:{2} \r\n【Body引數】:{3}", new object[] { url, method, queryString, argments }); log.ControllerName = controllerName; log.ActionName = actionName; //請求方式 0:get, 1:Post log.Menthod = (method.Equals("get", StringComparison.InvariantCultureIgnoreCase) || method.Equals("httpget", StringComparison.InvariantCultureIgnoreCase)) ? 0 : 1; log.CreateTime = DateTime.Now; log.RequstParms = logStr; var _context = context.HttpContext; if (_context != null) { var tokenStr = context.HttpContext.Request.Headers[ConstData.Authorization].ToString(); log.userId = string.IsNullOrEmpty(tokenStr) ? 0 : TokenHelper.GetUserModel(context.HttpContext)?.UserId; } await base.OnActionExecutionAsync(context, next); } public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { _watting.Stop(); longtime = 0; if (context.Result is ObjectResult result) { if (result != null) log.ResposeParam = JsonConvert.SerializeObject(result.Value); } longtime = _watting.Elapsed.TotalMilliseconds; log.LongTimeMs = longtime.Value; _watting.Reset(); log.RequstParms += "\r\n【響應引數】:" + log.ResposeParam + "\r\n============================================"; _logger.LogCritical(log.RequstParms); // await DbScoped.Sugar.Insertable<ActionLogModel>(log).ExecuteCommandAsync(); await LogQueueHelper.EnQueueLogAsync(log); await base.OnResultExecutionAsync(context, next); } } }
3:後臺自帶的定時器
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using QzjcService.Helper; using QzjcService.Models.Dto.LogModels; using SqlSugar.IOC; using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; namespace QzjcService.Services { public class LogTimeService : BackgroundService { private readonly ILogger<LogTimeService> _logger; public LogTimeService(ILogger<LogTimeService> logger ) { _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await Task.Factory.StartNew(async () => { while (!stoppingToken.IsCancellationRequested) { try { var model = await LogQueueHelper.DeQueueLogAsync(); if (model != null) { Console.WriteLine($"===={DateTime.Now}=LogTimeService=DeQueueLog Success===="); await DbScoped.Sugar.Insertable<ActionLogModel>(model).ExecuteCommandAsync(); } await Task.Delay(3000); } catch (Exception ex) { _logger.LogError($"====={DateTime.Now}===LogTimeService異常:=={ex.Message}=========="); continue; } } }); } } }
4:Log記錄Model
using SqlSugar; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Threading.Tasks; namespace QzjcService.Models.Dto.LogModels { [Table("qzjc_action_loginfos")] [SugarTable("qzjc_action_loginfos")] public class ActionLogModel { /// <summary> /// /// </summary> [Column("id")] [SugarColumn(ColumnName = "id")] public int id { get; set; } /// <summary> /// /// </summary> [Column("controller_name")] [SugarColumn(ColumnName = "controller_name")] public string ControllerName { get; set; } /// <summary> /// /// </summary> [Column("action_name")] [SugarColumn(ColumnName = "action_name")] public string ActionName { get; set; } /// <summary> /// /// </summary> [Column("request_parms")] [SugarColumn(ColumnName = "request_parms")] public string RequstParms { get; set; } /// <summary> /// /// </summary> [Column("long_time")] [SugarColumn(ColumnName = "long_time")] public double LongTimeMs { get; set; } /// <summary> /// /// </summary> [Column("create_time")] [SugarColumn(ColumnName = "create_time")] public DateTime CreateTime { get; set; } /// <summary> /// /// </summary> [Column("create_userid")] [SugarColumn(ColumnName = "create_userid")] public int? userId { get; set; } [Column("menthod")] [SugarColumn(ColumnName ="")] public int? Menthod { get; set; } //[Column("state")] //[SugarColumn(ColumnName = "state")] //public int? State { get; set; } [Column("respose_parms")] [SugarColumn(ColumnName = "respose_parms")] public string ResposeParam { get; set; } } }
5:貼上系統自帶的佇列Queue
using QzjcService.Models.Dto.LogModels; using System.Collections; using System.Threading.Channels; using System.Threading.Tasks; namespace QzjcService.Helper { public static class LogQueueHelper { public static Queue queue; private static readonly object Lock = new object(); static LogQueueHelper() { queue = new Queue(); } /// <summary> /// /// </summary> /// <returns></returns> private static async Task<Queue> GetQueueAsync() { if (queue == null) { lock (Lock) { if (queue == null) queue = new Queue(); } } await Task.CompletedTask; return queue; } public static async Task<bool> EnQueueLogAsync(ActionLogModel model) { try { queue = await GetQueueAsync(); queue.Enqueue(model); return true; } catch (System.Exception) { return false; } } public static async Task<ActionLogModel> DeQueueLogAsync() { try { queue = await GetQueueAsync(); object obj = queue.Dequeue(); if (obj != null) { ActionLogModel model = obj as ActionLogModel; return model ?? null; } return null; } catch (System.Exception) { return null; } } } }
6:這裡也貼出Serilog相關code
using System; using System.IO; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Configuration; using Serilog; using Serilog.Events; namespace QzjcService { public class Program { public static void Main(string[] args) { string dataTime = DateTime.Now.ToString("yyyy-MM-dd");//這裡去掉更好,讓其自增長 string fileStr = $"Logs/{dataTime}_logs.txt"; Log.Logger = new LoggerConfiguration() .MinimumLevel.Warning() //Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("System", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning) .Enrich.FromLogContext() .WriteTo.Async(c => c.File(fileStr, rollOnFileSizeLimit: true, fileSizeLimitBytes: 1024 * 1024 * 10, retainedFileCountLimit: 30)) .CreateLogger(); try { Log.Information("=========Starting web host=========="); CreateHostBuilder(args).Build().Run(); } catch (Exception ex) { Log.Fatal(ex, "Host terminated unexpectedly!"); } finally { Log.CloseAndFlush(); } } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureLogging((hostingContext, builder) => { builder.ClearProviders(); }) .ConfigureWebHostDefaults(webBuilder => { webBuilder.ConfigureKestrel(c => { c.Limits.MaxRequestBodySize = 1024 * 1024 * 300; }); webBuilder.UseUrls("http://*:4444"); webBuilder.UseStartup<Startup>(); }) .UseSerilog(); } }
<PackageReference Include="Serilog.Extensions.Hosting" Version="3.1.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.2.0" />
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
好了今天就先到這裡,下次有時間再更新,如果存在不合理的地方,歡迎大家多多指教留言!!!
我的部落格園地址:https://www.cnblogs.com/Fengge518